16fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org#!/usr/bin/python 26fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org# 36fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org# Copyright (c) 2009 Google Inc. All rights reserved. 46fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org# 56fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org# Redistribution and use in source and binary forms, with or without 66fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org# modification, are permitted provided that the following conditions are 76fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org# met: 86fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org# 96fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org# * Redistributions of source code must retain the above copyright 106fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org# notice, this list of conditions and the following disclaimer. 116fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org# * Redistributions in binary form must reproduce the above 126fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org# copyright notice, this list of conditions and the following disclaimer 136fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org# in the documentation and/or other materials provided with the 146fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org# distribution. 156fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org# * Neither the name of Google Inc. nor the names of its 166fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org# contributors may be used to endorse or promote products derived from 176fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org# this software without specific prior written permission. 186fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org# 196fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 206fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 216fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 226fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 236fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 246fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 256fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 266fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 276fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 286fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 296fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 306fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 316fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org"""Does google-lint on c++ files. 326fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 336fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.orgThe goal of this script is to identify places in the code that *may* 346fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.orgbe in non-compliance with google style. It does not attempt to fix 356fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.orgup these problems -- the point is to educate. It does also not 366fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.orgattempt to find all problems, or to ensure that everything it does 376fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.orgfind is legitimately a problem. 386fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 396fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.orgIn particular, we can get very confused by /* and // inside strings! 406fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.orgWe do a small hack, which is to ignore //'s with "'s after them on the 416fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.orgsame line, but it is far from perfect (in either direction). 426fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org""" 436fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 446fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.orgimport codecs 4510a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.orgimport copy 466fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.orgimport getopt 476fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.orgimport math # for log 486fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.orgimport os 496fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.orgimport re 506fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.orgimport sre_compile 516fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.orgimport string 526fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.orgimport sys 536fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.orgimport unicodedata 546fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 556fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 566fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org_USAGE = """ 576fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.orgSyntax: cpplint.py [--verbose=#] [--output=vs7] [--filter=-x,+y,...] 58dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org [--counting=total|toplevel|detailed] [--root=subdir] 59dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org [--linelength=digits] 606fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org <file> [file] ... 616fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 626fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org The style guidelines this tries to follow are those in 636fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml 646fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 656fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org Every problem is given a confidence score from 1-5, with 5 meaning we are 666fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org certain of the problem, and 1 meaning it could be a legitimate construct. 676fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org This will miss some errors, and is not a substitute for a code review. 686fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 696fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org To suppress false-positive errors of a certain category, add a 706fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'NOLINT(category)' comment to the line. NOLINT or NOLINT(*) 716fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org suppresses errors of all categories on that line. 726fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 736fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org The files passed in will be linted; at least one file must be provided. 74dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org Default linted extensions are .cc, .cpp, .cu, .cuh and .h. Change the 75dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org extensions with the --extensions flag. 766fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 776fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org Flags: 786fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 796fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org output=vs7 806fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org By default, the output is formatted to ease emacs parsing. Visual Studio 816fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org compatible output (vs7) may also be used. Other formats are unsupported. 826fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 836fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org verbose=# 846fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org Specify a number 0-5 to restrict errors to certain verbosity levels. 856fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 866fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org filter=-x,+y,... 876fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org Specify a comma-separated list of category-filters to apply: only 886fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org error messages whose category names pass the filters will be printed. 896fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org (Category names are printed with the message and look like 906fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org "[whitespace/indent]".) Filters are evaluated left to right. 916fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org "-FOO" and "FOO" means "do not print categories that start with FOO". 926fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org "+FOO" means "do print categories that start with FOO". 936fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 946fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org Examples: --filter=-whitespace,+whitespace/braces 956fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org --filter=whitespace,runtime/printf,+runtime/printf_format 966fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org --filter=-,+build/include_what_you_use 976fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 986fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org To see a list of all the categories used in cpplint, pass no arg: 996fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org --filter= 1006fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 1016fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org counting=total|toplevel|detailed 1026fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org The total number of errors found is always printed. If 1036fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'toplevel' is provided, then the count of errors in each of 1046fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org the top-level categories like 'build' and 'whitespace' will 1056fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org also be printed. If 'detailed' is provided, then a count 1066fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org is provided for each category like 'build/class'. 10710a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org 10810a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org root=subdir 10910a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org The root directory used for deriving header guard CPP variable. 11010a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org By default, the header guard CPP variable is calculated as the relative 11110a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org path to the directory that contains .git, .hg, or .svn. When this flag 11210a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org is specified, the relative path is calculated from the specified 11310a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org directory. If the specified directory does not exist, this flag is 11410a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org ignored. 11510a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org 11610a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org Examples: 11710a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org Assuing that src/.git exists, the header guard CPP variables for 11810a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org src/chrome/browser/ui/browser.h are: 11910a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org 12010a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org No flag => CHROME_BROWSER_UI_BROWSER_H_ 12110a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org --root=chrome => BROWSER_UI_BROWSER_H_ 12210a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org --root=chrome/browser => UI_BROWSER_H_ 123dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 124dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org linelength=digits 125dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org This is the allowed line length for the project. The default value is 126dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 80 characters. 127dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 128dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org Examples: 129dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org --linelength=120 130dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 131dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org extensions=extension,extension,... 132dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org The allowed file extensions that cpplint will check 133dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 134dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org Examples: 135dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org --extensions=hpp,cpp 1366fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org""" 1376fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 1386fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org# We categorize each error message we print. Here are the categories. 1396fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org# We want an explicit list so we can list them all in cpplint --filter=. 1406fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org# If you add a new error message with a new category, add it to the list 1416fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org# here! cpplint_unittest.py should tell you if you forget to do this. 1426fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org_ERROR_CATEGORIES = [ 1436fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'build/class', 1446fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'build/deprecated', 1456fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'build/endif_comment', 1466fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'build/explicit_make_pair', 1476fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'build/forward_decl', 1486fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'build/header_guard', 1496fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'build/include', 1506fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'build/include_alpha', 1516fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'build/include_order', 1526fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'build/include_what_you_use', 1536fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'build/namespaces', 1546fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'build/printf_format', 1556fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'build/storage_class', 1566fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'legal/copyright', 15710a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org 'readability/alt_tokens', 1586fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'readability/braces', 1596fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'readability/casting', 1606fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'readability/check', 1616fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'readability/constructors', 1626fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'readability/fn_size', 1636fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'readability/function', 1646fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'readability/multiline_comment', 1656fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'readability/multiline_string', 16610a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org 'readability/namespace', 1676fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'readability/nolint', 168dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'readability/nul', 1696fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'readability/streams', 1706fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'readability/todo', 1716fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'readability/utf8', 1726fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'runtime/arrays', 1736fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'runtime/casting', 1746fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'runtime/explicit', 1756fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'runtime/int', 1766fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'runtime/init', 1776fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'runtime/invalid_increment', 1786fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'runtime/member_string_references', 1796fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'runtime/memset', 1806fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'runtime/operator', 1816fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'runtime/printf', 1826fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'runtime/printf_format', 1836fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'runtime/references', 1846fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'runtime/sizeof', 1856fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'runtime/string', 1866fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'runtime/threadsafe_fn', 187dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'runtime/vlog', 1886fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'whitespace/blank_line', 1896fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'whitespace/braces', 1906fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'whitespace/comma', 1916fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'whitespace/comments', 192dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'whitespace/empty_conditional_body', 19310a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org 'whitespace/empty_loop_body', 1946fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'whitespace/end_of_line', 1956fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'whitespace/ending_newline', 19610a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org 'whitespace/forcolon', 1976fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'whitespace/indent', 1986fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'whitespace/line_length', 1996fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'whitespace/newline', 2006fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'whitespace/operators', 2016fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'whitespace/parens', 2026fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'whitespace/semicolon', 2036fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'whitespace/tab', 2046fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'whitespace/todo' 2056fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org ] 2066fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 2076fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org# The default state of the category filter. This is overrided by the --filter= 2086fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org# flag. By default all errors are on, so only add here categories that should be 2096fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org# off by default (i.e., categories that must be enabled by the --filter= flags). 2106fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org# All entries here should start with a '-' or '+', as in the --filter= flag. 2116fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org_DEFAULT_FILTERS = ['-build/include_alpha'] 2126fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 2136fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org# We used to check for high-bit characters, but after much discussion we 2146fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org# decided those were OK, as long as they were in UTF-8 and didn't represent 2156fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org# hard-coded international strings, which belong in a separate i18n file. 2166fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 2176fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 218dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org# C++ headers 2196fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org_CPP_HEADERS = frozenset([ 220dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # Legacy 221dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'algobase.h', 222dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'algo.h', 223dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'alloc.h', 224dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'builtinbuf.h', 225dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'bvector.h', 226dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'complex.h', 227dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'defalloc.h', 228dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'deque.h', 229dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'editbuf.h', 230dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'fstream.h', 231dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'function.h', 232dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'hash_map', 233dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'hash_map.h', 234dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'hash_set', 235dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'hash_set.h', 236dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'hashtable.h', 237dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'heap.h', 238dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'indstream.h', 239dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'iomanip.h', 240dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'iostream.h', 241dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'istream.h', 242dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'iterator.h', 243dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'list.h', 244dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'map.h', 245dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'multimap.h', 246dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'multiset.h', 247dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'ostream.h', 248dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'pair.h', 249dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'parsestream.h', 250dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'pfstream.h', 251dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'procbuf.h', 252dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'pthread_alloc', 253dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'pthread_alloc.h', 254dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'rope', 255dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'rope.h', 256dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'ropeimpl.h', 257dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'set.h', 258dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'slist', 259dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'slist.h', 260dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'stack.h', 261dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'stdiostream.h', 262dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'stl_alloc.h', 263dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'stl_relops.h', 264dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'streambuf.h', 265dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'stream.h', 266dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'strfile.h', 267dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'strstream.h', 268dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'tempbuf.h', 269dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'tree.h', 270dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'type_traits.h', 271dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'vector.h', 272dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # 17.6.1.2 C++ library headers 273dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'algorithm', 274dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'array', 275dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'atomic', 276dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'bitset', 277dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'chrono', 278dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'codecvt', 279dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'complex', 280dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'condition_variable', 281dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'deque', 282dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'exception', 283dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'forward_list', 284dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'fstream', 285dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'functional', 286dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'future', 287dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'initializer_list', 288dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'iomanip', 289dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'ios', 290dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'iosfwd', 291dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'iostream', 292dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'istream', 293dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'iterator', 294dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'limits', 295dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'list', 296dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'locale', 297dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'map', 298dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'memory', 299dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'mutex', 300dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'new', 301dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'numeric', 302dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'ostream', 303dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'queue', 304dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'random', 305dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'ratio', 306dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'regex', 307dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'set', 308dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'sstream', 309dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'stack', 310dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'stdexcept', 311dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'streambuf', 312dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'string', 313dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'strstream', 314dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'system_error', 315dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'thread', 316dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'tuple', 317dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'typeindex', 318dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'typeinfo', 319dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'type_traits', 320dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'unordered_map', 321dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'unordered_set', 322dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'utility', 323dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'valarray', 324dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'vector', 325dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # 17.6.1.2 C++ headers for C library facilities 326dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'cassert', 327dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'ccomplex', 328dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'cctype', 329dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'cerrno', 330dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'cfenv', 331dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'cfloat', 332dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'cinttypes', 333dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'ciso646', 334dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'climits', 335dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'clocale', 336dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'cmath', 337dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'csetjmp', 338dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'csignal', 339dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'cstdalign', 340dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'cstdarg', 341dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'cstdbool', 342dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'cstddef', 343dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'cstdint', 344dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'cstdio', 345dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'cstdlib', 346dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'cstring', 347dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'ctgmath', 348dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'ctime', 349dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'cuchar', 350dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'cwchar', 351dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'cwctype', 3526fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org ]) 3536fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 3546fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org# Assertion macros. These are defined in base/logging.h and 3556fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org# testing/base/gunit.h. Note that the _M versions need to come first 3566fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org# for substring matching to work. 3576fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org_CHECK_MACROS = [ 3586fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'DCHECK', 'CHECK', 3596fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'EXPECT_TRUE_M', 'EXPECT_TRUE', 3606fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'ASSERT_TRUE_M', 'ASSERT_TRUE', 3616fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'EXPECT_FALSE_M', 'EXPECT_FALSE', 3626fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'ASSERT_FALSE_M', 'ASSERT_FALSE', 3636fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org ] 3646fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 3656fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org# Replacement macros for CHECK/DCHECK/EXPECT_TRUE/EXPECT_FALSE 3666fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org_CHECK_REPLACEMENT = dict([(m, {}) for m in _CHECK_MACROS]) 3676fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 3686fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.orgfor op, replacement in [('==', 'EQ'), ('!=', 'NE'), 3696fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org ('>=', 'GE'), ('>', 'GT'), 3706fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org ('<=', 'LE'), ('<', 'LT')]: 3716fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org _CHECK_REPLACEMENT['DCHECK'][op] = 'DCHECK_%s' % replacement 3726fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org _CHECK_REPLACEMENT['CHECK'][op] = 'CHECK_%s' % replacement 3736fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org _CHECK_REPLACEMENT['EXPECT_TRUE'][op] = 'EXPECT_%s' % replacement 3746fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org _CHECK_REPLACEMENT['ASSERT_TRUE'][op] = 'ASSERT_%s' % replacement 3756fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org _CHECK_REPLACEMENT['EXPECT_TRUE_M'][op] = 'EXPECT_%s_M' % replacement 3766fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org _CHECK_REPLACEMENT['ASSERT_TRUE_M'][op] = 'ASSERT_%s_M' % replacement 3776fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 3786fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.orgfor op, inv_replacement in [('==', 'NE'), ('!=', 'EQ'), 3796fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org ('>=', 'LT'), ('>', 'LE'), 3806fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org ('<=', 'GT'), ('<', 'GE')]: 3816fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org _CHECK_REPLACEMENT['EXPECT_FALSE'][op] = 'EXPECT_%s' % inv_replacement 3826fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org _CHECK_REPLACEMENT['ASSERT_FALSE'][op] = 'ASSERT_%s' % inv_replacement 3836fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org _CHECK_REPLACEMENT['EXPECT_FALSE_M'][op] = 'EXPECT_%s_M' % inv_replacement 3846fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org _CHECK_REPLACEMENT['ASSERT_FALSE_M'][op] = 'ASSERT_%s_M' % inv_replacement 3856fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 38610a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org# Alternative tokens and their replacements. For full list, see section 2.5 38710a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org# Alternative tokens [lex.digraph] in the C++ standard. 38810a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org# 38910a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org# Digraphs (such as '%:') are not included here since it's a mess to 39010a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org# match those on a word boundary. 39110a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org_ALT_TOKEN_REPLACEMENT = { 39210a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org 'and': '&&', 39310a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org 'bitor': '|', 39410a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org 'or': '||', 39510a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org 'xor': '^', 39610a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org 'compl': '~', 39710a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org 'bitand': '&', 39810a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org 'and_eq': '&=', 39910a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org 'or_eq': '|=', 40010a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org 'xor_eq': '^=', 40110a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org 'not': '!', 40210a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org 'not_eq': '!=' 40310a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org } 40410a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org 40510a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org# Compile regular expression that matches all the above keywords. The "[ =()]" 40610a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org# bit is meant to avoid matching these keywords outside of boolean expressions. 40710a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org# 408dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org# False positives include C-style multi-line comments and multi-line strings 409dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org# but those have always been troublesome for cpplint. 41010a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org_ALT_TOKEN_REPLACEMENT_PATTERN = re.compile( 41110a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org r'[ =()](' + ('|'.join(_ALT_TOKEN_REPLACEMENT.keys())) + r')(?=[ (]|$)') 41210a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org 4136fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 4146fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org# These constants define types of headers for use with 4156fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org# _IncludeState.CheckNextIncludeOrder(). 4166fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org_C_SYS_HEADER = 1 4176fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org_CPP_SYS_HEADER = 2 4186fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org_LIKELY_MY_HEADER = 3 4196fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org_POSSIBLE_MY_HEADER = 4 4206fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org_OTHER_HEADER = 5 4216fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 42210a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org# These constants define the current inline assembly state 42310a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org_NO_ASM = 0 # Outside of inline assembly block 42410a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org_INSIDE_ASM = 1 # Inside inline assembly block 42510a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org_END_ASM = 2 # Last line of inline assembly block 42610a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org_BLOCK_ASM = 3 # The whole block is an inline assembly block 42710a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org 42810a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org# Match start of assembly blocks 42910a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org_MATCH_ASM = re.compile(r'^\s*(?:asm|_asm|__asm|__asm__)' 43010a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org r'(?:\s+(volatile|__volatile__))?' 43110a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org r'\s*[{(]') 43210a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org 4336fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 4346fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org_regexp_compile_cache = {} 4356fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 4366fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org# Finds occurrences of NOLINT or NOLINT(...). 4376fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org_RE_SUPPRESSION = re.compile(r'\bNOLINT\b(\([^)]*\))?') 4386fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 4396fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org# {str, set(int)}: a map from error categories to sets of linenumbers 4406fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org# on which those errors are expected and should be suppressed. 4416fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org_error_suppressions = {} 4426fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 44310a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org# The root directory used for deriving header guard CPP variable. 44410a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org# This is set by --root flag. 44510a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org_root = None 44610a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org 447dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org# The allowed line length of files. 448dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org# This is set by --linelength flag. 449dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org_line_length = 80 450dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 451dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org# The allowed extensions for file names 452dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org# This is set by --extensions flag. 453dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org_valid_extensions = set(['cc', 'h', 'cpp', 'cu', 'cuh']) 454dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 4556fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.orgdef ParseNolintSuppressions(filename, raw_line, linenum, error): 4566fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org """Updates the global list of error-suppressions. 4576fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 4586fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org Parses any NOLINT comments on the current line, updating the global 4596fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org error_suppressions store. Reports an error if the NOLINT comment 4606fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org was malformed. 4616fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 4626fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org Args: 4636fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org filename: str, the name of the input file. 4646fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org raw_line: str, the line of input text, with comments. 4656fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org linenum: int, the number of the current line. 4666fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org error: function, an error handler. 4676fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org """ 4686fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # FIXME(adonovan): "NOLINT(" is misparsed as NOLINT(*). 4696fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org matched = _RE_SUPPRESSION.search(raw_line) 4706fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if matched: 4716fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org category = matched.group(1) 4726fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if category in (None, '(*)'): # => "suppress all" 4736fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org _error_suppressions.setdefault(None, set()).add(linenum) 4746fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org else: 4756fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if category.startswith('(') and category.endswith(')'): 4766fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org category = category[1:-1] 4776fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if category in _ERROR_CATEGORIES: 4786fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org _error_suppressions.setdefault(category, set()).add(linenum) 4796fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org else: 4806fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org error(filename, linenum, 'readability/nolint', 5, 4816fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'Unknown NOLINT error category: %s' % category) 4826fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 4836fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 4846fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.orgdef ResetNolintSuppressions(): 4856fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org "Resets the set of NOLINT suppressions to empty." 4866fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org _error_suppressions.clear() 4876fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 4886fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 4896fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.orgdef IsErrorSuppressedByNolint(category, linenum): 4906fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org """Returns true if the specified error category is suppressed on this line. 4916fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 4926fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org Consults the global error_suppressions map populated by 4936fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org ParseNolintSuppressions/ResetNolintSuppressions. 4946fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 4956fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org Args: 4966fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org category: str, the category of the error. 4976fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org linenum: int, the current line number. 4986fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org Returns: 4996fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org bool, True iff the error should be suppressed due to a NOLINT comment. 5006fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org """ 5016fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org return (linenum in _error_suppressions.get(category, set()) or 5026fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org linenum in _error_suppressions.get(None, set())) 5036fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 5046fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.orgdef Match(pattern, s): 5056fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org """Matches the string with the pattern, caching the compiled regexp.""" 5066fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # The regexp compilation caching is inlined in both Match and Search for 5076fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # performance reasons; factoring it out into a separate function turns out 5086fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # to be noticeably expensive. 509dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org if pattern not in _regexp_compile_cache: 5106fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org _regexp_compile_cache[pattern] = sre_compile.compile(pattern) 5116fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org return _regexp_compile_cache[pattern].match(s) 5126fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 5136fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 514dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.orgdef ReplaceAll(pattern, rep, s): 515dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org """Replaces instances of pattern in a string with a replacement. 516dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 517dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org The compiled regex is kept in a cache shared by Match and Search. 518dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 519dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org Args: 520dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org pattern: regex pattern 521dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org rep: replacement text 522dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org s: search string 523dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 524dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org Returns: 525dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org string with replacements made (or original string if no replacements) 526dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org """ 527dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org if pattern not in _regexp_compile_cache: 528dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org _regexp_compile_cache[pattern] = sre_compile.compile(pattern) 529dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org return _regexp_compile_cache[pattern].sub(rep, s) 530dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 531dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 5326fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.orgdef Search(pattern, s): 5336fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org """Searches the string for the pattern, caching the compiled regexp.""" 534dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org if pattern not in _regexp_compile_cache: 5356fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org _regexp_compile_cache[pattern] = sre_compile.compile(pattern) 5366fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org return _regexp_compile_cache[pattern].search(s) 5376fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 5386fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 5396fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.orgclass _IncludeState(dict): 5406fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org """Tracks line numbers for includes, and the order in which includes appear. 5416fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 5426fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org As a dict, an _IncludeState object serves as a mapping between include 5436fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org filename and line number on which that file was included. 5446fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 5456fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org Call CheckNextIncludeOrder() once for each header in the file, passing 5466fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org in the type constants defined above. Calls in an illegal order will 5476fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org raise an _IncludeError with an appropriate error message. 5486fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 5496fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org """ 5506fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # self._section will move monotonically through this set. If it ever 5516fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # needs to move backwards, CheckNextIncludeOrder will raise an error. 5526fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org _INITIAL_SECTION = 0 5536fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org _MY_H_SECTION = 1 5546fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org _C_SECTION = 2 5556fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org _CPP_SECTION = 3 5566fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org _OTHER_H_SECTION = 4 5576fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 5586fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org _TYPE_NAMES = { 5596fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org _C_SYS_HEADER: 'C system header', 5606fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org _CPP_SYS_HEADER: 'C++ system header', 5616fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org _LIKELY_MY_HEADER: 'header this file implements', 5626fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org _POSSIBLE_MY_HEADER: 'header this file may implement', 5636fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org _OTHER_HEADER: 'other header', 5646fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org } 5656fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org _SECTION_NAMES = { 5666fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org _INITIAL_SECTION: "... nothing. (This can't be an error.)", 5676fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org _MY_H_SECTION: 'a header this file implements', 5686fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org _C_SECTION: 'C system header', 5696fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org _CPP_SECTION: 'C++ system header', 5706fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org _OTHER_H_SECTION: 'other header', 5716fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org } 5726fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 5736fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org def __init__(self): 5746fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org dict.__init__(self) 575dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org self.ResetSection() 576dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 577dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org def ResetSection(self): 5786fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # The name of the current section. 5796fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org self._section = self._INITIAL_SECTION 5806fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # The path of last found header. 5816fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org self._last_header = '' 5826fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 583dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org def SetLastHeader(self, header_path): 584dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org self._last_header = header_path 585dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 5866fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org def CanonicalizeAlphabeticalOrder(self, header_path): 5876fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org """Returns a path canonicalized for alphabetical comparison. 5886fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 5896fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org - replaces "-" with "_" so they both cmp the same. 5906fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org - removes '-inl' since we don't require them to be after the main header. 5916fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org - lowercase everything, just in case. 5926fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 5936fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org Args: 5946fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org header_path: Path to be canonicalized. 5956fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 5966fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org Returns: 5976fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org Canonicalized path. 5986fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org """ 5996fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org return header_path.replace('-inl.h', '.h').replace('-', '_').lower() 6006fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 601dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org def IsInAlphabeticalOrder(self, clean_lines, linenum, header_path): 6026fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org """Check if a header is in alphabetical order with the previous header. 6036fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 6046fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org Args: 605dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org clean_lines: A CleansedLines instance containing the file. 606dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org linenum: The number of the line to check. 607dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org header_path: Canonicalized header to be checked. 6086fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 6096fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org Returns: 6106fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org Returns true if the header is in alphabetical order. 6116fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org """ 612dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # If previous section is different from current section, _last_header will 613dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # be reset to empty string, so it's always less than current header. 614dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # 615dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # If previous line was a blank line, assume that the headers are 616dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # intentionally sorted the way they are. 617dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org if (self._last_header > header_path and 618dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org not Match(r'^\s*$', clean_lines.elided[linenum - 1])): 6196fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org return False 6206fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org return True 6216fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 6226fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org def CheckNextIncludeOrder(self, header_type): 6236fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org """Returns a non-empty error message if the next header is out of order. 6246fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 6256fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org This function also updates the internal state to be ready to check 6266fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org the next include. 6276fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 6286fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org Args: 6296fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org header_type: One of the _XXX_HEADER constants defined above. 6306fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 6316fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org Returns: 6326fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org The empty string if the header is in the right order, or an 6336fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org error message describing what's wrong. 6346fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 6356fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org """ 6366fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org error_message = ('Found %s after %s' % 6376fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org (self._TYPE_NAMES[header_type], 6386fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org self._SECTION_NAMES[self._section])) 6396fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 6406fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org last_section = self._section 6416fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 6426fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if header_type == _C_SYS_HEADER: 6436fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if self._section <= self._C_SECTION: 6446fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org self._section = self._C_SECTION 6456fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org else: 6466fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org self._last_header = '' 6476fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org return error_message 6486fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org elif header_type == _CPP_SYS_HEADER: 6496fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if self._section <= self._CPP_SECTION: 6506fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org self._section = self._CPP_SECTION 6516fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org else: 6526fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org self._last_header = '' 6536fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org return error_message 6546fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org elif header_type == _LIKELY_MY_HEADER: 6556fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if self._section <= self._MY_H_SECTION: 6566fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org self._section = self._MY_H_SECTION 6576fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org else: 6586fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org self._section = self._OTHER_H_SECTION 6596fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org elif header_type == _POSSIBLE_MY_HEADER: 6606fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if self._section <= self._MY_H_SECTION: 6616fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org self._section = self._MY_H_SECTION 6626fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org else: 6636fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # This will always be the fallback because we're not sure 6646fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # enough that the header is associated with this file. 6656fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org self._section = self._OTHER_H_SECTION 6666fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org else: 6676fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org assert header_type == _OTHER_HEADER 6686fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org self._section = self._OTHER_H_SECTION 6696fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 6706fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if last_section != self._section: 6716fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org self._last_header = '' 6726fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 6736fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org return '' 6746fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 6756fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 6766fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.orgclass _CppLintState(object): 6776fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org """Maintains module-wide state..""" 6786fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 6796fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org def __init__(self): 6806fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org self.verbose_level = 1 # global setting. 6816fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org self.error_count = 0 # global count of reported errors 6826fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # filters to apply when emitting error messages 6836fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org self.filters = _DEFAULT_FILTERS[:] 6846fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org self.counting = 'total' # In what way are we counting errors? 6856fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org self.errors_by_category = {} # string to int dict storing error counts 6866fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 6876fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # output format: 6886fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # "emacs" - format that emacs can parse (default) 6896fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # "vs7" - format that Microsoft Visual Studio 7 can parse 6906fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org self.output_format = 'emacs' 6916fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 6926fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org def SetOutputFormat(self, output_format): 6936fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org """Sets the output format for errors.""" 6946fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org self.output_format = output_format 6956fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 6966fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org def SetVerboseLevel(self, level): 6976fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org """Sets the module's verbosity, and returns the previous setting.""" 6986fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org last_verbose_level = self.verbose_level 6996fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org self.verbose_level = level 7006fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org return last_verbose_level 7016fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 7026fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org def SetCountingStyle(self, counting_style): 7036fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org """Sets the module's counting options.""" 7046fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org self.counting = counting_style 7056fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 7066fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org def SetFilters(self, filters): 7076fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org """Sets the error-message filters. 7086fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 7096fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org These filters are applied when deciding whether to emit a given 7106fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org error message. 7116fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 7126fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org Args: 7136fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org filters: A string of comma-separated filters (eg "+whitespace/indent"). 7146fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org Each filter should start with + or -; else we die. 7156fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 7166fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org Raises: 7176fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org ValueError: The comma-separated filters did not all start with '+' or '-'. 7186fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org E.g. "-,+whitespace,-whitespace/indent,whitespace/badfilter" 7196fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org """ 7206fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # Default filters always have less priority than the flag ones. 7216fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org self.filters = _DEFAULT_FILTERS[:] 7226fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org for filt in filters.split(','): 7236fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org clean_filt = filt.strip() 7246fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if clean_filt: 7256fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org self.filters.append(clean_filt) 7266fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org for filt in self.filters: 7276fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if not (filt.startswith('+') or filt.startswith('-')): 7286fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org raise ValueError('Every filter in --filters must start with + or -' 7296fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org ' (%s does not)' % filt) 7306fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 7316fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org def ResetErrorCounts(self): 7326fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org """Sets the module's error statistic back to zero.""" 7336fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org self.error_count = 0 7346fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org self.errors_by_category = {} 7356fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 7366fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org def IncrementErrorCount(self, category): 7376fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org """Bumps the module's error statistic.""" 7386fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org self.error_count += 1 7396fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if self.counting in ('toplevel', 'detailed'): 7406fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if self.counting != 'detailed': 7416fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org category = category.split('/')[0] 7426fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if category not in self.errors_by_category: 7436fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org self.errors_by_category[category] = 0 7446fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org self.errors_by_category[category] += 1 7456fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 7466fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org def PrintErrorCounts(self): 7476fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org """Print a summary of errors by category, and the total.""" 7486fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org for category, count in self.errors_by_category.iteritems(): 7496fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org sys.stderr.write('Category \'%s\' errors found: %d\n' % 7506fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org (category, count)) 7516fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org sys.stderr.write('Total errors found: %d\n' % self.error_count) 7526fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 7536fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org_cpplint_state = _CppLintState() 7546fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 7556fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 7566fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.orgdef _OutputFormat(): 7576fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org """Gets the module's output format.""" 7586fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org return _cpplint_state.output_format 7596fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 7606fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 7616fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.orgdef _SetOutputFormat(output_format): 7626fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org """Sets the module's output format.""" 7636fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org _cpplint_state.SetOutputFormat(output_format) 7646fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 7656fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 7666fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.orgdef _VerboseLevel(): 7676fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org """Returns the module's verbosity setting.""" 7686fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org return _cpplint_state.verbose_level 7696fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 7706fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 7716fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.orgdef _SetVerboseLevel(level): 7726fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org """Sets the module's verbosity, and returns the previous setting.""" 7736fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org return _cpplint_state.SetVerboseLevel(level) 7746fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 7756fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 7766fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.orgdef _SetCountingStyle(level): 7776fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org """Sets the module's counting options.""" 7786fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org _cpplint_state.SetCountingStyle(level) 7796fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 7806fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 7816fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.orgdef _Filters(): 7826fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org """Returns the module's list of output filters, as a list.""" 7836fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org return _cpplint_state.filters 7846fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 7856fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 7866fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.orgdef _SetFilters(filters): 7876fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org """Sets the module's error-message filters. 7886fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 7896fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org These filters are applied when deciding whether to emit a given 7906fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org error message. 7916fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 7926fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org Args: 7936fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org filters: A string of comma-separated filters (eg "whitespace/indent"). 7946fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org Each filter should start with + or -; else we die. 7956fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org """ 7966fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org _cpplint_state.SetFilters(filters) 7976fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 7986fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 7996fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.orgclass _FunctionState(object): 8006fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org """Tracks current function name and the number of lines in its body.""" 8016fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 8026fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org _NORMAL_TRIGGER = 250 # for --v=0, 500 for --v=1, etc. 8036fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org _TEST_TRIGGER = 400 # about 50% more than _NORMAL_TRIGGER. 8046fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 8056fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org def __init__(self): 8066fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org self.in_a_function = False 8076fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org self.lines_in_function = 0 8086fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org self.current_function = '' 8096fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 8106fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org def Begin(self, function_name): 8116fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org """Start analyzing function body. 8126fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 8136fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org Args: 8146fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org function_name: The name of the function being tracked. 8156fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org """ 8166fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org self.in_a_function = True 8176fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org self.lines_in_function = 0 8186fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org self.current_function = function_name 8196fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 8206fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org def Count(self): 8216fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org """Count line in current function body.""" 8226fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if self.in_a_function: 8236fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org self.lines_in_function += 1 8246fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 8256fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org def Check(self, error, filename, linenum): 8266fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org """Report if too many lines in function body. 8276fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 8286fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org Args: 8296fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org error: The function to call with any errors found. 8306fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org filename: The name of the current file. 8316fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org linenum: The number of the line to check. 8326fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org """ 8336fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if Match(r'T(EST|est)', self.current_function): 8346fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org base_trigger = self._TEST_TRIGGER 8356fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org else: 8366fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org base_trigger = self._NORMAL_TRIGGER 8376fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org trigger = base_trigger * 2**_VerboseLevel() 8386fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 8396fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if self.lines_in_function > trigger: 8406fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org error_level = int(math.log(self.lines_in_function / base_trigger, 2)) 8416fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # 50 => 0, 100 => 1, 200 => 2, 400 => 3, 800 => 4, 1600 => 5, ... 8426fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if error_level > 5: 8436fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org error_level = 5 8446fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org error(filename, linenum, 'readability/fn_size', error_level, 8456fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'Small and focused functions are preferred:' 8466fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org ' %s has %d non-comment lines' 8476fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org ' (error triggered by exceeding %d lines).' % ( 8486fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org self.current_function, self.lines_in_function, trigger)) 8496fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 8506fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org def End(self): 8516fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org """Stop analyzing function body.""" 8526fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org self.in_a_function = False 8536fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 8546fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 8556fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.orgclass _IncludeError(Exception): 8566fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org """Indicates a problem with the include order in a file.""" 8576fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org pass 8586fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 8596fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 8606fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.orgclass FileInfo: 8616fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org """Provides utility functions for filenames. 8626fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 8636fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org FileInfo provides easy access to the components of a file's path 8646fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org relative to the project root. 8656fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org """ 8666fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 8676fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org def __init__(self, filename): 8686fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org self._filename = filename 8696fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 8706fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org def FullName(self): 8716fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org """Make Windows paths like Unix.""" 8726fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org return os.path.abspath(self._filename).replace('\\', '/') 8736fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 8746fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org def RepositoryName(self): 8756fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org """FullName after removing the local path to the repository. 8766fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 8776fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org If we have a real absolute path name here we can try to do something smart: 8786fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org detecting the root of the checkout and truncating /path/to/checkout from 8796fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org the name so that we get header guards that don't include things like 8806fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org "C:\Documents and Settings\..." or "/home/username/..." in them and thus 8816fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org people on different computers who have checked the source out to different 8826fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org locations won't see bogus errors. 8836fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org """ 8846fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org fullname = self.FullName() 8856fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 8866fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if os.path.exists(fullname): 8876fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org project_dir = os.path.dirname(fullname) 8886fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 8896fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if os.path.exists(os.path.join(project_dir, ".svn")): 8906fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # If there's a .svn file in the current directory, we recursively look 8916fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # up the directory tree for the top of the SVN checkout 8926fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org root_dir = project_dir 8936fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org one_up_dir = os.path.dirname(root_dir) 8946fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org while os.path.exists(os.path.join(one_up_dir, ".svn")): 8956fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org root_dir = os.path.dirname(root_dir) 8966fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org one_up_dir = os.path.dirname(one_up_dir) 8976fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 8986fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org prefix = os.path.commonprefix([root_dir, project_dir]) 8996fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org return fullname[len(prefix) + 1:] 9006fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 9016fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # Not SVN <= 1.6? Try to find a git, hg, or svn top level directory by 9026fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # searching up from the current path. 9036fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org root_dir = os.path.dirname(fullname) 9046fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org while (root_dir != os.path.dirname(root_dir) and 9056fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org not os.path.exists(os.path.join(root_dir, ".git")) and 9066fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org not os.path.exists(os.path.join(root_dir, ".hg")) and 9076fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org not os.path.exists(os.path.join(root_dir, ".svn"))): 9086fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org root_dir = os.path.dirname(root_dir) 9096fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 9106fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if (os.path.exists(os.path.join(root_dir, ".git")) or 9116fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org os.path.exists(os.path.join(root_dir, ".hg")) or 9126fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org os.path.exists(os.path.join(root_dir, ".svn"))): 9136fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org prefix = os.path.commonprefix([root_dir, project_dir]) 9146fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org return fullname[len(prefix) + 1:] 9156fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 9166fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # Don't know what to do; header guard warnings may be wrong... 9176fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org return fullname 9186fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 9196fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org def Split(self): 9206fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org """Splits the file into the directory, basename, and extension. 9216fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 9226fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org For 'chrome/browser/browser.cc', Split() would 9236fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org return ('chrome/browser', 'browser', '.cc') 9246fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 9256fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org Returns: 9266fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org A tuple of (directory, basename, extension). 9276fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org """ 9286fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 9296fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org googlename = self.RepositoryName() 9306fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org project, rest = os.path.split(googlename) 9316fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org return (project,) + os.path.splitext(rest) 9326fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 9336fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org def BaseName(self): 9346fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org """File base name - text after the final slash, before the final period.""" 9356fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org return self.Split()[1] 9366fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 9376fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org def Extension(self): 9386fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org """File extension - text following the final period.""" 9396fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org return self.Split()[2] 9406fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 9416fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org def NoExtension(self): 9426fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org """File has no source file extension.""" 9436fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org return '/'.join(self.Split()[0:2]) 9446fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 9456fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org def IsSource(self): 9466fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org """File has a source file extension.""" 9476fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org return self.Extension()[1:] in ('c', 'cc', 'cpp', 'cxx') 9486fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 9496fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 9506fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.orgdef _ShouldPrintError(category, confidence, linenum): 9516fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org """If confidence >= verbose, category passes filter and is not suppressed.""" 9526fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 9536fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # There are three ways we might decide not to print an error message: 9546fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # a "NOLINT(category)" comment appears in the source, 9556fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # the verbosity level isn't high enough, or the filters filter it out. 9566fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if IsErrorSuppressedByNolint(category, linenum): 9576fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org return False 9586fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if confidence < _cpplint_state.verbose_level: 9596fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org return False 9606fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 9616fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org is_filtered = False 9626fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org for one_filter in _Filters(): 9636fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if one_filter.startswith('-'): 9646fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if category.startswith(one_filter[1:]): 9656fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org is_filtered = True 9666fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org elif one_filter.startswith('+'): 9676fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if category.startswith(one_filter[1:]): 9686fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org is_filtered = False 9696fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org else: 9706fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org assert False # should have been checked for in SetFilter. 9716fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if is_filtered: 9726fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org return False 9736fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 9746fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org return True 9756fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 9766fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 9776fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.orgdef Error(filename, linenum, category, confidence, message): 9786fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org """Logs the fact we've found a lint error. 9796fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 9806fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org We log where the error was found, and also our confidence in the error, 9816fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org that is, how certain we are this is a legitimate style regression, and 9826fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org not a misidentification or a use that's sometimes justified. 9836fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 9846fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org False positives can be suppressed by the use of 9856fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org "cpplint(category)" comments on the offending line. These are 9866fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org parsed into _error_suppressions. 9876fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 9886fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org Args: 9896fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org filename: The name of the file containing the error. 9906fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org linenum: The number of the line containing the error. 9916fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org category: A string used to describe the "category" this bug 9926fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org falls under: "whitespace", say, or "runtime". Categories 9936fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org may have a hierarchy separated by slashes: "whitespace/indent". 9946fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org confidence: A number from 1-5 representing a confidence score for 9956fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org the error, with 5 meaning that we are certain of the problem, 9966fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org and 1 meaning that it could be a legitimate construct. 9976fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org message: The error message. 9986fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org """ 9996fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if _ShouldPrintError(category, confidence, linenum): 10006fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org _cpplint_state.IncrementErrorCount(category) 10016fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if _cpplint_state.output_format == 'vs7': 10026fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org sys.stderr.write('%s(%s): %s [%s] [%d]\n' % ( 10036fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org filename, linenum, message, category, confidence)) 1004dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org elif _cpplint_state.output_format == 'eclipse': 1005dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org sys.stderr.write('%s:%s: warning: %s [%s] [%d]\n' % ( 1006dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org filename, linenum, message, category, confidence)) 10076fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org else: 10086fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org sys.stderr.write('%s:%s: %s [%s] [%d]\n' % ( 10096fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org filename, linenum, message, category, confidence)) 10106fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 10116fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 1012dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org# Matches standard C++ escape sequences per 2.13.2.3 of the C++ standard. 10136fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org_RE_PATTERN_CLEANSE_LINE_ESCAPES = re.compile( 10146fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org r'\\([abfnrtv?"\\\']|\d+|x[0-9a-fA-F]+)') 10156fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org# Matches strings. Escape codes should already be removed by ESCAPES. 10166fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org_RE_PATTERN_CLEANSE_LINE_DOUBLE_QUOTES = re.compile(r'"[^"]*"') 10176fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org# Matches characters. Escape codes should already be removed by ESCAPES. 10186fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org_RE_PATTERN_CLEANSE_LINE_SINGLE_QUOTES = re.compile(r"'.'") 10196fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org# Matches multi-line C++ comments. 10206fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org# This RE is a little bit more complicated than one might expect, because we 10216fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org# have to take care of space removals tools so we can handle comments inside 10226fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org# statements better. 10236fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org# The current rule is: We only clear spaces from both sides when we're at the 10246fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org# end of the line. Otherwise, we try to remove spaces from the right side, 10256fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org# if this doesn't work we try on left side but only if there's a non-character 10266fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org# on the right. 10276fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org_RE_PATTERN_CLEANSE_LINE_C_COMMENTS = re.compile( 10286fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org r"""(\s*/\*.*\*/\s*$| 10296fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org /\*.*\*/\s+| 10306fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org \s+/\*.*\*/(?=\W)| 10316fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org /\*.*\*/)""", re.VERBOSE) 10326fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 10336fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 10346fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.orgdef IsCppString(line): 10356fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org """Does line terminate so, that the next symbol is in string constant. 10366fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 10376fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org This function does not consider single-line nor multi-line comments. 10386fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 10396fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org Args: 10406fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org line: is a partial line of code starting from the 0..n. 10416fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 10426fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org Returns: 10436fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org True, if next character appended to 'line' is inside a 10446fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org string constant. 10456fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org """ 10466fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 10476fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org line = line.replace(r'\\', 'XX') # after this, \\" does not match to \" 10486fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org return ((line.count('"') - line.count(r'\"') - line.count("'\"'")) & 1) == 1 10496fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 10506fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 1051dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.orgdef CleanseRawStrings(raw_lines): 1052dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org """Removes C++11 raw strings from lines. 1053dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 1054dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org Before: 1055dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org static const char kData[] = R"( 1056dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org multi-line string 1057dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org )"; 1058dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 1059dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org After: 1060dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org static const char kData[] = "" 1061dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org (replaced by blank line) 1062dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org ""; 1063dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 1064dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org Args: 1065dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org raw_lines: list of raw lines. 1066dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 1067dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org Returns: 1068dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org list of lines with C++11 raw strings replaced by empty strings. 1069dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org """ 1070dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 1071dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org delimiter = None 1072dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org lines_without_raw_strings = [] 1073dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org for line in raw_lines: 1074dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org if delimiter: 1075dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # Inside a raw string, look for the end 1076dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org end = line.find(delimiter) 1077dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org if end >= 0: 1078dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # Found the end of the string, match leading space for this 1079dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # line and resume copying the original lines, and also insert 1080dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # a "" on the last line. 1081dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org leading_space = Match(r'^(\s*)\S', line) 1082dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org line = leading_space.group(1) + '""' + line[end + len(delimiter):] 1083dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org delimiter = None 1084dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org else: 1085dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # Haven't found the end yet, append a blank line. 1086dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org line = '' 1087dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 1088dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org else: 1089dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # Look for beginning of a raw string. 1090dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # See 2.14.15 [lex.string] for syntax. 1091dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org matched = Match(r'^(.*)\b(?:R|u8R|uR|UR|LR)"([^\s\\()]*)\((.*)$', line) 1092dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org if matched: 1093dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org delimiter = ')' + matched.group(2) + '"' 1094dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 1095dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org end = matched.group(3).find(delimiter) 1096dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org if end >= 0: 1097dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # Raw string ended on same line 1098dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org line = (matched.group(1) + '""' + 1099dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org matched.group(3)[end + len(delimiter):]) 1100dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org delimiter = None 1101dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org else: 1102dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # Start of a multi-line raw string 1103dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org line = matched.group(1) + '""' 1104dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 1105dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org lines_without_raw_strings.append(line) 1106dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 1107dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # TODO(unknown): if delimiter is not None here, we might want to 1108dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # emit a warning for unterminated string. 1109dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org return lines_without_raw_strings 1110dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 1111dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 11126fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.orgdef FindNextMultiLineCommentStart(lines, lineix): 11136fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org """Find the beginning marker for a multiline comment.""" 11146fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org while lineix < len(lines): 11156fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if lines[lineix].strip().startswith('/*'): 11166fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # Only return this marker if the comment goes beyond this line 11176fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if lines[lineix].strip().find('*/', 2) < 0: 11186fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org return lineix 11196fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org lineix += 1 11206fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org return len(lines) 11216fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 11226fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 11236fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.orgdef FindNextMultiLineCommentEnd(lines, lineix): 11246fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org """We are inside a comment, find the end marker.""" 11256fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org while lineix < len(lines): 11266fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if lines[lineix].strip().endswith('*/'): 11276fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org return lineix 11286fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org lineix += 1 11296fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org return len(lines) 11306fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 11316fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 11326fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.orgdef RemoveMultiLineCommentsFromRange(lines, begin, end): 11336fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org """Clears a range of lines for multi-line comments.""" 11346fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # Having // dummy comments makes the lines non-empty, so we will not get 11356fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # unnecessary blank line warnings later in the code. 11366fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org for i in range(begin, end): 11376fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org lines[i] = '// dummy' 11386fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 11396fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 11406fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.orgdef RemoveMultiLineComments(filename, lines, error): 11416fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org """Removes multiline (c-style) comments from lines.""" 11426fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org lineix = 0 11436fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org while lineix < len(lines): 11446fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org lineix_begin = FindNextMultiLineCommentStart(lines, lineix) 11456fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if lineix_begin >= len(lines): 11466fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org return 11476fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org lineix_end = FindNextMultiLineCommentEnd(lines, lineix_begin) 11486fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if lineix_end >= len(lines): 11496fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org error(filename, lineix_begin + 1, 'readability/multiline_comment', 5, 11506fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'Could not find end of multi-line comment') 11516fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org return 11526fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org RemoveMultiLineCommentsFromRange(lines, lineix_begin, lineix_end + 1) 11536fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org lineix = lineix_end + 1 11546fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 11556fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 11566fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.orgdef CleanseComments(line): 11576fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org """Removes //-comments and single-line C-style /* */ comments. 11586fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 11596fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org Args: 11606fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org line: A line of C++ source. 11616fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 11626fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org Returns: 11636fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org The line with single-line comments removed. 11646fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org """ 11656fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org commentpos = line.find('//') 11666fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if commentpos != -1 and not IsCppString(line[:commentpos]): 11676fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org line = line[:commentpos].rstrip() 11686fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # get rid of /* ... */ 11696fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org return _RE_PATTERN_CLEANSE_LINE_C_COMMENTS.sub('', line) 11706fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 11716fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 11726fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.orgclass CleansedLines(object): 11736fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org """Holds 3 copies of all lines with different preprocessing applied to them. 11746fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 11756fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 1) elided member contains lines without strings and comments, 11766fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 2) lines member contains lines without comments, and 117710a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org 3) raw_lines member contains all the lines without processing. 11786fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org All these three members are of <type 'list'>, and of the same length. 11796fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org """ 11806fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 11816fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org def __init__(self, lines): 11826fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org self.elided = [] 11836fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org self.lines = [] 11846fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org self.raw_lines = lines 11856fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org self.num_lines = len(lines) 1186dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org self.lines_without_raw_strings = CleanseRawStrings(lines) 1187dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org for linenum in range(len(self.lines_without_raw_strings)): 1188dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org self.lines.append(CleanseComments( 1189dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org self.lines_without_raw_strings[linenum])) 1190dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org elided = self._CollapseStrings(self.lines_without_raw_strings[linenum]) 11916fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org self.elided.append(CleanseComments(elided)) 11926fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 11936fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org def NumLines(self): 11946fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org """Returns the number of lines represented.""" 11956fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org return self.num_lines 11966fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 11976fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org @staticmethod 11986fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org def _CollapseStrings(elided): 11996fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org """Collapses strings and chars on a line to simple "" or '' blocks. 12006fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 12016fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org We nix strings first so we're not fooled by text like '"http://"' 12026fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 12036fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org Args: 12046fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org elided: The line being processed. 12056fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 12066fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org Returns: 12076fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org The line with collapsed strings. 12086fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org """ 12096fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if not _RE_PATTERN_INCLUDE.match(elided): 12106fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # Remove escaped characters first to make quote/single quote collapsing 12116fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # basic. Things that look like escaped characters shouldn't occur 12126fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # outside of strings and chars. 12136fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org elided = _RE_PATTERN_CLEANSE_LINE_ESCAPES.sub('', elided) 12146fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org elided = _RE_PATTERN_CLEANSE_LINE_SINGLE_QUOTES.sub("''", elided) 12156fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org elided = _RE_PATTERN_CLEANSE_LINE_DOUBLE_QUOTES.sub('""', elided) 12166fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org return elided 12176fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 12186fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 121910a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.orgdef FindEndOfExpressionInLine(line, startpos, depth, startchar, endchar): 122010a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org """Find the position just after the matching endchar. 122110a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org 122210a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org Args: 122310a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org line: a CleansedLines line. 122410a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org startpos: start searching at this position. 122510a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org depth: nesting level at startpos. 122610a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org startchar: expression opening character. 122710a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org endchar: expression closing character. 122810a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org 122910a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org Returns: 1230dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org On finding matching endchar: (index just after matching endchar, 0) 1231dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org Otherwise: (-1, new depth at end of this line) 123210a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org """ 123310a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org for i in xrange(startpos, len(line)): 123410a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org if line[i] == startchar: 123510a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org depth += 1 123610a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org elif line[i] == endchar: 123710a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org depth -= 1 123810a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org if depth == 0: 1239dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org return (i + 1, 0) 1240dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org return (-1, depth) 124110a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org 124210a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org 12436fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.orgdef CloseExpression(clean_lines, linenum, pos): 1244dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org """If input points to ( or { or [ or <, finds the position that closes it. 12456fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 1246dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org If lines[linenum][pos] points to a '(' or '{' or '[' or '<', finds the 12476fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org linenum/pos that correspond to the closing of the expression. 12486fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 12496fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org Args: 12506fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org clean_lines: A CleansedLines instance containing the file. 12516fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org linenum: The number of the line to check. 12526fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org pos: A position on the line. 12536fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 12546fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org Returns: 12556fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org A tuple (line, linenum, pos) pointer *past* the closing brace, or 12566fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org (line, len(lines), -1) if we never find a close. Note we ignore 12576fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org strings and comments when matching; and the line we return is the 12586fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'cleansed' line at linenum. 12596fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org """ 12606fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 12616fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org line = clean_lines.elided[linenum] 12626fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org startchar = line[pos] 1263dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org if startchar not in '({[<': 12646fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org return (line, clean_lines.NumLines(), -1) 12656fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if startchar == '(': endchar = ')' 12666fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if startchar == '[': endchar = ']' 12676fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if startchar == '{': endchar = '}' 1268dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org if startchar == '<': endchar = '>' 12696fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 127010a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # Check first line 1271dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org (end_pos, num_open) = FindEndOfExpressionInLine( 1272dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org line, pos, 0, startchar, endchar) 127310a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org if end_pos > -1: 127410a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org return (line, linenum, end_pos) 1275dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 1276dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # Continue scanning forward 127710a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org while linenum < clean_lines.NumLines() - 1: 12786fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org linenum += 1 12796fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org line = clean_lines.elided[linenum] 1280dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org (end_pos, num_open) = FindEndOfExpressionInLine( 1281dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org line, 0, num_open, startchar, endchar) 1282dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org if end_pos > -1: 1283dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org return (line, linenum, end_pos) 12846fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 128510a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # Did not find endchar before end of file, give up 128610a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org return (line, clean_lines.NumLines(), -1) 12876fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 1288dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 1289dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.orgdef FindStartOfExpressionInLine(line, endpos, depth, startchar, endchar): 1290dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org """Find position at the matching startchar. 1291dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 1292dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org This is almost the reverse of FindEndOfExpressionInLine, but note 1293dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org that the input position and returned position differs by 1. 1294dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 1295dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org Args: 1296dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org line: a CleansedLines line. 1297dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org endpos: start searching at this position. 1298dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org depth: nesting level at endpos. 1299dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org startchar: expression opening character. 1300dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org endchar: expression closing character. 1301dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 1302dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org Returns: 1303dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org On finding matching startchar: (index at matching startchar, 0) 1304dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org Otherwise: (-1, new depth at beginning of this line) 1305dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org """ 1306dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org for i in xrange(endpos, -1, -1): 1307dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org if line[i] == endchar: 1308dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org depth += 1 1309dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org elif line[i] == startchar: 1310dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org depth -= 1 1311dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org if depth == 0: 1312dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org return (i, 0) 1313dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org return (-1, depth) 1314dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 1315dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 1316dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.orgdef ReverseCloseExpression(clean_lines, linenum, pos): 1317dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org """If input points to ) or } or ] or >, finds the position that opens it. 1318dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 1319dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org If lines[linenum][pos] points to a ')' or '}' or ']' or '>', finds the 1320dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org linenum/pos that correspond to the opening of the expression. 1321dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 1322dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org Args: 1323dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org clean_lines: A CleansedLines instance containing the file. 1324dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org linenum: The number of the line to check. 1325dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org pos: A position on the line. 1326dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 1327dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org Returns: 1328dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org A tuple (line, linenum, pos) pointer *at* the opening brace, or 1329dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org (line, 0, -1) if we never find the matching opening brace. Note 1330dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org we ignore strings and comments when matching; and the line we 1331dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org return is the 'cleansed' line at linenum. 1332dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org """ 1333dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org line = clean_lines.elided[linenum] 1334dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org endchar = line[pos] 1335dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org if endchar not in ')}]>': 1336dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org return (line, 0, -1) 1337dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org if endchar == ')': startchar = '(' 1338dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org if endchar == ']': startchar = '[' 1339dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org if endchar == '}': startchar = '{' 1340dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org if endchar == '>': startchar = '<' 1341dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 1342dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # Check last line 1343dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org (start_pos, num_open) = FindStartOfExpressionInLine( 1344dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org line, pos, 0, startchar, endchar) 1345dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org if start_pos > -1: 1346dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org return (line, linenum, start_pos) 1347dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 1348dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # Continue scanning backward 1349dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org while linenum > 0: 1350dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org linenum -= 1 1351dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org line = clean_lines.elided[linenum] 1352dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org (start_pos, num_open) = FindStartOfExpressionInLine( 1353dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org line, len(line) - 1, num_open, startchar, endchar) 1354dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org if start_pos > -1: 1355dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org return (line, linenum, start_pos) 1356dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 1357dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # Did not find startchar before beginning of file, give up 1358dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org return (line, 0, -1) 1359dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 1360dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 13616fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.orgdef CheckForCopyright(filename, lines, error): 13626fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org """Logs an error if no Copyright message appears at the top of the file.""" 13636fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 13646fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # We'll say it should occur by line 10. Don't forget there's a 13656fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # dummy line at the front. 13666fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org for line in xrange(1, min(len(lines), 11)): 13676fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if re.search(r'Copyright', lines[line], re.I): break 13686fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org else: # means no copyright line was found 13696fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org error(filename, 0, 'legal/copyright', 5, 13706fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'No copyright message found. ' 13716fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'You should have a line: "Copyright [year] <Copyright Owner>"') 13726fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 13736fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 13746fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.orgdef GetHeaderGuardCPPVariable(filename): 13756fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org """Returns the CPP variable that should be used as a header guard. 13766fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 13776fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org Args: 13786fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org filename: The name of a C++ header file. 13796fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 13806fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org Returns: 13816fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org The CPP variable that should be used as a header guard in the 13826fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org named file. 13836fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 13846fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org """ 13856fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 13866fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # Restores original filename in case that cpplint is invoked from Emacs's 13876fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # flymake. 13886fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org filename = re.sub(r'_flymake\.h$', '.h', filename) 138910a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org filename = re.sub(r'/\.flymake/([^/]*)$', r'/\1', filename) 13906fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 13916fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org fileinfo = FileInfo(filename) 139210a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org file_path_from_root = fileinfo.RepositoryName() 139310a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org if _root: 139410a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org file_path_from_root = re.sub('^' + _root + os.sep, '', file_path_from_root) 139510a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org return re.sub(r'[-./\s]', '_', file_path_from_root).upper() + '_' 13966fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 13976fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 13986fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.orgdef CheckForHeaderGuard(filename, lines, error): 13996fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org """Checks that the file contains a header guard. 14006fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 14016fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org Logs an error if no #ifndef header guard is present. For other 14026fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org headers, checks that the full pathname is used. 14036fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 14046fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org Args: 14056fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org filename: The name of the C++ header file. 14066fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org lines: An array of strings, each representing a line of the file. 14076fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org error: The function to call with any errors found. 14086fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org """ 14096fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 14106fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org cppvar = GetHeaderGuardCPPVariable(filename) 14116fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 14126fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org ifndef = None 14136fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org ifndef_linenum = 0 14146fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org define = None 14156fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org endif = None 14166fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org endif_linenum = 0 14176fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org for linenum, line in enumerate(lines): 14186fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org linesplit = line.split() 14196fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if len(linesplit) >= 2: 14206fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # find the first occurrence of #ifndef and #define, save arg 14216fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if not ifndef and linesplit[0] == '#ifndef': 14226fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # set ifndef to the header guard presented on the #ifndef line. 14236fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org ifndef = linesplit[1] 14246fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org ifndef_linenum = linenum 14256fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if not define and linesplit[0] == '#define': 14266fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org define = linesplit[1] 14276fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # find the last occurrence of #endif, save entire line 14286fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if line.startswith('#endif'): 14296fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org endif = line 14306fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org endif_linenum = linenum 14316fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 14326fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if not ifndef: 14336fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org error(filename, 0, 'build/header_guard', 5, 14346fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'No #ifndef header guard found, suggested CPP variable is: %s' % 14356fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org cppvar) 14366fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org return 14376fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 14386fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if not define: 14396fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org error(filename, 0, 'build/header_guard', 5, 14406fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'No #define header guard found, suggested CPP variable is: %s' % 14416fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org cppvar) 14426fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org return 14436fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 14446fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # The guard should be PATH_FILE_H_, but we also allow PATH_FILE_H__ 14456fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # for backward compatibility. 14466fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if ifndef != cppvar: 14476fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org error_level = 0 14486fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if ifndef != cppvar + '_': 14496fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org error_level = 5 14506fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 14516fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org ParseNolintSuppressions(filename, lines[ifndef_linenum], ifndef_linenum, 14526fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org error) 14536fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org error(filename, ifndef_linenum, 'build/header_guard', error_level, 14546fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org '#ifndef header guard has wrong style, please use: %s' % cppvar) 14556fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 14566fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if define != ifndef: 14576fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org error(filename, 0, 'build/header_guard', 5, 14586fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org '#ifndef and #define don\'t match, suggested CPP variable is: %s' % 14596fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org cppvar) 14606fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org return 14616fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 14626fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if endif != ('#endif // %s' % cppvar): 14636fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org error_level = 0 14646fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if endif != ('#endif // %s' % (cppvar + '_')): 14656fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org error_level = 5 14666fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 14676fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org ParseNolintSuppressions(filename, lines[endif_linenum], endif_linenum, 14686fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org error) 14696fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org error(filename, endif_linenum, 'build/header_guard', error_level, 14706fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org '#endif line should be "#endif // %s"' % cppvar) 14716fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 14726fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 1473dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.orgdef CheckForBadCharacters(filename, lines, error): 1474dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org """Logs an error for each line containing bad characters. 1475dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 1476dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org Two kinds of bad characters: 14776fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 1478dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 1. Unicode replacement characters: These indicate that either the file 1479dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org contained invalid UTF-8 (likely) or Unicode replacement characters (which 1480dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org it shouldn't). Note that it's possible for this to throw off line 1481dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org numbering if the invalid UTF-8 occurred adjacent to a newline. 1482dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 1483dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 2. NUL bytes. These are problematic for some tools. 14846fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 14856fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org Args: 14866fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org filename: The name of the current file. 14876fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org lines: An array of strings, each representing a line of the file. 14886fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org error: The function to call with any errors found. 14896fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org """ 14906fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org for linenum, line in enumerate(lines): 14916fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if u'\ufffd' in line: 14926fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org error(filename, linenum, 'readability/utf8', 5, 14936fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'Line contains invalid UTF-8 (or Unicode replacement character).') 1494dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org if '\0' in line: 1495dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org error(filename, linenum, 'readability/nul', 5, 'Line contains NUL byte.') 14966fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 14976fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 14986fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.orgdef CheckForNewlineAtEOF(filename, lines, error): 14996fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org """Logs an error if there is no newline char at the end of the file. 15006fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 15016fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org Args: 15026fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org filename: The name of the current file. 15036fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org lines: An array of strings, each representing a line of the file. 15046fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org error: The function to call with any errors found. 15056fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org """ 15066fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 15076fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # The array lines() was created by adding two newlines to the 15086fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # original file (go figure), then splitting on \n. 15096fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # To verify that the file ends in \n, we just have to make sure the 15106fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # last-but-two element of lines() exists and is empty. 15116fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if len(lines) < 3 or lines[-2]: 15126fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org error(filename, len(lines) - 2, 'whitespace/ending_newline', 5, 15136fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'Could not find a newline character at the end of the file.') 15146fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 15156fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 15166fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.orgdef CheckForMultilineCommentsAndStrings(filename, clean_lines, linenum, error): 15176fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org """Logs an error if we see /* ... */ or "..." that extend past one line. 15186fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 15196fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org /* ... */ comments are legit inside macros, for one line. 15206fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org Otherwise, we prefer // comments, so it's ok to warn about the 15216fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org other. Likewise, it's ok for strings to extend across multiple 15226fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org lines, as long as a line continuation character (backslash) 15236fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org terminates each line. Although not currently prohibited by the C++ 15246fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org style guide, it's ugly and unnecessary. We don't do well with either 15256fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org in this lint program, so we warn about both. 15266fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 15276fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org Args: 15286fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org filename: The name of the current file. 15296fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org clean_lines: A CleansedLines instance containing the file. 15306fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org linenum: The number of the line to check. 15316fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org error: The function to call with any errors found. 15326fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org """ 15336fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org line = clean_lines.elided[linenum] 15346fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 15356fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # Remove all \\ (escaped backslashes) from the line. They are OK, and the 15366fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # second (escaped) slash may trigger later \" detection erroneously. 15376fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org line = line.replace('\\\\', '') 15386fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 15396fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if line.count('/*') > line.count('*/'): 15406fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org error(filename, linenum, 'readability/multiline_comment', 5, 15416fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'Complex multi-line /*...*/-style comment found. ' 15426fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'Lint may give bogus warnings. ' 15436fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'Consider replacing these with //-style comments, ' 15446fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'with #if 0...#endif, ' 15456fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'or with more clearly structured multi-line comments.') 15466fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 15476fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if (line.count('"') - line.count('\\"')) % 2: 15486fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org error(filename, linenum, 'readability/multiline_string', 5, 15496fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'Multi-line string ("...") found. This lint script doesn\'t ' 1550dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'do well with such strings, and may give bogus warnings. ' 1551dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'Use C++11 raw strings or concatenation instead.') 15526fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 15536fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 15546fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.orgthreading_list = ( 15556fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org ('asctime(', 'asctime_r('), 15566fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org ('ctime(', 'ctime_r('), 15576fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org ('getgrgid(', 'getgrgid_r('), 15586fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org ('getgrnam(', 'getgrnam_r('), 15596fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org ('getlogin(', 'getlogin_r('), 15606fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org ('getpwnam(', 'getpwnam_r('), 15616fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org ('getpwuid(', 'getpwuid_r('), 15626fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org ('gmtime(', 'gmtime_r('), 15636fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org ('localtime(', 'localtime_r('), 15646fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org ('rand(', 'rand_r('), 15656fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org ('strtok(', 'strtok_r('), 15666fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org ('ttyname(', 'ttyname_r('), 15676fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org ) 15686fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 15696fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 15706fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.orgdef CheckPosixThreading(filename, clean_lines, linenum, error): 15716fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org """Checks for calls to thread-unsafe functions. 15726fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 15736fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org Much code has been originally written without consideration of 15746fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org multi-threading. Also, engineers are relying on their old experience; 15756fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org they have learned posix before threading extensions were added. These 15766fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org tests guide the engineers to use thread-safe functions (when using 15776fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org posix directly). 15786fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 15796fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org Args: 15806fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org filename: The name of the current file. 15816fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org clean_lines: A CleansedLines instance containing the file. 15826fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org linenum: The number of the line to check. 15836fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org error: The function to call with any errors found. 15846fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org """ 15856fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org line = clean_lines.elided[linenum] 15866fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org for single_thread_function, multithread_safe_function in threading_list: 15876fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org ix = line.find(single_thread_function) 1588dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # Comparisons made explicit for clarity -- pylint: disable=g-explicit-bool-comparison 15896fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if ix >= 0 and (ix == 0 or (not line[ix - 1].isalnum() and 15906fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org line[ix - 1] not in ('_', '.', '>'))): 15916fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org error(filename, linenum, 'runtime/threadsafe_fn', 2, 15926fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'Consider using ' + multithread_safe_function + 15936fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org '...) instead of ' + single_thread_function + 15946fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org '...) for improved thread safety.') 15956fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 15966fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 1597dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.orgdef CheckVlogArguments(filename, clean_lines, linenum, error): 1598dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org """Checks that VLOG() is only used for defining a logging level. 1599dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 1600dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org For example, VLOG(2) is correct. VLOG(INFO), VLOG(WARNING), VLOG(ERROR), and 1601dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org VLOG(FATAL) are not. 1602dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 1603dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org Args: 1604dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org filename: The name of the current file. 1605dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org clean_lines: A CleansedLines instance containing the file. 1606dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org linenum: The number of the line to check. 1607dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org error: The function to call with any errors found. 1608dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org """ 1609dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org line = clean_lines.elided[linenum] 1610dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org if Search(r'\bVLOG\((INFO|ERROR|WARNING|DFATAL|FATAL)\)', line): 1611dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org error(filename, linenum, 'runtime/vlog', 5, 1612dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'VLOG() should be used with numeric verbosity level. ' 1613dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'Use LOG() if you want symbolic severity levels.') 1614dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 1615dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 16166fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org# Matches invalid increment: *count++, which moves pointer instead of 16176fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org# incrementing a value. 16186fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org_RE_PATTERN_INVALID_INCREMENT = re.compile( 16196fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org r'^\s*\*\w+(\+\+|--);') 16206fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 16216fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 16226fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.orgdef CheckInvalidIncrement(filename, clean_lines, linenum, error): 16236fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org """Checks for invalid increment *count++. 16246fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 16256fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org For example following function: 16266fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org void increment_counter(int* count) { 16276fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org *count++; 16286fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org } 16296fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org is invalid, because it effectively does count++, moving pointer, and should 16306fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org be replaced with ++*count, (*count)++ or *count += 1. 16316fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 16326fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org Args: 16336fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org filename: The name of the current file. 16346fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org clean_lines: A CleansedLines instance containing the file. 16356fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org linenum: The number of the line to check. 16366fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org error: The function to call with any errors found. 16376fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org """ 16386fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org line = clean_lines.elided[linenum] 16396fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if _RE_PATTERN_INVALID_INCREMENT.match(line): 16406fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org error(filename, linenum, 'runtime/invalid_increment', 5, 16416fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'Changing pointer instead of value (or unused value of operator*).') 16426fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 16436fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 164410a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.orgclass _BlockInfo(object): 164510a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org """Stores information about a generic block of code.""" 164610a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org 164710a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org def __init__(self, seen_open_brace): 164810a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org self.seen_open_brace = seen_open_brace 164910a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org self.open_parentheses = 0 165010a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org self.inline_asm = _NO_ASM 165110a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org 165210a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org def CheckBegin(self, filename, clean_lines, linenum, error): 165310a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org """Run checks that applies to text up to the opening brace. 165410a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org 165510a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org This is mostly for checking the text after the class identifier 165610a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org and the "{", usually where the base class is specified. For other 165710a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org blocks, there isn't much to check, so we always pass. 165810a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org 165910a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org Args: 166010a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org filename: The name of the current file. 166110a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org clean_lines: A CleansedLines instance containing the file. 166210a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org linenum: The number of the line to check. 166310a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org error: The function to call with any errors found. 166410a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org """ 166510a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org pass 166610a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org 166710a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org def CheckEnd(self, filename, clean_lines, linenum, error): 166810a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org """Run checks that applies to text after the closing brace. 166910a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org 167010a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org This is mostly used for checking end of namespace comments. 167110a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org 167210a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org Args: 167310a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org filename: The name of the current file. 167410a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org clean_lines: A CleansedLines instance containing the file. 167510a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org linenum: The number of the line to check. 167610a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org error: The function to call with any errors found. 167710a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org """ 167810a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org pass 167910a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org 168010a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org 168110a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.orgclass _ClassInfo(_BlockInfo): 16826fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org """Stores information about a class.""" 16836fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 168410a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org def __init__(self, name, class_or_struct, clean_lines, linenum): 168510a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org _BlockInfo.__init__(self, False) 16866fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org self.name = name 168710a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org self.starting_linenum = linenum 16886fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org self.is_derived = False 168910a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org if class_or_struct == 'struct': 169010a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org self.access = 'public' 1691dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org self.is_struct = True 169210a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org else: 169310a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org self.access = 'private' 1694dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org self.is_struct = False 1695dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 1696dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # Remember initial indentation level for this class. Using raw_lines here 1697dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # instead of elided to account for leading comments. 1698dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org initial_indent = Match(r'^( *)\S', clean_lines.raw_lines[linenum]) 1699dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org if initial_indent: 1700dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org self.class_indent = len(initial_indent.group(1)) 1701dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org else: 1702dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org self.class_indent = 0 17036fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 17046fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # Try to find the end of the class. This will be confused by things like: 17056fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # class A { 17066fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # } *x = { ... 17076fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # 17086fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # But it's still good enough for CheckSectionSpacing. 17096fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org self.last_line = 0 17106fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org depth = 0 17116fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org for i in range(linenum, clean_lines.NumLines()): 171210a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org line = clean_lines.elided[i] 17136fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org depth += line.count('{') - line.count('}') 17146fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if not depth: 17156fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org self.last_line = i 17166fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org break 17176fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 171810a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org def CheckBegin(self, filename, clean_lines, linenum, error): 171910a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # Look for a bare ':' 172010a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org if Search('(^|[^:]):($|[^:])', clean_lines.elided[linenum]): 172110a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org self.is_derived = True 17226fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 1723dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org def CheckEnd(self, filename, clean_lines, linenum, error): 1724dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # Check that closing brace is aligned with beginning of the class. 1725dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # Only do this if the closing brace is indented by only whitespaces. 1726dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # This means we will not check single-line class definitions. 1727dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org indent = Match(r'^( *)\}', clean_lines.elided[linenum]) 1728dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org if indent and len(indent.group(1)) != self.class_indent: 1729dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org if self.is_struct: 1730dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org parent = 'struct ' + self.name 1731dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org else: 1732dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org parent = 'class ' + self.name 1733dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org error(filename, linenum, 'whitespace/indent', 3, 1734dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'Closing brace should be aligned with beginning of %s' % parent) 1735dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 17366fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 173710a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.orgclass _NamespaceInfo(_BlockInfo): 173810a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org """Stores information about a namespace.""" 173910a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org 174010a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org def __init__(self, name, linenum): 174110a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org _BlockInfo.__init__(self, False) 174210a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org self.name = name or '' 174310a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org self.starting_linenum = linenum 174410a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org 174510a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org def CheckEnd(self, filename, clean_lines, linenum, error): 174610a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org """Check end of namespace comments.""" 174710a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org line = clean_lines.raw_lines[linenum] 174810a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org 174910a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # Check how many lines is enclosed in this namespace. Don't issue 175010a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # warning for missing namespace comments if there aren't enough 175110a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # lines. However, do apply checks if there is already an end of 175210a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # namespace comment and it's incorrect. 175310a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # 175410a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # TODO(unknown): We always want to check end of namespace comments 175510a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # if a namespace is large, but sometimes we also want to apply the 175610a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # check if a short namespace contained nontrivial things (something 175710a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # other than forward declarations). There is currently no logic on 175810a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # deciding what these nontrivial things are, so this check is 175910a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # triggered by namespace size only, which works most of the time. 176010a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org if (linenum - self.starting_linenum < 10 176110a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org and not Match(r'};*\s*(//|/\*).*\bnamespace\b', line)): 176210a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org return 176310a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org 176410a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # Look for matching comment at end of namespace. 176510a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # 176610a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # Note that we accept C style "/* */" comments for terminating 176710a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # namespaces, so that code that terminate namespaces inside 1768dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # preprocessor macros can be cpplint clean. 176910a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # 177010a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # We also accept stuff like "// end of namespace <name>." with the 177110a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # period at the end. 177210a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # 177310a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # Besides these, we don't accept anything else, otherwise we might 177410a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # get false negatives when existing comment is a substring of the 1775dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # expected namespace. 177610a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org if self.name: 177710a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # Named namespace 177810a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org if not Match((r'};*\s*(//|/\*).*\bnamespace\s+' + re.escape(self.name) + 177910a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org r'[\*/\.\\\s]*$'), 178010a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org line): 178110a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org error(filename, linenum, 'readability/namespace', 5, 178210a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org 'Namespace should be terminated with "// namespace %s"' % 178310a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org self.name) 178410a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org else: 178510a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # Anonymous namespace 178610a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org if not Match(r'};*\s*(//|/\*).*\bnamespace[\*/\.\\\s]*$', line): 178710a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org error(filename, linenum, 'readability/namespace', 5, 178810a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org 'Namespace should be terminated with "// namespace"') 178910a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org 179010a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org 179110a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.orgclass _PreprocessorInfo(object): 179210a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org """Stores checkpoints of nesting stacks when #if/#else is seen.""" 179310a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org 179410a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org def __init__(self, stack_before_if): 179510a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # The entire nesting stack before #if 179610a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org self.stack_before_if = stack_before_if 179710a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org 179810a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # The entire nesting stack up to #else 179910a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org self.stack_before_else = [] 180010a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org 180110a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # Whether we have already seen #else or #elif 180210a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org self.seen_else = False 180310a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org 180410a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org 180510a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.orgclass _NestingState(object): 180610a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org """Holds states related to parsing braces.""" 18076fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 18086fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org def __init__(self): 180910a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # Stack for tracking all braces. An object is pushed whenever we 181010a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # see a "{", and popped when we see a "}". Only 3 types of 181110a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # objects are possible: 181210a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # - _ClassInfo: a class or struct. 181310a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # - _NamespaceInfo: a namespace. 181410a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # - _BlockInfo: some other type of block. 181510a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org self.stack = [] 181610a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org 181710a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # Stack of _PreprocessorInfo objects. 181810a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org self.pp_stack = [] 181910a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org 182010a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org def SeenOpenBrace(self): 182110a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org """Check if we have seen the opening brace for the innermost block. 18226fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 182310a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org Returns: 182410a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org True if we have seen the opening brace, False if the innermost 182510a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org block is still expecting an opening brace. 182610a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org """ 182710a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org return (not self.stack) or self.stack[-1].seen_open_brace 182810a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org 182910a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org def InNamespaceBody(self): 183010a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org """Check if we are currently one level inside a namespace body. 183110a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org 183210a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org Returns: 183310a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org True if top of the stack is a namespace block, False otherwise. 183410a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org """ 183510a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org return self.stack and isinstance(self.stack[-1], _NamespaceInfo) 183610a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org 183710a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org def UpdatePreprocessor(self, line): 183810a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org """Update preprocessor stack. 183910a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org 184010a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org We need to handle preprocessors due to classes like this: 184110a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org #ifdef SWIG 184210a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org struct ResultDetailsPageElementExtensionPoint { 184310a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org #else 184410a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org struct ResultDetailsPageElementExtensionPoint : public Extension { 184510a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org #endif 184610a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org 184710a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org We make the following assumptions (good enough for most files): 184810a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org - Preprocessor condition evaluates to true from #if up to first 184910a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org #else/#elif/#endif. 185010a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org 185110a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org - Preprocessor condition evaluates to false from #else/#elif up 185210a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org to #endif. We still perform lint checks on these lines, but 185310a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org these do not affect nesting stack. 185410a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org 185510a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org Args: 185610a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org line: current line to check. 185710a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org """ 185810a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org if Match(r'^\s*#\s*(if|ifdef|ifndef)\b', line): 185910a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # Beginning of #if block, save the nesting stack here. The saved 186010a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # stack will allow us to restore the parsing state in the #else case. 186110a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org self.pp_stack.append(_PreprocessorInfo(copy.deepcopy(self.stack))) 186210a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org elif Match(r'^\s*#\s*(else|elif)\b', line): 186310a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # Beginning of #else block 186410a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org if self.pp_stack: 186510a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org if not self.pp_stack[-1].seen_else: 186610a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # This is the first #else or #elif block. Remember the 186710a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # whole nesting stack up to this point. This is what we 186810a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # keep after the #endif. 186910a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org self.pp_stack[-1].seen_else = True 187010a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org self.pp_stack[-1].stack_before_else = copy.deepcopy(self.stack) 187110a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org 187210a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # Restore the stack to how it was before the #if 187310a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org self.stack = copy.deepcopy(self.pp_stack[-1].stack_before_if) 187410a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org else: 187510a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # TODO(unknown): unexpected #else, issue warning? 187610a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org pass 187710a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org elif Match(r'^\s*#\s*endif\b', line): 187810a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # End of #if or #else blocks. 187910a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org if self.pp_stack: 188010a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # If we saw an #else, we will need to restore the nesting 188110a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # stack to its former state before the #else, otherwise we 188210a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # will just continue from where we left off. 188310a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org if self.pp_stack[-1].seen_else: 188410a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # Here we can just use a shallow copy since we are the last 188510a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # reference to it. 188610a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org self.stack = self.pp_stack[-1].stack_before_else 188710a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # Drop the corresponding #if 188810a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org self.pp_stack.pop() 188910a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org else: 189010a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # TODO(unknown): unexpected #endif, issue warning? 189110a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org pass 189210a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org 189310a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org def Update(self, filename, clean_lines, linenum, error): 189410a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org """Update nesting state with current line. 189510a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org 189610a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org Args: 189710a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org filename: The name of the current file. 189810a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org clean_lines: A CleansedLines instance containing the file. 189910a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org linenum: The number of the line to check. 190010a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org error: The function to call with any errors found. 190110a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org """ 190210a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org line = clean_lines.elided[linenum] 190310a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org 190410a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # Update pp_stack first 190510a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org self.UpdatePreprocessor(line) 190610a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org 190710a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # Count parentheses. This is to avoid adding struct arguments to 190810a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # the nesting stack. 190910a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org if self.stack: 191010a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org inner_block = self.stack[-1] 191110a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org depth_change = line.count('(') - line.count(')') 191210a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org inner_block.open_parentheses += depth_change 191310a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org 191410a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # Also check if we are starting or ending an inline assembly block. 191510a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org if inner_block.inline_asm in (_NO_ASM, _END_ASM): 191610a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org if (depth_change != 0 and 191710a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org inner_block.open_parentheses == 1 and 191810a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org _MATCH_ASM.match(line)): 191910a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # Enter assembly block 192010a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org inner_block.inline_asm = _INSIDE_ASM 192110a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org else: 192210a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # Not entering assembly block. If previous line was _END_ASM, 192310a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # we will now shift to _NO_ASM state. 192410a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org inner_block.inline_asm = _NO_ASM 192510a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org elif (inner_block.inline_asm == _INSIDE_ASM and 192610a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org inner_block.open_parentheses == 0): 192710a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # Exit assembly block 192810a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org inner_block.inline_asm = _END_ASM 192910a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org 193010a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # Consume namespace declaration at the beginning of the line. Do 193110a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # this in a loop so that we catch same line declarations like this: 193210a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # namespace proto2 { namespace bridge { class MessageSet; } } 193310a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org while True: 193410a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # Match start of namespace. The "\b\s*" below catches namespace 193510a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # declarations even if it weren't followed by a whitespace, this 193610a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # is so that we don't confuse our namespace checker. The 193710a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # missing spaces will be flagged by CheckSpacing. 193810a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org namespace_decl_match = Match(r'^\s*namespace\b\s*([:\w]+)?(.*)$', line) 193910a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org if not namespace_decl_match: 194010a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org break 194110a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org 194210a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org new_namespace = _NamespaceInfo(namespace_decl_match.group(1), linenum) 194310a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org self.stack.append(new_namespace) 194410a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org 194510a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org line = namespace_decl_match.group(2) 194610a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org if line.find('{') != -1: 194710a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org new_namespace.seen_open_brace = True 194810a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org line = line[line.find('{') + 1:] 194910a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org 195010a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # Look for a class declaration in whatever is left of the line 195110a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # after parsing namespaces. The regexp accounts for decorated classes 195210a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # such as in: 195310a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # class LOCKABLE API Object { 195410a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # }; 195510a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # 195610a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # Templates with class arguments may confuse the parser, for example: 195710a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # template <class T 195810a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # class Comparator = less<T>, 195910a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # class Vector = vector<T> > 196010a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # class HeapQueue { 196110a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # 196210a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # Because this parser has no nesting state about templates, by the 196310a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # time it saw "class Comparator", it may think that it's a new class. 196410a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # Nested templates have a similar problem: 196510a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # template < 196610a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # typename ExportedType, 196710a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # typename TupleType, 196810a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # template <typename, typename> class ImplTemplate> 196910a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # 197010a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # To avoid these cases, we ignore classes that are followed by '=' or '>' 197110a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org class_decl_match = Match( 197210a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org r'\s*(template\s*<[\w\s<>,:]*>\s*)?' 1973dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org r'(class|struct)\s+([A-Z_]+\s+)*(\w+(?:::\w+)*)' 1974dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org r'(([^=>]|<[^<>]*>|<[^<>]*<[^<>]*>\s*>)*)$', line) 197510a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org if (class_decl_match and 197610a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org (not self.stack or self.stack[-1].open_parentheses == 0)): 197710a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org self.stack.append(_ClassInfo( 197810a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org class_decl_match.group(4), class_decl_match.group(2), 197910a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org clean_lines, linenum)) 198010a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org line = class_decl_match.group(5) 198110a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org 198210a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # If we have not yet seen the opening brace for the innermost block, 198310a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # run checks here. 198410a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org if not self.SeenOpenBrace(): 198510a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org self.stack[-1].CheckBegin(filename, clean_lines, linenum, error) 198610a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org 198710a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # Update access control if we are inside a class/struct 198810a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org if self.stack and isinstance(self.stack[-1], _ClassInfo): 1989dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org classinfo = self.stack[-1] 1990dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org access_match = Match( 1991dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org r'^(.*)\b(public|private|protected|signals)(\s+(?:slots\s*)?)?' 1992dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org r':(?:[^:]|$)', 1993dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org line) 199410a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org if access_match: 1995dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org classinfo.access = access_match.group(2) 1996dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 1997dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # Check that access keywords are indented +1 space. Skip this 1998dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # check if the keywords are not preceded by whitespaces. 1999dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org indent = access_match.group(1) 2000dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org if (len(indent) != classinfo.class_indent + 1 and 2001dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org Match(r'^\s*$', indent)): 2002dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org if classinfo.is_struct: 2003dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org parent = 'struct ' + classinfo.name 2004dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org else: 2005dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org parent = 'class ' + classinfo.name 2006dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org slots = '' 2007dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org if access_match.group(3): 2008dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org slots = access_match.group(3) 2009dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org error(filename, linenum, 'whitespace/indent', 3, 2010dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org '%s%s: should be indented +1 space inside %s' % ( 2011dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org access_match.group(2), slots, parent)) 201210a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org 201310a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # Consume braces or semicolons from what's left of the line 201410a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org while True: 201510a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # Match first brace, semicolon, or closed parenthesis. 201610a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org matched = Match(r'^[^{;)}]*([{;)}])(.*)$', line) 201710a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org if not matched: 201810a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org break 201910a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org 202010a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org token = matched.group(1) 202110a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org if token == '{': 202210a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # If namespace or class hasn't seen a opening brace yet, mark 202310a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # namespace/class head as complete. Push a new block onto the 202410a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # stack otherwise. 202510a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org if not self.SeenOpenBrace(): 202610a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org self.stack[-1].seen_open_brace = True 202710a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org else: 202810a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org self.stack.append(_BlockInfo(True)) 202910a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org if _MATCH_ASM.match(line): 203010a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org self.stack[-1].inline_asm = _BLOCK_ASM 203110a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org elif token == ';' or token == ')': 203210a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # If we haven't seen an opening brace yet, but we already saw 203310a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # a semicolon, this is probably a forward declaration. Pop 203410a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # the stack for these. 203510a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # 203610a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # Similarly, if we haven't seen an opening brace yet, but we 203710a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # already saw a closing parenthesis, then these are probably 203810a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # function arguments with extra "class" or "struct" keywords. 203910a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # Also pop these stack for these. 204010a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org if not self.SeenOpenBrace(): 204110a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org self.stack.pop() 204210a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org else: # token == '}' 204310a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # Perform end of block checks and pop the stack. 204410a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org if self.stack: 204510a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org self.stack[-1].CheckEnd(filename, clean_lines, linenum, error) 204610a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org self.stack.pop() 204710a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org line = matched.group(2) 204810a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org 204910a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org def InnermostClass(self): 205010a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org """Get class info on the top of the stack. 205110a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org 205210a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org Returns: 205310a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org A _ClassInfo object if we are inside a class, or None otherwise. 205410a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org """ 205510a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org for i in range(len(self.stack), 0, -1): 205610a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org classinfo = self.stack[i - 1] 205710a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org if isinstance(classinfo, _ClassInfo): 205810a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org return classinfo 205910a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org return None 206010a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org 2061dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org def CheckCompletedBlocks(self, filename, error): 2062dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org """Checks that all classes and namespaces have been completely parsed. 20636fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 20646fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org Call this when all lines in a file have been processed. 20656fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org Args: 20666fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org filename: The name of the current file. 20676fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org error: The function to call with any errors found. 20686fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org """ 206910a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # Note: This test can result in false positives if #ifdef constructs 207010a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # get in the way of brace matching. See the testBuildClass test in 207110a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # cpplint_unittest.py for an example of this. 207210a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org for obj in self.stack: 207310a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org if isinstance(obj, _ClassInfo): 207410a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org error(filename, obj.starting_linenum, 'build/class', 5, 207510a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org 'Failed to find complete declaration of class %s' % 207610a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org obj.name) 2077dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org elif isinstance(obj, _NamespaceInfo): 2078dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org error(filename, obj.starting_linenum, 'build/namespaces', 5, 2079dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'Failed to find complete declaration of namespace %s' % 2080dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org obj.name) 20816fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 20826fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 20836fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.orgdef CheckForNonStandardConstructs(filename, clean_lines, linenum, 208410a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org nesting_state, error): 2085dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org r"""Logs an error if we see certain non-ANSI constructs ignored by gcc-2. 20866fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 20876fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org Complain about several constructs which gcc-2 accepts, but which are 20886fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org not standard C++. Warning about these in lint is one way to ease the 20896fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org transition to new compilers. 20906fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org - put storage class first (e.g. "static const" instead of "const static"). 20916fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org - "%lld" instead of %qd" in printf-type functions. 20926fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org - "%1$d" is non-standard in printf-type functions. 20936fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org - "\%" is an undefined character escape sequence. 20946fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org - text after #endif is not allowed. 20956fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org - invalid inner-style forward declaration. 20966fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org - >? and <? operators, and their >?= and <?= cousins. 20976fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 20986fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org Additionally, check for constructor/destructor style violations and reference 20996fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org members, as it is very convenient to do so while checking for 21006fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org gcc-2 compliance. 21016fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 21026fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org Args: 21036fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org filename: The name of the current file. 21046fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org clean_lines: A CleansedLines instance containing the file. 21056fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org linenum: The number of the line to check. 210610a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org nesting_state: A _NestingState instance which maintains information about 210710a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org the current stack of nested blocks being parsed. 21086fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org error: A callable to which errors are reported, which takes 4 arguments: 21096fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org filename, line number, error level, and message 21106fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org """ 21116fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 21126fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # Remove comments from the line, but leave in strings for now. 21136fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org line = clean_lines.lines[linenum] 21146fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 21156fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if Search(r'printf\s*\(.*".*%[-+ ]?\d*q', line): 21166fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org error(filename, linenum, 'runtime/printf_format', 3, 21176fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org '%q in format strings is deprecated. Use %ll instead.') 21186fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 21196fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if Search(r'printf\s*\(.*".*%\d+\$', line): 21206fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org error(filename, linenum, 'runtime/printf_format', 2, 21216fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org '%N$ formats are unconventional. Try rewriting to avoid them.') 21226fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 21236fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # Remove escaped backslashes before looking for undefined escapes. 21246fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org line = line.replace('\\\\', '') 21256fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 21266fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if Search(r'("|\').*\\(%|\[|\(|{)', line): 21276fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org error(filename, linenum, 'build/printf_format', 3, 21286fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org '%, [, (, and { are undefined character escapes. Unescape them.') 21296fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 21306fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # For the rest, work with both comments and strings removed. 21316fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org line = clean_lines.elided[linenum] 21326fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 21336fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if Search(r'\b(const|volatile|void|char|short|int|long' 21346fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org r'|float|double|signed|unsigned' 21356fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org r'|schar|u?int8|u?int16|u?int32|u?int64)' 213610a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org r'\s+(register|static|extern|typedef)\b', 21376fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org line): 21386fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org error(filename, linenum, 'build/storage_class', 5, 21396fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'Storage class (static, extern, typedef, etc) should be first.') 21406fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 21416fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if Match(r'\s*#\s*endif\s*[^/\s]+', line): 21426fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org error(filename, linenum, 'build/endif_comment', 5, 21436fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'Uncommented text after #endif is non-standard. Use a comment.') 21446fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 21456fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if Match(r'\s*class\s+(\w+\s*::\s*)+\w+\s*;', line): 21466fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org error(filename, linenum, 'build/forward_decl', 5, 21476fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'Inner-style forward declarations are invalid. Remove this line.') 21486fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 21496fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if Search(r'(\w+|[+-]?\d+(\.\d*)?)\s*(<|>)\?=?\s*(\w+|[+-]?\d+)(\.\d*)?', 21506fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org line): 21516fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org error(filename, linenum, 'build/deprecated', 3, 21526fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org '>? and <? (max and min) operators are non-standard and deprecated.') 21536fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 21546fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if Search(r'^\s*const\s*string\s*&\s*\w+\s*;', line): 21556fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # TODO(unknown): Could it be expanded safely to arbitrary references, 21566fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # without triggering too many false positives? The first 21576fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # attempt triggered 5 warnings for mostly benign code in the regtest, hence 21586fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # the restriction. 21596fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # Here's the original regexp, for the reference: 21606fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # type_name = r'\w+((\s*::\s*\w+)|(\s*<\s*\w+?\s*>))?' 21616fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # r'\s*const\s*' + type_name + '\s*&\s*\w+\s*;' 21626fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org error(filename, linenum, 'runtime/member_string_references', 2, 21636fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'const string& members are dangerous. It is much better to use ' 21646fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'alternatives, such as pointers or simple constants.') 21656fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 216610a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # Everything else in this function operates on class declarations. 216710a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # Return early if the top of the nesting stack is not a class, or if 216810a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # the class head is not completed yet. 216910a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org classinfo = nesting_state.InnermostClass() 217010a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org if not classinfo or not classinfo.seen_open_brace: 21716fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org return 21726fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 21736fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # The class may have been declared with namespace or classname qualifiers. 21746fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # The constructor and destructor will not have those qualifiers. 21756fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org base_classname = classinfo.name.split('::')[-1] 21766fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 21776fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # Look for single-argument constructors that aren't marked explicit. 21786fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # Technically a valid construct, but against style. 21796fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org args = Match(r'\s+(?:inline\s+)?%s\s*\(([^,()]+)\)' 21806fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org % re.escape(base_classname), 21816fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org line) 21826fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if (args and 21836fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org args.group(1) != 'void' and 2184dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org not Match(r'(const\s+)?%s(\s+const)?\s*(?:<\w+>\s*)?&' 2185dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org % re.escape(base_classname), args.group(1).strip())): 21866fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org error(filename, linenum, 'runtime/explicit', 5, 21876fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'Single-argument constructors should be marked explicit.') 21886fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 21896fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 21906fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.orgdef CheckSpacingForFunctionCall(filename, line, linenum, error): 21916fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org """Checks for the correctness of various spacing around function calls. 21926fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 21936fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org Args: 21946fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org filename: The name of the current file. 21956fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org line: The text of the line to check. 21966fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org linenum: The number of the line to check. 21976fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org error: The function to call with any errors found. 21986fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org """ 21996fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 22006fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # Since function calls often occur inside if/for/while/switch 22016fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # expressions - which have their own, more liberal conventions - we 22026fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # first see if we should be looking inside such an expression for a 22036fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # function call, to which we can apply more strict standards. 22046fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org fncall = line # if there's no control flow construct, look at whole line 22056fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org for pattern in (r'\bif\s*\((.*)\)\s*{', 22066fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org r'\bfor\s*\((.*)\)\s*{', 22076fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org r'\bwhile\s*\((.*)\)\s*[{;]', 22086fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org r'\bswitch\s*\((.*)\)\s*{'): 22096fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org match = Search(pattern, line) 22106fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if match: 22116fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org fncall = match.group(1) # look inside the parens for function calls 22126fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org break 22136fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 22146fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # Except in if/for/while/switch, there should never be space 22156fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # immediately inside parens (eg "f( 3, 4 )"). We make an exception 22166fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # for nested parens ( (a+b) + c ). Likewise, there should never be 22176fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # a space before a ( when it's a function argument. I assume it's a 22186fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # function argument when the char before the whitespace is legal in 22196fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # a function name (alnum + _) and we're not starting a macro. Also ignore 22206fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # pointers and references to arrays and functions coz they're too tricky: 22216fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # we use a very simple way to recognize these: 22226fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # " (something)(maybe-something)" or 22236fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # " (something)(maybe-something," or 22246fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # " (something)[something]" 22256fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # Note that we assume the contents of [] to be short enough that 22266fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # they'll never need to wrap. 22276fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if ( # Ignore control structures. 2228dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org not Search(r'\b(if|for|while|switch|return|new|delete|catch|sizeof)\b', 2229dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org fncall) and 22306fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # Ignore pointers/references to functions. 22316fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org not Search(r' \([^)]+\)\([^)]*(\)|,$)', fncall) and 22326fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # Ignore pointers/references to arrays. 22336fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org not Search(r' \([^)]+\)\[[^\]]+\]', fncall)): 22346fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if Search(r'\w\s*\(\s(?!\s*\\$)', fncall): # a ( used for a fn call 22356fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org error(filename, linenum, 'whitespace/parens', 4, 22366fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'Extra space after ( in function call') 22376fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org elif Search(r'\(\s+(?!(\s*\\)|\()', fncall): 22386fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org error(filename, linenum, 'whitespace/parens', 2, 22396fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'Extra space after (') 22406fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if (Search(r'\w\s+\(', fncall) and 224110a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org not Search(r'#\s*define|typedef', fncall) and 2242dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org not Search(r'\w\s+\((\w+::)*\*\w+\)\(', fncall)): 22436fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org error(filename, linenum, 'whitespace/parens', 4, 22446fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'Extra space before ( in function call') 22456fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # If the ) is followed only by a newline or a { + newline, assume it's 22466fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # part of a control statement (if/while/etc), and don't complain 22476fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if Search(r'[^)]\s+\)\s*[^{\s]', fncall): 22486fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # If the closing parenthesis is preceded by only whitespaces, 22496fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # try to give a more descriptive error message. 22506fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if Search(r'^\s+\)', fncall): 22516fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org error(filename, linenum, 'whitespace/parens', 2, 22526fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'Closing ) should be moved to the previous line') 22536fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org else: 22546fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org error(filename, linenum, 'whitespace/parens', 2, 22556fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'Extra space before )') 22566fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 22576fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 22586fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.orgdef IsBlankLine(line): 22596fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org """Returns true if the given line is blank. 22606fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 22616fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org We consider a line to be blank if the line is empty or consists of 22626fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org only white spaces. 22636fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 22646fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org Args: 22656fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org line: A line of a string. 22666fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 22676fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org Returns: 22686fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org True, if the given line is blank. 22696fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org """ 22706fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org return not line or line.isspace() 22716fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 22726fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 22736fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.orgdef CheckForFunctionLengths(filename, clean_lines, linenum, 22746fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org function_state, error): 22756fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org """Reports for long function bodies. 22766fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 22776fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org For an overview why this is done, see: 22786fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml#Write_Short_Functions 22796fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 22806fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org Uses a simplistic algorithm assuming other style guidelines 22816fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org (especially spacing) are followed. 22826fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org Only checks unindented functions, so class members are unchecked. 22836fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org Trivial bodies are unchecked, so constructors with huge initializer lists 22846fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org may be missed. 22856fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org Blank/comment lines are not counted so as to avoid encouraging the removal 22866fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org of vertical space and comments just to get through a lint check. 22876fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org NOLINT *on the last line of a function* disables this check. 22886fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 22896fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org Args: 22906fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org filename: The name of the current file. 22916fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org clean_lines: A CleansedLines instance containing the file. 22926fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org linenum: The number of the line to check. 22936fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org function_state: Current function name and lines in body so far. 22946fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org error: The function to call with any errors found. 22956fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org """ 22966fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org lines = clean_lines.lines 22976fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org line = lines[linenum] 22986fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org raw = clean_lines.raw_lines 22996fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org raw_line = raw[linenum] 23006fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org joined_line = '' 23016fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 23026fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org starting_func = False 23036fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org regexp = r'(\w(\w|::|\*|\&|\s)*)\(' # decls * & space::name( ... 23046fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org match_result = Match(regexp, line) 23056fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if match_result: 23066fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # If the name is all caps and underscores, figure it's a macro and 23076fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # ignore it, unless it's TEST or TEST_F. 23086fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org function_name = match_result.group(1).split()[-1] 23096fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if function_name == 'TEST' or function_name == 'TEST_F' or ( 23106fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org not Match(r'[A-Z_]+$', function_name)): 23116fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org starting_func = True 23126fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 23136fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if starting_func: 23146fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org body_found = False 23156fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org for start_linenum in xrange(linenum, clean_lines.NumLines()): 23166fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org start_line = lines[start_linenum] 23176fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org joined_line += ' ' + start_line.lstrip() 23186fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if Search(r'(;|})', start_line): # Declarations and trivial functions 23196fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org body_found = True 23206fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org break # ... ignore 23216fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org elif Search(r'{', start_line): 23226fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org body_found = True 23236fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org function = Search(r'((\w|:)*)\(', line).group(1) 23246fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if Match(r'TEST', function): # Handle TEST... macros 23256fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org parameter_regexp = Search(r'(\(.*\))', joined_line) 23266fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if parameter_regexp: # Ignore bad syntax 23276fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org function += parameter_regexp.group(1) 23286fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org else: 23296fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org function += '()' 23306fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org function_state.Begin(function) 23316fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org break 23326fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if not body_found: 23336fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # No body for the function (or evidence of a non-function) was found. 23346fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org error(filename, linenum, 'readability/fn_size', 5, 23356fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'Lint failed to find start of function body.') 23366fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org elif Match(r'^\}\s*$', line): # function end 23376fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org function_state.Check(error, filename, linenum) 23386fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org function_state.End() 23396fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org elif not Match(r'^\s*$', line): 23406fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org function_state.Count() # Count non-blank/non-comment lines. 23416fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 23426fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 23436fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org_RE_PATTERN_TODO = re.compile(r'^//(\s*)TODO(\(.+?\))?:?(\s|$)?') 23446fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 23456fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 23466fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.orgdef CheckComment(comment, filename, linenum, error): 23476fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org """Checks for common mistakes in TODO comments. 23486fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 23496fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org Args: 23506fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org comment: The text of the comment from the line in question. 23516fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org filename: The name of the current file. 23526fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org linenum: The number of the line to check. 23536fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org error: The function to call with any errors found. 23546fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org """ 23556fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org match = _RE_PATTERN_TODO.match(comment) 23566fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if match: 23576fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # One whitespace is correct; zero whitespace is handled elsewhere. 23586fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org leading_whitespace = match.group(1) 23596fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if len(leading_whitespace) > 1: 23606fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org error(filename, linenum, 'whitespace/todo', 2, 23616fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'Too many spaces before TODO') 23626fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 23636fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org username = match.group(2) 23646fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if not username: 23656fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org error(filename, linenum, 'readability/todo', 2, 23666fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'Missing username in TODO; it should look like ' 23676fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org '"// TODO(my_username): Stuff."') 23686fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 23696fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org middle_whitespace = match.group(3) 2370dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # Comparisons made explicit for correctness -- pylint: disable=g-explicit-bool-comparison 23716fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if middle_whitespace != ' ' and middle_whitespace != '': 23726fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org error(filename, linenum, 'whitespace/todo', 2, 23736fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'TODO(my_username) should be followed by a space') 23746fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 237510a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.orgdef CheckAccess(filename, clean_lines, linenum, nesting_state, error): 237610a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org """Checks for improper use of DISALLOW* macros. 237710a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org 237810a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org Args: 237910a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org filename: The name of the current file. 238010a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org clean_lines: A CleansedLines instance containing the file. 238110a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org linenum: The number of the line to check. 238210a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org nesting_state: A _NestingState instance which maintains information about 238310a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org the current stack of nested blocks being parsed. 238410a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org error: The function to call with any errors found. 238510a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org """ 238610a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org line = clean_lines.elided[linenum] # get rid of comments and strings 238710a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org 238810a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org matched = Match((r'\s*(DISALLOW_COPY_AND_ASSIGN|' 238910a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org r'DISALLOW_EVIL_CONSTRUCTORS|' 239010a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org r'DISALLOW_IMPLICIT_CONSTRUCTORS)'), line) 239110a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org if not matched: 239210a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org return 239310a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org if nesting_state.stack and isinstance(nesting_state.stack[-1], _ClassInfo): 239410a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org if nesting_state.stack[-1].access != 'private': 239510a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org error(filename, linenum, 'readability/constructors', 3, 239610a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org '%s must be in the private: section' % matched.group(1)) 239710a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org 239810a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org else: 239910a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # Found DISALLOW* macro outside a class declaration, or perhaps it 240010a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # was used inside a function when it should have been part of the 240110a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # class declaration. We could issue a warning here, but it 240210a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # probably resulted in a compiler error already. 240310a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org pass 240410a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org 240510a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org 240610a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.orgdef FindNextMatchingAngleBracket(clean_lines, linenum, init_suffix): 240710a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org """Find the corresponding > to close a template. 240810a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org 240910a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org Args: 241010a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org clean_lines: A CleansedLines instance containing the file. 241110a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org linenum: Current line number. 241210a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org init_suffix: Remainder of the current line after the initial <. 241310a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org 241410a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org Returns: 241510a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org True if a matching bracket exists. 241610a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org """ 241710a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org line = init_suffix 241810a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org nesting_stack = ['<'] 241910a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org while True: 242010a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # Find the next operator that can tell us whether < is used as an 242110a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # opening bracket or as a less-than operator. We only want to 242210a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # warn on the latter case. 242310a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # 242410a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # We could also check all other operators and terminate the search 242510a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # early, e.g. if we got something like this "a<b+c", the "<" is 242610a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # most likely a less-than operator, but then we will get false 2427dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # positives for default arguments and other template expressions. 242810a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org match = Search(r'^[^<>(),;\[\]]*([<>(),;\[\]])(.*)$', line) 242910a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org if match: 243010a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # Found an operator, update nesting stack 243110a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org operator = match.group(1) 243210a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org line = match.group(2) 243310a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org 243410a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org if nesting_stack[-1] == '<': 243510a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # Expecting closing angle bracket 243610a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org if operator in ('<', '(', '['): 243710a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org nesting_stack.append(operator) 243810a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org elif operator == '>': 243910a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org nesting_stack.pop() 244010a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org if not nesting_stack: 244110a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # Found matching angle bracket 244210a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org return True 244310a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org elif operator == ',': 244410a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # Got a comma after a bracket, this is most likely a template 244510a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # argument. We have not seen a closing angle bracket yet, but 244610a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # it's probably a few lines later if we look for it, so just 244710a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # return early here. 244810a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org return True 244910a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org else: 245010a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # Got some other operator. 245110a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org return False 245210a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org 245310a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org else: 245410a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # Expecting closing parenthesis or closing bracket 245510a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org if operator in ('<', '(', '['): 245610a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org nesting_stack.append(operator) 245710a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org elif operator in (')', ']'): 245810a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # We don't bother checking for matching () or []. If we got 245910a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # something like (] or [), it would have been a syntax error. 246010a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org nesting_stack.pop() 246110a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org 246210a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org else: 246310a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # Scan the next line 246410a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org linenum += 1 246510a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org if linenum >= len(clean_lines.elided): 246610a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org break 246710a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org line = clean_lines.elided[linenum] 246810a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org 246910a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # Exhausted all remaining lines and still no matching angle bracket. 247010a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # Most likely the input was incomplete, otherwise we should have 247110a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # seen a semicolon and returned early. 247210a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org return True 247310a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org 247410a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org 247510a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.orgdef FindPreviousMatchingAngleBracket(clean_lines, linenum, init_prefix): 247610a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org """Find the corresponding < that started a template. 247710a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org 247810a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org Args: 247910a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org clean_lines: A CleansedLines instance containing the file. 248010a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org linenum: Current line number. 248110a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org init_prefix: Part of the current line before the initial >. 248210a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org 248310a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org Returns: 248410a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org True if a matching bracket exists. 248510a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org """ 248610a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org line = init_prefix 248710a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org nesting_stack = ['>'] 248810a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org while True: 248910a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # Find the previous operator 249010a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org match = Search(r'^(.*)([<>(),;\[\]])[^<>(),;\[\]]*$', line) 249110a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org if match: 249210a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # Found an operator, update nesting stack 249310a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org operator = match.group(2) 249410a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org line = match.group(1) 249510a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org 249610a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org if nesting_stack[-1] == '>': 249710a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # Expecting opening angle bracket 249810a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org if operator in ('>', ')', ']'): 249910a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org nesting_stack.append(operator) 250010a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org elif operator == '<': 250110a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org nesting_stack.pop() 250210a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org if not nesting_stack: 250310a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # Found matching angle bracket 250410a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org return True 250510a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org elif operator == ',': 250610a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # Got a comma before a bracket, this is most likely a 250710a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # template argument. The opening angle bracket is probably 250810a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # there if we look for it, so just return early here. 250910a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org return True 251010a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org else: 251110a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # Got some other operator. 251210a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org return False 251310a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org 251410a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org else: 251510a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # Expecting opening parenthesis or opening bracket 251610a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org if operator in ('>', ')', ']'): 251710a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org nesting_stack.append(operator) 251810a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org elif operator in ('(', '['): 251910a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org nesting_stack.pop() 25206fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 252110a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org else: 252210a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # Scan the previous line 252310a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org linenum -= 1 252410a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org if linenum < 0: 252510a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org break 252610a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org line = clean_lines.elided[linenum] 252710a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org 252810a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # Exhausted all earlier lines and still no matching angle bracket. 252910a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org return False 253010a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org 253110a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org 253210a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.orgdef CheckSpacing(filename, clean_lines, linenum, nesting_state, error): 25336fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org """Checks for the correctness of various spacing issues in the code. 25346fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 25356fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org Things we check for: spaces around operators, spaces after 25366fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if/for/while/switch, no spaces around parens in function calls, two 25376fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org spaces between code and comment, don't start a block with a blank 25386fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org line, don't end a function with a blank line, don't add a blank line 25396fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org after public/protected/private, don't have too many blank lines in a row. 25406fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 25416fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org Args: 25426fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org filename: The name of the current file. 25436fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org clean_lines: A CleansedLines instance containing the file. 25446fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org linenum: The number of the line to check. 254510a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org nesting_state: A _NestingState instance which maintains information about 254610a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org the current stack of nested blocks being parsed. 25476fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org error: The function to call with any errors found. 25486fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org """ 25496fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 2550dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # Don't use "elided" lines here, otherwise we can't check commented lines. 2551dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # Don't want to use "raw" either, because we don't want to check inside C++11 2552dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # raw strings, 2553dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org raw = clean_lines.lines_without_raw_strings 25546fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org line = raw[linenum] 25556fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 25566fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # Before nixing comments, check if the line is blank for no good 25576fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # reason. This includes the first line after a block is opened, and 25586fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # blank lines at the end of a function (ie, right before a line like '}' 255910a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # 256010a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # Skip all the blank line checks if we are immediately inside a 256110a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # namespace body. In other words, don't issue blank line warnings 256210a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # for this block: 256310a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # namespace { 256410a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # 256510a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # } 256610a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # 256710a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # A warning about missing end of namespace comments will be issued instead. 256810a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org if IsBlankLine(line) and not nesting_state.InNamespaceBody(): 25696fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org elided = clean_lines.elided 25706fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org prev_line = elided[linenum - 1] 25716fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org prevbrace = prev_line.rfind('{') 25726fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # TODO(unknown): Don't complain if line before blank line, and line after, 25736fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # both start with alnums and are indented the same amount. 25746fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # This ignores whitespace at the start of a namespace block 25756fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # because those are not usually indented. 257610a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org if prevbrace != -1 and prev_line[prevbrace:].find('}') == -1: 25776fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # OK, we have a blank line at the start of a code block. Before we 25786fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # complain, we check if it is an exception to the rule: The previous 25796fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # non-empty line has the parameters of a function header that are indented 25806fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # 4 spaces (because they did not fit in a 80 column line when placed on 25816fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # the same line as the function name). We also check for the case where 25826fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # the previous line is indented 6 spaces, which may happen when the 25836fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # initializers of a constructor do not fit into a 80 column line. 25846fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org exception = False 25856fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if Match(r' {6}\w', prev_line): # Initializer list? 25866fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # We are looking for the opening column of initializer list, which 25876fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # should be indented 4 spaces to cause 6 space indentation afterwards. 25886fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org search_position = linenum-2 25896fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org while (search_position >= 0 25906fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org and Match(r' {6}\w', elided[search_position])): 25916fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org search_position -= 1 25926fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org exception = (search_position >= 0 25936fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org and elided[search_position][:5] == ' :') 25946fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org else: 25956fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # Search for the function arguments or an initializer list. We use a 25966fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # simple heuristic here: If the line is indented 4 spaces; and we have a 25976fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # closing paren, without the opening paren, followed by an opening brace 25986fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # or colon (for initializer lists) we assume that it is the last line of 25996fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # a function header. If we have a colon indented 4 spaces, it is an 26006fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # initializer list. 26016fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org exception = (Match(r' {4}\w[^\(]*\)\s*(const\s*)?(\{\s*$|:)', 26026fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org prev_line) 26036fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org or Match(r' {4}:', prev_line)) 26046fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 26056fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if not exception: 26066fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org error(filename, linenum, 'whitespace/blank_line', 2, 2607dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'Redundant blank line at the start of a code block ' 2608dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'should be deleted.') 260910a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # Ignore blank lines at the end of a block in a long if-else 26106fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # chain, like this: 26116fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # if (condition1) { 26126fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # // Something followed by a blank line 26136fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # 26146fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # } else if (condition2) { 26156fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # // Something else 26166fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # } 26176fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if linenum + 1 < clean_lines.NumLines(): 26186fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org next_line = raw[linenum + 1] 26196fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if (next_line 26206fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org and Match(r'\s*}', next_line) 26216fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org and next_line.find('} else ') == -1): 26226fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org error(filename, linenum, 'whitespace/blank_line', 3, 2623dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'Redundant blank line at the end of a code block ' 2624dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'should be deleted.') 26256fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 26266fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org matched = Match(r'\s*(public|protected|private):', prev_line) 26276fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if matched: 26286fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org error(filename, linenum, 'whitespace/blank_line', 3, 26296fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'Do not leave a blank line after "%s:"' % matched.group(1)) 26306fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 26316fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # Next, we complain if there's a comment too near the text 26326fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org commentpos = line.find('//') 26336fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if commentpos != -1: 26346fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # Check if the // may be in quotes. If so, ignore it 2635dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # Comparisons made explicit for clarity -- pylint: disable=g-explicit-bool-comparison 26366fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if (line.count('"', 0, commentpos) - 26376fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org line.count('\\"', 0, commentpos)) % 2 == 0: # not in quotes 26386fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # Allow one space for new scopes, two spaces otherwise: 26396fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if (not Match(r'^\s*{ //', line) and 26406fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org ((commentpos >= 1 and 26416fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org line[commentpos-1] not in string.whitespace) or 26426fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org (commentpos >= 2 and 26436fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org line[commentpos-2] not in string.whitespace))): 26446fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org error(filename, linenum, 'whitespace/comments', 2, 26456fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'At least two spaces is best between code and comments') 26466fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # There should always be a space between the // and the comment 26476fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org commentend = commentpos + 2 26486fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if commentend < len(line) and not line[commentend] == ' ': 26496fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # but some lines are exceptions -- e.g. if they're big 26506fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # comment delimiters like: 26516fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # //---------------------------------------------------------- 26526fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # or are an empty C++ style Doxygen comment, like: 26536fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # /// 2654dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # or C++ style Doxygen comments placed after the variable: 2655dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # ///< Header comment 2656dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # //!< Header comment 26576fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # or they begin with multiple slashes followed by a space: 26586fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # //////// Header comment 26596fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org match = (Search(r'[=/-]{4,}\s*$', line[commentend:]) or 26606fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org Search(r'^/$', line[commentend:]) or 2661dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org Search(r'^!< ', line[commentend:]) or 2662dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org Search(r'^/< ', line[commentend:]) or 26636fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org Search(r'^/+ ', line[commentend:])) 26646fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if not match: 26656fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org error(filename, linenum, 'whitespace/comments', 4, 26666fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'Should have a space between // and comment') 26676fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org CheckComment(line[commentpos:], filename, linenum, error) 26686fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 26696fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org line = clean_lines.elided[linenum] # get rid of comments and strings 26706fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 26716fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # Don't try to do spacing checks for operator methods 26726fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org line = re.sub(r'operator(==|!=|<|<<|<=|>=|>>|>)\(', 'operator\(', line) 26736fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 26746fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # We allow no-spaces around = within an if: "if ( (a=Foo()) == 0 )". 26756fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # Otherwise not. Note we only check for non-spaces on *both* sides; 26766fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # sometimes people put non-spaces on one side when aligning ='s among 26776fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # many lines (not that this is behavior that I approve of...) 26786fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if Search(r'[\w.]=[\w.]', line) and not Search(r'\b(if|while) ', line): 26796fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org error(filename, linenum, 'whitespace/operators', 4, 26806fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'Missing spaces around =') 26816fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 26826fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # It's ok not to have spaces around binary operators like + - * /, but if 26836fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # there's too little whitespace, we get concerned. It's hard to tell, 26846fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # though, so we punt on this one for now. TODO. 26856fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 26866fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # You should always have whitespace around binary operators. 268710a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # 268810a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # Check <= and >= first to avoid false positives with < and >, then 268910a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # check non-include lines for spacing around < and >. 26906fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org match = Search(r'[^<>=!\s](==|!=|<=|>=)[^<>=!\s]', line) 26916fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if match: 26926fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org error(filename, linenum, 'whitespace/operators', 3, 26936fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'Missing spaces around %s' % match.group(1)) 269410a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # We allow no-spaces around << when used like this: 10<<20, but 26956fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # not otherwise (particularly, not when used as streams) 2696dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # Also ignore using ns::operator<<; 2697dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org match = Search(r'(operator|\S)(?:L|UL|ULL|l|ul|ull)?<<(\S)', line) 2698dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org if (match and 2699dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org not (match.group(1).isdigit() and match.group(2).isdigit()) and 2700dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org not (match.group(1) == 'operator' and match.group(2) == ';')): 270110a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org error(filename, linenum, 'whitespace/operators', 3, 270210a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org 'Missing spaces around <<') 270310a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org elif not Match(r'#.*include', line): 270410a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # Avoid false positives on -> 270510a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org reduced_line = line.replace('->', '') 270610a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org 270710a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # Look for < that is not surrounded by spaces. This is only 270810a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # triggered if both sides are missing spaces, even though 270910a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # technically should should flag if at least one side is missing a 271010a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # space. This is done to avoid some false positives with shifts. 271110a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org match = Search(r'[^\s<]<([^\s=<].*)', reduced_line) 271210a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org if (match and 271310a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org not FindNextMatchingAngleBracket(clean_lines, linenum, match.group(1))): 271410a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org error(filename, linenum, 'whitespace/operators', 3, 271510a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org 'Missing spaces around <') 271610a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org 271710a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # Look for > that is not surrounded by spaces. Similar to the 271810a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # above, we only trigger if both sides are missing spaces to avoid 271910a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # false positives with shifts. 272010a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org match = Search(r'^(.*[^\s>])>[^\s=>]', reduced_line) 272110a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org if (match and 272210a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org not FindPreviousMatchingAngleBracket(clean_lines, linenum, 272310a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org match.group(1))): 272410a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org error(filename, linenum, 'whitespace/operators', 3, 272510a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org 'Missing spaces around >') 272610a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org 272710a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # We allow no-spaces around >> for almost anything. This is because 272810a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # C++11 allows ">>" to close nested templates, which accounts for 272910a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # most cases when ">>" is not followed by a space. 273010a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # 273110a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # We still warn on ">>" followed by alpha character, because that is 273210a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # likely due to ">>" being used for right shifts, e.g.: 273310a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # value >> alpha 273410a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # 273510a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # When ">>" is used to close templates, the alphanumeric letter that 273610a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # follows would be part of an identifier, and there should still be 273710a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # a space separating the template type and the identifier. 273810a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # type<type<type>> alpha 273910a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org match = Search(r'>>[a-zA-Z_]', line) 27406fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if match: 27416fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org error(filename, linenum, 'whitespace/operators', 3, 274210a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org 'Missing spaces around >>') 27436fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 27446fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # There shouldn't be space around unary operators 27456fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org match = Search(r'(!\s|~\s|[\s]--[\s;]|[\s]\+\+[\s;])', line) 27466fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if match: 27476fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org error(filename, linenum, 'whitespace/operators', 4, 27486fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'Extra space for operator %s' % match.group(1)) 27496fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 27506fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # A pet peeve of mine: no spaces after an if, while, switch, or for 27516fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org match = Search(r' (if\(|for\(|while\(|switch\()', line) 27526fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if match: 27536fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org error(filename, linenum, 'whitespace/parens', 5, 27546fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'Missing space before ( in %s' % match.group(1)) 27556fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 27566fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # For if/for/while/switch, the left and right parens should be 27576fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # consistent about how many spaces are inside the parens, and 27586fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # there should either be zero or one spaces inside the parens. 27596fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # We don't want: "if ( foo)" or "if ( foo )". 27606fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # Exception: "for ( ; foo; bar)" and "for (foo; bar; )" are allowed. 27616fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org match = Search(r'\b(if|for|while|switch)\s*' 27626fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org r'\(([ ]*)(.).*[^ ]+([ ]*)\)\s*{\s*$', 27636fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org line) 27646fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if match: 27656fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if len(match.group(2)) != len(match.group(4)): 27666fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if not (match.group(3) == ';' and 27676fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org len(match.group(2)) == 1 + len(match.group(4)) or 27686fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org not match.group(2) and Search(r'\bfor\s*\(.*; \)', line)): 27696fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org error(filename, linenum, 'whitespace/parens', 5, 27706fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'Mismatching spaces inside () in %s' % match.group(1)) 2771dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org if len(match.group(2)) not in [0, 1]: 27726fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org error(filename, linenum, 'whitespace/parens', 5, 27736fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'Should have zero or one spaces inside ( and ) in %s' % 27746fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org match.group(1)) 27756fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 27766fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # You should always have a space after a comma (either as fn arg or operator) 2777dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # 2778dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # This does not apply when the non-space character following the 2779dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # comma is another comma, since the only time when that happens is 2780dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # for empty macro arguments. 2781dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # 2782dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # We run this check in two passes: first pass on elided lines to 2783dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # verify that lines contain missing whitespaces, second pass on raw 2784dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # lines to confirm that those missing whitespaces are not due to 2785dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # elided comments. 2786dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org if Search(r',[^,\s]', line) and Search(r',[^,\s]', raw[linenum]): 27876fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org error(filename, linenum, 'whitespace/comma', 3, 27886fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'Missing space after ,') 27896fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 27906fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # You should always have a space after a semicolon 27916fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # except for few corner cases 27926fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # TODO(unknown): clarify if 'if (1) { return 1;}' is requires one more 27936fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # space after ; 27946fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if Search(r';[^\s};\\)/]', line): 27956fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org error(filename, linenum, 'whitespace/semicolon', 3, 27966fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'Missing space after ;') 27976fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 27986fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # Next we will look for issues with function calls. 27996fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org CheckSpacingForFunctionCall(filename, line, linenum, error) 28006fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 28016fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # Except after an opening paren, or after another opening brace (in case of 28026fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # an initializer list, for instance), you should have spaces before your 28036fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # braces. And since you should never have braces at the beginning of a line, 28046fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # this is an easy test. 2805dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org match = Match(r'^(.*[^ ({]){', line) 2806dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org if match: 2807dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # Try a bit harder to check for brace initialization. This 2808dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # happens in one of the following forms: 2809dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # Constructor() : initializer_list_{} { ... } 2810dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # Constructor{}.MemberFunction() 2811dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # Type variable{}; 2812dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # FunctionCall(type{}, ...); 2813dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # LastArgument(..., type{}); 2814dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # LOG(INFO) << type{} << " ..."; 2815dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # map_of_type[{...}] = ...; 2816dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # 2817dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # We check for the character following the closing brace, and 2818dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # silence the warning if it's one of those listed above, i.e. 2819dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # "{.;,)<]". 2820dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # 2821dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # To account for nested initializer list, we allow any number of 2822dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # closing braces up to "{;,)<". We can't simply silence the 2823dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # warning on first sight of closing brace, because that would 2824dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # cause false negatives for things that are not initializer lists. 2825dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # Silence this: But not this: 2826dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # Outer{ if (...) { 2827dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # Inner{...} if (...){ // Missing space before { 2828dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # }; } 2829dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # 2830dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # There is a false negative with this approach if people inserted 2831dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # spurious semicolons, e.g. "if (cond){};", but we will catch the 2832dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # spurious semicolon with a separate check. 2833dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org (endline, endlinenum, endpos) = CloseExpression( 2834dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org clean_lines, linenum, len(match.group(1))) 2835dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org trailing_text = '' 2836dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org if endpos > -1: 2837dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org trailing_text = endline[endpos:] 2838dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org for offset in xrange(endlinenum + 1, 2839dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org min(endlinenum + 3, clean_lines.NumLines() - 1)): 2840dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org trailing_text += clean_lines.elided[offset] 2841dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org if not Match(r'^[\s}]*[{.;,)<\]]', trailing_text): 2842dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org error(filename, linenum, 'whitespace/braces', 5, 2843dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'Missing space before {') 28446fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 28456fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # Make sure '} else {' has spaces. 28466fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if Search(r'}else', line): 28476fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org error(filename, linenum, 'whitespace/braces', 5, 28486fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'Missing space before else') 28496fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 28506fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # You shouldn't have spaces before your brackets, except maybe after 28516fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # 'delete []' or 'new char * []'. 28526fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if Search(r'\w\s+\[', line) and not Search(r'delete\s+\[', line): 28536fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org error(filename, linenum, 'whitespace/braces', 5, 28546fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'Extra space before [') 28556fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 28566fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # You shouldn't have a space before a semicolon at the end of the line. 28576fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # There's a special case for "for" since the style guide allows space before 28586fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # the semicolon there. 28596fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if Search(r':\s*;\s*$', line): 28606fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org error(filename, linenum, 'whitespace/semicolon', 5, 286110a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org 'Semicolon defining empty statement. Use {} instead.') 28626fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org elif Search(r'^\s*;\s*$', line): 28636fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org error(filename, linenum, 'whitespace/semicolon', 5, 28646fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'Line contains only semicolon. If this should be an empty statement, ' 286510a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org 'use {} instead.') 28666fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org elif (Search(r'\s+;\s*$', line) and 28676fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org not Search(r'\bfor\b', line)): 28686fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org error(filename, linenum, 'whitespace/semicolon', 5, 28696fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'Extra space before last semicolon. If this should be an empty ' 287010a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org 'statement, use {} instead.') 287110a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org 287210a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # In range-based for, we wanted spaces before and after the colon, but 287310a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # not around "::" tokens that might appear. 287410a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org if (Search('for *\(.*[^:]:[^: ]', line) or 287510a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org Search('for *\(.*[^: ]:[^:]', line)): 287610a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org error(filename, linenum, 'whitespace/forcolon', 2, 287710a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org 'Missing space around colon in range-based for loop') 28786fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 28796fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 28806fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.orgdef CheckSectionSpacing(filename, clean_lines, class_info, linenum, error): 28816fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org """Checks for additional blank line issues related to sections. 28826fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 28836fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org Currently the only thing checked here is blank line before protected/private. 28846fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 28856fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org Args: 28866fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org filename: The name of the current file. 28876fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org clean_lines: A CleansedLines instance containing the file. 28886fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org class_info: A _ClassInfo objects. 28896fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org linenum: The number of the line to check. 28906fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org error: The function to call with any errors found. 28916fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org """ 28926fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # Skip checks if the class is small, where small means 25 lines or less. 28936fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # 25 lines seems like a good cutoff since that's the usual height of 28946fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # terminals, and any class that can't fit in one screen can't really 28956fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # be considered "small". 28966fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # 28976fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # Also skip checks if we are on the first line. This accounts for 28986fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # classes that look like 28996fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # class Foo { public: ... }; 29006fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # 29016fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # If we didn't find the end of the class, last_line would be zero, 29026fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # and the check will be skipped by the first condition. 290310a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org if (class_info.last_line - class_info.starting_linenum <= 24 or 290410a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org linenum <= class_info.starting_linenum): 29056fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org return 29066fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 29076fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org matched = Match(r'\s*(public|protected|private):', clean_lines.lines[linenum]) 29086fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if matched: 29096fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # Issue warning if the line before public/protected/private was 29106fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # not a blank line, but don't do this if the previous line contains 29116fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # "class" or "struct". This can happen two ways: 29126fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # - We are at the beginning of the class. 29136fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # - We are forward-declaring an inner class that is semantically 29146fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # private, but needed to be public for implementation reasons. 291510a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # Also ignores cases where the previous line ends with a backslash as can be 291610a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # common when defining classes in C macros. 29176fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org prev_line = clean_lines.lines[linenum - 1] 29186fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if (not IsBlankLine(prev_line) and 291910a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org not Search(r'\b(class|struct)\b', prev_line) and 292010a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org not Search(r'\\$', prev_line)): 29216fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # Try a bit harder to find the beginning of the class. This is to 29226fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # account for multi-line base-specifier lists, e.g.: 29236fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # class Derived 29246fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # : public Base { 292510a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org end_class_head = class_info.starting_linenum 292610a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org for i in range(class_info.starting_linenum, linenum): 29276fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if Search(r'\{\s*$', clean_lines.lines[i]): 29286fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org end_class_head = i 29296fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org break 29306fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if end_class_head < linenum - 1: 29316fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org error(filename, linenum, 'whitespace/blank_line', 3, 29326fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org '"%s:" should be preceded by a blank line' % matched.group(1)) 29336fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 29346fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 29356fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.orgdef GetPreviousNonBlankLine(clean_lines, linenum): 29366fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org """Return the most recent non-blank line and its line number. 29376fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 29386fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org Args: 29396fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org clean_lines: A CleansedLines instance containing the file contents. 29406fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org linenum: The number of the line to check. 29416fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 29426fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org Returns: 29436fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org A tuple with two elements. The first element is the contents of the last 29446fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org non-blank line before the current line, or the empty string if this is the 29456fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org first non-blank line. The second is the line number of that line, or -1 29466fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if this is the first non-blank line. 29476fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org """ 29486fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 29496fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org prevlinenum = linenum - 1 29506fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org while prevlinenum >= 0: 29516fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org prevline = clean_lines.elided[prevlinenum] 29526fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if not IsBlankLine(prevline): # if not a blank line... 29536fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org return (prevline, prevlinenum) 29546fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org prevlinenum -= 1 29556fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org return ('', -1) 29566fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 29576fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 29586fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.orgdef CheckBraces(filename, clean_lines, linenum, error): 29596fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org """Looks for misplaced braces (e.g. at the end of line). 29606fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 29616fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org Args: 29626fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org filename: The name of the current file. 29636fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org clean_lines: A CleansedLines instance containing the file. 29646fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org linenum: The number of the line to check. 29656fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org error: The function to call with any errors found. 29666fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org """ 29676fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 29686fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org line = clean_lines.elided[linenum] # get rid of comments and strings 29696fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 29706fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if Match(r'\s*{\s*$', line): 2971dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # We allow an open brace to start a line in the case where someone is using 2972dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # braces in a block to explicitly create a new scope, which is commonly used 2973dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # to control the lifetime of stack-allocated variables. Braces are also 2974dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # used for brace initializers inside function calls. We don't detect this 2975dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # perfectly: we just don't complain if the last non-whitespace character on 2976dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # the previous non-blank line is ',', ';', ':', '(', '{', or '}', or if the 2977dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # previous line starts a preprocessor block. 29786fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org prevline = GetPreviousNonBlankLine(clean_lines, linenum)[0] 2979dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org if (not Search(r'[,;:}{(]\s*$', prevline) and 298010a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org not Match(r'\s*#', prevline)): 29816fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org error(filename, linenum, 'whitespace/braces', 4, 29826fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org '{ should almost always be at the end of the previous line') 29836fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 29846fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # An else clause should be on the same line as the preceding closing brace. 29856fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if Match(r'\s*else\s*', line): 29866fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org prevline = GetPreviousNonBlankLine(clean_lines, linenum)[0] 29876fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if Match(r'\s*}\s*$', prevline): 29886fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org error(filename, linenum, 'whitespace/newline', 4, 29896fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'An else should appear on the same line as the preceding }') 29906fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 29916fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # If braces come on one side of an else, they should be on both. 29926fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # However, we have to worry about "else if" that spans multiple lines! 29936fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if Search(r'}\s*else[^{]*$', line) or Match(r'[^}]*else\s*{', line): 29946fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if Search(r'}\s*else if([^{]*)$', line): # could be multi-line if 29956fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # find the ( after the if 29966fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org pos = line.find('else if') 29976fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org pos = line.find('(', pos) 29986fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if pos > 0: 29996fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org (endline, _, endpos) = CloseExpression(clean_lines, linenum, pos) 30006fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if endline[endpos:].find('{') == -1: # must be brace after if 30016fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org error(filename, linenum, 'readability/braces', 5, 30026fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'If an else has a brace on one side, it should have it on both') 30036fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org else: # common case: else not followed by a multi-line if 30046fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org error(filename, linenum, 'readability/braces', 5, 30056fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'If an else has a brace on one side, it should have it on both') 30066fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 30076fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # Likewise, an else should never have the else clause on the same line 30086fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if Search(r'\belse [^\s{]', line) and not Search(r'\belse if\b', line): 30096fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org error(filename, linenum, 'whitespace/newline', 4, 30106fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'Else clause should never be on same line as else (use 2 lines)') 30116fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 30126fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # In the same way, a do/while should never be on one line 30136fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if Match(r'\s*do [^\s{]', line): 30146fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org error(filename, linenum, 'whitespace/newline', 4, 30156fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'do/while clauses should not be on a single line') 30166fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 3017dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # Block bodies should not be followed by a semicolon. Due to C++11 3018dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # brace initialization, there are more places where semicolons are 3019dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # required than not, so we use a whitelist approach to check these 3020dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # rather than a blacklist. These are the places where "};" should 3021dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # be replaced by just "}": 3022dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # 1. Some flavor of block following closing parenthesis: 3023dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # for (;;) {}; 3024dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # while (...) {}; 3025dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # switch (...) {}; 3026dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # Function(...) {}; 3027dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # if (...) {}; 3028dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # if (...) else if (...) {}; 3029dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # 3030dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # 2. else block: 3031dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # if (...) else {}; 3032dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # 3033dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # 3. const member function: 3034dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # Function(...) const {}; 3035dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # 3036dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # 4. Block following some statement: 3037dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # x = 42; 3038dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # {}; 3039dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # 3040dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # 5. Block at the beginning of a function: 3041dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # Function(...) { 3042dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # {}; 3043dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # } 3044dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # 3045dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # Note that naively checking for the preceding "{" will also match 3046dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # braces inside multi-dimensional arrays, but this is fine since 3047dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # that expression will not contain semicolons. 3048dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # 3049dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # 6. Block following another block: 3050dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # while (true) {} 3051dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # {}; 3052dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # 3053dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # 7. End of namespaces: 3054dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # namespace {}; 3055dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # 3056dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # These semicolons seems far more common than other kinds of 3057dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # redundant semicolons, possibly due to people converting classes 3058dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # to namespaces. For now we do not warn for this case. 3059dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # 3060dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # Try matching case 1 first. 3061dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org match = Match(r'^(.*\)\s*)\{', line) 3062dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org if match: 3063dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # Matched closing parenthesis (case 1). Check the token before the 3064dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # matching opening parenthesis, and don't warn if it looks like a 3065dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # macro. This avoids these false positives: 3066dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # - macro that defines a base class 3067dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # - multi-line macro that defines a base class 3068dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # - macro that defines the whole class-head 3069dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # 3070dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # But we still issue warnings for macros that we know are safe to 3071dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # warn, specifically: 3072dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # - TEST, TEST_F, TEST_P, MATCHER, MATCHER_P 3073dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # - TYPED_TEST 3074dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # - INTERFACE_DEF 3075dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # - EXCLUSIVE_LOCKS_REQUIRED, SHARED_LOCKS_REQUIRED, LOCKS_EXCLUDED: 3076dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # 3077dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # We implement a whitelist of safe macros instead of a blacklist of 3078dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # unsafe macros, even though the latter appears less frequently in 3079dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # google code and would have been easier to implement. This is because 3080dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # the downside for getting the whitelist wrong means some extra 3081dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # semicolons, while the downside for getting the blacklist wrong 3082dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # would result in compile errors. 3083dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # 3084dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # In addition to macros, we also don't want to warn on compound 3085dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # literals. 3086dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org closing_brace_pos = match.group(1).rfind(')') 3087dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org opening_parenthesis = ReverseCloseExpression( 3088dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org clean_lines, linenum, closing_brace_pos) 3089dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org if opening_parenthesis[2] > -1: 3090dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org line_prefix = opening_parenthesis[0][0:opening_parenthesis[2]] 3091dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org macro = Search(r'\b([A-Z_]+)\s*$', line_prefix) 3092dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org if ((macro and 3093dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org macro.group(1) not in ( 3094dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'TEST', 'TEST_F', 'MATCHER', 'MATCHER_P', 'TYPED_TEST', 3095dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'EXCLUSIVE_LOCKS_REQUIRED', 'SHARED_LOCKS_REQUIRED', 3096dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'LOCKS_EXCLUDED', 'INTERFACE_DEF')) or 3097dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org Search(r'\s+=\s*$', line_prefix)): 3098dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org match = None 3099dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 3100dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org else: 3101dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # Try matching cases 2-3. 3102dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org match = Match(r'^(.*(?:else|\)\s*const)\s*)\{', line) 3103dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org if not match: 3104dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # Try matching cases 4-6. These are always matched on separate lines. 3105dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # 3106dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # Note that we can't simply concatenate the previous line to the 3107dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # current line and do a single match, otherwise we may output 3108dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # duplicate warnings for the blank line case: 3109dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # if (cond) { 3110dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # // blank line 3111dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # } 3112dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org prevline = GetPreviousNonBlankLine(clean_lines, linenum)[0] 3113dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org if prevline and Search(r'[;{}]\s*$', prevline): 3114dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org match = Match(r'^(\s*)\{', line) 3115dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 3116dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # Check matching closing brace 3117dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org if match: 3118dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org (endline, endlinenum, endpos) = CloseExpression( 3119dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org clean_lines, linenum, len(match.group(1))) 3120dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org if endpos > -1 and Match(r'^\s*;', endline[endpos:]): 3121dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # Current {} pair is eligible for semicolon check, and we have found 3122dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # the redundant semicolon, output warning here. 3123dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # 3124dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # Note: because we are scanning forward for opening braces, and 3125dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # outputting warnings for the matching closing brace, if there are 3126dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # nested blocks with trailing semicolons, we will get the error 3127dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # messages in reversed order. 3128dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org error(filename, endlinenum, 'readability/braces', 4, 3129dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org "You don't need a ; after a }") 31306fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 31316fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 3132dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.orgdef CheckEmptyBlockBody(filename, clean_lines, linenum, error): 3133dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org """Look for empty loop/conditional body with only a single semicolon. 313410a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org 313510a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org Args: 313610a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org filename: The name of the current file. 313710a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org clean_lines: A CleansedLines instance containing the file. 313810a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org linenum: The number of the line to check. 313910a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org error: The function to call with any errors found. 314010a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org """ 314110a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org 314210a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # Search for loop keywords at the beginning of the line. Because only 314310a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # whitespaces are allowed before the keywords, this will also ignore most 314410a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # do-while-loops, since those lines should start with closing brace. 3145dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # 3146dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # We also check "if" blocks here, since an empty conditional block 3147dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # is likely an error. 314810a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org line = clean_lines.elided[linenum] 3149dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org matched = Match(r'\s*(for|while|if)\s*\(', line) 3150dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org if matched: 315110a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # Find the end of the conditional expression 315210a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org (end_line, end_linenum, end_pos) = CloseExpression( 315310a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org clean_lines, linenum, line.find('(')) 315410a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org 315510a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # Output warning if what follows the condition expression is a semicolon. 315610a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # No warning for all other cases, including whitespace or newline, since we 315710a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # have a separate check for semicolons preceded by whitespace. 315810a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org if end_pos >= 0 and Match(r';', end_line[end_pos:]): 3159dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org if matched.group(1) == 'if': 3160dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org error(filename, end_linenum, 'whitespace/empty_conditional_body', 5, 3161dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'Empty conditional bodies should use {}') 3162dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org else: 3163dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org error(filename, end_linenum, 'whitespace/empty_loop_body', 5, 3164dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'Empty loop bodies should use {} or continue') 31656fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 31666fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 31676fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.orgdef CheckCheck(filename, clean_lines, linenum, error): 31686fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org """Checks the use of CHECK and EXPECT macros. 31696fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 31706fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org Args: 31716fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org filename: The name of the current file. 31726fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org clean_lines: A CleansedLines instance containing the file. 31736fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org linenum: The number of the line to check. 31746fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org error: The function to call with any errors found. 31756fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org """ 31766fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 31776fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # Decide the set of replacement macros that should be suggested 3178dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org lines = clean_lines.elided 3179dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org check_macro = None 3180dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org start_pos = -1 31816fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org for macro in _CHECK_MACROS: 3182dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org i = lines[linenum].find(macro) 3183dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org if i >= 0: 3184dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org check_macro = macro 3185dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 3186dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # Find opening parenthesis. Do a regular expression match here 3187dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # to make sure that we are matching the expected CHECK macro, as 3188dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # opposed to some other macro that happens to contain the CHECK 3189dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # substring. 3190dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org matched = Match(r'^(.*\b' + check_macro + r'\s*)\(', lines[linenum]) 3191dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org if not matched: 3192dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org continue 3193dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org start_pos = len(matched.group(1)) 31946fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org break 3195dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org if not check_macro or start_pos < 0: 31966fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # Don't waste time here if line doesn't contain 'CHECK' or 'EXPECT' 31976fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org return 31986fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 3199dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # Find end of the boolean expression by matching parentheses 3200dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org (last_line, end_line, end_pos) = CloseExpression( 3201dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org clean_lines, linenum, start_pos) 3202dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org if end_pos < 0: 3203dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org return 3204dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org if linenum == end_line: 3205dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org expression = lines[linenum][start_pos + 1:end_pos - 1] 3206dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org else: 3207dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org expression = lines[linenum][start_pos + 1:] 3208dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org for i in xrange(linenum + 1, end_line): 3209dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org expression += lines[i] 3210dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org expression += last_line[0:end_pos - 1] 3211dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 3212dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # Parse expression so that we can take parentheses into account. 3213dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # This avoids false positives for inputs like "CHECK((a < 4) == b)", 3214dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # which is not replaceable by CHECK_LE. 3215dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org lhs = '' 3216dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org rhs = '' 3217dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org operator = None 3218dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org while expression: 3219dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org matched = Match(r'^\s*(<<|<<=|>>|>>=|->\*|->|&&|\|\||' 3220dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org r'==|!=|>=|>|<=|<|\()(.*)$', expression) 3221dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org if matched: 3222dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org token = matched.group(1) 3223dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org if token == '(': 3224dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # Parenthesized operand 3225dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org expression = matched.group(2) 3226dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org (end, _) = FindEndOfExpressionInLine(expression, 0, 1, '(', ')') 3227dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org if end < 0: 3228dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org return # Unmatched parenthesis 3229dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org lhs += '(' + expression[0:end] 3230dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org expression = expression[end:] 3231dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org elif token in ('&&', '||'): 3232dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # Logical and/or operators. This means the expression 3233dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # contains more than one term, for example: 3234dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # CHECK(42 < a && a < b); 3235dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # 3236dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # These are not replaceable with CHECK_LE, so bail out early. 3237dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org return 3238dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org elif token in ('<<', '<<=', '>>', '>>=', '->*', '->'): 3239dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # Non-relational operator 3240dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org lhs += token 3241dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org expression = matched.group(2) 3242dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org else: 3243dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # Relational operator 3244dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org operator = token 3245dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org rhs = matched.group(2) 3246dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org break 3247dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org else: 3248dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # Unparenthesized operand. Instead of appending to lhs one character 3249dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # at a time, we do another regular expression match to consume several 3250dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # characters at once if possible. Trivial benchmark shows that this 3251dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # is more efficient when the operands are longer than a single 3252dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # character, which is generally the case. 3253dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org matched = Match(r'^([^-=!<>()&|]+)(.*)$', expression) 3254dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org if not matched: 3255dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org matched = Match(r'^(\s*\S)(.*)$', expression) 3256dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org if not matched: 3257dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org break 3258dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org lhs += matched.group(1) 3259dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org expression = matched.group(2) 32606fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 3261dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # Only apply checks if we got all parts of the boolean expression 3262dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org if not (lhs and operator and rhs): 3263dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org return 3264dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 3265dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # Check that rhs do not contain logical operators. We already know 3266dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # that lhs is fine since the loop above parses out && and ||. 3267dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org if rhs.find('&&') > -1 or rhs.find('||') > -1: 3268dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org return 3269dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 3270dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # At least one of the operands must be a constant literal. This is 3271dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # to avoid suggesting replacements for unprintable things like 3272dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # CHECK(variable != iterator) 3273dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # 3274dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # The following pattern matches decimal, hex integers, strings, and 3275dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # characters (in that order). 3276dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org lhs = lhs.strip() 3277dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org rhs = rhs.strip() 3278dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org match_constant = r'^([-+]?(\d+|0[xX][0-9a-fA-F]+)[lLuU]{0,3}|".*"|\'.*\')$' 3279dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org if Match(match_constant, lhs) or Match(match_constant, rhs): 3280dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # Note: since we know both lhs and rhs, we can provide a more 3281dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # descriptive error message like: 3282dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # Consider using CHECK_EQ(x, 42) instead of CHECK(x == 42) 3283dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # Instead of: 3284dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # Consider using CHECK_EQ instead of CHECK(a == b) 3285dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # 3286dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # We are still keeping the less descriptive message because if lhs 3287dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # or rhs gets long, the error message might become unreadable. 3288dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org error(filename, linenum, 'readability/check', 2, 3289dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'Consider using %s instead of %s(a %s b)' % ( 3290dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org _CHECK_REPLACEMENT[check_macro][operator], 3291dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org check_macro, operator)) 32926fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 32936fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 329410a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.orgdef CheckAltTokens(filename, clean_lines, linenum, error): 329510a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org """Check alternative keywords being used in boolean expressions. 329610a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org 329710a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org Args: 329810a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org filename: The name of the current file. 329910a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org clean_lines: A CleansedLines instance containing the file. 330010a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org linenum: The number of the line to check. 330110a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org error: The function to call with any errors found. 330210a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org """ 330310a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org line = clean_lines.elided[linenum] 330410a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org 330510a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # Avoid preprocessor lines 330610a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org if Match(r'^\s*#', line): 330710a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org return 330810a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org 330910a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # Last ditch effort to avoid multi-line comments. This will not help 331010a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # if the comment started before the current line or ended after the 331110a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # current line, but it catches most of the false positives. At least, 331210a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # it provides a way to workaround this warning for people who use 331310a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # multi-line comments in preprocessor macros. 331410a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # 331510a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # TODO(unknown): remove this once cpplint has better support for 331610a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # multi-line comments. 331710a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org if line.find('/*') >= 0 or line.find('*/') >= 0: 331810a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org return 331910a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org 332010a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org for match in _ALT_TOKEN_REPLACEMENT_PATTERN.finditer(line): 332110a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org error(filename, linenum, 'readability/alt_tokens', 2, 332210a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org 'Use operator %s instead of %s' % ( 332310a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org _ALT_TOKEN_REPLACEMENT[match.group(1)], match.group(1))) 332410a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org 332510a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org 33266fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.orgdef GetLineWidth(line): 33276fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org """Determines the width of the line in column positions. 33286fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 33296fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org Args: 33306fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org line: A string, which may be a Unicode string. 33316fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 33326fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org Returns: 33336fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org The width of the line in column positions, accounting for Unicode 33346fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org combining characters and wide characters. 33356fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org """ 33366fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if isinstance(line, unicode): 33376fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org width = 0 33386fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org for uc in unicodedata.normalize('NFC', line): 33396fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if unicodedata.east_asian_width(uc) in ('W', 'F'): 33406fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org width += 2 33416fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org elif not unicodedata.combining(uc): 33426fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org width += 1 33436fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org return width 33446fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org else: 33456fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org return len(line) 33466fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 33476fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 334810a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.orgdef CheckStyle(filename, clean_lines, linenum, file_extension, nesting_state, 33496fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org error): 33506fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org """Checks rules from the 'C++ style rules' section of cppguide.html. 33516fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 33526fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org Most of these rules are hard to test (naming, comment style), but we 33536fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org do what we can. In particular we check for 2-space indents, line lengths, 33546fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org tab usage, spaces inside code, etc. 33556fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 33566fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org Args: 33576fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org filename: The name of the current file. 33586fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org clean_lines: A CleansedLines instance containing the file. 33596fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org linenum: The number of the line to check. 33606fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org file_extension: The extension (without the dot) of the filename. 336110a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org nesting_state: A _NestingState instance which maintains information about 336210a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org the current stack of nested blocks being parsed. 33636fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org error: The function to call with any errors found. 33646fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org """ 33656fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 3366dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # Don't use "elided" lines here, otherwise we can't check commented lines. 3367dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # Don't want to use "raw" either, because we don't want to check inside C++11 3368dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # raw strings, 3369dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org raw_lines = clean_lines.lines_without_raw_strings 33706fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org line = raw_lines[linenum] 33716fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 33726fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if line.find('\t') != -1: 33736fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org error(filename, linenum, 'whitespace/tab', 1, 33746fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'Tab found; better to use spaces') 33756fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 33766fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # One or three blank spaces at the beginning of the line is weird; it's 33776fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # hard to reconcile that with 2-space indents. 33786fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # NOTE: here are the conditions rob pike used for his tests. Mine aren't 33796fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # as sophisticated, but it may be worth becoming so: RLENGTH==initial_spaces 33806fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # if(RLENGTH > 20) complain = 0; 33816fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # if(match($0, " +(error|private|public|protected):")) complain = 0; 33826fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # if(match(prev, "&& *$")) complain = 0; 33836fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # if(match(prev, "\\|\\| *$")) complain = 0; 33846fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # if(match(prev, "[\",=><] *$")) complain = 0; 33856fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # if(match($0, " <<")) complain = 0; 33866fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # if(match(prev, " +for \\(")) complain = 0; 33876fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # if(prevodd && match(prevprev, " +for \\(")) complain = 0; 33886fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org initial_spaces = 0 33896fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org cleansed_line = clean_lines.elided[linenum] 33906fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org while initial_spaces < len(line) and line[initial_spaces] == ' ': 33916fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org initial_spaces += 1 33926fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if line and line[-1].isspace(): 33936fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org error(filename, linenum, 'whitespace/end_of_line', 4, 33946fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'Line ends in whitespace. Consider deleting these extra spaces.') 3395dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # There are certain situations we allow one space, notably for section labels 33966fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org elif ((initial_spaces == 1 or initial_spaces == 3) and 33976fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org not Match(r'\s*\w+\s*:\s*$', cleansed_line)): 33986fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org error(filename, linenum, 'whitespace/indent', 3, 33996fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'Weird number of spaces at line-start. ' 34006fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'Are you using a 2-space indent?') 34016fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 34026fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # Check if the line is a header guard. 34036fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org is_header_guard = False 34046fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if file_extension == 'h': 34056fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org cppvar = GetHeaderGuardCPPVariable(filename) 34066fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if (line.startswith('#ifndef %s' % cppvar) or 34076fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org line.startswith('#define %s' % cppvar) or 34086fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org line.startswith('#endif // %s' % cppvar)): 34096fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org is_header_guard = True 34106fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # #include lines and header guards can be long, since there's no clean way to 34116fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # split them. 34126fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # 34136fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # URLs can be long too. It's possible to split these, but it makes them 34146fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # harder to cut&paste. 34156fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # 34166fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # The "$Id:...$" comment may also get very long without it being the 34176fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # developers fault. 34186fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if (not line.startswith('#include') and not is_header_guard and 34196fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org not Match(r'^\s*//.*http(s?)://\S*$', line) and 34206fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org not Match(r'^// \$Id:.*#[0-9]+ \$$', line)): 34216fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org line_width = GetLineWidth(line) 3422dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org extended_length = int((_line_length * 1.25)) 3423dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org if line_width > extended_length: 34246fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org error(filename, linenum, 'whitespace/line_length', 4, 3425dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'Lines should very rarely be longer than %i characters' % 3426dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org extended_length) 3427dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org elif line_width > _line_length: 34286fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org error(filename, linenum, 'whitespace/line_length', 2, 3429dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'Lines should be <= %i characters long' % _line_length) 34306fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 34316fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if (cleansed_line.count(';') > 1 and 34326fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # for loops are allowed two ;'s (and may run over two lines). 34336fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org cleansed_line.find('for') == -1 and 34346fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org (GetPreviousNonBlankLine(clean_lines, linenum)[0].find('for') == -1 or 34356fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org GetPreviousNonBlankLine(clean_lines, linenum)[0].find(';') != -1) and 34366fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # It's ok to have many commands in a switch case that fits in 1 line 34376fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org not ((cleansed_line.find('case ') != -1 or 34386fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org cleansed_line.find('default:') != -1) and 34396fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org cleansed_line.find('break;') != -1)): 344010a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org error(filename, linenum, 'whitespace/newline', 0, 34416fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'More than one command on the same line') 34426fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 34436fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # Some more style checks 34446fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org CheckBraces(filename, clean_lines, linenum, error) 3445dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org CheckEmptyBlockBody(filename, clean_lines, linenum, error) 344610a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org CheckAccess(filename, clean_lines, linenum, nesting_state, error) 344710a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org CheckSpacing(filename, clean_lines, linenum, nesting_state, error) 34486fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org CheckCheck(filename, clean_lines, linenum, error) 344910a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org CheckAltTokens(filename, clean_lines, linenum, error) 345010a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org classinfo = nesting_state.InnermostClass() 345110a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org if classinfo: 345210a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org CheckSectionSpacing(filename, clean_lines, classinfo, linenum, error) 34536fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 34546fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 34556fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org_RE_PATTERN_INCLUDE_NEW_STYLE = re.compile(r'#include +"[^/]+\.h"') 34566fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org_RE_PATTERN_INCLUDE = re.compile(r'^\s*#\s*include\s*([<"])([^>"]*)[>"].*$') 34576fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org# Matches the first component of a filename delimited by -s and _s. That is: 34586fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org# _RE_FIRST_COMPONENT.match('foo').group(0) == 'foo' 34596fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org# _RE_FIRST_COMPONENT.match('foo.cc').group(0) == 'foo' 34606fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org# _RE_FIRST_COMPONENT.match('foo-bar_baz.cc').group(0) == 'foo' 34616fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org# _RE_FIRST_COMPONENT.match('foo_bar-baz.cc').group(0) == 'foo' 34626fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org_RE_FIRST_COMPONENT = re.compile(r'^[^-_.]+') 34636fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 34646fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 34656fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.orgdef _DropCommonSuffixes(filename): 34666fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org """Drops common suffixes like _test.cc or -inl.h from filename. 34676fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 34686fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org For example: 34696fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org >>> _DropCommonSuffixes('foo/foo-inl.h') 34706fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'foo/foo' 34716fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org >>> _DropCommonSuffixes('foo/bar/foo.cc') 34726fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'foo/bar/foo' 34736fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org >>> _DropCommonSuffixes('foo/foo_internal.h') 34746fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'foo/foo' 34756fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org >>> _DropCommonSuffixes('foo/foo_unusualinternal.h') 34766fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'foo/foo_unusualinternal' 34776fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 34786fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org Args: 34796fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org filename: The input filename. 34806fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 34816fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org Returns: 34826fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org The filename with the common suffix removed. 34836fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org """ 34846fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org for suffix in ('test.cc', 'regtest.cc', 'unittest.cc', 34856fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'inl.h', 'impl.h', 'internal.h'): 34866fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if (filename.endswith(suffix) and len(filename) > len(suffix) and 34876fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org filename[-len(suffix) - 1] in ('-', '_')): 34886fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org return filename[:-len(suffix) - 1] 34896fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org return os.path.splitext(filename)[0] 34906fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 34916fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 34926fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.orgdef _IsTestFilename(filename): 34936fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org """Determines if the given filename has a suffix that identifies it as a test. 34946fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 34956fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org Args: 34966fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org filename: The input filename. 34976fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 34986fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org Returns: 34996fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org True if 'filename' looks like a test, False otherwise. 35006fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org """ 35016fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if (filename.endswith('_test.cc') or 35026fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org filename.endswith('_unittest.cc') or 35036fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org filename.endswith('_regtest.cc')): 35046fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org return True 35056fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org else: 35066fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org return False 35076fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 35086fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 35096fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.orgdef _ClassifyInclude(fileinfo, include, is_system): 35106fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org """Figures out what kind of header 'include' is. 35116fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 35126fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org Args: 35136fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org fileinfo: The current file cpplint is running over. A FileInfo instance. 35146fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org include: The path to a #included file. 35156fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org is_system: True if the #include used <> rather than "". 35166fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 35176fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org Returns: 35186fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org One of the _XXX_HEADER constants. 35196fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 35206fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org For example: 35216fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org >>> _ClassifyInclude(FileInfo('foo/foo.cc'), 'stdio.h', True) 35226fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org _C_SYS_HEADER 35236fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org >>> _ClassifyInclude(FileInfo('foo/foo.cc'), 'string', True) 35246fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org _CPP_SYS_HEADER 35256fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org >>> _ClassifyInclude(FileInfo('foo/foo.cc'), 'foo/foo.h', False) 35266fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org _LIKELY_MY_HEADER 35276fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org >>> _ClassifyInclude(FileInfo('foo/foo_unknown_extension.cc'), 35286fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org ... 'bar/foo_other_ext.h', False) 35296fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org _POSSIBLE_MY_HEADER 35306fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org >>> _ClassifyInclude(FileInfo('foo/foo.cc'), 'foo/bar.h', False) 35316fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org _OTHER_HEADER 35326fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org """ 35336fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # This is a list of all standard c++ header files, except 35346fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # those already checked for above. 3535dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org is_cpp_h = include in _CPP_HEADERS 35366fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 35376fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if is_system: 35386fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if is_cpp_h: 35396fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org return _CPP_SYS_HEADER 35406fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org else: 35416fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org return _C_SYS_HEADER 35426fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 35436fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # If the target file and the include we're checking share a 35446fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # basename when we drop common extensions, and the include 35456fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # lives in . , then it's likely to be owned by the target file. 35466fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org target_dir, target_base = ( 35476fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org os.path.split(_DropCommonSuffixes(fileinfo.RepositoryName()))) 35486fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org include_dir, include_base = os.path.split(_DropCommonSuffixes(include)) 35496fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if target_base == include_base and ( 35506fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org include_dir == target_dir or 35516fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org include_dir == os.path.normpath(target_dir + '/../public')): 35526fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org return _LIKELY_MY_HEADER 35536fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 35546fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # If the target and include share some initial basename 35556fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # component, it's possible the target is implementing the 35566fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # include, so it's allowed to be first, but we'll never 35576fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # complain if it's not there. 35586fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org target_first_component = _RE_FIRST_COMPONENT.match(target_base) 35596fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org include_first_component = _RE_FIRST_COMPONENT.match(include_base) 35606fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if (target_first_component and include_first_component and 35616fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org target_first_component.group(0) == 35626fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org include_first_component.group(0)): 35636fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org return _POSSIBLE_MY_HEADER 35646fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 35656fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org return _OTHER_HEADER 35666fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 35676fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 35686fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 35696fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.orgdef CheckIncludeLine(filename, clean_lines, linenum, include_state, error): 35706fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org """Check rules that are applicable to #include lines. 35716fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 35726fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org Strings on #include lines are NOT removed from elided line, to make 35736fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org certain tasks easier. However, to prevent false positives, checks 35746fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org applicable to #include lines in CheckLanguage must be put here. 35756fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 35766fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org Args: 35776fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org filename: The name of the current file. 35786fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org clean_lines: A CleansedLines instance containing the file. 35796fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org linenum: The number of the line to check. 35806fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org include_state: An _IncludeState instance in which the headers are inserted. 35816fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org error: The function to call with any errors found. 35826fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org """ 35836fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org fileinfo = FileInfo(filename) 35846fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 35856fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org line = clean_lines.lines[linenum] 35866fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 35876fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # "include" should use the new style "foo/bar.h" instead of just "bar.h" 35886fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if _RE_PATTERN_INCLUDE_NEW_STYLE.search(line): 35896fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org error(filename, linenum, 'build/include', 4, 35906fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'Include the directory when naming .h files') 35916fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 35926fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # we shouldn't include a file more than once. actually, there are a 35936fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # handful of instances where doing so is okay, but in general it's 35946fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # not. 35956fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org match = _RE_PATTERN_INCLUDE.search(line) 35966fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if match: 35976fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org include = match.group(2) 35986fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org is_system = (match.group(1) == '<') 35996fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if include in include_state: 36006fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org error(filename, linenum, 'build/include', 4, 36016fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org '"%s" already included at %s:%s' % 36026fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org (include, filename, include_state[include])) 36036fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org else: 36046fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org include_state[include] = linenum 36056fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 36066fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # We want to ensure that headers appear in the right order: 36076fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # 1) for foo.cc, foo.h (preferred location) 36086fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # 2) c system files 36096fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # 3) cpp system files 36106fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # 4) for foo.cc, foo.h (deprecated location) 36116fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # 5) other google headers 36126fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # 36136fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # We classify each include statement as one of those 5 types 36146fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # using a number of techniques. The include_state object keeps 36156fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # track of the highest type seen, and complains if we see a 36166fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # lower type after that. 36176fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org error_message = include_state.CheckNextIncludeOrder( 36186fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org _ClassifyInclude(fileinfo, include, is_system)) 36196fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if error_message: 36206fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org error(filename, linenum, 'build/include_order', 4, 36216fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org '%s. Should be: %s.h, c system, c++ system, other.' % 36226fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org (error_message, fileinfo.BaseName())) 3623dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org canonical_include = include_state.CanonicalizeAlphabeticalOrder(include) 3624dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org if not include_state.IsInAlphabeticalOrder( 3625dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org clean_lines, linenum, canonical_include): 36266fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org error(filename, linenum, 'build/include_alpha', 4, 36276fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'Include "%s" not in alphabetical order' % include) 3628dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org include_state.SetLastHeader(canonical_include) 36296fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 36306fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # Look for any of the stream classes that are part of standard C++. 36316fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org match = _RE_PATTERN_INCLUDE.match(line) 36326fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if match: 36336fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org include = match.group(2) 36346fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if Match(r'(f|ind|io|i|o|parse|pf|stdio|str|)?stream$', include): 36356fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # Many unit tests use cout, so we exempt them. 36366fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if not _IsTestFilename(filename): 36376fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org error(filename, linenum, 'readability/streams', 3, 36386fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'Streams are highly discouraged.') 36396fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 36406fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 36416fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.orgdef _GetTextInside(text, start_pattern): 3642dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org r"""Retrieves all the text between matching open and close parentheses. 36436fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 36446fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org Given a string of lines and a regular expression string, retrieve all the text 36456fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org following the expression and between opening punctuation symbols like 36466fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org (, [, or {, and the matching close-punctuation symbol. This properly nested 36476fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org occurrences of the punctuations, so for the text like 36486fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org printf(a(), b(c())); 36496fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org a call to _GetTextInside(text, r'printf\(') will return 'a(), b(c())'. 36506fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org start_pattern must match string having an open punctuation symbol at the end. 36516fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 36526fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org Args: 36536fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org text: The lines to extract text. Its comments and strings must be elided. 36546fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org It can be single line and can span multiple lines. 36556fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org start_pattern: The regexp string indicating where to start extracting 36566fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org the text. 36576fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org Returns: 36586fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org The extracted text. 36596fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org None if either the opening string or ending punctuation could not be found. 36606fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org """ 36616fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # TODO(sugawarayu): Audit cpplint.py to see what places could be profitably 36626fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # rewritten to use _GetTextInside (and use inferior regexp matching today). 36636fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 36646fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # Give opening punctuations to get the matching close-punctuations. 36656fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org matching_punctuation = {'(': ')', '{': '}', '[': ']'} 36666fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org closing_punctuation = set(matching_punctuation.itervalues()) 36676fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 36686fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # Find the position to start extracting text. 36696fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org match = re.search(start_pattern, text, re.M) 36706fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if not match: # start_pattern not found in text. 36716fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org return None 36726fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org start_position = match.end(0) 36736fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 36746fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org assert start_position > 0, ( 36756fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'start_pattern must ends with an opening punctuation.') 36766fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org assert text[start_position - 1] in matching_punctuation, ( 36776fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'start_pattern must ends with an opening punctuation.') 36786fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # Stack of closing punctuations we expect to have in text after position. 36796fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org punctuation_stack = [matching_punctuation[text[start_position - 1]]] 36806fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org position = start_position 36816fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org while punctuation_stack and position < len(text): 36826fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if text[position] == punctuation_stack[-1]: 36836fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org punctuation_stack.pop() 36846fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org elif text[position] in closing_punctuation: 36856fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # A closing punctuation without matching opening punctuations. 36866fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org return None 36876fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org elif text[position] in matching_punctuation: 36886fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org punctuation_stack.append(matching_punctuation[text[position]]) 36896fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org position += 1 36906fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if punctuation_stack: 36916fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # Opening punctuations left without matching close-punctuations. 36926fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org return None 36936fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # punctuations match. 36946fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org return text[start_position:position - 1] 36956fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 36966fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 3697dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org# Patterns for matching call-by-reference parameters. 3698dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org# 3699dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org# Supports nested templates up to 2 levels deep using this messy pattern: 3700dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org# < (?: < (?: < [^<>]* 3701dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org# > 3702dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org# | [^<>] )* 3703dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org# > 3704dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org# | [^<>] )* 3705dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org# > 3706dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org_RE_PATTERN_IDENT = r'[_a-zA-Z]\w*' # =~ [[:alpha:]][[:alnum:]]* 3707dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org_RE_PATTERN_TYPE = ( 3708dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org r'(?:const\s+)?(?:typename\s+|class\s+|struct\s+|union\s+|enum\s+)?' 3709dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org r'(?:\w|' 3710dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org r'\s*<(?:<(?:<[^<>]*>|[^<>])*>|[^<>])*>|' 3711dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org r'::)+') 3712dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org# A call-by-reference parameter ends with '& identifier'. 3713dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org_RE_PATTERN_REF_PARAM = re.compile( 3714dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org r'(' + _RE_PATTERN_TYPE + r'(?:\s*(?:\bconst\b|[*]))*\s*' 3715dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org r'&\s*' + _RE_PATTERN_IDENT + r')\s*(?:=[^,()]+)?[,)]') 3716dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org# A call-by-const-reference parameter either ends with 'const& identifier' 3717dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org# or looks like 'const type& identifier' when 'type' is atomic. 3718dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org_RE_PATTERN_CONST_REF_PARAM = ( 3719dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org r'(?:.*\s*\bconst\s*&\s*' + _RE_PATTERN_IDENT + 3720dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org r'|const\s+' + _RE_PATTERN_TYPE + r'\s*&\s*' + _RE_PATTERN_IDENT + r')') 3721dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 3722dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 3723dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.orgdef CheckLanguage(filename, clean_lines, linenum, file_extension, 3724dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org include_state, nesting_state, error): 37256fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org """Checks rules from the 'C++ language rules' section of cppguide.html. 37266fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 37276fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org Some of these rules are hard to test (function overloading, using 37286fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org uint32 inappropriately), but we do the best we can. 37296fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 37306fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org Args: 37316fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org filename: The name of the current file. 37326fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org clean_lines: A CleansedLines instance containing the file. 37336fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org linenum: The number of the line to check. 37346fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org file_extension: The extension (without the dot) of the filename. 37356fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org include_state: An _IncludeState instance in which the headers are inserted. 3736dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org nesting_state: A _NestingState instance which maintains information about 3737dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org the current stack of nested blocks being parsed. 37386fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org error: The function to call with any errors found. 37396fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org """ 37406fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # If the line is empty or consists of entirely a comment, no need to 37416fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # check it. 37426fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org line = clean_lines.elided[linenum] 37436fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if not line: 37446fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org return 37456fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 37466fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org match = _RE_PATTERN_INCLUDE.search(line) 37476fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if match: 37486fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org CheckIncludeLine(filename, clean_lines, linenum, include_state, error) 37496fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org return 37506fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 3751dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # Reset include state across preprocessor directives. This is meant 3752dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # to silence warnings for conditional includes. 3753dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org if Match(r'^\s*#\s*(?:ifdef|elif|else|endif)\b', line): 3754dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org include_state.ResetSection() 37556fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 37566fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # Make Windows paths like Unix. 37576fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org fullname = os.path.abspath(filename).replace('\\', '/') 37586fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 37596fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # TODO(unknown): figure out if they're using default arguments in fn proto. 37606fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 37616fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # Check to see if they're using an conversion function cast. 37626fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # I just try to capture the most common basic types, though there are more. 37636fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # Parameterless conversion functions, such as bool(), are allowed as they are 37646fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # probably a member operator declaration or default constructor. 37656fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org match = Search( 37666fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org r'(\bnew\s+)?\b' # Grab 'new' operator, if it's there 3767dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org r'(int|float|double|bool|char|int32|uint32|int64|uint64)' 3768dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org r'(\([^)].*)', line) 37696fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if match: 3770dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org matched_new = match.group(1) 3771dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org matched_type = match.group(2) 3772dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org matched_funcptr = match.group(3) 3773dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 37746fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # gMock methods are defined using some variant of MOCK_METHODx(name, type) 37756fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # where type may be float(), int(string), etc. Without context they are 37766fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # virtually indistinguishable from int(x) casts. Likewise, gMock's 37776fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # MockCallback takes a template parameter of the form return_type(arg_type), 37786fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # which looks much like the cast we're trying to detect. 3779dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # 3780dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # std::function<> wrapper has a similar problem. 3781dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # 3782dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # Return types for function pointers also look like casts if they 3783dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # don't have an extra space. 3784dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org if (matched_new is None and # If new operator, then this isn't a cast 37856fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org not (Match(r'^\s*MOCK_(CONST_)?METHOD\d+(_T)?\(', line) or 3786dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org Search(r'\bMockCallback<.*>', line) or 3787dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org Search(r'\bstd::function<.*>', line)) and 3788dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org not (matched_funcptr and 3789dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org Match(r'\((?:[^() ]+::\s*\*\s*)?[^() ]+\)\s*\(', 3790dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org matched_funcptr))): 379110a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # Try a bit harder to catch gmock lines: the only place where 379210a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # something looks like an old-style cast is where we declare the 379310a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # return type of the mocked method, and the only time when we 379410a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # are missing context is if MOCK_METHOD was split across 3795dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # multiple lines. The missing MOCK_METHOD is usually one or two 3796dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # lines back, so scan back one or two lines. 3797dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # 3798dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # It's not possible for gmock macros to appear in the first 2 3799dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # lines, since the class head + section name takes up 2 lines. 3800dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org if (linenum < 2 or 3801dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org not (Match(r'^\s*MOCK_(?:CONST_)?METHOD\d+(?:_T)?\((?:\S+,)?\s*$', 3802dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org clean_lines.elided[linenum - 1]) or 3803dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org Match(r'^\s*MOCK_(?:CONST_)?METHOD\d+(?:_T)?\(\s*$', 3804dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org clean_lines.elided[linenum - 2]))): 380510a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org error(filename, linenum, 'readability/casting', 4, 380610a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org 'Using deprecated casting style. ' 380710a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org 'Use static_cast<%s>(...) instead' % 3808dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org matched_type) 38096fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 38106fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org CheckCStyleCast(filename, linenum, line, clean_lines.raw_lines[linenum], 38116fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'static_cast', 38126fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org r'\((int|float|double|bool|char|u?int(16|32|64))\)', error) 38136fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 38146fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # This doesn't catch all cases. Consider (const char * const)"hello". 38156fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # 38166fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # (char *) "foo" should always be a const_cast (reinterpret_cast won't 38176fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # compile). 38186fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if CheckCStyleCast(filename, linenum, line, clean_lines.raw_lines[linenum], 38196fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'const_cast', r'\((char\s?\*+\s?)\)\s*"', error): 38206fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org pass 38216fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org else: 38226fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # Check pointer casts for other than string constants 38236fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org CheckCStyleCast(filename, linenum, line, clean_lines.raw_lines[linenum], 38246fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'reinterpret_cast', r'\((\w+\s?\*+\s?)\)', error) 38256fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 38266fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # In addition, we look for people taking the address of a cast. This 38276fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # is dangerous -- casts can assign to temporaries, so the pointer doesn't 38286fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # point where you think. 3829dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org match = Search( 3830dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org r'(?:&\(([^)]+)\)[\w(])|' 3831dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org r'(?:&(static|dynamic|down|reinterpret)_cast\b)', line) 3832dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org if match and match.group(1) != '*': 38336fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org error(filename, linenum, 'runtime/casting', 4, 38346fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org ('Are you taking an address of a cast? ' 38356fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'This is dangerous: could be a temp var. ' 38366fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'Take the address before doing the cast, rather than after')) 38376fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 3838dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # Create an extended_line, which is the concatenation of the current and 3839dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # next lines, for more effective checking of code that may span more than one 3840dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # line. 3841dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org if linenum + 1 < clean_lines.NumLines(): 3842dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org extended_line = line + clean_lines.elided[linenum + 1] 3843dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org else: 3844dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org extended_line = line 3845dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 38466fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # Check for people declaring static/global STL strings at the top level. 38476fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # This is dangerous because the C++ language does not guarantee that 38486fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # globals with constructors are initialized before the first access. 38496fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org match = Match( 38506fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org r'((?:|static +)(?:|const +))string +([a-zA-Z0-9_:]+)\b(.*)', 38516fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org line) 38526fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # Make sure it's not a function. 38536fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # Function template specialization looks like: "string foo<Type>(...". 38546fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # Class template definitions look like: "string Foo<Type>::Method(...". 3855dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # 3856dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # Also ignore things that look like operators. These are matched separately 3857dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # because operator names cross non-word boundaries. If we change the pattern 3858dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # above, we would decrease the accuracy of matching identifiers. 3859dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org if (match and 3860dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org not Search(r'\boperator\W', line) and 3861dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org not Match(r'\s*(<.*>)?(::[a-zA-Z0-9_]+)?\s*\(([^"]|$)', match.group(3))): 38626fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org error(filename, linenum, 'runtime/string', 4, 38636fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'For a static/global string constant, use a C style string instead: ' 38646fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org '"%schar %s[]".' % 38656fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org (match.group(1), match.group(2))) 38666fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 38676fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if Search(r'\b([A-Za-z0-9_]*_)\(\1\)', line): 38686fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org error(filename, linenum, 'runtime/init', 4, 38696fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'You seem to be initializing a member variable with itself.') 38706fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 38716fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if file_extension == 'h': 38726fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # TODO(unknown): check that 1-arg constructors are explicit. 38736fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # How to tell it's a constructor? 38746fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # (handled in CheckForNonStandardConstructs for now) 38756fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # TODO(unknown): check that classes have DISALLOW_EVIL_CONSTRUCTORS 38766fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # (level 1 error) 38776fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org pass 38786fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 38796fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # Check if people are using the verboten C basic types. The only exception 38806fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # we regularly allow is "unsigned short port" for port. 38816fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if Search(r'\bshort port\b', line): 38826fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if not Search(r'\bunsigned short port\b', line): 38836fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org error(filename, linenum, 'runtime/int', 4, 38846fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'Use "unsigned short" for ports, not "short"') 38856fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org else: 38866fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org match = Search(r'\b(short|long(?! +double)|long long)\b', line) 38876fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if match: 38886fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org error(filename, linenum, 'runtime/int', 4, 38896fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'Use int16/int64/etc, rather than the C type %s' % match.group(1)) 38906fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 38916fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # When snprintf is used, the second argument shouldn't be a literal. 38926fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org match = Search(r'snprintf\s*\(([^,]*),\s*([0-9]*)\s*,', line) 38936fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if match and match.group(2) != '0': 38946fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # If 2nd arg is zero, snprintf is used to calculate size. 38956fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org error(filename, linenum, 'runtime/printf', 3, 38966fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'If you can, use sizeof(%s) instead of %s as the 2nd arg ' 38976fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'to snprintf.' % (match.group(1), match.group(2))) 38986fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 38996fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # Check if some verboten C functions are being used. 39006fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if Search(r'\bsprintf\b', line): 39016fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org error(filename, linenum, 'runtime/printf', 5, 39026fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'Never use sprintf. Use snprintf instead.') 39036fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org match = Search(r'\b(strcpy|strcat)\b', line) 39046fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if match: 39056fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org error(filename, linenum, 'runtime/printf', 4, 39066fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'Almost always, snprintf is better than %s' % match.group(1)) 39076fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 39086fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # Check if some verboten operator overloading is going on 39096fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # TODO(unknown): catch out-of-line unary operator&: 39106fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # class X {}; 39116fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # int operator&(const X& x) { return 42; } // unary operator& 39126fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # The trick is it's hard to tell apart from binary operator&: 39136fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # class Y { int operator&(const Y& x) { return 23; } }; // binary operator& 39146fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if Search(r'\boperator\s*&\s*\(\s*\)', line): 39156fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org error(filename, linenum, 'runtime/operator', 4, 39166fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'Unary operator& is dangerous. Do not use it.') 39176fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 39186fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # Check for suspicious usage of "if" like 39196fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # } if (a == b) { 39206fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if Search(r'\}\s*if\s*\(', line): 39216fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org error(filename, linenum, 'readability/braces', 4, 39226fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'Did you mean "else if"? If not, start a new line for "if".') 39236fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 39246fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # Check for potential format string bugs like printf(foo). 39256fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # We constrain the pattern not to pick things like DocidForPrintf(foo). 39266fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # Not perfect but it can catch printf(foo.c_str()) and printf(foo->c_str()) 39276fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # TODO(sugawarayu): Catch the following case. Need to change the calling 39286fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # convention of the whole function to process multiple line to handle it. 39296fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # printf( 39306fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # boy_this_is_a_really_long_variable_that_cannot_fit_on_the_prev_line); 39316fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org printf_args = _GetTextInside(line, r'(?i)\b(string)?printf\s*\(') 39326fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if printf_args: 39336fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org match = Match(r'([\w.\->()]+)$', printf_args) 393410a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org if match and match.group(1) != '__VA_ARGS__': 39356fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org function_name = re.search(r'\b((?:string)?printf)\s*\(', 39366fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org line, re.I).group(1) 39376fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org error(filename, linenum, 'runtime/printf', 4, 39386fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'Potential format string bug. Do %s("%%s", %s) instead.' 39396fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org % (function_name, match.group(1))) 39406fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 39416fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # Check for potential memset bugs like memset(buf, sizeof(buf), 0). 39426fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org match = Search(r'memset\s*\(([^,]*),\s*([^,]*),\s*0\s*\)', line) 39436fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if match and not Match(r"^''|-?[0-9]+|0x[0-9A-Fa-f]$", match.group(2)): 39446fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org error(filename, linenum, 'runtime/memset', 4, 39456fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'Did you mean "memset(%s, 0, %s)"?' 39466fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org % (match.group(1), match.group(2))) 39476fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 39486fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if Search(r'\busing namespace\b', line): 39496fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org error(filename, linenum, 'build/namespaces', 5, 39506fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'Do not use namespace using-directives. ' 39516fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'Use using-declarations instead.') 39526fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 39536fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # Detect variable-length arrays. 39546fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org match = Match(r'\s*(.+::)?(\w+) [a-z]\w*\[(.+)];', line) 39556fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if (match and match.group(2) != 'return' and match.group(2) != 'delete' and 39566fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org match.group(3).find(']') == -1): 39576fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # Split the size using space and arithmetic operators as delimiters. 39586fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # If any of the resulting tokens are not compile time constants then 39596fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # report the error. 39606fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org tokens = re.split(r'\s|\+|\-|\*|\/|<<|>>]', match.group(3)) 39616fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org is_const = True 39626fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org skip_next = False 39636fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org for tok in tokens: 39646fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if skip_next: 39656fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org skip_next = False 39666fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org continue 39676fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 39686fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if Search(r'sizeof\(.+\)', tok): continue 39696fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if Search(r'arraysize\(\w+\)', tok): continue 39706fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 39716fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org tok = tok.lstrip('(') 39726fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org tok = tok.rstrip(')') 39736fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if not tok: continue 39746fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if Match(r'\d+', tok): continue 39756fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if Match(r'0[xX][0-9a-fA-F]+', tok): continue 39766fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if Match(r'k[A-Z0-9]\w*', tok): continue 39776fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if Match(r'(.+::)?k[A-Z0-9]\w*', tok): continue 39786fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if Match(r'(.+::)?[A-Z][A-Z0-9_]*', tok): continue 39796fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # A catch all for tricky sizeof cases, including 'sizeof expression', 39806fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # 'sizeof(*type)', 'sizeof(const type)', 'sizeof(struct StructName)' 39816fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # requires skipping the next token because we split on ' ' and '*'. 39826fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if tok.startswith('sizeof'): 39836fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org skip_next = True 39846fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org continue 39856fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org is_const = False 39866fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org break 39876fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if not is_const: 39886fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org error(filename, linenum, 'runtime/arrays', 1, 39896fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'Do not use variable-length arrays. Use an appropriately named ' 39906fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org "('k' followed by CamelCase) compile-time constant for the size.") 39916fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 39926fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # If DISALLOW_EVIL_CONSTRUCTORS, DISALLOW_COPY_AND_ASSIGN, or 39936fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # DISALLOW_IMPLICIT_CONSTRUCTORS is present, then it should be the last thing 39946fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # in the class declaration. 39956fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org match = Match( 39966fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org (r'\s*' 39976fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org r'(DISALLOW_(EVIL_CONSTRUCTORS|COPY_AND_ASSIGN|IMPLICIT_CONSTRUCTORS))' 39986fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org r'\(.*\);$'), 39996fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org line) 40006fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if match and linenum + 1 < clean_lines.NumLines(): 40016fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org next_line = clean_lines.elided[linenum + 1] 40026fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # We allow some, but not all, declarations of variables to be present 40036fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # in the statement that defines the class. The [\w\*,\s]* fragment of 40046fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # the regular expression below allows users to declare instances of 40056fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # the class or pointers to instances, but not less common types such 40066fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # as function pointers or arrays. It's a tradeoff between allowing 40076fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # reasonable code and avoiding trying to parse more C++ using regexps. 40086fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if not Search(r'^\s*}[\w\*,\s]*;', next_line): 40096fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org error(filename, linenum, 'readability/constructors', 3, 40106fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org match.group(1) + ' should be the last thing in the class') 40116fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 40126fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # Check for use of unnamed namespaces in header files. Registration 40136fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # macros are typically OK, so we allow use of "namespace {" on lines 40146fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # that end with backslashes. 40156fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if (file_extension == 'h' 40166fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org and Search(r'\bnamespace\s*{', line) 40176fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org and line[-1] != '\\'): 40186fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org error(filename, linenum, 'build/namespaces', 4, 40196fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'Do not use unnamed namespaces in header files. See ' 40206fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml#Namespaces' 40216fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org ' for more information.') 40226fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 4023dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.orgdef CheckForNonConstReference(filename, clean_lines, linenum, 4024dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org nesting_state, error): 4025dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org """Check for non-const references. 4026dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 4027dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org Separate from CheckLanguage since it scans backwards from current 4028dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org line, instead of scanning forward. 4029dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 4030dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org Args: 4031dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org filename: The name of the current file. 4032dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org clean_lines: A CleansedLines instance containing the file. 4033dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org linenum: The number of the line to check. 4034dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org nesting_state: A _NestingState instance which maintains information about 4035dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org the current stack of nested blocks being parsed. 4036dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org error: The function to call with any errors found. 4037dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org """ 4038dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # Do nothing if there is no '&' on current line. 4039dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org line = clean_lines.elided[linenum] 4040dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org if '&' not in line: 4041dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org return 4042dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 4043dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # Long type names may be broken across multiple lines, usually in one 4044dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # of these forms: 4045dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # LongType 4046dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # ::LongTypeContinued &identifier 4047dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # LongType:: 4048dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # LongTypeContinued &identifier 4049dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # LongType< 4050dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # ...>::LongTypeContinued &identifier 4051dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # 4052dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # If we detected a type split across two lines, join the previous 4053dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # line to current line so that we can match const references 4054dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # accordingly. 4055dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # 4056dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # Note that this only scans back one line, since scanning back 4057dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # arbitrary number of lines would be expensive. If you have a type 4058dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # that spans more than 2 lines, please use a typedef. 4059dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org if linenum > 1: 4060dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org previous = None 4061dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org if Match(r'\s*::(?:[\w<>]|::)+\s*&\s*\S', line): 4062dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # previous_line\n + ::current_line 4063dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org previous = Search(r'\b((?:const\s*)?(?:[\w<>]|::)+[\w<>])\s*$', 4064dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org clean_lines.elided[linenum - 1]) 4065dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org elif Match(r'\s*[a-zA-Z_]([\w<>]|::)+\s*&\s*\S', line): 4066dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # previous_line::\n + current_line 4067dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org previous = Search(r'\b((?:const\s*)?(?:[\w<>]|::)+::)\s*$', 4068dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org clean_lines.elided[linenum - 1]) 4069dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org if previous: 4070dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org line = previous.group(1) + line.lstrip() 4071dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org else: 4072dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # Check for templated parameter that is split across multiple lines 4073dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org endpos = line.rfind('>') 4074dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org if endpos > -1: 4075dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org (_, startline, startpos) = ReverseCloseExpression( 4076dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org clean_lines, linenum, endpos) 4077dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org if startpos > -1 and startline < linenum: 4078dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # Found the matching < on an earlier line, collect all 4079dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # pieces up to current line. 4080dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org line = '' 4081dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org for i in xrange(startline, linenum + 1): 4082dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org line += clean_lines.elided[i].strip() 4083dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 4084dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # Check for non-const references in function parameters. A single '&' may 4085dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # found in the following places: 4086dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # inside expression: binary & for bitwise AND 4087dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # inside expression: unary & for taking the address of something 4088dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # inside declarators: reference parameter 4089dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # We will exclude the first two cases by checking that we are not inside a 4090dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # function body, including one that was just introduced by a trailing '{'. 4091dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # TODO(unknwon): Doesn't account for preprocessor directives. 4092dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # TODO(unknown): Doesn't account for 'catch(Exception& e)' [rare]. 4093dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org check_params = False 4094dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org if not nesting_state.stack: 4095dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org check_params = True # top level 4096dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org elif (isinstance(nesting_state.stack[-1], _ClassInfo) or 4097dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org isinstance(nesting_state.stack[-1], _NamespaceInfo)): 4098dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org check_params = True # within class or namespace 4099dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org elif Match(r'.*{\s*$', line): 4100dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org if (len(nesting_state.stack) == 1 or 4101dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org isinstance(nesting_state.stack[-2], _ClassInfo) or 4102dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org isinstance(nesting_state.stack[-2], _NamespaceInfo)): 4103dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org check_params = True # just opened global/class/namespace block 4104dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # We allow non-const references in a few standard places, like functions 4105dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # called "swap()" or iostream operators like "<<" or ">>". Do not check 4106dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # those function parameters. 4107dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # 4108dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # We also accept & in static_assert, which looks like a function but 4109dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # it's actually a declaration expression. 4110dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org whitelisted_functions = (r'(?:[sS]wap(?:<\w:+>)?|' 4111dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org r'operator\s*[<>][<>]|' 4112dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org r'static_assert|COMPILE_ASSERT' 4113dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org r')\s*\(') 4114dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org if Search(whitelisted_functions, line): 4115dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org check_params = False 4116dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org elif not Search(r'\S+\([^)]*$', line): 4117dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # Don't see a whitelisted function on this line. Actually we 4118dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # didn't see any function name on this line, so this is likely a 4119dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # multi-line parameter list. Try a bit harder to catch this case. 4120dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org for i in xrange(2): 4121dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org if (linenum > i and 4122dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org Search(whitelisted_functions, clean_lines.elided[linenum - i - 1])): 4123dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org check_params = False 4124dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org break 4125dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 4126dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org if check_params: 4127dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org decls = ReplaceAll(r'{[^}]*}', ' ', line) # exclude function body 4128dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org for parameter in re.findall(_RE_PATTERN_REF_PARAM, decls): 4129dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org if not Match(_RE_PATTERN_CONST_REF_PARAM, parameter): 4130dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org error(filename, linenum, 'runtime/references', 2, 4131dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'Is this a non-const reference? ' 4132dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'If so, make const or use a pointer: ' + 4133dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org ReplaceAll(' *<', '<', parameter)) 4134dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 41356fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 41366fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.orgdef CheckCStyleCast(filename, linenum, line, raw_line, cast_type, pattern, 41376fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org error): 41386fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org """Checks for a C-style cast by looking for the pattern. 41396fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 41406fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org Args: 41416fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org filename: The name of the current file. 41426fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org linenum: The number of the line to check. 41436fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org line: The line of code to check. 41446fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org raw_line: The raw line of code to check, with comments. 41456fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org cast_type: The string for the C++ cast to recommend. This is either 41466fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org reinterpret_cast, static_cast, or const_cast, depending. 41476fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org pattern: The regular expression used to find C-style casts. 41486fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org error: The function to call with any errors found. 41496fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 41506fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org Returns: 41516fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org True if an error was emitted. 41526fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org False otherwise. 41536fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org """ 41546fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org match = Search(pattern, line) 41556fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if not match: 41566fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org return False 41576fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 41586fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # e.g., sizeof(int) 41596fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org sizeof_match = Match(r'.*sizeof\s*$', line[0:match.start(1) - 1]) 41606fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if sizeof_match: 41616fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org error(filename, linenum, 'runtime/sizeof', 1, 41626fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'Using sizeof(type). Use sizeof(varname) instead if possible') 41636fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org return True 41646fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 416510a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org # operator++(int) and operator--(int) 416610a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org if (line[0:match.start(1) - 1].endswith(' operator++') or 416710a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org line[0:match.start(1) - 1].endswith(' operator--')): 416810a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org return False 416910a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org 4170dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # A single unnamed argument for a function tends to look like old 4171dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # style cast. If we see those, don't issue warnings for deprecated 4172dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # casts, instead issue warnings for unnamed arguments where 4173dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # appropriate. 4174dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # 4175dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # These are things that we want warnings for, since the style guide 4176dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # explicitly require all parameters to be named: 4177dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # Function(int); 4178dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # Function(int) { 4179dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # ConstMember(int) const; 4180dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # ConstMember(int) const { 4181dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # ExceptionMember(int) throw (...); 4182dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # ExceptionMember(int) throw (...) { 4183dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # PureVirtual(int) = 0; 4184dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # 4185dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # These are functions of some sort, where the compiler would be fine 4186dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # if they had named parameters, but people often omit those 4187dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # identifiers to reduce clutter: 4188dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # (FunctionPointer)(int); 4189dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # (FunctionPointer)(int) = value; 4190dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # Function((function_pointer_arg)(int)) 4191dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # <TemplateArgument(int)>; 4192dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # <(FunctionPointerTemplateArgument)(int)>; 41936fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org remainder = line[match.end(0):] 4194dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org if Match(r'^\s*(?:;|const\b|throw\b|=|>|\{|\))', remainder): 4195dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # Looks like an unnamed parameter. 41966fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 4197dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # Don't warn on any kind of template arguments. 4198dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org if Match(r'^\s*>', remainder): 4199dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org return False 4200dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 4201dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # Don't warn on assignments to function pointers, but keep warnings for 4202dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # unnamed parameters to pure virtual functions. Note that this pattern 4203dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # will also pass on assignments of "0" to function pointers, but the 4204dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # preferred values for those would be "nullptr" or "NULL". 4205dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org matched_zero = Match(r'^\s=\s*(\S+)\s*;', remainder) 4206dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org if matched_zero and matched_zero.group(1) != '0': 4207dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org return False 4208dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 4209dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # Don't warn on function pointer declarations. For this we need 4210dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # to check what came before the "(type)" string. 4211dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org if Match(r'.*\)\s*$', line[0:match.start(0)]): 4212dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org return False 4213dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 4214dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # Don't warn if the parameter is named with block comments, e.g.: 4215dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # Function(int /*unused_param*/); 4216dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org if '/*' in raw_line: 4217dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org return False 4218dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 4219dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org # Passed all filters, issue warning here. 4220dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org error(filename, linenum, 'readability/function', 3, 4221dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'All parameters should be named in a function') 42226fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org return True 42236fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 42246fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # At this point, all that should be left is actual casts. 42256fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org error(filename, linenum, 'readability/casting', 4, 42266fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'Using C-style cast. Use %s<%s>(...) instead' % 42276fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org (cast_type, match.group(1))) 42286fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 42296fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org return True 42306fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 42316fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 42326fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org_HEADERS_CONTAINING_TEMPLATES = ( 42336fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org ('<deque>', ('deque',)), 42346fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org ('<functional>', ('unary_function', 'binary_function', 42356fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'plus', 'minus', 'multiplies', 'divides', 'modulus', 42366fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'negate', 42376fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'equal_to', 'not_equal_to', 'greater', 'less', 42386fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'greater_equal', 'less_equal', 42396fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'logical_and', 'logical_or', 'logical_not', 42406fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'unary_negate', 'not1', 'binary_negate', 'not2', 42416fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'bind1st', 'bind2nd', 42426fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'pointer_to_unary_function', 42436fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'pointer_to_binary_function', 42446fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'ptr_fun', 42456fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'mem_fun_t', 'mem_fun', 'mem_fun1_t', 'mem_fun1_ref_t', 42466fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'mem_fun_ref_t', 42476fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'const_mem_fun_t', 'const_mem_fun1_t', 42486fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'const_mem_fun_ref_t', 'const_mem_fun1_ref_t', 42496fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'mem_fun_ref', 42506fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org )), 42516fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org ('<limits>', ('numeric_limits',)), 42526fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org ('<list>', ('list',)), 42536fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org ('<map>', ('map', 'multimap',)), 42546fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org ('<memory>', ('allocator',)), 42556fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org ('<queue>', ('queue', 'priority_queue',)), 42566fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org ('<set>', ('set', 'multiset',)), 42576fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org ('<stack>', ('stack',)), 42586fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org ('<string>', ('char_traits', 'basic_string',)), 42596fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org ('<utility>', ('pair',)), 42606fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org ('<vector>', ('vector',)), 42616fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 42626fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # gcc extensions. 42636fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # Note: std::hash is their hash, ::hash is our hash 42646fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org ('<hash_map>', ('hash_map', 'hash_multimap',)), 42656fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org ('<hash_set>', ('hash_set', 'hash_multiset',)), 42666fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org ('<slist>', ('slist',)), 42676fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org ) 42686fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 42696fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org_RE_PATTERN_STRING = re.compile(r'\bstring\b') 42706fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 42716fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org_re_pattern_algorithm_header = [] 42726fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.orgfor _template in ('copy', 'max', 'min', 'min_element', 'sort', 'swap', 42736fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'transform'): 42746fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # Match max<type>(..., ...), max(..., ...), but not foo->max, foo.max or 42756fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # type::max(). 42766fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org _re_pattern_algorithm_header.append( 42776fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org (re.compile(r'[^>.]\b' + _template + r'(<.*?>)?\([^\)]'), 42786fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org _template, 42796fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org '<algorithm>')) 42806fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 42816fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org_re_pattern_templates = [] 42826fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.orgfor _header, _templates in _HEADERS_CONTAINING_TEMPLATES: 42836fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org for _template in _templates: 42846fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org _re_pattern_templates.append( 42856fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org (re.compile(r'(\<|\b)' + _template + r'\s*\<'), 42866fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org _template + '<>', 42876fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org _header)) 42886fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 42896fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 42906fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.orgdef FilesBelongToSameModule(filename_cc, filename_h): 42916fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org """Check if these two filenames belong to the same module. 42926fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 42936fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org The concept of a 'module' here is a as follows: 42946fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org foo.h, foo-inl.h, foo.cc, foo_test.cc and foo_unittest.cc belong to the 42956fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org same 'module' if they are in the same directory. 42966fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org some/path/public/xyzzy and some/path/internal/xyzzy are also considered 42976fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org to belong to the same module here. 42986fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 42996fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org If the filename_cc contains a longer path than the filename_h, for example, 43006fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org '/absolute/path/to/base/sysinfo.cc', and this file would include 43016fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'base/sysinfo.h', this function also produces the prefix needed to open the 43026fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org header. This is used by the caller of this function to more robustly open the 43036fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org header file. We don't have access to the real include paths in this context, 43046fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org so we need this guesswork here. 43056fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 43066fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org Known bugs: tools/base/bar.cc and base/bar.h belong to the same module 43076fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org according to this implementation. Because of this, this function gives 43086fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org some false positives. This should be sufficiently rare in practice. 43096fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 43106fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org Args: 43116fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org filename_cc: is the path for the .cc file 43126fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org filename_h: is the path for the header path 43136fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 43146fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org Returns: 43156fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org Tuple with a bool and a string: 43166fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org bool: True if filename_cc and filename_h belong to the same module. 43176fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org string: the additional prefix needed to open the header file. 43186fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org """ 43196fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 43206fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if not filename_cc.endswith('.cc'): 43216fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org return (False, '') 43226fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org filename_cc = filename_cc[:-len('.cc')] 43236fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if filename_cc.endswith('_unittest'): 43246fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org filename_cc = filename_cc[:-len('_unittest')] 43256fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org elif filename_cc.endswith('_test'): 43266fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org filename_cc = filename_cc[:-len('_test')] 43276fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org filename_cc = filename_cc.replace('/public/', '/') 43286fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org filename_cc = filename_cc.replace('/internal/', '/') 43296fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 43306fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if not filename_h.endswith('.h'): 43316fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org return (False, '') 43326fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org filename_h = filename_h[:-len('.h')] 43336fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if filename_h.endswith('-inl'): 43346fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org filename_h = filename_h[:-len('-inl')] 43356fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org filename_h = filename_h.replace('/public/', '/') 43366fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org filename_h = filename_h.replace('/internal/', '/') 43376fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 43386fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org files_belong_to_same_module = filename_cc.endswith(filename_h) 43396fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org common_path = '' 43406fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if files_belong_to_same_module: 43416fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org common_path = filename_cc[:-len(filename_h)] 43426fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org return files_belong_to_same_module, common_path 43436fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 43446fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 43456fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.orgdef UpdateIncludeState(filename, include_state, io=codecs): 43466fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org """Fill up the include_state with new includes found from the file. 43476fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 43486fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org Args: 43496fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org filename: the name of the header to read. 43506fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org include_state: an _IncludeState instance in which the headers are inserted. 43516fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org io: The io factory to use to read the file. Provided for testability. 43526fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 43536fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org Returns: 43546fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org True if a header was succesfully added. False otherwise. 43556fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org """ 43566fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org headerfile = None 43576fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org try: 43586fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org headerfile = io.open(filename, 'r', 'utf8', 'replace') 43596fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org except IOError: 43606fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org return False 43616fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org linenum = 0 43626fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org for line in headerfile: 43636fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org linenum += 1 43646fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org clean_line = CleanseComments(line) 43656fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org match = _RE_PATTERN_INCLUDE.search(clean_line) 43666fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if match: 43676fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org include = match.group(2) 43686fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # The value formatting is cute, but not really used right now. 43696fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # What matters here is that the key is in include_state. 43706fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org include_state.setdefault(include, '%s:%d' % (filename, linenum)) 43716fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org return True 43726fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 43736fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 43746fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.orgdef CheckForIncludeWhatYouUse(filename, clean_lines, include_state, error, 43756fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org io=codecs): 43766fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org """Reports for missing stl includes. 43776fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 43786fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org This function will output warnings to make sure you are including the headers 43796fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org necessary for the stl containers and functions that you use. We only give one 43806fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org reason to include a header. For example, if you use both equal_to<> and 43816fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org less<> in a .h file, only one (the latter in the file) of these will be 43826fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org reported as a reason to include the <functional>. 43836fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 43846fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org Args: 43856fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org filename: The name of the current file. 43866fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org clean_lines: A CleansedLines instance containing the file. 43876fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org include_state: An _IncludeState instance. 43886fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org error: The function to call with any errors found. 43896fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org io: The IO factory to use to read the header file. Provided for unittest 43906fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org injection. 43916fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org """ 43926fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org required = {} # A map of header name to linenumber and the template entity. 43936fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # Example of required: { '<functional>': (1219, 'less<>') } 43946fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 43956fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org for linenum in xrange(clean_lines.NumLines()): 43966fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org line = clean_lines.elided[linenum] 43976fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if not line or line[0] == '#': 43986fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org continue 43996fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 44006fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # String is special -- it is a non-templatized type in STL. 44016fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org matched = _RE_PATTERN_STRING.search(line) 44026fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if matched: 44036fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # Don't warn about strings in non-STL namespaces: 44046fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # (We check only the first match per line; good enough.) 44056fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org prefix = line[:matched.start()] 44066fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if prefix.endswith('std::') or not prefix.endswith('::'): 44076fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org required['<string>'] = (linenum, 'string') 44086fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 44096fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org for pattern, template, header in _re_pattern_algorithm_header: 44106fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if pattern.search(line): 44116fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org required[header] = (linenum, template) 44126fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 44136fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # The following function is just a speed up, no semantics are changed. 44146fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if not '<' in line: # Reduces the cpu time usage by skipping lines. 44156fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org continue 44166fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 44176fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org for pattern, template, header in _re_pattern_templates: 44186fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if pattern.search(line): 44196fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org required[header] = (linenum, template) 44206fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 44216fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # The policy is that if you #include something in foo.h you don't need to 44226fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # include it again in foo.cc. Here, we will look at possible includes. 44236fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # Let's copy the include_state so it is only messed up within this function. 44246fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org include_state = include_state.copy() 44256fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 44266fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # Did we find the header for this file (if any) and succesfully load it? 44276fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org header_found = False 44286fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 44296fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # Use the absolute path so that matching works properly. 44306fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org abs_filename = FileInfo(filename).FullName() 44316fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 44326fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # For Emacs's flymake. 44336fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # If cpplint is invoked from Emacs's flymake, a temporary file is generated 44346fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # by flymake and that file name might end with '_flymake.cc'. In that case, 44356fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # restore original file name here so that the corresponding header file can be 44366fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # found. 44376fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # e.g. If the file name is 'foo_flymake.cc', we should search for 'foo.h' 44386fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # instead of 'foo_flymake.h' 44396fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org abs_filename = re.sub(r'_flymake\.cc$', '.cc', abs_filename) 44406fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 44416fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # include_state is modified during iteration, so we iterate over a copy of 44426fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # the keys. 44436fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org header_keys = include_state.keys() 44446fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org for header in header_keys: 44456fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org (same_module, common_path) = FilesBelongToSameModule(abs_filename, header) 44466fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org fullpath = common_path + header 44476fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if same_module and UpdateIncludeState(fullpath, include_state, io): 44486fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org header_found = True 44496fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 44506fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # If we can't find the header file for a .cc, assume it's because we don't 44516fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # know where to look. In that case we'll give up as we're not sure they 44526fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # didn't include it in the .h file. 44536fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # TODO(unknown): Do a better job of finding .h files so we are confident that 44546fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # not having the .h file means there isn't one. 44556fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if filename.endswith('.cc') and not header_found: 44566fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org return 44576fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 44586fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # All the lines have been processed, report the errors found. 44596fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org for required_header_unstripped in required: 44606fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org template = required[required_header_unstripped][1] 44616fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if required_header_unstripped.strip('<>"') not in include_state: 44626fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org error(filename, required[required_header_unstripped][0], 44636fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'build/include_what_you_use', 4, 44646fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'Add #include ' + required_header_unstripped + ' for ' + template) 44656fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 44666fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 44676fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org_RE_PATTERN_EXPLICIT_MAKEPAIR = re.compile(r'\bmake_pair\s*<') 44686fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 44696fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 44706fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.orgdef CheckMakePairUsesDeduction(filename, clean_lines, linenum, error): 44716fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org """Check that make_pair's template arguments are deduced. 44726fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 44736fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org G++ 4.6 in C++0x mode fails badly if make_pair's template arguments are 44746fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org specified explicitly, and such use isn't intended in any case. 44756fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 44766fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org Args: 44776fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org filename: The name of the current file. 44786fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org clean_lines: A CleansedLines instance containing the file. 44796fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org linenum: The number of the line to check. 44806fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org error: The function to call with any errors found. 44816fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org """ 4482dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org line = clean_lines.elided[linenum] 44836fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org match = _RE_PATTERN_EXPLICIT_MAKEPAIR.search(line) 44846fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if match: 44856fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org error(filename, linenum, 'build/explicit_make_pair', 44866fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 4, # 4 = high confidence 448710a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org 'For C++11-compatibility, omit template arguments from make_pair' 448810a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org ' OR use pair directly OR if appropriate, construct a pair directly') 44896fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 44906fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 449110a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.orgdef ProcessLine(filename, file_extension, clean_lines, line, 449210a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org include_state, function_state, nesting_state, error, 449310a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org extra_check_functions=[]): 44946fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org """Processes a single line in the file. 44956fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 44966fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org Args: 44976fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org filename: Filename of the file that is being processed. 44986fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org file_extension: The extension (dot not included) of the file. 44996fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org clean_lines: An array of strings, each representing a line of the file, 45006fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org with comments stripped. 45016fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org line: Number of line being processed. 45026fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org include_state: An _IncludeState instance in which the headers are inserted. 45036fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org function_state: A _FunctionState instance which counts function lines, etc. 450410a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org nesting_state: A _NestingState instance which maintains information about 450510a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org the current stack of nested blocks being parsed. 45066fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org error: A callable to which errors are reported, which takes 4 arguments: 45076fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org filename, line number, error level, and message 45086fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org extra_check_functions: An array of additional check functions that will be 45096fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org run on each source line. Each function takes 4 45106fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org arguments: filename, clean_lines, line, error 45116fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org """ 45126fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org raw_lines = clean_lines.raw_lines 45136fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org ParseNolintSuppressions(filename, raw_lines[line], line, error) 451410a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org nesting_state.Update(filename, clean_lines, line, error) 451510a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org if nesting_state.stack and nesting_state.stack[-1].inline_asm != _NO_ASM: 451610a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org return 45176fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org CheckForFunctionLengths(filename, clean_lines, line, function_state, error) 45186fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org CheckForMultilineCommentsAndStrings(filename, clean_lines, line, error) 451910a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org CheckStyle(filename, clean_lines, line, file_extension, nesting_state, error) 45206fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org CheckLanguage(filename, clean_lines, line, file_extension, include_state, 4521dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org nesting_state, error) 4522dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org CheckForNonConstReference(filename, clean_lines, line, nesting_state, error) 45236fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org CheckForNonStandardConstructs(filename, clean_lines, line, 452410a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org nesting_state, error) 4525dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org CheckVlogArguments(filename, clean_lines, line, error) 45266fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org CheckPosixThreading(filename, clean_lines, line, error) 45276fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org CheckInvalidIncrement(filename, clean_lines, line, error) 45286fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org CheckMakePairUsesDeduction(filename, clean_lines, line, error) 45296fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org for check_fn in extra_check_functions: 45306fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org check_fn(filename, clean_lines, line, error) 45316fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 45326fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.orgdef ProcessFileData(filename, file_extension, lines, error, 45336fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org extra_check_functions=[]): 45346fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org """Performs lint checks and reports any errors to the given error function. 45356fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 45366fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org Args: 45376fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org filename: Filename of the file that is being processed. 45386fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org file_extension: The extension (dot not included) of the file. 45396fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org lines: An array of strings, each representing a line of the file, with the 45406fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org last element being empty if the file is terminated with a newline. 45416fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org error: A callable to which errors are reported, which takes 4 arguments: 45426fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org filename, line number, error level, and message 45436fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org extra_check_functions: An array of additional check functions that will be 45446fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org run on each source line. Each function takes 4 45456fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org arguments: filename, clean_lines, line, error 45466fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org """ 45476fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org lines = (['// marker so line numbers and indices both start at 1'] + lines + 45486fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org ['// marker so line numbers end in a known way']) 45496fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 45506fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org include_state = _IncludeState() 45516fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org function_state = _FunctionState() 455210a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org nesting_state = _NestingState() 45536fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 45546fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org ResetNolintSuppressions() 45556fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 45566fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org CheckForCopyright(filename, lines, error) 45576fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 45586fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if file_extension == 'h': 45596fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org CheckForHeaderGuard(filename, lines, error) 45606fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 45616fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org RemoveMultiLineComments(filename, lines, error) 45626fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org clean_lines = CleansedLines(lines) 45636fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org for line in xrange(clean_lines.NumLines()): 45646fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org ProcessLine(filename, file_extension, clean_lines, line, 456510a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org include_state, function_state, nesting_state, error, 45666fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org extra_check_functions) 4567dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org nesting_state.CheckCompletedBlocks(filename, error) 45686fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 45696fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org CheckForIncludeWhatYouUse(filename, clean_lines, include_state, error) 45706fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 45716fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # We check here rather than inside ProcessLine so that we see raw 45726fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # lines rather than "cleaned" lines. 4573dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org CheckForBadCharacters(filename, lines, error) 45746fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 45756fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org CheckForNewlineAtEOF(filename, lines, error) 45766fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 45776fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.orgdef ProcessFile(filename, vlevel, extra_check_functions=[]): 45786fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org """Does google-lint on a single file. 45796fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 45806fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org Args: 45816fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org filename: The name of the file to parse. 45826fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 45836fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org vlevel: The level of errors to report. Every error of confidence 45846fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org >= verbose_level will be reported. 0 is a good default. 45856fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 45866fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org extra_check_functions: An array of additional check functions that will be 45876fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org run on each source line. Each function takes 4 45886fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org arguments: filename, clean_lines, line, error 45896fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org """ 45906fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 45916fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org _SetVerboseLevel(vlevel) 45926fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 45936fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org try: 45946fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # Support the UNIX convention of using "-" for stdin. Note that 45956fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # we are not opening the file with universal newline support 45966fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # (which codecs doesn't support anyway), so the resulting lines do 45976fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # contain trailing '\r' characters if we are reading a file that 45986fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # has CRLF endings. 45996fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # If after the split a trailing '\r' is present, it is removed 46006fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # below. If it is not expected to be present (i.e. os.linesep != 46016fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # '\r\n' as in Windows), a warning is issued below if this file 46026fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # is processed. 46036fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 46046fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if filename == '-': 46056fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org lines = codecs.StreamReaderWriter(sys.stdin, 46066fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org codecs.getreader('utf8'), 46076fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org codecs.getwriter('utf8'), 46086fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'replace').read().split('\n') 46096fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org else: 46106fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org lines = codecs.open(filename, 'r', 'utf8', 'replace').read().split('\n') 46116fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 46126fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org carriage_return_found = False 46136fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # Remove trailing '\r'. 46146fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org for linenum in range(len(lines)): 46156fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if lines[linenum].endswith('\r'): 46166fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org lines[linenum] = lines[linenum].rstrip('\r') 46176fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org carriage_return_found = True 46186fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 46196fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org except IOError: 46206fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org sys.stderr.write( 46216fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org "Skipping input '%s': Can't open for reading\n" % filename) 46226fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org return 46236fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 46246fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # Note, if no dot is found, this will give the entire filename as the ext. 46256fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org file_extension = filename[filename.rfind('.') + 1:] 46266fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 46276fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # When reading from stdin, the extension is unknown, so no cpplint tests 46286fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # should rely on the extension. 4629dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org if filename != '-' and file_extension not in _valid_extensions: 4630dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org sys.stderr.write('Ignoring %s; not a valid file name ' 4631dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org '(%s)\n' % (filename, ', '.join(_valid_extensions))) 46326fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org else: 46336fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org ProcessFileData(filename, file_extension, lines, Error, 46346fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org extra_check_functions) 46356fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if carriage_return_found and os.linesep != '\r\n': 46366fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # Use 0 for linenum since outputting only one error for potentially 46376fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # several lines. 46386fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org Error(filename, 0, 'whitespace/newline', 1, 46396fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'One or more unexpected \\r (^M) found;' 46406fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'better to use only a \\n') 46416fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 46426fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org sys.stderr.write('Done processing %s\n' % filename) 46436fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 46446fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 46456fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.orgdef PrintUsage(message): 46466fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org """Prints a brief usage string and exits, optionally with an error message. 46476fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 46486fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org Args: 46496fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org message: The optional error message. 46506fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org """ 46516fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org sys.stderr.write(_USAGE) 46526fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if message: 46536fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org sys.exit('\nFATAL ERROR: ' + message) 46546fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org else: 46556fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org sys.exit(1) 46566fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 46576fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 46586fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.orgdef PrintCategories(): 46596fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org """Prints a list of all the error-categories used by error messages. 46606fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 46616fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org These are the categories used to filter messages via --filter. 46626fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org """ 46636fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org sys.stderr.write(''.join(' %s\n' % cat for cat in _ERROR_CATEGORIES)) 46646fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org sys.exit(0) 46656fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 46666fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 46676fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.orgdef ParseArguments(args): 46686fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org """Parses the command line arguments. 46696fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 46706fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org This may set the output format and verbosity level as side-effects. 46716fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 46726fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org Args: 46736fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org args: The command line arguments: 46746fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 46756fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org Returns: 46766fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org The list of filenames to lint. 46776fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org """ 46786fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org try: 46796fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org (opts, filenames) = getopt.getopt(args, '', ['help', 'output=', 'verbose=', 46806fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'counting=', 468110a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org 'filter=', 4682dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'root=', 4683dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'linelength=', 4684dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org 'extensions=']) 46856fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org except getopt.GetoptError: 46866fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org PrintUsage('Invalid arguments.') 46876fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 46886fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org verbosity = _VerboseLevel() 46896fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org output_format = _OutputFormat() 46906fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org filters = '' 46916fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org counting_style = '' 46926fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 46936fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org for (opt, val) in opts: 46946fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if opt == '--help': 46956fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org PrintUsage(None) 46966fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org elif opt == '--output': 4697dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org if val not in ('emacs', 'vs7', 'eclipse'): 4698dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org PrintUsage('The only allowed output formats are emacs, vs7 and eclipse.') 46996fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org output_format = val 47006fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org elif opt == '--verbose': 47016fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org verbosity = int(val) 47026fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org elif opt == '--filter': 47036fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org filters = val 47046fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if not filters: 47056fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org PrintCategories() 47066fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org elif opt == '--counting': 47076fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if val not in ('total', 'toplevel', 'detailed'): 47086fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org PrintUsage('Valid counting options are total, toplevel, and detailed') 47096fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org counting_style = val 471010a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org elif opt == '--root': 471110a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org global _root 471210a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org _root = val 4713dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org elif opt == '--linelength': 4714dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org global _line_length 4715dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org try: 4716dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org _line_length = int(val) 4717dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org except ValueError: 4718dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org PrintUsage('Line length must be digits.') 4719dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org elif opt == '--extensions': 4720dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org global _valid_extensions 4721dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org try: 4722dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org _valid_extensions = set(val.split(',')) 4723dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org except ValueError: 4724dddee1ec7cedf276305b107429f684539b105276johannkoenig@chromium.org PrintUsage('Extensions must be comma seperated list.') 47256fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 47266fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org if not filenames: 47276fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org PrintUsage('No files were specified.') 47286fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 47296fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org _SetOutputFormat(output_format) 47306fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org _SetVerboseLevel(verbosity) 47316fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org _SetFilters(filters) 47326fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org _SetCountingStyle(counting_style) 47336fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 47346fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org return filenames 47356fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 47366fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 47376fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.orgdef main(): 47386fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org filenames = ParseArguments(sys.argv[1:]) 47396fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 47406fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # Change stderr to write with replacement characters so we don't die 47416fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org # if we try to print something containing non-ASCII characters. 47426fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org sys.stderr = codecs.StreamReaderWriter(sys.stderr, 47436fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org codecs.getreader('utf8'), 47446fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org codecs.getwriter('utf8'), 47456fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 'replace') 47466fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 47476fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org _cpplint_state.ResetErrorCounts() 47486fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org for filename in filenames: 47496fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org ProcessFile(filename, _cpplint_state.verbose_level) 47506fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org _cpplint_state.PrintErrorCounts() 47516fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 47526fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org sys.exit(_cpplint_state.error_count > 0) 47536fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 47546fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org 47556fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.orgif __name__ == '__main__': 47566fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org main() 4757