1fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov#!/usr/bin/python
2fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov#
3fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# Copyright (c) 2009 Google Inc. All rights reserved.
4fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov#
5fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# Redistribution and use in source and binary forms, with or without
6fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# modification, are permitted provided that the following conditions are
7fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# met:
8fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov#
9fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov#    * Redistributions of source code must retain the above copyright
10fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# notice, this list of conditions and the following disclaimer.
11fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov#    * Redistributions in binary form must reproduce the above
12fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# copyright notice, this list of conditions and the following disclaimer
13fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# in the documentation and/or other materials provided with the
14fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# distribution.
15fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov#    * Neither the name of Google Inc. nor the names of its
16fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# contributors may be used to endorse or promote products derived from
17fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# this software without specific prior written permission.
18fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov#
19fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
31fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# Here are some issues that I've had people identify in my code during reviews,
32fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# that I think are possible to flag automatically in a lint tool.  If these were
33fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# caught by lint, it would save time both for myself and that of my reviewers.
34fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# Most likely, some of these are beyond the scope of the current lint framework,
35fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# but I think it is valuable to retain these wish-list items even if they cannot
36fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# be immediately implemented.
37fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov#
38fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov#  Suggestions
39fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov#  -----------
40fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov#  - Check for no 'explicit' for multi-arg ctor
41fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov#  - Check for boolean assign RHS in parens
42fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov#  - Check for ctor initializer-list colon position and spacing
43fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov#  - Check that if there's a ctor, there should be a dtor
44fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov#  - Check accessors that return non-pointer member variables are
45fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov#    declared const
46fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov#  - Check accessors that return non-const pointer member vars are
47fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov#    *not* declared const
48fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov#  - Check for using public includes for testing
49fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov#  - Check for spaces between brackets in one-line inline method
50fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov#  - Check for no assert()
51fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov#  - Check for spaces surrounding operators
52fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov#  - Check for 0 in pointer context (should be NULL)
53fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov#  - Check for 0 in char context (should be '\0')
54fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov#  - Check for camel-case method name conventions for methods
55fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov#    that are not simple inline getters and setters
56fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov#  - Do not indent namespace contents
57fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov#  - Avoid inlining non-trivial constructors in header files
58fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov#  - Check for old-school (void) cast for call-sites of functions
59fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov#    ignored return value
60fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov#  - Check gUnit usage of anonymous namespace
61fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov#  - Check for class declaration order (typedefs, consts, enums,
62fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov#    ctor(s?), dtor, friend declarations, methods, member vars)
63fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov#
64fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
65fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov"""Does google-lint on c++ files.
66fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
67fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey SamsonovThe goal of this script is to identify places in the code that *may*
68fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovbe in non-compliance with google style.  It does not attempt to fix
69fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovup these problems -- the point is to educate.  It does also not
70fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovattempt to find all problems, or to ensure that everything it does
71fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovfind is legitimately a problem.
72fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
73fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey SamsonovIn particular, we can get very confused by /* and // inside strings!
74fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey SamsonovWe do a small hack, which is to ignore //'s with "'s after them on the
75fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovsame line, but it is far from perfect (in either direction).
76fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov"""
77fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
78fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovimport codecs
79fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovimport copy
80fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovimport getopt
81fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovimport math  # for log
82fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovimport os
83fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovimport re
84fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovimport sre_compile
85fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovimport string
86fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovimport sys
87fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovimport unicodedata
88fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
89fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
90fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov_USAGE = """
91fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey SamsonovSyntax: cpplint.py [--verbose=#] [--output=vs7] [--filter=-x,+y,...]
92fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov                   [--counting=total|toplevel|detailed]
93fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        <file> [file] ...
94fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
95fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  The style guidelines this tries to follow are those in
96fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml
97fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
98fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  Every problem is given a confidence score from 1-5, with 5 meaning we are
99fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  certain of the problem, and 1 meaning it could be a legitimate construct.
100fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  This will miss some errors, and is not a substitute for a code review.
101fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
102fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  To suppress false-positive errors of a certain category, add a
103fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  'NOLINT(category)' comment to the line.  NOLINT or NOLINT(*)
104fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  suppresses errors of all categories on that line.
105fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
106fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  The files passed in will be linted; at least one file must be provided.
107fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  Linted extensions are .cc, .cpp, and .h.  Other file types will be ignored.
108fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
109fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  Flags:
110fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
111fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    output=vs7
112fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      By default, the output is formatted to ease emacs parsing.  Visual Studio
113fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      compatible output (vs7) may also be used.  Other formats are unsupported.
114fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
115fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    verbose=#
116fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      Specify a number 0-5 to restrict errors to certain verbosity levels.
117fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
118fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    filter=-x,+y,...
119fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      Specify a comma-separated list of category-filters to apply: only
120fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      error messages whose category names pass the filters will be printed.
121fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      (Category names are printed with the message and look like
122fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      "[whitespace/indent]".)  Filters are evaluated left to right.
123fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      "-FOO" and "FOO" means "do not print categories that start with FOO".
124fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      "+FOO" means "do print categories that start with FOO".
125fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
126fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      Examples: --filter=-whitespace,+whitespace/braces
127fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov                --filter=whitespace,runtime/printf,+runtime/printf_format
128fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov                --filter=-,+build/include_what_you_use
129fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
130fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      To see a list of all the categories used in cpplint, pass no arg:
131fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov         --filter=
132fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
133fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    counting=total|toplevel|detailed
134fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      The total number of errors found is always printed. If
135fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      'toplevel' is provided, then the count of errors in each of
136fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      the top-level categories like 'build' and 'whitespace' will
137fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      also be printed. If 'detailed' is provided, then a count
138fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      is provided for each category like 'build/class'.
139fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
140fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    root=subdir
141fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      The root directory used for deriving header guard CPP variable.
142fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      By default, the header guard CPP variable is calculated as the relative
143fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      path to the directory that contains .git, .hg, or .svn.  When this flag
144fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      is specified, the relative path is calculated from the specified
145fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      directory. If the specified directory does not exist, this flag is
146fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      ignored.
147fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
148fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      Examples:
149fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        Assuing that src/.git exists, the header guard CPP variables for
150fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        src/chrome/browser/ui/browser.h are:
151fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
152fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        No flag => CHROME_BROWSER_UI_BROWSER_H_
153fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        --root=chrome => BROWSER_UI_BROWSER_H_
154fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        --root=chrome/browser => UI_BROWSER_H_
155fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov"""
156fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
157fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# We categorize each error message we print.  Here are the categories.
158fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# We want an explicit list so we can list them all in cpplint --filter=.
159fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# If you add a new error message with a new category, add it to the list
160fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# here!  cpplint_unittest.py should tell you if you forget to do this.
161fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# \ used for clearer layout -- pylint: disable-msg=C6013
162fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov_ERROR_CATEGORIES = [
163fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  'build/class',
164fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  'build/deprecated',
165fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  'build/endif_comment',
166fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  'build/explicit_make_pair',
167fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  'build/forward_decl',
168fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  'build/header_guard',
169fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  'build/include',
170fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  'build/include_alpha',
171fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  'build/include_order',
172fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  'build/include_what_you_use',
173fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  'build/namespaces',
174fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  'build/printf_format',
175fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  'build/storage_class',
176fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  'legal/copyright',
177fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  'readability/alt_tokens',
178fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  'readability/braces',
179fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  'readability/casting',
180fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  'readability/check',
181fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  'readability/constructors',
182fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  'readability/fn_size',
183fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  'readability/function',
184fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  'readability/multiline_comment',
185fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  'readability/multiline_string',
186fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  'readability/namespace',
187fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  'readability/nolint',
188fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  'readability/streams',
189fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  'readability/todo',
190fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  'readability/utf8',
191fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  'runtime/arrays',
192fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  'runtime/casting',
193fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  'runtime/explicit',
194fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  'runtime/int',
195fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  'runtime/init',
196fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  'runtime/invalid_increment',
197fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  'runtime/member_string_references',
198fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  'runtime/memset',
199fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  'runtime/operator',
200fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  'runtime/printf',
201fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  'runtime/printf_format',
202fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  'runtime/references',
203fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  'runtime/rtti',
204fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  'runtime/sizeof',
205fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  'runtime/string',
206fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  'runtime/threadsafe_fn',
207fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  'whitespace/blank_line',
208fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  'whitespace/braces',
209fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  'whitespace/comma',
210fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  'whitespace/comments',
211fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  'whitespace/empty_loop_body',
212fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  'whitespace/end_of_line',
213fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  'whitespace/ending_newline',
214fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  'whitespace/forcolon',
215fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  'whitespace/indent',
216fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  'whitespace/labels',
217fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  'whitespace/line_length',
218fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  'whitespace/newline',
219fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  'whitespace/operators',
220fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  'whitespace/parens',
221fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  'whitespace/semicolon',
222fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  'whitespace/tab',
223fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  'whitespace/todo'
224fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  ]
225fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
226fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# The default state of the category filter. This is overrided by the --filter=
227fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# flag. By default all errors are on, so only add here categories that should be
228fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# off by default (i.e., categories that must be enabled by the --filter= flags).
229fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# All entries here should start with a '-' or '+', as in the --filter= flag.
230fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov_DEFAULT_FILTERS = ['-build/include_alpha']
231fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
232fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# We used to check for high-bit characters, but after much discussion we
233fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# decided those were OK, as long as they were in UTF-8 and didn't represent
234fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# hard-coded international strings, which belong in a separate i18n file.
235fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
236fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# Headers that we consider STL headers.
237fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov_STL_HEADERS = frozenset([
238fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    'algobase.h', 'algorithm', 'alloc.h', 'bitset', 'deque', 'exception',
239fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    'function.h', 'functional', 'hash_map', 'hash_map.h', 'hash_set',
240fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    'hash_set.h', 'iterator', 'list', 'list.h', 'map', 'memory', 'new',
241fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    'pair.h', 'pthread_alloc', 'queue', 'set', 'set.h', 'sstream', 'stack',
242fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    'stl_alloc.h', 'stl_relops.h', 'type_traits.h',
243fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    'utility', 'vector', 'vector.h',
244fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    ])
245fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
246fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
247fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# Non-STL C++ system headers.
248fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov_CPP_HEADERS = frozenset([
249fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    'algo.h', 'builtinbuf.h', 'bvector.h', 'cassert', 'cctype',
250fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    'cerrno', 'cfloat', 'ciso646', 'climits', 'clocale', 'cmath',
251fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    'complex', 'complex.h', 'csetjmp', 'csignal', 'cstdarg', 'cstddef',
252fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    'cstdio', 'cstdlib', 'cstring', 'ctime', 'cwchar', 'cwctype',
253fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    'defalloc.h', 'deque.h', 'editbuf.h', 'exception', 'fstream',
254fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    'fstream.h', 'hashtable.h', 'heap.h', 'indstream.h', 'iomanip',
255fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    'iomanip.h', 'ios', 'iosfwd', 'iostream', 'iostream.h', 'istream',
256fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    'istream.h', 'iterator.h', 'limits', 'map.h', 'multimap.h', 'multiset.h',
257fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    'numeric', 'ostream', 'ostream.h', 'parsestream.h', 'pfstream.h',
258fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    'PlotFile.h', 'procbuf.h', 'pthread_alloc.h', 'rope', 'rope.h',
259fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    'ropeimpl.h', 'SFile.h', 'slist', 'slist.h', 'stack.h', 'stdexcept',
260fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    'stdiostream.h', 'streambuf', 'streambuf.h', 'stream.h', 'strfile.h',
261fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    'string', 'strstream', 'strstream.h', 'tempbuf.h', 'tree.h', 'typeinfo',
262fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    'valarray',
263fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    ])
264fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
265fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
266fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# Assertion macros.  These are defined in base/logging.h and
267fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# testing/base/gunit.h.  Note that the _M versions need to come first
268fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# for substring matching to work.
269fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov_CHECK_MACROS = [
270fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    'DCHECK', 'CHECK',
271fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    'EXPECT_TRUE_M', 'EXPECT_TRUE',
272fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    'ASSERT_TRUE_M', 'ASSERT_TRUE',
273fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    'EXPECT_FALSE_M', 'EXPECT_FALSE',
274fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    'ASSERT_FALSE_M', 'ASSERT_FALSE',
275fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    ]
276fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
277fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# Replacement macros for CHECK/DCHECK/EXPECT_TRUE/EXPECT_FALSE
278fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov_CHECK_REPLACEMENT = dict([(m, {}) for m in _CHECK_MACROS])
279fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
280fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovfor op, replacement in [('==', 'EQ'), ('!=', 'NE'),
281fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov                        ('>=', 'GE'), ('>', 'GT'),
282fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov                        ('<=', 'LE'), ('<', 'LT')]:
283fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  _CHECK_REPLACEMENT['DCHECK'][op] = 'DCHECK_%s' % replacement
284fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  _CHECK_REPLACEMENT['CHECK'][op] = 'CHECK_%s' % replacement
285fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  _CHECK_REPLACEMENT['EXPECT_TRUE'][op] = 'EXPECT_%s' % replacement
286fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  _CHECK_REPLACEMENT['ASSERT_TRUE'][op] = 'ASSERT_%s' % replacement
287fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  _CHECK_REPLACEMENT['EXPECT_TRUE_M'][op] = 'EXPECT_%s_M' % replacement
288fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  _CHECK_REPLACEMENT['ASSERT_TRUE_M'][op] = 'ASSERT_%s_M' % replacement
289fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
290fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovfor op, inv_replacement in [('==', 'NE'), ('!=', 'EQ'),
291fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov                            ('>=', 'LT'), ('>', 'LE'),
292fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov                            ('<=', 'GT'), ('<', 'GE')]:
293fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  _CHECK_REPLACEMENT['EXPECT_FALSE'][op] = 'EXPECT_%s' % inv_replacement
294fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  _CHECK_REPLACEMENT['ASSERT_FALSE'][op] = 'ASSERT_%s' % inv_replacement
295fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  _CHECK_REPLACEMENT['EXPECT_FALSE_M'][op] = 'EXPECT_%s_M' % inv_replacement
296fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  _CHECK_REPLACEMENT['ASSERT_FALSE_M'][op] = 'ASSERT_%s_M' % inv_replacement
297fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
298fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# Alternative tokens and their replacements.  For full list, see section 2.5
299fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# Alternative tokens [lex.digraph] in the C++ standard.
300fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov#
301fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# Digraphs (such as '%:') are not included here since it's a mess to
302fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# match those on a word boundary.
303fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov_ALT_TOKEN_REPLACEMENT = {
304fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    'and': '&&',
305fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    'bitor': '|',
306fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    'or': '||',
307fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    'xor': '^',
308fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    'compl': '~',
309fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    'bitand': '&',
310fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    'and_eq': '&=',
311fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    'or_eq': '|=',
312fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    'xor_eq': '^=',
313fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    'not': '!',
314fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    'not_eq': '!='
315fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    }
316fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
317fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# Compile regular expression that matches all the above keywords.  The "[ =()]"
318fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# bit is meant to avoid matching these keywords outside of boolean expressions.
319fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov#
320fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# False positives include C-style multi-line comments (http://go/nsiut )
321fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# and multi-line strings (http://go/beujw ), but those have always been
322fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# troublesome for cpplint.
323fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov_ALT_TOKEN_REPLACEMENT_PATTERN = re.compile(
324fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    r'[ =()](' + ('|'.join(_ALT_TOKEN_REPLACEMENT.keys())) + r')(?=[ (]|$)')
325fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
326fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
327fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# These constants define types of headers for use with
328fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# _IncludeState.CheckNextIncludeOrder().
329fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov_C_SYS_HEADER = 1
330fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov_CPP_SYS_HEADER = 2
331fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov_LIKELY_MY_HEADER = 3
332fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov_POSSIBLE_MY_HEADER = 4
333fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov_OTHER_HEADER = 5
334fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
335fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# These constants define the current inline assembly state
336fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov_NO_ASM = 0       # Outside of inline assembly block
337fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov_INSIDE_ASM = 1   # Inside inline assembly block
338fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov_END_ASM = 2      # Last line of inline assembly block
339fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov_BLOCK_ASM = 3    # The whole block is an inline assembly block
340fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
341fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# Match start of assembly blocks
342fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov_MATCH_ASM = re.compile(r'^\s*(?:asm|_asm|__asm|__asm__)'
343fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov                        r'(?:\s+(volatile|__volatile__))?'
344fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov                        r'\s*[{(]')
345fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
346fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
347fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov_regexp_compile_cache = {}
348fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
349fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# Finds occurrences of NOLINT or NOLINT(...).
350fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov_RE_SUPPRESSION = re.compile(r'\bNOLINT\b(\([^)]*\))?')
351fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
352fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# {str, set(int)}: a map from error categories to sets of linenumbers
353fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# on which those errors are expected and should be suppressed.
354fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov_error_suppressions = {}
355fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
356fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# The root directory used for deriving header guard CPP variable.
357fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# This is set by --root flag.
358fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov_root = None
359fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
360fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovdef ParseNolintSuppressions(filename, raw_line, linenum, error):
361fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  """Updates the global list of error-suppressions.
362fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
363fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  Parses any NOLINT comments on the current line, updating the global
364fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  error_suppressions store.  Reports an error if the NOLINT comment
365fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  was malformed.
366fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
367fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  Args:
368fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    filename: str, the name of the input file.
369fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    raw_line: str, the line of input text, with comments.
370fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    linenum: int, the number of the current line.
371fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    error: function, an error handler.
372fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  """
373fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # FIXME(adonovan): "NOLINT(" is misparsed as NOLINT(*).
374fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  matched = _RE_SUPPRESSION.search(raw_line)
375fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  if matched:
376fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    category = matched.group(1)
377fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    if category in (None, '(*)'):  # => "suppress all"
378fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      _error_suppressions.setdefault(None, set()).add(linenum)
379fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    else:
380fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      if category.startswith('(') and category.endswith(')'):
381fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        category = category[1:-1]
382fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        if category in _ERROR_CATEGORIES:
383fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          _error_suppressions.setdefault(category, set()).add(linenum)
384fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        else:
385fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          error(filename, linenum, 'readability/nolint', 5,
386fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov                'Unknown NOLINT error category: %s' % category)
387fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
388fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
389fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovdef ResetNolintSuppressions():
390fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  "Resets the set of NOLINT suppressions to empty."
391fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  _error_suppressions.clear()
392fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
393fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
394fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovdef IsErrorSuppressedByNolint(category, linenum):
395fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  """Returns true if the specified error category is suppressed on this line.
396fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
397fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  Consults the global error_suppressions map populated by
398fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  ParseNolintSuppressions/ResetNolintSuppressions.
399fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
400fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  Args:
401fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    category: str, the category of the error.
402fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    linenum: int, the current line number.
403fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  Returns:
404fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    bool, True iff the error should be suppressed due to a NOLINT comment.
405fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  """
406fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  return (linenum in _error_suppressions.get(category, set()) or
407fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          linenum in _error_suppressions.get(None, set()))
408fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
409fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovdef Match(pattern, s):
410fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  """Matches the string with the pattern, caching the compiled regexp."""
411fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # The regexp compilation caching is inlined in both Match and Search for
412fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # performance reasons; factoring it out into a separate function turns out
413fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # to be noticeably expensive.
414fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  if not pattern in _regexp_compile_cache:
415fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    _regexp_compile_cache[pattern] = sre_compile.compile(pattern)
416fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  return _regexp_compile_cache[pattern].match(s)
417fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
418fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
419fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovdef Search(pattern, s):
420fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  """Searches the string for the pattern, caching the compiled regexp."""
421fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  if not pattern in _regexp_compile_cache:
422fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    _regexp_compile_cache[pattern] = sre_compile.compile(pattern)
423fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  return _regexp_compile_cache[pattern].search(s)
424fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
425fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
426fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovclass _IncludeState(dict):
427fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  """Tracks line numbers for includes, and the order in which includes appear.
428fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
429fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  As a dict, an _IncludeState object serves as a mapping between include
430fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  filename and line number on which that file was included.
431fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
432fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  Call CheckNextIncludeOrder() once for each header in the file, passing
433fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  in the type constants defined above. Calls in an illegal order will
434fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  raise an _IncludeError with an appropriate error message.
435fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
436fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  """
437fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # self._section will move monotonically through this set. If it ever
438fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # needs to move backwards, CheckNextIncludeOrder will raise an error.
439fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  _INITIAL_SECTION = 0
440fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  _MY_H_SECTION = 1
441fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  _C_SECTION = 2
442fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  _CPP_SECTION = 3
443fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  _OTHER_H_SECTION = 4
444fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
445fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  _TYPE_NAMES = {
446fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      _C_SYS_HEADER: 'C system header',
447fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      _CPP_SYS_HEADER: 'C++ system header',
448fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      _LIKELY_MY_HEADER: 'header this file implements',
449fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      _POSSIBLE_MY_HEADER: 'header this file may implement',
450fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      _OTHER_HEADER: 'other header',
451fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      }
452fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  _SECTION_NAMES = {
453fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      _INITIAL_SECTION: "... nothing. (This can't be an error.)",
454fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      _MY_H_SECTION: 'a header this file implements',
455fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      _C_SECTION: 'C system header',
456fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      _CPP_SECTION: 'C++ system header',
457fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      _OTHER_H_SECTION: 'other header',
458fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      }
459fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
460fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  def __init__(self):
461fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    dict.__init__(self)
462fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    # The name of the current section.
463fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    self._section = self._INITIAL_SECTION
464fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    # The path of last found header.
465fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    self._last_header = ''
466fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
467fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  def CanonicalizeAlphabeticalOrder(self, header_path):
468fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    """Returns a path canonicalized for alphabetical comparison.
469fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
470fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    - replaces "-" with "_" so they both cmp the same.
471fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    - removes '-inl' since we don't require them to be after the main header.
472fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    - lowercase everything, just in case.
473fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
474fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    Args:
475fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      header_path: Path to be canonicalized.
476fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
477fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    Returns:
478fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      Canonicalized path.
479fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    """
480fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    return header_path.replace('-inl.h', '.h').replace('-', '_').lower()
481fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
482fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  def IsInAlphabeticalOrder(self, header_path):
483fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    """Check if a header is in alphabetical order with the previous header.
484fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
485fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    Args:
486fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      header_path: Header to be checked.
487fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
488fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    Returns:
489fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      Returns true if the header is in alphabetical order.
490fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    """
491fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    canonical_header = self.CanonicalizeAlphabeticalOrder(header_path)
492fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    if self._last_header > canonical_header:
493fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      return False
494fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    self._last_header = canonical_header
495fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    return True
496fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
497fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  def CheckNextIncludeOrder(self, header_type):
498fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    """Returns a non-empty error message if the next header is out of order.
499fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
500fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    This function also updates the internal state to be ready to check
501fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    the next include.
502fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
503fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    Args:
504fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      header_type: One of the _XXX_HEADER constants defined above.
505fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
506fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    Returns:
507fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      The empty string if the header is in the right order, or an
508fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      error message describing what's wrong.
509fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
510fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    """
511fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    error_message = ('Found %s after %s' %
512fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov                     (self._TYPE_NAMES[header_type],
513fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov                      self._SECTION_NAMES[self._section]))
514fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
515fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    last_section = self._section
516fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
517fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    if header_type == _C_SYS_HEADER:
518fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      if self._section <= self._C_SECTION:
519fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        self._section = self._C_SECTION
520fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      else:
521fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        self._last_header = ''
522fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        return error_message
523fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    elif header_type == _CPP_SYS_HEADER:
524fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      if self._section <= self._CPP_SECTION:
525fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        self._section = self._CPP_SECTION
526fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      else:
527fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        self._last_header = ''
528fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        return error_message
529fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    elif header_type == _LIKELY_MY_HEADER:
530fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      if self._section <= self._MY_H_SECTION:
531fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        self._section = self._MY_H_SECTION
532fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      else:
533fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        self._section = self._OTHER_H_SECTION
534fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    elif header_type == _POSSIBLE_MY_HEADER:
535fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      if self._section <= self._MY_H_SECTION:
536fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        self._section = self._MY_H_SECTION
537fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      else:
538fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        # This will always be the fallback because we're not sure
539fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        # enough that the header is associated with this file.
540fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        self._section = self._OTHER_H_SECTION
541fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    else:
542fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      assert header_type == _OTHER_HEADER
543fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      self._section = self._OTHER_H_SECTION
544fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
545fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    if last_section != self._section:
546fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      self._last_header = ''
547fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
548fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    return ''
549fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
550fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
551fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovclass _CppLintState(object):
552fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  """Maintains module-wide state.."""
553fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
554fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  def __init__(self):
555fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    self.verbose_level = 1  # global setting.
556fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    self.error_count = 0    # global count of reported errors
557fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    # filters to apply when emitting error messages
558fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    self.filters = _DEFAULT_FILTERS[:]
559fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    self.counting = 'total'  # In what way are we counting errors?
560fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    self.errors_by_category = {}  # string to int dict storing error counts
561fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
562fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    # output format:
563fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    # "emacs" - format that emacs can parse (default)
564fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    # "vs7" - format that Microsoft Visual Studio 7 can parse
565fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    self.output_format = 'emacs'
566fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
567fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  def SetOutputFormat(self, output_format):
568fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    """Sets the output format for errors."""
569fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    self.output_format = output_format
570fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
571fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  def SetVerboseLevel(self, level):
572fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    """Sets the module's verbosity, and returns the previous setting."""
573fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    last_verbose_level = self.verbose_level
574fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    self.verbose_level = level
575fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    return last_verbose_level
576fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
577fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  def SetCountingStyle(self, counting_style):
578fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    """Sets the module's counting options."""
579fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    self.counting = counting_style
580fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
581fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  def SetFilters(self, filters):
582fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    """Sets the error-message filters.
583fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
584fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    These filters are applied when deciding whether to emit a given
585fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    error message.
586fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
587fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    Args:
588fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      filters: A string of comma-separated filters (eg "+whitespace/indent").
589fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov               Each filter should start with + or -; else we die.
590fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
591fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    Raises:
592fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      ValueError: The comma-separated filters did not all start with '+' or '-'.
593fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov                  E.g. "-,+whitespace,-whitespace/indent,whitespace/badfilter"
594fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    """
595fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    # Default filters always have less priority than the flag ones.
596fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    self.filters = _DEFAULT_FILTERS[:]
597fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    for filt in filters.split(','):
598fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      clean_filt = filt.strip()
599fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      if clean_filt:
600fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        self.filters.append(clean_filt)
601fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    for filt in self.filters:
602fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      if not (filt.startswith('+') or filt.startswith('-')):
603fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        raise ValueError('Every filter in --filters must start with + or -'
604fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov                         ' (%s does not)' % filt)
605fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
606fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  def ResetErrorCounts(self):
607fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    """Sets the module's error statistic back to zero."""
608fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    self.error_count = 0
609fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    self.errors_by_category = {}
610fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
611fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  def IncrementErrorCount(self, category):
612fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    """Bumps the module's error statistic."""
613fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    self.error_count += 1
614fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    if self.counting in ('toplevel', 'detailed'):
615fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      if self.counting != 'detailed':
616fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        category = category.split('/')[0]
617fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      if category not in self.errors_by_category:
618fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        self.errors_by_category[category] = 0
619fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      self.errors_by_category[category] += 1
620fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
621fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  def PrintErrorCounts(self):
622fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    """Print a summary of errors by category, and the total."""
623fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    for category, count in self.errors_by_category.iteritems():
624fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      sys.stderr.write('Category \'%s\' errors found: %d\n' %
625fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov                       (category, count))
626fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    sys.stderr.write('Total errors found: %d\n' % self.error_count)
627fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
628fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov_cpplint_state = _CppLintState()
629fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
630fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
631fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovdef _OutputFormat():
632fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  """Gets the module's output format."""
633fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  return _cpplint_state.output_format
634fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
635fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
636fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovdef _SetOutputFormat(output_format):
637fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  """Sets the module's output format."""
638fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  _cpplint_state.SetOutputFormat(output_format)
639fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
640fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
641fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovdef _VerboseLevel():
642fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  """Returns the module's verbosity setting."""
643fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  return _cpplint_state.verbose_level
644fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
645fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
646fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovdef _SetVerboseLevel(level):
647fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  """Sets the module's verbosity, and returns the previous setting."""
648fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  return _cpplint_state.SetVerboseLevel(level)
649fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
650fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
651fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovdef _SetCountingStyle(level):
652fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  """Sets the module's counting options."""
653fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  _cpplint_state.SetCountingStyle(level)
654fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
655fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
656fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovdef _Filters():
657fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  """Returns the module's list of output filters, as a list."""
658fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  return _cpplint_state.filters
659fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
660fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
661fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovdef _SetFilters(filters):
662fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  """Sets the module's error-message filters.
663fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
664fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  These filters are applied when deciding whether to emit a given
665fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  error message.
666fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
667fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  Args:
668fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    filters: A string of comma-separated filters (eg "whitespace/indent").
669fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov             Each filter should start with + or -; else we die.
670fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  """
671fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  _cpplint_state.SetFilters(filters)
672fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
673fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
674fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovclass _FunctionState(object):
675fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  """Tracks current function name and the number of lines in its body."""
676fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
677fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  _NORMAL_TRIGGER = 250  # for --v=0, 500 for --v=1, etc.
678fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  _TEST_TRIGGER = 400    # about 50% more than _NORMAL_TRIGGER.
679fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
680fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  def __init__(self):
681fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    self.in_a_function = False
682fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    self.lines_in_function = 0
683fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    self.current_function = ''
684fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
685fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  def Begin(self, function_name):
686fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    """Start analyzing function body.
687fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
688fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    Args:
689fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      function_name: The name of the function being tracked.
690fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    """
691fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    self.in_a_function = True
692fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    self.lines_in_function = 0
693fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    self.current_function = function_name
694fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
695fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  def Count(self):
696fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    """Count line in current function body."""
697fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    if self.in_a_function:
698fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      self.lines_in_function += 1
699fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
700fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  def Check(self, error, filename, linenum):
701fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    """Report if too many lines in function body.
702fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
703fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    Args:
704fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      error: The function to call with any errors found.
705fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      filename: The name of the current file.
706fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      linenum: The number of the line to check.
707fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    """
708fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    if Match(r'T(EST|est)', self.current_function):
709fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      base_trigger = self._TEST_TRIGGER
710fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    else:
711fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      base_trigger = self._NORMAL_TRIGGER
712fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    trigger = base_trigger * 2**_VerboseLevel()
713fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
714fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    if self.lines_in_function > trigger:
715fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      error_level = int(math.log(self.lines_in_function / base_trigger, 2))
716fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      # 50 => 0, 100 => 1, 200 => 2, 400 => 3, 800 => 4, 1600 => 5, ...
717fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      if error_level > 5:
718fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        error_level = 5
719fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      error(filename, linenum, 'readability/fn_size', error_level,
720fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov            'Small and focused functions are preferred:'
721fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov            ' %s has %d non-comment lines'
722fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov            ' (error triggered by exceeding %d lines).'  % (
723fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov                self.current_function, self.lines_in_function, trigger))
724fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
725fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  def End(self):
726fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    """Stop analyzing function body."""
727fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    self.in_a_function = False
728fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
729fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
730fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovclass _IncludeError(Exception):
731fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  """Indicates a problem with the include order in a file."""
732fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  pass
733fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
734fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
735fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovclass FileInfo:
736fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  """Provides utility functions for filenames.
737fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
738fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  FileInfo provides easy access to the components of a file's path
739fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  relative to the project root.
740fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  """
741fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
742fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  def __init__(self, filename):
743fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    self._filename = filename
744fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
745fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  def FullName(self):
746fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    """Make Windows paths like Unix."""
747fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    return os.path.abspath(self._filename).replace('\\', '/')
748fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
749fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  def RepositoryName(self):
750fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    """FullName after removing the local path to the repository.
751fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
752fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    If we have a real absolute path name here we can try to do something smart:
753fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    detecting the root of the checkout and truncating /path/to/checkout from
754fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    the name so that we get header guards that don't include things like
755fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    "C:\Documents and Settings\..." or "/home/username/..." in them and thus
756fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    people on different computers who have checked the source out to different
757fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    locations won't see bogus errors.
758fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    """
759fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    fullname = self.FullName()
760fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
761fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    if os.path.exists(fullname):
762fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      project_dir = os.path.dirname(fullname)
763fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
764fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      if os.path.exists(os.path.join(project_dir, ".svn")):
765fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        # If there's a .svn file in the current directory, we recursively look
766fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        # up the directory tree for the top of the SVN checkout
767fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        root_dir = project_dir
768fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        one_up_dir = os.path.dirname(root_dir)
769fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        while os.path.exists(os.path.join(one_up_dir, ".svn")):
770fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          root_dir = os.path.dirname(root_dir)
771fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          one_up_dir = os.path.dirname(one_up_dir)
772fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
773fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        prefix = os.path.commonprefix([root_dir, project_dir])
774fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        return fullname[len(prefix) + 1:]
775fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
776fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      # Not SVN <= 1.6? Try to find a git, hg, or svn top level directory by
777fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      # searching up from the current path.
778fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      root_dir = os.path.dirname(fullname)
779fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      while (root_dir != os.path.dirname(root_dir) and
780fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov             not os.path.exists(os.path.join(root_dir, ".git")) and
781fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov             not os.path.exists(os.path.join(root_dir, ".hg")) and
782fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov             not os.path.exists(os.path.join(root_dir, ".svn"))):
783fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        root_dir = os.path.dirname(root_dir)
784fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
785fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      if (os.path.exists(os.path.join(root_dir, ".git")) or
786fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          os.path.exists(os.path.join(root_dir, ".hg")) or
787fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          os.path.exists(os.path.join(root_dir, ".svn"))):
788fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        prefix = os.path.commonprefix([root_dir, project_dir])
789fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        return fullname[len(prefix) + 1:]
790fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
791fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    # Don't know what to do; header guard warnings may be wrong...
792fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    return fullname
793fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
794fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  def Split(self):
795fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    """Splits the file into the directory, basename, and extension.
796fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
797fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    For 'chrome/browser/browser.cc', Split() would
798fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    return ('chrome/browser', 'browser', '.cc')
799fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
800fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    Returns:
801fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      A tuple of (directory, basename, extension).
802fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    """
803fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
804fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    googlename = self.RepositoryName()
805fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    project, rest = os.path.split(googlename)
806fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    return (project,) + os.path.splitext(rest)
807fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
808fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  def BaseName(self):
809fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    """File base name - text after the final slash, before the final period."""
810fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    return self.Split()[1]
811fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
812fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  def Extension(self):
813fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    """File extension - text following the final period."""
814fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    return self.Split()[2]
815fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
816fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  def NoExtension(self):
817fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    """File has no source file extension."""
818fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    return '/'.join(self.Split()[0:2])
819fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
820fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  def IsSource(self):
821fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    """File has a source file extension."""
822fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    return self.Extension()[1:] in ('c', 'cc', 'cpp', 'cxx')
823fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
824fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
825fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovdef _ShouldPrintError(category, confidence, linenum):
826fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  """If confidence >= verbose, category passes filter and is not suppressed."""
827fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
828fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # There are three ways we might decide not to print an error message:
829fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # a "NOLINT(category)" comment appears in the source,
830fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # the verbosity level isn't high enough, or the filters filter it out.
831fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  if IsErrorSuppressedByNolint(category, linenum):
832fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    return False
833fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  if confidence < _cpplint_state.verbose_level:
834fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    return False
835fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
836fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  is_filtered = False
837fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  for one_filter in _Filters():
838fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    if one_filter.startswith('-'):
839fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      if category.startswith(one_filter[1:]):
840fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        is_filtered = True
841fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    elif one_filter.startswith('+'):
842fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      if category.startswith(one_filter[1:]):
843fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        is_filtered = False
844fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    else:
845fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      assert False  # should have been checked for in SetFilter.
846fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  if is_filtered:
847fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    return False
848fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
849fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  return True
850fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
851fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
852fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovdef Error(filename, linenum, category, confidence, message):
853fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  """Logs the fact we've found a lint error.
854fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
855fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  We log where the error was found, and also our confidence in the error,
856fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  that is, how certain we are this is a legitimate style regression, and
857fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  not a misidentification or a use that's sometimes justified.
858fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
859fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  False positives can be suppressed by the use of
860fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  "cpplint(category)"  comments on the offending line.  These are
861fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  parsed into _error_suppressions.
862fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
863fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  Args:
864fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    filename: The name of the file containing the error.
865fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    linenum: The number of the line containing the error.
866fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    category: A string used to describe the "category" this bug
867fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      falls under: "whitespace", say, or "runtime".  Categories
868fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      may have a hierarchy separated by slashes: "whitespace/indent".
869fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    confidence: A number from 1-5 representing a confidence score for
870fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      the error, with 5 meaning that we are certain of the problem,
871fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      and 1 meaning that it could be a legitimate construct.
872fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    message: The error message.
873fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  """
874fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  if _ShouldPrintError(category, confidence, linenum):
875fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    _cpplint_state.IncrementErrorCount(category)
876fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    if _cpplint_state.output_format == 'vs7':
877fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      sys.stderr.write('%s(%s):  %s  [%s] [%d]\n' % (
878fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          filename, linenum, message, category, confidence))
879fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    elif _cpplint_state.output_format == 'eclipse':
880fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      sys.stderr.write('%s:%s: warning: %s  [%s] [%d]\n' % (
881fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          filename, linenum, message, category, confidence))
882fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    else:
883fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      sys.stderr.write('%s:%s:  %s  [%s] [%d]\n' % (
884fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          filename, linenum, message, category, confidence))
885fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
886fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
887fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# Matches standard C++ escape esequences per 2.13.2.3 of the C++ standard.
888fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov_RE_PATTERN_CLEANSE_LINE_ESCAPES = re.compile(
889fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    r'\\([abfnrtv?"\\\']|\d+|x[0-9a-fA-F]+)')
890fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# Matches strings.  Escape codes should already be removed by ESCAPES.
891fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov_RE_PATTERN_CLEANSE_LINE_DOUBLE_QUOTES = re.compile(r'"[^"]*"')
892fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# Matches characters.  Escape codes should already be removed by ESCAPES.
893fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov_RE_PATTERN_CLEANSE_LINE_SINGLE_QUOTES = re.compile(r"'.'")
894fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# Matches multi-line C++ comments.
895fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# This RE is a little bit more complicated than one might expect, because we
896fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# have to take care of space removals tools so we can handle comments inside
897fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# statements better.
898fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# The current rule is: We only clear spaces from both sides when we're at the
899fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# end of the line. Otherwise, we try to remove spaces from the right side,
900fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# if this doesn't work we try on left side but only if there's a non-character
901fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# on the right.
902fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov_RE_PATTERN_CLEANSE_LINE_C_COMMENTS = re.compile(
903fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    r"""(\s*/\*.*\*/\s*$|
904fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov            /\*.*\*/\s+|
905fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov         \s+/\*.*\*/(?=\W)|
906fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov            /\*.*\*/)""", re.VERBOSE)
907fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
908fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
909fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovdef IsCppString(line):
910fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  """Does line terminate so, that the next symbol is in string constant.
911fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
912fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  This function does not consider single-line nor multi-line comments.
913fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
914fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  Args:
915fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    line: is a partial line of code starting from the 0..n.
916fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
917fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  Returns:
918fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    True, if next character appended to 'line' is inside a
919fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    string constant.
920fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  """
921fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
922fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  line = line.replace(r'\\', 'XX')  # after this, \\" does not match to \"
923fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  return ((line.count('"') - line.count(r'\"') - line.count("'\"'")) & 1) == 1
924fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
925fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
926fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovdef FindNextMultiLineCommentStart(lines, lineix):
927fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  """Find the beginning marker for a multiline comment."""
928fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  while lineix < len(lines):
929fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    if lines[lineix].strip().startswith('/*'):
930fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      # Only return this marker if the comment goes beyond this line
931fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      if lines[lineix].strip().find('*/', 2) < 0:
932fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        return lineix
933fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    lineix += 1
934fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  return len(lines)
935fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
936fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
937fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovdef FindNextMultiLineCommentEnd(lines, lineix):
938fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  """We are inside a comment, find the end marker."""
939fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  while lineix < len(lines):
940fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    if lines[lineix].strip().endswith('*/'):
941fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      return lineix
942fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    lineix += 1
943fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  return len(lines)
944fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
945fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
946fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovdef RemoveMultiLineCommentsFromRange(lines, begin, end):
947fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  """Clears a range of lines for multi-line comments."""
948fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # Having // dummy comments makes the lines non-empty, so we will not get
949fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # unnecessary blank line warnings later in the code.
950fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  for i in range(begin, end):
951fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    lines[i] = '// dummy'
952fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
953fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
954fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovdef RemoveMultiLineComments(filename, lines, error):
955fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  """Removes multiline (c-style) comments from lines."""
956fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  lineix = 0
957fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  while lineix < len(lines):
958fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    lineix_begin = FindNextMultiLineCommentStart(lines, lineix)
959fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    if lineix_begin >= len(lines):
960fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      return
961fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    lineix_end = FindNextMultiLineCommentEnd(lines, lineix_begin)
962fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    if lineix_end >= len(lines):
963fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      error(filename, lineix_begin + 1, 'readability/multiline_comment', 5,
964fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov            'Could not find end of multi-line comment')
965fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      return
966fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    RemoveMultiLineCommentsFromRange(lines, lineix_begin, lineix_end + 1)
967fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    lineix = lineix_end + 1
968fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
969fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
970fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovdef CleanseComments(line):
971fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  """Removes //-comments and single-line C-style /* */ comments.
972fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
973fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  Args:
974fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    line: A line of C++ source.
975fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
976fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  Returns:
977fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    The line with single-line comments removed.
978fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  """
979fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  commentpos = line.find('//')
980fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  if commentpos != -1 and not IsCppString(line[:commentpos]):
981fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    line = line[:commentpos].rstrip()
982fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # get rid of /* ... */
983fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  return _RE_PATTERN_CLEANSE_LINE_C_COMMENTS.sub('', line)
984fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
985fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
986fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovclass CleansedLines(object):
987fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  """Holds 3 copies of all lines with different preprocessing applied to them.
988fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
989fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  1) elided member contains lines without strings and comments,
990fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  2) lines member contains lines without comments, and
991fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  3) raw_lines member contains all the lines without processing.
992fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  All these three members are of <type 'list'>, and of the same length.
993fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  """
994fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
995fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  def __init__(self, lines):
996fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    self.elided = []
997fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    self.lines = []
998fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    self.raw_lines = lines
999fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    self.num_lines = len(lines)
1000fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    for linenum in range(len(lines)):
1001fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      self.lines.append(CleanseComments(lines[linenum]))
1002fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      elided = self._CollapseStrings(lines[linenum])
1003fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      self.elided.append(CleanseComments(elided))
1004fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1005fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  def NumLines(self):
1006fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    """Returns the number of lines represented."""
1007fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    return self.num_lines
1008fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1009fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  @staticmethod
1010fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  def _CollapseStrings(elided):
1011fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    """Collapses strings and chars on a line to simple "" or '' blocks.
1012fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1013fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    We nix strings first so we're not fooled by text like '"http://"'
1014fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1015fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    Args:
1016fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      elided: The line being processed.
1017fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1018fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    Returns:
1019fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      The line with collapsed strings.
1020fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    """
1021fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    if not _RE_PATTERN_INCLUDE.match(elided):
1022fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      # Remove escaped characters first to make quote/single quote collapsing
1023fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      # basic.  Things that look like escaped characters shouldn't occur
1024fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      # outside of strings and chars.
1025fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      elided = _RE_PATTERN_CLEANSE_LINE_ESCAPES.sub('', elided)
1026fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      elided = _RE_PATTERN_CLEANSE_LINE_SINGLE_QUOTES.sub("''", elided)
1027fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      elided = _RE_PATTERN_CLEANSE_LINE_DOUBLE_QUOTES.sub('""', elided)
1028fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    return elided
1029fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1030fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1031fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovdef FindEndOfExpressionInLine(line, startpos, depth, startchar, endchar):
1032fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  """Find the position just after the matching endchar.
1033fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1034fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  Args:
1035fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    line: a CleansedLines line.
1036fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    startpos: start searching at this position.
1037fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    depth: nesting level at startpos.
1038fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    startchar: expression opening character.
1039fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    endchar: expression closing character.
1040fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1041fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  Returns:
1042fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    Index just after endchar.
1043fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  """
1044fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  for i in xrange(startpos, len(line)):
1045fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    if line[i] == startchar:
1046fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      depth += 1
1047fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    elif line[i] == endchar:
1048fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      depth -= 1
1049fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      if depth == 0:
1050fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        return i + 1
1051fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  return -1
1052fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1053fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1054fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovdef CloseExpression(clean_lines, linenum, pos):
1055fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  """If input points to ( or { or [, finds the position that closes it.
1056fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1057fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  If lines[linenum][pos] points to a '(' or '{' or '[', finds the
1058fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  linenum/pos that correspond to the closing of the expression.
1059fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1060fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  Args:
1061fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    clean_lines: A CleansedLines instance containing the file.
1062fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    linenum: The number of the line to check.
1063fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    pos: A position on the line.
1064fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1065fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  Returns:
1066fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    A tuple (line, linenum, pos) pointer *past* the closing brace, or
1067fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    (line, len(lines), -1) if we never find a close.  Note we ignore
1068fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    strings and comments when matching; and the line we return is the
1069fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    'cleansed' line at linenum.
1070fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  """
1071fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1072fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  line = clean_lines.elided[linenum]
1073fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  startchar = line[pos]
1074fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  if startchar not in '({[':
1075fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    return (line, clean_lines.NumLines(), -1)
1076fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  if startchar == '(': endchar = ')'
1077fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  if startchar == '[': endchar = ']'
1078fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  if startchar == '{': endchar = '}'
1079fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1080fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # Check first line
1081fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  end_pos = FindEndOfExpressionInLine(line, pos, 0, startchar, endchar)
1082fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  if end_pos > -1:
1083fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    return (line, linenum, end_pos)
1084fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  tail = line[pos:]
1085fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  num_open = tail.count(startchar) - tail.count(endchar)
1086fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  while linenum < clean_lines.NumLines() - 1:
1087fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    linenum += 1
1088fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    line = clean_lines.elided[linenum]
1089fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    delta = line.count(startchar) - line.count(endchar)
1090fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    if num_open + delta <= 0:
1091fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      return (line, linenum,
1092fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov              FindEndOfExpressionInLine(line, 0, num_open, startchar, endchar))
1093fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    num_open += delta
1094fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1095fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # Did not find endchar before end of file, give up
1096fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  return (line, clean_lines.NumLines(), -1)
1097fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1098fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovdef CheckForCopyright(filename, lines, error):
1099fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  """Logs an error if no Copyright message appears at the top of the file."""
1100fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1101fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # We'll say it should occur by line 10. Don't forget there's a
1102fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # dummy line at the front.
1103fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  for line in xrange(1, min(len(lines), 11)):
1104fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    if re.search(r'Copyright', lines[line], re.I): break
1105fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  else:                       # means no copyright line was found
1106fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    error(filename, 0, 'legal/copyright', 5,
1107fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          'No copyright message found.  '
1108fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          'You should have a line: "Copyright [year] <Copyright Owner>"')
1109fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1110fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1111fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovdef GetHeaderGuardCPPVariable(filename):
1112fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  """Returns the CPP variable that should be used as a header guard.
1113fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1114fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  Args:
1115fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    filename: The name of a C++ header file.
1116fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1117fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  Returns:
1118fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    The CPP variable that should be used as a header guard in the
1119fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    named file.
1120fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1121fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  """
1122fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1123fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # Restores original filename in case that cpplint is invoked from Emacs's
1124fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # flymake.
1125fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  filename = re.sub(r'_flymake\.h$', '.h', filename)
1126fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  filename = re.sub(r'/\.flymake/([^/]*)$', r'/\1', filename)
1127fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1128fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  fileinfo = FileInfo(filename)
1129fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  file_path_from_root = fileinfo.RepositoryName()
1130fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  if _root:
1131fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    file_path_from_root = re.sub('^' + _root + os.sep, '', file_path_from_root)
1132fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  return re.sub(r'[-./\s]', '_', file_path_from_root).upper() + '_'
1133fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1134fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1135fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovdef CheckForHeaderGuard(filename, lines, error):
1136fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  """Checks that the file contains a header guard.
1137fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1138fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  Logs an error if no #ifndef header guard is present.  For other
1139fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  headers, checks that the full pathname is used.
1140fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1141fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  Args:
1142fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    filename: The name of the C++ header file.
1143fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    lines: An array of strings, each representing a line of the file.
1144fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    error: The function to call with any errors found.
1145fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  """
1146fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1147fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  cppvar = GetHeaderGuardCPPVariable(filename)
1148fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1149fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  ifndef = None
1150fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  ifndef_linenum = 0
1151fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  define = None
1152fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  endif = None
1153fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  endif_linenum = 0
1154fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  for linenum, line in enumerate(lines):
1155fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    linesplit = line.split()
1156fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    if len(linesplit) >= 2:
1157fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      # find the first occurrence of #ifndef and #define, save arg
1158fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      if not ifndef and linesplit[0] == '#ifndef':
1159fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        # set ifndef to the header guard presented on the #ifndef line.
1160fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        ifndef = linesplit[1]
1161fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        ifndef_linenum = linenum
1162fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      if not define and linesplit[0] == '#define':
1163fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        define = linesplit[1]
1164fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    # find the last occurrence of #endif, save entire line
1165fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    if line.startswith('#endif'):
1166fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      endif = line
1167fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      endif_linenum = linenum
1168fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1169fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  if not ifndef:
1170fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    error(filename, 0, 'build/header_guard', 5,
1171fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          'No #ifndef header guard found, suggested CPP variable is: %s' %
1172fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          cppvar)
1173fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    return
1174fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1175fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  if not define:
1176fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    error(filename, 0, 'build/header_guard', 5,
1177fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          'No #define header guard found, suggested CPP variable is: %s' %
1178fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          cppvar)
1179fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    return
1180fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1181fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # The guard should be PATH_FILE_H_, but we also allow PATH_FILE_H__
1182fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # for backward compatibility.
1183fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  if ifndef != cppvar:
1184fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    error_level = 0
1185fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    if ifndef != cppvar + '_':
1186fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      error_level = 5
1187fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1188fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    ParseNolintSuppressions(filename, lines[ifndef_linenum], ifndef_linenum,
1189fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov                            error)
1190fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    error(filename, ifndef_linenum, 'build/header_guard', error_level,
1191fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          '#ifndef header guard has wrong style, please use: %s' % cppvar)
1192fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1193fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  if define != ifndef:
1194fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    error(filename, 0, 'build/header_guard', 5,
1195fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          '#ifndef and #define don\'t match, suggested CPP variable is: %s' %
1196fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          cppvar)
1197fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    return
1198fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1199fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  if endif != ('#endif  // %s' % cppvar):
1200fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    error_level = 0
1201fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    if endif != ('#endif  // %s' % (cppvar + '_')):
1202fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      error_level = 5
1203fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1204fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    ParseNolintSuppressions(filename, lines[endif_linenum], endif_linenum,
1205fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov                            error)
1206fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    error(filename, endif_linenum, 'build/header_guard', error_level,
1207fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          '#endif line should be "#endif  // %s"' % cppvar)
1208fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1209fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1210fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovdef CheckForUnicodeReplacementCharacters(filename, lines, error):
1211fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  """Logs an error for each line containing Unicode replacement characters.
1212fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1213fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  These indicate that either the file contained invalid UTF-8 (likely)
1214fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  or Unicode replacement characters (which it shouldn't).  Note that
1215fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  it's possible for this to throw off line numbering if the invalid
1216fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  UTF-8 occurred adjacent to a newline.
1217fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1218fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  Args:
1219fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    filename: The name of the current file.
1220fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    lines: An array of strings, each representing a line of the file.
1221fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    error: The function to call with any errors found.
1222fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  """
1223fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  for linenum, line in enumerate(lines):
1224fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    if u'\ufffd' in line:
1225fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      error(filename, linenum, 'readability/utf8', 5,
1226fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov            'Line contains invalid UTF-8 (or Unicode replacement character).')
1227fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1228fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1229fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovdef CheckForNewlineAtEOF(filename, lines, error):
1230fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  """Logs an error if there is no newline char at the end of the file.
1231fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1232fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  Args:
1233fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    filename: The name of the current file.
1234fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    lines: An array of strings, each representing a line of the file.
1235fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    error: The function to call with any errors found.
1236fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  """
1237fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1238fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # The array lines() was created by adding two newlines to the
1239fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # original file (go figure), then splitting on \n.
1240fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # To verify that the file ends in \n, we just have to make sure the
1241fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # last-but-two element of lines() exists and is empty.
1242fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  if len(lines) < 3 or lines[-2]:
1243fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    error(filename, len(lines) - 2, 'whitespace/ending_newline', 5,
1244fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          'Could not find a newline character at the end of the file.')
1245fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1246fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1247fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovdef CheckForMultilineCommentsAndStrings(filename, clean_lines, linenum, error):
1248fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  """Logs an error if we see /* ... */ or "..." that extend past one line.
1249fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1250fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  /* ... */ comments are legit inside macros, for one line.
1251fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  Otherwise, we prefer // comments, so it's ok to warn about the
1252fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  other.  Likewise, it's ok for strings to extend across multiple
1253fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  lines, as long as a line continuation character (backslash)
1254fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  terminates each line. Although not currently prohibited by the C++
1255fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  style guide, it's ugly and unnecessary. We don't do well with either
1256fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  in this lint program, so we warn about both.
1257fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1258fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  Args:
1259fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    filename: The name of the current file.
1260fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    clean_lines: A CleansedLines instance containing the file.
1261fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    linenum: The number of the line to check.
1262fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    error: The function to call with any errors found.
1263fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  """
1264fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  line = clean_lines.elided[linenum]
1265fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1266fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # Remove all \\ (escaped backslashes) from the line. They are OK, and the
1267fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # second (escaped) slash may trigger later \" detection erroneously.
1268fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  line = line.replace('\\\\', '')
1269fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1270fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  if line.count('/*') > line.count('*/'):
1271fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    error(filename, linenum, 'readability/multiline_comment', 5,
1272fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          'Complex multi-line /*...*/-style comment found. '
1273fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          'Lint may give bogus warnings.  '
1274fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          'Consider replacing these with //-style comments, '
1275fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          'with #if 0...#endif, '
1276fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          'or with more clearly structured multi-line comments.')
1277fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1278fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  if (line.count('"') - line.count('\\"')) % 2:
1279fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    error(filename, linenum, 'readability/multiline_string', 5,
1280fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          'Multi-line string ("...") found.  This lint script doesn\'t '
1281fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          'do well with such strings, and may give bogus warnings.  They\'re '
1282fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          'ugly and unnecessary, and you should use concatenation instead".')
1283fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1284fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1285fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovthreading_list = (
1286fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    ('asctime(', 'asctime_r('),
1287fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    ('ctime(', 'ctime_r('),
1288fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    ('getgrgid(', 'getgrgid_r('),
1289fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    ('getgrnam(', 'getgrnam_r('),
1290fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    ('getlogin(', 'getlogin_r('),
1291fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    ('getpwnam(', 'getpwnam_r('),
1292fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    ('getpwuid(', 'getpwuid_r('),
1293fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    ('gmtime(', 'gmtime_r('),
1294fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    ('localtime(', 'localtime_r('),
1295fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    ('rand(', 'rand_r('),
1296fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    ('readdir(', 'readdir_r('),
1297fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    ('strtok(', 'strtok_r('),
1298fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    ('ttyname(', 'ttyname_r('),
1299fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    )
1300fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1301fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1302fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovdef CheckPosixThreading(filename, clean_lines, linenum, error):
1303fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  """Checks for calls to thread-unsafe functions.
1304fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1305fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  Much code has been originally written without consideration of
1306fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  multi-threading. Also, engineers are relying on their old experience;
1307fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  they have learned posix before threading extensions were added. These
1308fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  tests guide the engineers to use thread-safe functions (when using
1309fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  posix directly).
1310fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1311fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  Args:
1312fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    filename: The name of the current file.
1313fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    clean_lines: A CleansedLines instance containing the file.
1314fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    linenum: The number of the line to check.
1315fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    error: The function to call with any errors found.
1316fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  """
1317fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  line = clean_lines.elided[linenum]
1318fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  for single_thread_function, multithread_safe_function in threading_list:
1319fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    ix = line.find(single_thread_function)
1320fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    # Comparisons made explicit for clarity -- pylint: disable-msg=C6403
1321fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    if ix >= 0 and (ix == 0 or (not line[ix - 1].isalnum() and
1322fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov                                line[ix - 1] not in ('_', '.', '>'))):
1323fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      error(filename, linenum, 'runtime/threadsafe_fn', 2,
1324fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov            'Consider using ' + multithread_safe_function +
1325fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov            '...) instead of ' + single_thread_function +
1326fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov            '...) for improved thread safety.')
1327fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1328fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1329fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# Matches invalid increment: *count++, which moves pointer instead of
1330fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# incrementing a value.
1331fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov_RE_PATTERN_INVALID_INCREMENT = re.compile(
1332fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    r'^\s*\*\w+(\+\+|--);')
1333fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1334fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1335fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovdef CheckInvalidIncrement(filename, clean_lines, linenum, error):
1336fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  """Checks for invalid increment *count++.
1337fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1338fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  For example following function:
1339fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  void increment_counter(int* count) {
1340fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    *count++;
1341fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  }
1342fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  is invalid, because it effectively does count++, moving pointer, and should
1343fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  be replaced with ++*count, (*count)++ or *count += 1.
1344fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1345fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  Args:
1346fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    filename: The name of the current file.
1347fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    clean_lines: A CleansedLines instance containing the file.
1348fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    linenum: The number of the line to check.
1349fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    error: The function to call with any errors found.
1350fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  """
1351fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  line = clean_lines.elided[linenum]
1352fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  if _RE_PATTERN_INVALID_INCREMENT.match(line):
1353fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    error(filename, linenum, 'runtime/invalid_increment', 5,
1354fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          'Changing pointer instead of value (or unused value of operator*).')
1355fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1356fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1357fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovclass _BlockInfo(object):
1358fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  """Stores information about a generic block of code."""
1359fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1360fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  def __init__(self, seen_open_brace):
1361fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    self.seen_open_brace = seen_open_brace
1362fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    self.open_parentheses = 0
1363fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    self.inline_asm = _NO_ASM
1364fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1365fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  def CheckBegin(self, filename, clean_lines, linenum, error):
1366fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    """Run checks that applies to text up to the opening brace.
1367fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1368fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    This is mostly for checking the text after the class identifier
1369fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    and the "{", usually where the base class is specified.  For other
1370fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    blocks, there isn't much to check, so we always pass.
1371fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1372fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    Args:
1373fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      filename: The name of the current file.
1374fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      clean_lines: A CleansedLines instance containing the file.
1375fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      linenum: The number of the line to check.
1376fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      error: The function to call with any errors found.
1377fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    """
1378fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    pass
1379fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1380fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  def CheckEnd(self, filename, clean_lines, linenum, error):
1381fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    """Run checks that applies to text after the closing brace.
1382fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1383fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    This is mostly used for checking end of namespace comments.
1384fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1385fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    Args:
1386fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      filename: The name of the current file.
1387fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      clean_lines: A CleansedLines instance containing the file.
1388fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      linenum: The number of the line to check.
1389fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      error: The function to call with any errors found.
1390fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    """
1391fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    pass
1392fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1393fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1394fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovclass _ClassInfo(_BlockInfo):
1395fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  """Stores information about a class."""
1396fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1397fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  def __init__(self, name, class_or_struct, clean_lines, linenum):
1398fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    _BlockInfo.__init__(self, False)
1399fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    self.name = name
1400fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    self.starting_linenum = linenum
1401fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    self.is_derived = False
1402fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    if class_or_struct == 'struct':
1403fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      self.access = 'public'
1404fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    else:
1405fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      self.access = 'private'
1406fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1407fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    # Try to find the end of the class.  This will be confused by things like:
1408fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    #   class A {
1409fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    #   } *x = { ...
1410fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    #
1411fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    # But it's still good enough for CheckSectionSpacing.
1412fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    self.last_line = 0
1413fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    depth = 0
1414fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    for i in range(linenum, clean_lines.NumLines()):
1415fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      line = clean_lines.elided[i]
1416fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      depth += line.count('{') - line.count('}')
1417fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      if not depth:
1418fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        self.last_line = i
1419fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        break
1420fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1421fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  def CheckBegin(self, filename, clean_lines, linenum, error):
1422fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    # Look for a bare ':'
1423fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    if Search('(^|[^:]):($|[^:])', clean_lines.elided[linenum]):
1424fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      self.is_derived = True
1425fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1426fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1427fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovclass _NamespaceInfo(_BlockInfo):
1428fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  """Stores information about a namespace."""
1429fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1430fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  def __init__(self, name, linenum):
1431fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    _BlockInfo.__init__(self, False)
1432fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    self.name = name or ''
1433fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    self.starting_linenum = linenum
1434fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1435fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  def CheckEnd(self, filename, clean_lines, linenum, error):
1436fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    """Check end of namespace comments."""
1437fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    line = clean_lines.raw_lines[linenum]
1438fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1439fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    # Check how many lines is enclosed in this namespace.  Don't issue
1440fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    # warning for missing namespace comments if there aren't enough
1441fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    # lines.  However, do apply checks if there is already an end of
1442fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    # namespace comment and it's incorrect.
1443fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    #
1444fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    # TODO(unknown): We always want to check end of namespace comments
1445fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    # if a namespace is large, but sometimes we also want to apply the
1446fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    # check if a short namespace contained nontrivial things (something
1447fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    # other than forward declarations).  There is currently no logic on
1448fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    # deciding what these nontrivial things are, so this check is
1449fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    # triggered by namespace size only, which works most of the time.
1450fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    if (linenum - self.starting_linenum < 10
1451fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        and not Match(r'};*\s*(//|/\*).*\bnamespace\b', line)):
1452fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      return
1453fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1454fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    # Look for matching comment at end of namespace.
1455fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    #
1456fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    # Note that we accept C style "/* */" comments for terminating
1457fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    # namespaces, so that code that terminate namespaces inside
1458fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    # preprocessor macros can be cpplint clean.  Example: http://go/nxpiz
1459fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    #
1460fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    # We also accept stuff like "// end of namespace <name>." with the
1461fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    # period at the end.
1462fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    #
1463fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    # Besides these, we don't accept anything else, otherwise we might
1464fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    # get false negatives when existing comment is a substring of the
1465fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    # expected namespace.  Example: http://go/ldkdc, http://cl/23548205
1466fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    if self.name:
1467fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      # Named namespace
1468fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      if not Match((r'};*\s*(//|/\*).*\bnamespace\s+' + re.escape(self.name) +
1469fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov                    r'[\*/\.\\\s]*$'),
1470fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov                   line):
1471fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        error(filename, linenum, 'readability/namespace', 5,
1472fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov              'Namespace should be terminated with "// namespace %s"' %
1473fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov              self.name)
1474fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    else:
1475fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      # Anonymous namespace
1476fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      if not Match(r'};*\s*(//|/\*).*\bnamespace[\*/\.\\\s]*$', line):
1477fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        error(filename, linenum, 'readability/namespace', 5,
1478fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov              'Namespace should be terminated with "// namespace"')
1479fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1480fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1481fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovclass _PreprocessorInfo(object):
1482fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  """Stores checkpoints of nesting stacks when #if/#else is seen."""
1483fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1484fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  def __init__(self, stack_before_if):
1485fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    # The entire nesting stack before #if
1486fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    self.stack_before_if = stack_before_if
1487fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1488fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    # The entire nesting stack up to #else
1489fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    self.stack_before_else = []
1490fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1491fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    # Whether we have already seen #else or #elif
1492fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    self.seen_else = False
1493fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1494fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1495fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovclass _NestingState(object):
1496fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  """Holds states related to parsing braces."""
1497fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1498fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  def __init__(self):
1499fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    # Stack for tracking all braces.  An object is pushed whenever we
1500fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    # see a "{", and popped when we see a "}".  Only 3 types of
1501fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    # objects are possible:
1502fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    # - _ClassInfo: a class or struct.
1503fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    # - _NamespaceInfo: a namespace.
1504fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    # - _BlockInfo: some other type of block.
1505fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    self.stack = []
1506fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1507fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    # Stack of _PreprocessorInfo objects.
1508fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    self.pp_stack = []
1509fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1510fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  def SeenOpenBrace(self):
1511fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    """Check if we have seen the opening brace for the innermost block.
1512fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1513fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    Returns:
1514fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      True if we have seen the opening brace, False if the innermost
1515fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      block is still expecting an opening brace.
1516fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    """
1517fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    return (not self.stack) or self.stack[-1].seen_open_brace
1518fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1519fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  def InNamespaceBody(self):
1520fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    """Check if we are currently one level inside a namespace body.
1521fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1522fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    Returns:
1523fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      True if top of the stack is a namespace block, False otherwise.
1524fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    """
1525fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    return self.stack and isinstance(self.stack[-1], _NamespaceInfo)
1526fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1527fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  def UpdatePreprocessor(self, line):
1528fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    """Update preprocessor stack.
1529fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1530fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    We need to handle preprocessors due to classes like this:
1531fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      #ifdef SWIG
1532fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      struct ResultDetailsPageElementExtensionPoint {
1533fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      #else
1534fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      struct ResultDetailsPageElementExtensionPoint : public Extension {
1535fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      #endif
1536fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    (see http://go/qwddn for original example)
1537fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1538fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    We make the following assumptions (good enough for most files):
1539fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    - Preprocessor condition evaluates to true from #if up to first
1540fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      #else/#elif/#endif.
1541fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1542fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    - Preprocessor condition evaluates to false from #else/#elif up
1543fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      to #endif.  We still perform lint checks on these lines, but
1544fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      these do not affect nesting stack.
1545fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1546fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    Args:
1547fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      line: current line to check.
1548fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    """
1549fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    if Match(r'^\s*#\s*(if|ifdef|ifndef)\b', line):
1550fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      # Beginning of #if block, save the nesting stack here.  The saved
1551fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      # stack will allow us to restore the parsing state in the #else case.
1552fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      self.pp_stack.append(_PreprocessorInfo(copy.deepcopy(self.stack)))
1553fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    elif Match(r'^\s*#\s*(else|elif)\b', line):
1554fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      # Beginning of #else block
1555fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      if self.pp_stack:
1556fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        if not self.pp_stack[-1].seen_else:
1557fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          # This is the first #else or #elif block.  Remember the
1558fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          # whole nesting stack up to this point.  This is what we
1559fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          # keep after the #endif.
1560fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          self.pp_stack[-1].seen_else = True
1561fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          self.pp_stack[-1].stack_before_else = copy.deepcopy(self.stack)
1562fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1563fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        # Restore the stack to how it was before the #if
1564fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        self.stack = copy.deepcopy(self.pp_stack[-1].stack_before_if)
1565fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      else:
1566fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        # TODO(unknown): unexpected #else, issue warning?
1567fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        pass
1568fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    elif Match(r'^\s*#\s*endif\b', line):
1569fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      # End of #if or #else blocks.
1570fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      if self.pp_stack:
1571fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        # If we saw an #else, we will need to restore the nesting
1572fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        # stack to its former state before the #else, otherwise we
1573fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        # will just continue from where we left off.
1574fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        if self.pp_stack[-1].seen_else:
1575fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          # Here we can just use a shallow copy since we are the last
1576fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          # reference to it.
1577fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          self.stack = self.pp_stack[-1].stack_before_else
1578fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        # Drop the corresponding #if
1579fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        self.pp_stack.pop()
1580fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      else:
1581fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        # TODO(unknown): unexpected #endif, issue warning?
1582fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        pass
1583fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1584fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  def Update(self, filename, clean_lines, linenum, error):
1585fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    """Update nesting state with current line.
1586fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1587fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    Args:
1588fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      filename: The name of the current file.
1589fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      clean_lines: A CleansedLines instance containing the file.
1590fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      linenum: The number of the line to check.
1591fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      error: The function to call with any errors found.
1592fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    """
1593fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    line = clean_lines.elided[linenum]
1594fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1595fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    # Update pp_stack first
1596fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    self.UpdatePreprocessor(line)
1597fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1598fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    # Count parentheses.  This is to avoid adding struct arguments to
1599fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    # the nesting stack.
1600fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    if self.stack:
1601fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      inner_block = self.stack[-1]
1602fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      depth_change = line.count('(') - line.count(')')
1603fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      inner_block.open_parentheses += depth_change
1604fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1605fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      # Also check if we are starting or ending an inline assembly block.
1606fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      if inner_block.inline_asm in (_NO_ASM, _END_ASM):
1607fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        if (depth_change != 0 and
1608fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov            inner_block.open_parentheses == 1 and
1609fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov            _MATCH_ASM.match(line)):
1610fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          # Enter assembly block
1611fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          inner_block.inline_asm = _INSIDE_ASM
1612fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        else:
1613fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          # Not entering assembly block.  If previous line was _END_ASM,
1614fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          # we will now shift to _NO_ASM state.
1615fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          inner_block.inline_asm = _NO_ASM
1616fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      elif (inner_block.inline_asm == _INSIDE_ASM and
1617fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov            inner_block.open_parentheses == 0):
1618fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        # Exit assembly block
1619fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        inner_block.inline_asm = _END_ASM
1620fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1621fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    # Consume namespace declaration at the beginning of the line.  Do
1622fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    # this in a loop so that we catch same line declarations like this:
1623fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    #   namespace proto2 { namespace bridge { class MessageSet; } }
1624fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    while True:
1625fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      # Match start of namespace.  The "\b\s*" below catches namespace
1626fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      # declarations even if it weren't followed by a whitespace, this
1627fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      # is so that we don't confuse our namespace checker.  The
1628fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      # missing spaces will be flagged by CheckSpacing.
1629fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      namespace_decl_match = Match(r'^\s*namespace\b\s*([:\w]+)?(.*)$', line)
1630fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      if not namespace_decl_match:
1631fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        break
1632fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1633fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      new_namespace = _NamespaceInfo(namespace_decl_match.group(1), linenum)
1634fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      self.stack.append(new_namespace)
1635fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1636fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      line = namespace_decl_match.group(2)
1637fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      if line.find('{') != -1:
1638fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        new_namespace.seen_open_brace = True
1639fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        line = line[line.find('{') + 1:]
1640fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1641fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    # Look for a class declaration in whatever is left of the line
1642fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    # after parsing namespaces.  The regexp accounts for decorated classes
1643fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    # such as in:
1644fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    #   class LOCKABLE API Object {
1645fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    #   };
1646fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    #
1647fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    # Templates with class arguments may confuse the parser, for example:
1648fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    #   template <class T
1649fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    #             class Comparator = less<T>,
1650fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    #             class Vector = vector<T> >
1651fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    #   class HeapQueue {
1652fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    #
1653fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    # Because this parser has no nesting state about templates, by the
1654fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    # time it saw "class Comparator", it may think that it's a new class.
1655fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    # Nested templates have a similar problem:
1656fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    #   template <
1657fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    #       typename ExportedType,
1658fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    #       typename TupleType,
1659fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    #       template <typename, typename> class ImplTemplate>
1660fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    #
1661fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    # To avoid these cases, we ignore classes that are followed by '=' or '>'
1662fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    class_decl_match = Match(
1663fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        r'\s*(template\s*<[\w\s<>,:]*>\s*)?'
1664fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        '(class|struct)\s+([A-Z_]+\s+)*(\w+(?:::\w+)*)'
1665fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        '(([^=>]|<[^<>]*>)*)$', line)
1666fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    if (class_decl_match and
1667fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        (not self.stack or self.stack[-1].open_parentheses == 0)):
1668fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      self.stack.append(_ClassInfo(
1669fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          class_decl_match.group(4), class_decl_match.group(2),
1670fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          clean_lines, linenum))
1671fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      line = class_decl_match.group(5)
1672fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1673fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    # If we have not yet seen the opening brace for the innermost block,
1674fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    # run checks here.
1675fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    if not self.SeenOpenBrace():
1676fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      self.stack[-1].CheckBegin(filename, clean_lines, linenum, error)
1677fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1678fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    # Update access control if we are inside a class/struct
1679fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    if self.stack and isinstance(self.stack[-1], _ClassInfo):
1680fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      access_match = Match(r'\s*(public|private|protected)\s*:', line)
1681fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      if access_match:
1682fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        self.stack[-1].access = access_match.group(1)
1683fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1684fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    # Consume braces or semicolons from what's left of the line
1685fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    while True:
1686fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      # Match first brace, semicolon, or closed parenthesis.
1687fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      matched = Match(r'^[^{;)}]*([{;)}])(.*)$', line)
1688fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      if not matched:
1689fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        break
1690fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1691fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      token = matched.group(1)
1692fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      if token == '{':
1693fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        # If namespace or class hasn't seen a opening brace yet, mark
1694fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        # namespace/class head as complete.  Push a new block onto the
1695fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        # stack otherwise.
1696fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        if not self.SeenOpenBrace():
1697fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          self.stack[-1].seen_open_brace = True
1698fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        else:
1699fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          self.stack.append(_BlockInfo(True))
1700fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          if _MATCH_ASM.match(line):
1701fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov            self.stack[-1].inline_asm = _BLOCK_ASM
1702fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      elif token == ';' or token == ')':
1703fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        # If we haven't seen an opening brace yet, but we already saw
1704fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        # a semicolon, this is probably a forward declaration.  Pop
1705fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        # the stack for these.
1706fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        #
1707fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        # Similarly, if we haven't seen an opening brace yet, but we
1708fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        # already saw a closing parenthesis, then these are probably
1709fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        # function arguments with extra "class" or "struct" keywords.
1710fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        # Also pop these stack for these.
1711fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        if not self.SeenOpenBrace():
1712fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          self.stack.pop()
1713fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      else:  # token == '}'
1714fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        # Perform end of block checks and pop the stack.
1715fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        if self.stack:
1716fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          self.stack[-1].CheckEnd(filename, clean_lines, linenum, error)
1717fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          self.stack.pop()
1718fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      line = matched.group(2)
1719fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1720fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  def InnermostClass(self):
1721fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    """Get class info on the top of the stack.
1722fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1723fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    Returns:
1724fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      A _ClassInfo object if we are inside a class, or None otherwise.
1725fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    """
1726fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    for i in range(len(self.stack), 0, -1):
1727fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      classinfo = self.stack[i - 1]
1728fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      if isinstance(classinfo, _ClassInfo):
1729fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        return classinfo
1730fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    return None
1731fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1732fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  def CheckClassFinished(self, filename, error):
1733fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    """Checks that all classes have been completely parsed.
1734fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1735fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    Call this when all lines in a file have been processed.
1736fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    Args:
1737fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      filename: The name of the current file.
1738fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      error: The function to call with any errors found.
1739fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    """
1740fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    # Note: This test can result in false positives if #ifdef constructs
1741fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    # get in the way of brace matching. See the testBuildClass test in
1742fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    # cpplint_unittest.py for an example of this.
1743fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    for obj in self.stack:
1744fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      if isinstance(obj, _ClassInfo):
1745fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        error(filename, obj.starting_linenum, 'build/class', 5,
1746fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov              'Failed to find complete declaration of class %s' %
1747fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov              obj.name)
1748fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1749fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1750fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovdef CheckForNonStandardConstructs(filename, clean_lines, linenum,
1751fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov                                  nesting_state, error):
1752fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  """Logs an error if we see certain non-ANSI constructs ignored by gcc-2.
1753fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1754fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  Complain about several constructs which gcc-2 accepts, but which are
1755fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  not standard C++.  Warning about these in lint is one way to ease the
1756fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  transition to new compilers.
1757fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  - put storage class first (e.g. "static const" instead of "const static").
1758fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  - "%lld" instead of %qd" in printf-type functions.
1759fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  - "%1$d" is non-standard in printf-type functions.
1760fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  - "\%" is an undefined character escape sequence.
1761fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  - text after #endif is not allowed.
1762fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  - invalid inner-style forward declaration.
1763fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  - >? and <? operators, and their >?= and <?= cousins.
1764fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1765fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  Additionally, check for constructor/destructor style violations and reference
1766fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  members, as it is very convenient to do so while checking for
1767fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  gcc-2 compliance.
1768fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1769fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  Args:
1770fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    filename: The name of the current file.
1771fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    clean_lines: A CleansedLines instance containing the file.
1772fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    linenum: The number of the line to check.
1773fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    nesting_state: A _NestingState instance which maintains information about
1774fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov                   the current stack of nested blocks being parsed.
1775fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    error: A callable to which errors are reported, which takes 4 arguments:
1776fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov           filename, line number, error level, and message
1777fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  """
1778fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1779fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # Remove comments from the line, but leave in strings for now.
1780fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  line = clean_lines.lines[linenum]
1781fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1782fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  if Search(r'printf\s*\(.*".*%[-+ ]?\d*q', line):
1783fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    error(filename, linenum, 'runtime/printf_format', 3,
1784fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          '%q in format strings is deprecated.  Use %ll instead.')
1785fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1786fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  if Search(r'printf\s*\(.*".*%\d+\$', line):
1787fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    error(filename, linenum, 'runtime/printf_format', 2,
1788fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          '%N$ formats are unconventional.  Try rewriting to avoid them.')
1789fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1790fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # Remove escaped backslashes before looking for undefined escapes.
1791fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  line = line.replace('\\\\', '')
1792fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1793fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  if Search(r'("|\').*\\(%|\[|\(|{)', line):
1794fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    error(filename, linenum, 'build/printf_format', 3,
1795fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          '%, [, (, and { are undefined character escapes.  Unescape them.')
1796fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1797fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # For the rest, work with both comments and strings removed.
1798fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  line = clean_lines.elided[linenum]
1799fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1800fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  if Search(r'\b(const|volatile|void|char|short|int|long'
1801fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov            r'|float|double|signed|unsigned'
1802fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov            r'|schar|u?int8|u?int16|u?int32|u?int64)'
1803fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov            r'\s+(register|static|extern|typedef)\b',
1804fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov            line):
1805fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    error(filename, linenum, 'build/storage_class', 5,
1806fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          'Storage class (static, extern, typedef, etc) should be first.')
1807fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1808fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  if Match(r'\s*#\s*endif\s*[^/\s]+', line):
1809fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    error(filename, linenum, 'build/endif_comment', 5,
1810fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          'Uncommented text after #endif is non-standard.  Use a comment.')
1811fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1812fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  if Match(r'\s*class\s+(\w+\s*::\s*)+\w+\s*;', line):
1813fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    error(filename, linenum, 'build/forward_decl', 5,
1814fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          'Inner-style forward declarations are invalid.  Remove this line.')
1815fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1816fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  if Search(r'(\w+|[+-]?\d+(\.\d*)?)\s*(<|>)\?=?\s*(\w+|[+-]?\d+)(\.\d*)?',
1817fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov            line):
1818fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    error(filename, linenum, 'build/deprecated', 3,
1819fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          '>? and <? (max and min) operators are non-standard and deprecated.')
1820fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1821fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  if Search(r'^\s*const\s*string\s*&\s*\w+\s*;', line):
1822fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    # TODO(unknown): Could it be expanded safely to arbitrary references,
1823fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    # without triggering too many false positives? The first
1824fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    # attempt triggered 5 warnings for mostly benign code in the regtest, hence
1825fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    # the restriction.
1826fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    # Here's the original regexp, for the reference:
1827fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    # type_name = r'\w+((\s*::\s*\w+)|(\s*<\s*\w+?\s*>))?'
1828fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    # r'\s*const\s*' + type_name + '\s*&\s*\w+\s*;'
1829fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    error(filename, linenum, 'runtime/member_string_references', 2,
1830fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          'const string& members are dangerous. It is much better to use '
1831fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          'alternatives, such as pointers or simple constants.')
1832fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1833fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # Everything else in this function operates on class declarations.
1834fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # Return early if the top of the nesting stack is not a class, or if
1835fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # the class head is not completed yet.
1836fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  classinfo = nesting_state.InnermostClass()
1837fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  if not classinfo or not classinfo.seen_open_brace:
1838fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    return
1839fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1840fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # The class may have been declared with namespace or classname qualifiers.
1841fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # The constructor and destructor will not have those qualifiers.
1842fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  base_classname = classinfo.name.split('::')[-1]
1843fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1844fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # Look for single-argument constructors that aren't marked explicit.
1845fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # Technically a valid construct, but against style.
1846fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  args = Match(r'\s+(?:inline\s+)?%s\s*\(([^,()]+)\)'
1847fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov               % re.escape(base_classname),
1848fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov               line)
1849fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  if (args and
1850fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      args.group(1) != 'void' and
1851fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      not Match(r'(const\s+)?%s\s*(?:<\w+>\s*)?&' % re.escape(base_classname),
1852fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov                args.group(1).strip())):
1853fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    error(filename, linenum, 'runtime/explicit', 5,
1854fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          'Single-argument constructors should be marked explicit.')
1855fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1856fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1857fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovdef CheckSpacingForFunctionCall(filename, line, linenum, error):
1858fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  """Checks for the correctness of various spacing around function calls.
1859fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1860fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  Args:
1861fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    filename: The name of the current file.
1862fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    line: The text of the line to check.
1863fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    linenum: The number of the line to check.
1864fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    error: The function to call with any errors found.
1865fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  """
1866fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1867fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # Since function calls often occur inside if/for/while/switch
1868fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # expressions - which have their own, more liberal conventions - we
1869fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # first see if we should be looking inside such an expression for a
1870fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # function call, to which we can apply more strict standards.
1871fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  fncall = line    # if there's no control flow construct, look at whole line
1872fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  for pattern in (r'\bif\s*\((.*)\)\s*{',
1873fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov                  r'\bfor\s*\((.*)\)\s*{',
1874fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov                  r'\bwhile\s*\((.*)\)\s*[{;]',
1875fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov                  r'\bswitch\s*\((.*)\)\s*{'):
1876fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    match = Search(pattern, line)
1877fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    if match:
1878fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      fncall = match.group(1)    # look inside the parens for function calls
1879fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      break
1880fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1881fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # Except in if/for/while/switch, there should never be space
1882fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # immediately inside parens (eg "f( 3, 4 )").  We make an exception
1883fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # for nested parens ( (a+b) + c ).  Likewise, there should never be
1884fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # a space before a ( when it's a function argument.  I assume it's a
1885fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # function argument when the char before the whitespace is legal in
1886fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # a function name (alnum + _) and we're not starting a macro. Also ignore
1887fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # pointers and references to arrays and functions coz they're too tricky:
1888fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # we use a very simple way to recognize these:
1889fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # " (something)(maybe-something)" or
1890fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # " (something)(maybe-something," or
1891fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # " (something)[something]"
1892fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # Note that we assume the contents of [] to be short enough that
1893fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # they'll never need to wrap.
1894fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  if (  # Ignore control structures.
1895fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      not Search(r'\b(if|for|while|switch|return|delete)\b', fncall) and
1896fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      # Ignore pointers/references to functions.
1897fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      not Search(r' \([^)]+\)\([^)]*(\)|,$)', fncall) and
1898fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      # Ignore pointers/references to arrays.
1899fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      not Search(r' \([^)]+\)\[[^\]]+\]', fncall)):
1900fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    if Search(r'\w\s*\(\s(?!\s*\\$)', fncall):      # a ( used for a fn call
1901fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      error(filename, linenum, 'whitespace/parens', 4,
1902fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov            'Extra space after ( in function call')
1903fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    elif Search(r'\(\s+(?!(\s*\\)|\()', fncall):
1904fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      error(filename, linenum, 'whitespace/parens', 2,
1905fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov            'Extra space after (')
1906fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    if (Search(r'\w\s+\(', fncall) and
1907fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        not Search(r'#\s*define|typedef', fncall) and
1908fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        not Search(r'\w\s+\((\w+::)?\*\w+\)\(', fncall)):
1909fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      error(filename, linenum, 'whitespace/parens', 4,
1910fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov            'Extra space before ( in function call')
1911fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    # If the ) is followed only by a newline or a { + newline, assume it's
1912fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    # part of a control statement (if/while/etc), and don't complain
1913fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    if Search(r'[^)]\s+\)\s*[^{\s]', fncall):
1914fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      # If the closing parenthesis is preceded by only whitespaces,
1915fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      # try to give a more descriptive error message.
1916fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      if Search(r'^\s+\)', fncall):
1917fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        error(filename, linenum, 'whitespace/parens', 2,
1918fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov              'Closing ) should be moved to the previous line')
1919fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      else:
1920fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        error(filename, linenum, 'whitespace/parens', 2,
1921fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov              'Extra space before )')
1922fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1923fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1924fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovdef IsBlankLine(line):
1925fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  """Returns true if the given line is blank.
1926fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1927fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  We consider a line to be blank if the line is empty or consists of
1928fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  only white spaces.
1929fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1930fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  Args:
1931fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    line: A line of a string.
1932fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1933fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  Returns:
1934fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    True, if the given line is blank.
1935fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  """
1936fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  return not line or line.isspace()
1937fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1938fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1939fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovdef CheckForFunctionLengths(filename, clean_lines, linenum,
1940fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov                            function_state, error):
1941fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  """Reports for long function bodies.
1942fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1943fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  For an overview why this is done, see:
1944fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml#Write_Short_Functions
1945fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1946fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  Uses a simplistic algorithm assuming other style guidelines
1947fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  (especially spacing) are followed.
1948fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  Only checks unindented functions, so class members are unchecked.
1949fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  Trivial bodies are unchecked, so constructors with huge initializer lists
1950fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  may be missed.
1951fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  Blank/comment lines are not counted so as to avoid encouraging the removal
1952fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  of vertical space and comments just to get through a lint check.
1953fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  NOLINT *on the last line of a function* disables this check.
1954fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1955fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  Args:
1956fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    filename: The name of the current file.
1957fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    clean_lines: A CleansedLines instance containing the file.
1958fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    linenum: The number of the line to check.
1959fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    function_state: Current function name and lines in body so far.
1960fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    error: The function to call with any errors found.
1961fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  """
1962fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  lines = clean_lines.lines
1963fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  line = lines[linenum]
1964fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  raw = clean_lines.raw_lines
1965fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  raw_line = raw[linenum]
1966fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  joined_line = ''
1967fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1968fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  starting_func = False
1969fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  regexp = r'(\w(\w|::|\*|\&|\s)*)\('  # decls * & space::name( ...
1970fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  match_result = Match(regexp, line)
1971fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  if match_result:
1972fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    # If the name is all caps and underscores, figure it's a macro and
1973fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    # ignore it, unless it's TEST or TEST_F.
1974fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    function_name = match_result.group(1).split()[-1]
1975fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    if function_name == 'TEST' or function_name == 'TEST_F' or (
1976fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        not Match(r'[A-Z_]+$', function_name)):
1977fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      starting_func = True
1978fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
1979fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  if starting_func:
1980fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    body_found = False
1981fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    for start_linenum in xrange(linenum, clean_lines.NumLines()):
1982fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      start_line = lines[start_linenum]
1983fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      joined_line += ' ' + start_line.lstrip()
1984fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      if Search(r'(;|})', start_line):  # Declarations and trivial functions
1985fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        body_found = True
1986fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        break                              # ... ignore
1987fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      elif Search(r'{', start_line):
1988fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        body_found = True
1989fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        function = Search(r'((\w|:)*)\(', line).group(1)
1990fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        if Match(r'TEST', function):    # Handle TEST... macros
1991fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          parameter_regexp = Search(r'(\(.*\))', joined_line)
1992fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          if parameter_regexp:             # Ignore bad syntax
1993fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov            function += parameter_regexp.group(1)
1994fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        else:
1995fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          function += '()'
1996fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        function_state.Begin(function)
1997fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        break
1998fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    if not body_found:
1999fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      # No body for the function (or evidence of a non-function) was found.
2000fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      error(filename, linenum, 'readability/fn_size', 5,
2001fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov            'Lint failed to find start of function body.')
2002fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  elif Match(r'^\}\s*$', line):  # function end
2003fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    function_state.Check(error, filename, linenum)
2004fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    function_state.End()
2005fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  elif not Match(r'^\s*$', line):
2006fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    function_state.Count()  # Count non-blank/non-comment lines.
2007fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
2008fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
2009fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov_RE_PATTERN_TODO = re.compile(r'^//(\s*)TODO(\(.+?\))?:?(\s|$)?')
2010fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
2011fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
2012fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovdef CheckComment(comment, filename, linenum, error):
2013fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  """Checks for common mistakes in TODO comments.
2014fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
2015fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  Args:
2016fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    comment: The text of the comment from the line in question.
2017fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    filename: The name of the current file.
2018fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    linenum: The number of the line to check.
2019fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    error: The function to call with any errors found.
2020fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  """
2021fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  match = _RE_PATTERN_TODO.match(comment)
2022fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  if match:
2023fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    # One whitespace is correct; zero whitespace is handled elsewhere.
2024fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    leading_whitespace = match.group(1)
2025fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    if len(leading_whitespace) > 1:
2026fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      error(filename, linenum, 'whitespace/todo', 2,
2027fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov            'Too many spaces before TODO')
2028fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
2029fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    username = match.group(2)
2030fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    if not username:
2031fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      error(filename, linenum, 'readability/todo', 2,
2032fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov            'Missing username in TODO; it should look like '
2033fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov            '"// TODO(my_username): Stuff."')
2034fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
2035fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    middle_whitespace = match.group(3)
2036fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    # Comparisons made explicit for correctness -- pylint: disable-msg=C6403
2037fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    if middle_whitespace != ' ' and middle_whitespace != '':
2038fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      error(filename, linenum, 'whitespace/todo', 2,
2039fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov            'TODO(my_username) should be followed by a space')
2040fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
2041fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovdef CheckAccess(filename, clean_lines, linenum, nesting_state, error):
2042fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  """Checks for improper use of DISALLOW* macros.
2043fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
2044fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  Args:
2045fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    filename: The name of the current file.
2046fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    clean_lines: A CleansedLines instance containing the file.
2047fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    linenum: The number of the line to check.
2048fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    nesting_state: A _NestingState instance which maintains information about
2049fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov                   the current stack of nested blocks being parsed.
2050fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    error: The function to call with any errors found.
2051fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  """
2052fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  line = clean_lines.elided[linenum]  # get rid of comments and strings
2053fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
2054fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  matched = Match((r'\s*(DISALLOW_COPY_AND_ASSIGN|'
2055fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov                   r'DISALLOW_EVIL_CONSTRUCTORS|'
2056fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov                   r'DISALLOW_IMPLICIT_CONSTRUCTORS)'), line)
2057fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  if not matched:
2058fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    return
2059fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  if nesting_state.stack and isinstance(nesting_state.stack[-1], _ClassInfo):
2060fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    if nesting_state.stack[-1].access != 'private':
2061fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      error(filename, linenum, 'readability/constructors', 3,
2062fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov            '%s must be in the private: section' % matched.group(1))
2063fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
2064fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  else:
2065fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    # Found DISALLOW* macro outside a class declaration, or perhaps it
2066fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    # was used inside a function when it should have been part of the
2067fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    # class declaration.  We could issue a warning here, but it
2068fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    # probably resulted in a compiler error already.
2069fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    pass
2070fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
2071fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
2072fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovdef FindNextMatchingAngleBracket(clean_lines, linenum, init_suffix):
2073fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  """Find the corresponding > to close a template.
2074fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
2075fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  Args:
2076fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    clean_lines: A CleansedLines instance containing the file.
2077fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    linenum: Current line number.
2078fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    init_suffix: Remainder of the current line after the initial <.
2079fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
2080fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  Returns:
2081fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    True if a matching bracket exists.
2082fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  """
2083fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  line = init_suffix
2084fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  nesting_stack = ['<']
2085fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  while True:
2086fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    # Find the next operator that can tell us whether < is used as an
2087fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    # opening bracket or as a less-than operator.  We only want to
2088fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    # warn on the latter case.
2089fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    #
2090fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    # We could also check all other operators and terminate the search
2091fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    # early, e.g. if we got something like this "a<b+c", the "<" is
2092fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    # most likely a less-than operator, but then we will get false
2093fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    # positives for default arguments (e.g. http://go/prccd) and
2094fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    # other template expressions (e.g. http://go/oxcjq).
2095fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    match = Search(r'^[^<>(),;\[\]]*([<>(),;\[\]])(.*)$', line)
2096fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    if match:
2097fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      # Found an operator, update nesting stack
2098fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      operator = match.group(1)
2099fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      line = match.group(2)
2100fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
2101fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      if nesting_stack[-1] == '<':
2102fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        # Expecting closing angle bracket
2103fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        if operator in ('<', '(', '['):
2104fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          nesting_stack.append(operator)
2105fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        elif operator == '>':
2106fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          nesting_stack.pop()
2107fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          if not nesting_stack:
2108fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov            # Found matching angle bracket
2109fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov            return True
2110fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        elif operator == ',':
2111fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          # Got a comma after a bracket, this is most likely a template
2112fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          # argument.  We have not seen a closing angle bracket yet, but
2113fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          # it's probably a few lines later if we look for it, so just
2114fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          # return early here.
2115fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          return True
2116fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        else:
2117fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          # Got some other operator.
2118fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          return False
2119fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
2120fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      else:
2121fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        # Expecting closing parenthesis or closing bracket
2122fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        if operator in ('<', '(', '['):
2123fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          nesting_stack.append(operator)
2124fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        elif operator in (')', ']'):
2125fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          # We don't bother checking for matching () or [].  If we got
2126fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          # something like (] or [), it would have been a syntax error.
2127fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          nesting_stack.pop()
2128fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
2129fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    else:
2130fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      # Scan the next line
2131fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      linenum += 1
2132fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      if linenum >= len(clean_lines.elided):
2133fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        break
2134fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      line = clean_lines.elided[linenum]
2135fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
2136fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # Exhausted all remaining lines and still no matching angle bracket.
2137fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # Most likely the input was incomplete, otherwise we should have
2138fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # seen a semicolon and returned early.
2139fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  return True
2140fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
2141fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
2142fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovdef FindPreviousMatchingAngleBracket(clean_lines, linenum, init_prefix):
2143fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  """Find the corresponding < that started a template.
2144fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
2145fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  Args:
2146fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    clean_lines: A CleansedLines instance containing the file.
2147fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    linenum: Current line number.
2148fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    init_prefix: Part of the current line before the initial >.
2149fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
2150fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  Returns:
2151fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    True if a matching bracket exists.
2152fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  """
2153fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  line = init_prefix
2154fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  nesting_stack = ['>']
2155fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  while True:
2156fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    # Find the previous operator
2157fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    match = Search(r'^(.*)([<>(),;\[\]])[^<>(),;\[\]]*$', line)
2158fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    if match:
2159fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      # Found an operator, update nesting stack
2160fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      operator = match.group(2)
2161fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      line = match.group(1)
2162fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
2163fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      if nesting_stack[-1] == '>':
2164fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        # Expecting opening angle bracket
2165fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        if operator in ('>', ')', ']'):
2166fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          nesting_stack.append(operator)
2167fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        elif operator == '<':
2168fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          nesting_stack.pop()
2169fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          if not nesting_stack:
2170fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov            # Found matching angle bracket
2171fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov            return True
2172fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        elif operator == ',':
2173fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          # Got a comma before a bracket, this is most likely a
2174fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          # template argument.  The opening angle bracket is probably
2175fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          # there if we look for it, so just return early here.
2176fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          return True
2177fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        else:
2178fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          # Got some other operator.
2179fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          return False
2180fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
2181fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      else:
2182fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        # Expecting opening parenthesis or opening bracket
2183fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        if operator in ('>', ')', ']'):
2184fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          nesting_stack.append(operator)
2185fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        elif operator in ('(', '['):
2186fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          nesting_stack.pop()
2187fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
2188fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    else:
2189fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      # Scan the previous line
2190fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      linenum -= 1
2191fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      if linenum < 0:
2192fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        break
2193fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      line = clean_lines.elided[linenum]
2194fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
2195fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # Exhausted all earlier lines and still no matching angle bracket.
2196fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  return False
2197fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
2198fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
2199fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovdef CheckSpacing(filename, clean_lines, linenum, nesting_state, error):
2200fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  """Checks for the correctness of various spacing issues in the code.
2201fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
2202fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  Things we check for: spaces around operators, spaces after
2203fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  if/for/while/switch, no spaces around parens in function calls, two
2204fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  spaces between code and comment, don't start a block with a blank
2205fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  line, don't end a function with a blank line, don't add a blank line
2206fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  after public/protected/private, don't have too many blank lines in a row.
2207fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
2208fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  Args:
2209fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    filename: The name of the current file.
2210fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    clean_lines: A CleansedLines instance containing the file.
2211fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    linenum: The number of the line to check.
2212fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    nesting_state: A _NestingState instance which maintains information about
2213fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov                   the current stack of nested blocks being parsed.
2214fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    error: The function to call with any errors found.
2215fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  """
2216fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
2217fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  raw = clean_lines.raw_lines
2218fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  line = raw[linenum]
2219fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
2220fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # Before nixing comments, check if the line is blank for no good
2221fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # reason.  This includes the first line after a block is opened, and
2222fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # blank lines at the end of a function (ie, right before a line like '}'
2223fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  #
2224fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # Skip all the blank line checks if we are immediately inside a
2225fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # namespace body.  In other words, don't issue blank line warnings
2226fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # for this block:
2227fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  #   namespace {
2228fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  #
2229fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  #   }
2230fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  #
2231fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # A warning about missing end of namespace comments will be issued instead.
2232fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  if IsBlankLine(line) and not nesting_state.InNamespaceBody():
2233fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    elided = clean_lines.elided
2234fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    prev_line = elided[linenum - 1]
2235fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    prevbrace = prev_line.rfind('{')
2236fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    # TODO(unknown): Don't complain if line before blank line, and line after,
2237fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    #                both start with alnums and are indented the same amount.
2238fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    #                This ignores whitespace at the start of a namespace block
2239fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    #                because those are not usually indented.
2240fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    if prevbrace != -1 and prev_line[prevbrace:].find('}') == -1:
2241fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      # OK, we have a blank line at the start of a code block.  Before we
2242fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      # complain, we check if it is an exception to the rule: The previous
2243fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      # non-empty line has the parameters of a function header that are indented
2244fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      # 4 spaces (because they did not fit in a 80 column line when placed on
2245fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      # the same line as the function name).  We also check for the case where
2246fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      # the previous line is indented 6 spaces, which may happen when the
2247fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      # initializers of a constructor do not fit into a 80 column line.
2248fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      exception = False
2249fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      if Match(r' {6}\w', prev_line):  # Initializer list?
2250fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        # We are looking for the opening column of initializer list, which
2251fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        # should be indented 4 spaces to cause 6 space indentation afterwards.
2252fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        search_position = linenum-2
2253fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        while (search_position >= 0
2254fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov               and Match(r' {6}\w', elided[search_position])):
2255fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          search_position -= 1
2256fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        exception = (search_position >= 0
2257fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov                     and elided[search_position][:5] == '    :')
2258fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      else:
2259fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        # Search for the function arguments or an initializer list.  We use a
2260fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        # simple heuristic here: If the line is indented 4 spaces; and we have a
2261fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        # closing paren, without the opening paren, followed by an opening brace
2262fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        # or colon (for initializer lists) we assume that it is the last line of
2263fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        # a function header.  If we have a colon indented 4 spaces, it is an
2264fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        # initializer list.
2265fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        exception = (Match(r' {4}\w[^\(]*\)\s*(const\s*)?(\{\s*$|:)',
2266fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov                           prev_line)
2267fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov                     or Match(r' {4}:', prev_line))
2268fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
2269fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      if not exception:
2270fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        error(filename, linenum, 'whitespace/blank_line', 2,
2271fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov              'Blank line at the start of a code block.  Is this needed?')
2272fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    # Ignore blank lines at the end of a block in a long if-else
2273fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    # chain, like this:
2274fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    #   if (condition1) {
2275fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    #     // Something followed by a blank line
2276fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    #
2277fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    #   } else if (condition2) {
2278fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    #     // Something else
2279fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    #   }
2280fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    if linenum + 1 < clean_lines.NumLines():
2281fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      next_line = raw[linenum + 1]
2282fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      if (next_line
2283fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          and Match(r'\s*}', next_line)
2284fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          and next_line.find('} else ') == -1):
2285fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        error(filename, linenum, 'whitespace/blank_line', 3,
2286fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov              'Blank line at the end of a code block.  Is this needed?')
2287fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
2288fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    matched = Match(r'\s*(public|protected|private):', prev_line)
2289fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    if matched:
2290fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      error(filename, linenum, 'whitespace/blank_line', 3,
2291fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov            'Do not leave a blank line after "%s:"' % matched.group(1))
2292fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
2293fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # Next, we complain if there's a comment too near the text
2294fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  commentpos = line.find('//')
2295fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  if commentpos != -1:
2296fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    # Check if the // may be in quotes.  If so, ignore it
2297fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    # Comparisons made explicit for clarity -- pylint: disable-msg=C6403
2298fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    if (line.count('"', 0, commentpos) -
2299fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        line.count('\\"', 0, commentpos)) % 2 == 0:   # not in quotes
2300fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      # Allow one space for new scopes, two spaces otherwise:
2301fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      if (not Match(r'^\s*{ //', line) and
2302fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          ((commentpos >= 1 and
2303fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov            line[commentpos-1] not in string.whitespace) or
2304fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov           (commentpos >= 2 and
2305fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov            line[commentpos-2] not in string.whitespace))):
2306fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        error(filename, linenum, 'whitespace/comments', 2,
2307fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov              'At least two spaces is best between code and comments')
2308fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      # There should always be a space between the // and the comment
2309fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      commentend = commentpos + 2
2310fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      if commentend < len(line) and not line[commentend] == ' ':
2311fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        # but some lines are exceptions -- e.g. if they're big
2312fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        # comment delimiters like:
2313fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        # //----------------------------------------------------------
2314fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        # or are an empty C++ style Doxygen comment, like:
2315fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        # ///
2316fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        # or they begin with multiple slashes followed by a space:
2317fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        # //////// Header comment
2318fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        match = (Search(r'[=/-]{4,}\s*$', line[commentend:]) or
2319fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov                 Search(r'^/$', line[commentend:]) or
2320fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov                 Search(r'^/+ ', line[commentend:]))
2321fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        if not match:
2322fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          error(filename, linenum, 'whitespace/comments', 4,
2323fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov                'Should have a space between // and comment')
2324fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      CheckComment(line[commentpos:], filename, linenum, error)
2325fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
2326fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  line = clean_lines.elided[linenum]  # get rid of comments and strings
2327fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
2328fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # Don't try to do spacing checks for operator methods
2329fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  line = re.sub(r'operator(==|!=|<|<<|<=|>=|>>|>)\(', 'operator\(', line)
2330fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
2331fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # We allow no-spaces around = within an if: "if ( (a=Foo()) == 0 )".
2332fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # Otherwise not.  Note we only check for non-spaces on *both* sides;
2333fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # sometimes people put non-spaces on one side when aligning ='s among
2334fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # many lines (not that this is behavior that I approve of...)
2335fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  if Search(r'[\w.]=[\w.]', line) and not Search(r'\b(if|while) ', line):
2336fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    error(filename, linenum, 'whitespace/operators', 4,
2337fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          'Missing spaces around =')
2338fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
2339fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # It's ok not to have spaces around binary operators like + - * /, but if
2340fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # there's too little whitespace, we get concerned.  It's hard to tell,
2341fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # though, so we punt on this one for now.  TODO.
2342fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
2343fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # You should always have whitespace around binary operators.
2344fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  #
2345fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # Check <= and >= first to avoid false positives with < and >, then
2346fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # check non-include lines for spacing around < and >.
2347fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  match = Search(r'[^<>=!\s](==|!=|<=|>=)[^<>=!\s]', line)
2348fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  if match:
2349fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    error(filename, linenum, 'whitespace/operators', 3,
2350fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          'Missing spaces around %s' % match.group(1))
2351fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # We allow no-spaces around << when used like this: 10<<20, but
2352fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # not otherwise (particularly, not when used as streams)
2353fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  match = Search(r'(\S)(?:L|UL|ULL|l|ul|ull)?<<(\S)', line)
2354fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  if match and not (match.group(1).isdigit() and match.group(2).isdigit()):
2355fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    error(filename, linenum, 'whitespace/operators', 3,
2356fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          'Missing spaces around <<')
2357fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  elif not Match(r'#.*include', line):
2358fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    # Avoid false positives on ->
2359fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    reduced_line = line.replace('->', '')
2360fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
2361fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    # Look for < that is not surrounded by spaces.  This is only
2362fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    # triggered if both sides are missing spaces, even though
2363fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    # technically should should flag if at least one side is missing a
2364fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    # space.  This is done to avoid some false positives with shifts.
2365fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    match = Search(r'[^\s<]<([^\s=<].*)', reduced_line)
2366fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    if (match and
2367fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        not FindNextMatchingAngleBracket(clean_lines, linenum, match.group(1))):
2368fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      error(filename, linenum, 'whitespace/operators', 3,
2369fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov            'Missing spaces around <')
2370fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
2371fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    # Look for > that is not surrounded by spaces.  Similar to the
2372fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    # above, we only trigger if both sides are missing spaces to avoid
2373fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    # false positives with shifts.
2374fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    match = Search(r'^(.*[^\s>])>[^\s=>]', reduced_line)
2375fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    if (match and
2376fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        not FindPreviousMatchingAngleBracket(clean_lines, linenum,
2377fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov                                             match.group(1))):
2378fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      error(filename, linenum, 'whitespace/operators', 3,
2379fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov            'Missing spaces around >')
2380fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
2381fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # We allow no-spaces around >> for almost anything.  This is because
2382fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # C++11 allows ">>" to close nested templates, which accounts for
2383fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # most cases when ">>" is not followed by a space.
2384fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  #
2385fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # We still warn on ">>" followed by alpha character, because that is
2386fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # likely due to ">>" being used for right shifts, e.g.:
2387fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  #   value >> alpha
2388fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  #
2389fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # When ">>" is used to close templates, the alphanumeric letter that
2390fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # follows would be part of an identifier, and there should still be
2391fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # a space separating the template type and the identifier.
2392fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  #   type<type<type>> alpha
2393fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  match = Search(r'>>[a-zA-Z_]', line)
2394fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  if match:
2395fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    error(filename, linenum, 'whitespace/operators', 3,
2396fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          'Missing spaces around >>')
2397fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
2398fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # There shouldn't be space around unary operators
2399fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  match = Search(r'(!\s|~\s|[\s]--[\s;]|[\s]\+\+[\s;])', line)
2400fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  if match:
2401fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    error(filename, linenum, 'whitespace/operators', 4,
2402fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          'Extra space for operator %s' % match.group(1))
2403fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
2404fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # A pet peeve of mine: no spaces after an if, while, switch, or for
2405fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  match = Search(r' (if\(|for\(|while\(|switch\()', line)
2406fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  if match:
2407fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    error(filename, linenum, 'whitespace/parens', 5,
2408fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          'Missing space before ( in %s' % match.group(1))
2409fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
2410fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # For if/for/while/switch, the left and right parens should be
2411fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # consistent about how many spaces are inside the parens, and
2412fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # there should either be zero or one spaces inside the parens.
2413fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # We don't want: "if ( foo)" or "if ( foo   )".
2414fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # Exception: "for ( ; foo; bar)" and "for (foo; bar; )" are allowed.
2415fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  match = Search(r'\b(if|for|while|switch)\s*'
2416fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov                 r'\(([ ]*)(.).*[^ ]+([ ]*)\)\s*{\s*$',
2417fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov                 line)
2418fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  if match:
2419fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    if len(match.group(2)) != len(match.group(4)):
2420fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      if not (match.group(3) == ';' and
2421fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov              len(match.group(2)) == 1 + len(match.group(4)) or
2422fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov              not match.group(2) and Search(r'\bfor\s*\(.*; \)', line)):
2423fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        error(filename, linenum, 'whitespace/parens', 5,
2424fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov              'Mismatching spaces inside () in %s' % match.group(1))
2425fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    if not len(match.group(2)) in [0, 1]:
2426fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      error(filename, linenum, 'whitespace/parens', 5,
2427fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov            'Should have zero or one spaces inside ( and ) in %s' %
2428fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov            match.group(1))
2429fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
2430fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # You should always have a space after a comma (either as fn arg or operator)
2431fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  if Search(r',[^\s]', line):
2432fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    error(filename, linenum, 'whitespace/comma', 3,
2433fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          'Missing space after ,')
2434fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
2435fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # You should always have a space after a semicolon
2436fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # except for few corner cases
2437fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # TODO(unknown): clarify if 'if (1) { return 1;}' is requires one more
2438fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # space after ;
2439fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  if Search(r';[^\s};\\)/]', line):
2440fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    error(filename, linenum, 'whitespace/semicolon', 3,
2441fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          'Missing space after ;')
2442fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
2443fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # Next we will look for issues with function calls.
2444fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  CheckSpacingForFunctionCall(filename, line, linenum, error)
2445fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
2446fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # Except after an opening paren, or after another opening brace (in case of
2447fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # an initializer list, for instance), you should have spaces before your
2448fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # braces. And since you should never have braces at the beginning of a line,
2449fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # this is an easy test.
2450fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  if Search(r'[^ ({]{', line):
2451fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    error(filename, linenum, 'whitespace/braces', 5,
2452fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          'Missing space before {')
2453fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
2454fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # Make sure '} else {' has spaces.
2455fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  if Search(r'}else', line):
2456fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    error(filename, linenum, 'whitespace/braces', 5,
2457fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          'Missing space before else')
2458fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
2459fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # You shouldn't have spaces before your brackets, except maybe after
2460fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # 'delete []' or 'new char * []'.
2461fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  if Search(r'\w\s+\[', line) and not Search(r'delete\s+\[', line):
2462fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    error(filename, linenum, 'whitespace/braces', 5,
2463fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          'Extra space before [')
2464fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
2465fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # You shouldn't have a space before a semicolon at the end of the line.
2466fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # There's a special case for "for" since the style guide allows space before
2467fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # the semicolon there.
2468fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  if Search(r':\s*;\s*$', line):
2469fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    error(filename, linenum, 'whitespace/semicolon', 5,
2470fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          'Semicolon defining empty statement. Use {} instead.')
2471fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  elif Search(r'^\s*;\s*$', line):
2472fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    error(filename, linenum, 'whitespace/semicolon', 5,
2473fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          'Line contains only semicolon. If this should be an empty statement, '
2474fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          'use {} instead.')
2475fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  elif (Search(r'\s+;\s*$', line) and
2476fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        not Search(r'\bfor\b', line)):
2477fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    error(filename, linenum, 'whitespace/semicolon', 5,
2478fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          'Extra space before last semicolon. If this should be an empty '
2479fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          'statement, use {} instead.')
2480fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
2481fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # In range-based for, we wanted spaces before and after the colon, but
2482fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # not around "::" tokens that might appear.
2483fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  if (Search('for *\(.*[^:]:[^: ]', line) or
2484fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      Search('for *\(.*[^: ]:[^:]', line)):
2485fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    error(filename, linenum, 'whitespace/forcolon', 2,
2486fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          'Missing space around colon in range-based for loop')
2487fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
2488fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
2489fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovdef CheckSectionSpacing(filename, clean_lines, class_info, linenum, error):
2490fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  """Checks for additional blank line issues related to sections.
2491fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
2492fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  Currently the only thing checked here is blank line before protected/private.
2493fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
2494fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  Args:
2495fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    filename: The name of the current file.
2496fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    clean_lines: A CleansedLines instance containing the file.
2497fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    class_info: A _ClassInfo objects.
2498fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    linenum: The number of the line to check.
2499fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    error: The function to call with any errors found.
2500fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  """
2501fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # Skip checks if the class is small, where small means 25 lines or less.
2502fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # 25 lines seems like a good cutoff since that's the usual height of
2503fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # terminals, and any class that can't fit in one screen can't really
2504fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # be considered "small".
2505fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  #
2506fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # Also skip checks if we are on the first line.  This accounts for
2507fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # classes that look like
2508fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  #   class Foo { public: ... };
2509fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  #
2510fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # If we didn't find the end of the class, last_line would be zero,
2511fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # and the check will be skipped by the first condition.
2512fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  if (class_info.last_line - class_info.starting_linenum <= 24 or
2513fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      linenum <= class_info.starting_linenum):
2514fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    return
2515fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
2516fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  matched = Match(r'\s*(public|protected|private):', clean_lines.lines[linenum])
2517fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  if matched:
2518fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    # Issue warning if the line before public/protected/private was
2519fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    # not a blank line, but don't do this if the previous line contains
2520fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    # "class" or "struct".  This can happen two ways:
2521fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    #  - We are at the beginning of the class.
2522fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    #  - We are forward-declaring an inner class that is semantically
2523fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    #    private, but needed to be public for implementation reasons.
2524fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    # Also ignores cases where the previous line ends with a backslash as can be
2525fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    # common when defining classes in C macros.
2526fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    prev_line = clean_lines.lines[linenum - 1]
2527fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    if (not IsBlankLine(prev_line) and
2528fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        not Search(r'\b(class|struct)\b', prev_line) and
2529fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        not Search(r'\\$', prev_line)):
2530fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      # Try a bit harder to find the beginning of the class.  This is to
2531fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      # account for multi-line base-specifier lists, e.g.:
2532fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      #   class Derived
2533fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      #       : public Base {
2534fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      end_class_head = class_info.starting_linenum
2535fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      for i in range(class_info.starting_linenum, linenum):
2536fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        if Search(r'\{\s*$', clean_lines.lines[i]):
2537fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          end_class_head = i
2538fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          break
2539fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      if end_class_head < linenum - 1:
2540fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        error(filename, linenum, 'whitespace/blank_line', 3,
2541fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov              '"%s:" should be preceded by a blank line' % matched.group(1))
2542fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
2543fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
2544fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovdef GetPreviousNonBlankLine(clean_lines, linenum):
2545fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  """Return the most recent non-blank line and its line number.
2546fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
2547fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  Args:
2548fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    clean_lines: A CleansedLines instance containing the file contents.
2549fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    linenum: The number of the line to check.
2550fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
2551fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  Returns:
2552fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    A tuple with two elements.  The first element is the contents of the last
2553fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    non-blank line before the current line, or the empty string if this is the
2554fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    first non-blank line.  The second is the line number of that line, or -1
2555fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    if this is the first non-blank line.
2556fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  """
2557fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
2558fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  prevlinenum = linenum - 1
2559fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  while prevlinenum >= 0:
2560fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    prevline = clean_lines.elided[prevlinenum]
2561fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    if not IsBlankLine(prevline):     # if not a blank line...
2562fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      return (prevline, prevlinenum)
2563fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    prevlinenum -= 1
2564fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  return ('', -1)
2565fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
2566fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
2567fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovdef CheckBraces(filename, clean_lines, linenum, error):
2568fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  """Looks for misplaced braces (e.g. at the end of line).
2569fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
2570fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  Args:
2571fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    filename: The name of the current file.
2572fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    clean_lines: A CleansedLines instance containing the file.
2573fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    linenum: The number of the line to check.
2574fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    error: The function to call with any errors found.
2575fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  """
2576fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
2577fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  line = clean_lines.elided[linenum]        # get rid of comments and strings
2578fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
2579fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  if Match(r'\s*{\s*$', line):
2580fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    # We allow an open brace to start a line in the case where someone
2581fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    # is using braces in a block to explicitly create a new scope,
2582fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    # which is commonly used to control the lifetime of
2583fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    # stack-allocated variables.  We don't detect this perfectly: we
2584fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    # just don't complain if the last non-whitespace character on the
2585fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    # previous non-blank line is ';', ':', '{', or '}', or if the previous
2586fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    # line starts a preprocessor block.
2587fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    prevline = GetPreviousNonBlankLine(clean_lines, linenum)[0]
2588fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    if (not Search(r'[;:}{]\s*$', prevline) and
2589fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        not Match(r'\s*#', prevline)):
2590fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      error(filename, linenum, 'whitespace/braces', 4,
2591fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov            '{ should almost always be at the end of the previous line')
2592fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
2593fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # An else clause should be on the same line as the preceding closing brace.
2594fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  if Match(r'\s*else\s*', line):
2595fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    prevline = GetPreviousNonBlankLine(clean_lines, linenum)[0]
2596fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    if Match(r'\s*}\s*$', prevline):
2597fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      error(filename, linenum, 'whitespace/newline', 4,
2598fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov            'An else should appear on the same line as the preceding }')
2599fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
2600fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # If braces come on one side of an else, they should be on both.
2601fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # However, we have to worry about "else if" that spans multiple lines!
2602fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  if Search(r'}\s*else[^{]*$', line) or Match(r'[^}]*else\s*{', line):
2603fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    if Search(r'}\s*else if([^{]*)$', line):       # could be multi-line if
2604fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      # find the ( after the if
2605fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      pos = line.find('else if')
2606fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      pos = line.find('(', pos)
2607fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      if pos > 0:
2608fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        (endline, _, endpos) = CloseExpression(clean_lines, linenum, pos)
2609fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        if endline[endpos:].find('{') == -1:    # must be brace after if
2610fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          error(filename, linenum, 'readability/braces', 5,
2611fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov                'If an else has a brace on one side, it should have it on both')
2612fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    else:            # common case: else not followed by a multi-line if
2613fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      error(filename, linenum, 'readability/braces', 5,
2614fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov            'If an else has a brace on one side, it should have it on both')
2615fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
2616fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # Likewise, an else should never have the else clause on the same line
2617fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  if Search(r'\belse [^\s{]', line) and not Search(r'\belse if\b', line):
2618fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    error(filename, linenum, 'whitespace/newline', 4,
2619fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          'Else clause should never be on same line as else (use 2 lines)')
2620fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
2621fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # In the same way, a do/while should never be on one line
2622fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  if Match(r'\s*do [^\s{]', line):
2623fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    error(filename, linenum, 'whitespace/newline', 4,
2624fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          'do/while clauses should not be on a single line')
2625fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
2626fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # Braces shouldn't be followed by a ; unless they're defining a struct
2627fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # or initializing an array.
2628fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # We can't tell in general, but we can for some common cases.
2629fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  prevlinenum = linenum
2630fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  while True:
2631fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    (prevline, prevlinenum) = GetPreviousNonBlankLine(clean_lines, prevlinenum)
2632fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    if Match(r'\s+{.*}\s*;', line) and not prevline.count(';'):
2633fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      line = prevline + line
2634fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    else:
2635fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      break
2636fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  if (Search(r'{.*}\s*;', line) and
2637fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      line.count('{') == line.count('}') and
2638fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      not Search(r'struct|class|enum|\s*=\s*{', line)):
2639fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    error(filename, linenum, 'readability/braces', 4,
2640fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          "You don't need a ; after a }")
2641fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
2642fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
2643fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovdef CheckEmptyLoopBody(filename, clean_lines, linenum, error):
2644fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  """Loop for empty loop body with only a single semicolon.
2645fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
2646fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  Args:
2647fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    filename: The name of the current file.
2648fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    clean_lines: A CleansedLines instance containing the file.
2649fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    linenum: The number of the line to check.
2650fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    error: The function to call with any errors found.
2651fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  """
2652fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
2653fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # Search for loop keywords at the beginning of the line.  Because only
2654fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # whitespaces are allowed before the keywords, this will also ignore most
2655fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # do-while-loops, since those lines should start with closing brace.
2656fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  line = clean_lines.elided[linenum]
2657fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  if Match(r'\s*(for|while)\s*\(', line):
2658fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    # Find the end of the conditional expression
2659fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    (end_line, end_linenum, end_pos) = CloseExpression(
2660fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        clean_lines, linenum, line.find('('))
2661fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
2662fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    # Output warning if what follows the condition expression is a semicolon.
2663fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    # No warning for all other cases, including whitespace or newline, since we
2664fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    # have a separate check for semicolons preceded by whitespace.
2665fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    if end_pos >= 0 and Match(r';', end_line[end_pos:]):
2666fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      error(filename, end_linenum, 'whitespace/empty_loop_body', 5,
2667fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov            'Empty loop bodies should use {} or continue')
2668fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
2669fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
2670fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovdef ReplaceableCheck(operator, macro, line):
2671fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  """Determine whether a basic CHECK can be replaced with a more specific one.
2672fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
2673fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  For example suggest using CHECK_EQ instead of CHECK(a == b) and
2674fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  similarly for CHECK_GE, CHECK_GT, CHECK_LE, CHECK_LT, CHECK_NE.
2675fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
2676fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  Args:
2677fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    operator: The C++ operator used in the CHECK.
2678fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    macro: The CHECK or EXPECT macro being called.
2679fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    line: The current source line.
2680fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
2681fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  Returns:
2682fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    True if the CHECK can be replaced with a more specific one.
2683fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  """
2684fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
2685fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # This matches decimal and hex integers, strings, and chars (in that order).
2686fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  match_constant = r'([-+]?(\d+|0[xX][0-9a-fA-F]+)[lLuU]{0,3}|".*"|\'.*\')'
2687fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
2688fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # Expression to match two sides of the operator with something that
2689fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # looks like a literal, since CHECK(x == iterator) won't compile.
2690fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # This means we can't catch all the cases where a more specific
2691fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # CHECK is possible, but it's less annoying than dealing with
2692fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # extraneous warnings.
2693fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  match_this = (r'\s*' + macro + r'\((\s*' +
2694fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov                match_constant + r'\s*' + operator + r'[^<>].*|'
2695fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov                r'.*[^<>]' + operator + r'\s*' + match_constant +
2696fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov                r'\s*\))')
2697fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
2698fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # Don't complain about CHECK(x == NULL) or similar because
2699fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # CHECK_EQ(x, NULL) won't compile (requires a cast).
2700fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # Also, don't complain about more complex boolean expressions
2701fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # involving && or || such as CHECK(a == b || c == d).
2702fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  return Match(match_this, line) and not Search(r'NULL|&&|\|\|', line)
2703fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
2704fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
2705fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovdef CheckCheck(filename, clean_lines, linenum, error):
2706fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  """Checks the use of CHECK and EXPECT macros.
2707fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
2708fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  Args:
2709fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    filename: The name of the current file.
2710fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    clean_lines: A CleansedLines instance containing the file.
2711fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    linenum: The number of the line to check.
2712fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    error: The function to call with any errors found.
2713fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  """
2714fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
2715fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # Decide the set of replacement macros that should be suggested
2716fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  raw_lines = clean_lines.raw_lines
2717fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  current_macro = ''
2718fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  for macro in _CHECK_MACROS:
2719fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    if raw_lines[linenum].find(macro) >= 0:
2720fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      current_macro = macro
2721fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      break
2722fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  if not current_macro:
2723fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    # Don't waste time here if line doesn't contain 'CHECK' or 'EXPECT'
2724fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    return
2725fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
2726fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  line = clean_lines.elided[linenum]        # get rid of comments and strings
2727fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
2728fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # Encourage replacing plain CHECKs with CHECK_EQ/CHECK_NE/etc.
2729fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  for operator in ['==', '!=', '>=', '>', '<=', '<']:
2730fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    if ReplaceableCheck(operator, current_macro, line):
2731fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      error(filename, linenum, 'readability/check', 2,
2732fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov            'Consider using %s instead of %s(a %s b)' % (
2733fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov                _CHECK_REPLACEMENT[current_macro][operator],
2734fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov                current_macro, operator))
2735fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      break
2736fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
2737fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
2738fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovdef CheckAltTokens(filename, clean_lines, linenum, error):
2739fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  """Check alternative keywords being used in boolean expressions.
2740fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
2741fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  Args:
2742fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    filename: The name of the current file.
2743fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    clean_lines: A CleansedLines instance containing the file.
2744fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    linenum: The number of the line to check.
2745fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    error: The function to call with any errors found.
2746fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  """
2747fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  line = clean_lines.elided[linenum]
2748fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
2749fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # Avoid preprocessor lines
2750fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  if Match(r'^\s*#', line):
2751fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    return
2752fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
2753fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # Last ditch effort to avoid multi-line comments.  This will not help
2754fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # if the comment started before the current line or ended after the
2755fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # current line, but it catches most of the false positives.  At least,
2756fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # it provides a way to workaround this warning for people who use
2757fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # multi-line comments in preprocessor macros.
2758fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  #
2759fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # TODO(unknown): remove this once cpplint has better support for
2760fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # multi-line comments.
2761fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  if line.find('/*') >= 0 or line.find('*/') >= 0:
2762fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    return
2763fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
2764fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  for match in _ALT_TOKEN_REPLACEMENT_PATTERN.finditer(line):
2765fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    error(filename, linenum, 'readability/alt_tokens', 2,
2766fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          'Use operator %s instead of %s' % (
2767fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov              _ALT_TOKEN_REPLACEMENT[match.group(1)], match.group(1)))
2768fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
2769fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
2770fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovdef GetLineWidth(line):
2771fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  """Determines the width of the line in column positions.
2772fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
2773fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  Args:
2774fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    line: A string, which may be a Unicode string.
2775fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
2776fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  Returns:
2777fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    The width of the line in column positions, accounting for Unicode
2778fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    combining characters and wide characters.
2779fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  """
2780fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  if isinstance(line, unicode):
2781fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    width = 0
2782fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    for uc in unicodedata.normalize('NFC', line):
2783fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      if unicodedata.east_asian_width(uc) in ('W', 'F'):
2784fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        width += 2
2785fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      elif not unicodedata.combining(uc):
2786fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        width += 1
2787fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    return width
2788fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  else:
2789fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    return len(line)
2790fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
2791fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
2792fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovdef CheckStyle(filename, clean_lines, linenum, file_extension, nesting_state,
2793fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov               error):
2794fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  """Checks rules from the 'C++ style rules' section of cppguide.html.
2795fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
2796fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  Most of these rules are hard to test (naming, comment style), but we
2797fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  do what we can.  In particular we check for 2-space indents, line lengths,
2798fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  tab usage, spaces inside code, etc.
2799fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
2800fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  Args:
2801fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    filename: The name of the current file.
2802fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    clean_lines: A CleansedLines instance containing the file.
2803fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    linenum: The number of the line to check.
2804fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    file_extension: The extension (without the dot) of the filename.
2805fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    nesting_state: A _NestingState instance which maintains information about
2806fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov                   the current stack of nested blocks being parsed.
2807fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    error: The function to call with any errors found.
2808fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  """
2809fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
2810fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  raw_lines = clean_lines.raw_lines
2811fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  line = raw_lines[linenum]
2812fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
2813fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  if line.find('\t') != -1:
2814fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    error(filename, linenum, 'whitespace/tab', 1,
2815fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          'Tab found; better to use spaces')
2816fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
2817fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # One or three blank spaces at the beginning of the line is weird; it's
2818fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # hard to reconcile that with 2-space indents.
2819fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # NOTE: here are the conditions rob pike used for his tests.  Mine aren't
2820fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # as sophisticated, but it may be worth becoming so:  RLENGTH==initial_spaces
2821fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # if(RLENGTH > 20) complain = 0;
2822fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # if(match($0, " +(error|private|public|protected):")) complain = 0;
2823fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # if(match(prev, "&& *$")) complain = 0;
2824fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # if(match(prev, "\\|\\| *$")) complain = 0;
2825fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # if(match(prev, "[\",=><] *$")) complain = 0;
2826fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # if(match($0, " <<")) complain = 0;
2827fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # if(match(prev, " +for \\(")) complain = 0;
2828fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # if(prevodd && match(prevprev, " +for \\(")) complain = 0;
2829fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  initial_spaces = 0
2830fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  cleansed_line = clean_lines.elided[linenum]
2831fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  while initial_spaces < len(line) and line[initial_spaces] == ' ':
2832fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    initial_spaces += 1
2833fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  if line and line[-1].isspace():
2834fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    error(filename, linenum, 'whitespace/end_of_line', 4,
2835fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          'Line ends in whitespace.  Consider deleting these extra spaces.')
2836fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # There are certain situations we allow one space, notably for labels
2837fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  elif ((initial_spaces == 1 or initial_spaces == 3) and
2838fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        not Match(r'\s*\w+\s*:\s*$', cleansed_line)):
2839fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    error(filename, linenum, 'whitespace/indent', 3,
2840fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          'Weird number of spaces at line-start.  '
2841fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          'Are you using a 2-space indent?')
2842fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # Labels should always be indented at least one space.
2843fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  elif not initial_spaces and line[:2] != '//' and Search(r'[^:]:\s*$',
2844fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov                                                          line):
2845fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    error(filename, linenum, 'whitespace/labels', 4,
2846fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          'Labels should always be indented at least one space.  '
2847fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          'If this is a member-initializer list in a constructor or '
2848fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          'the base class list in a class definition, the colon should '
2849fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          'be on the following line.')
2850fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
2851fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
2852fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # Check if the line is a header guard.
2853fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  is_header_guard = False
2854fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  if file_extension == 'h':
2855fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    cppvar = GetHeaderGuardCPPVariable(filename)
2856fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    if (line.startswith('#ifndef %s' % cppvar) or
2857fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        line.startswith('#define %s' % cppvar) or
2858fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        line.startswith('#endif  // %s' % cppvar)):
2859fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      is_header_guard = True
2860fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # #include lines and header guards can be long, since there's no clean way to
2861fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # split them.
2862fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  #
2863fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # URLs can be long too.  It's possible to split these, but it makes them
2864fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # harder to cut&paste.
2865fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  #
2866fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # The "$Id:...$" comment may also get very long without it being the
2867fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # developers fault.
2868fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  if (not line.startswith('#include') and not is_header_guard and
2869fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      not Match(r'^\s*//.*http(s?)://\S*$', line) and
2870fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      not Match(r'^// \$Id:.*#[0-9]+ \$$', line)):
2871fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    line_width = GetLineWidth(line)
2872fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    if line_width > 100:
2873fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      error(filename, linenum, 'whitespace/line_length', 4,
2874fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov            'Lines should very rarely be longer than 100 characters')
2875fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    elif line_width > 80:
2876fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      error(filename, linenum, 'whitespace/line_length', 2,
2877fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov            'Lines should be <= 80 characters long')
2878fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
2879fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  if (cleansed_line.count(';') > 1 and
2880fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      # for loops are allowed two ;'s (and may run over two lines).
2881fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      cleansed_line.find('for') == -1 and
2882fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      (GetPreviousNonBlankLine(clean_lines, linenum)[0].find('for') == -1 or
2883fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov       GetPreviousNonBlankLine(clean_lines, linenum)[0].find(';') != -1) and
2884fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      # It's ok to have many commands in a switch case that fits in 1 line
2885fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      not ((cleansed_line.find('case ') != -1 or
2886fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov            cleansed_line.find('default:') != -1) and
2887fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov           cleansed_line.find('break;') != -1)):
2888fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    error(filename, linenum, 'whitespace/newline', 0,
2889fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          'More than one command on the same line')
2890fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
2891fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # Some more style checks
2892fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  CheckBraces(filename, clean_lines, linenum, error)
2893fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  CheckEmptyLoopBody(filename, clean_lines, linenum, error)
2894fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  CheckAccess(filename, clean_lines, linenum, nesting_state, error)
2895fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  CheckSpacing(filename, clean_lines, linenum, nesting_state, error)
2896fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  CheckCheck(filename, clean_lines, linenum, error)
2897fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  CheckAltTokens(filename, clean_lines, linenum, error)
2898fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  classinfo = nesting_state.InnermostClass()
2899fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  if classinfo:
2900fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    CheckSectionSpacing(filename, clean_lines, classinfo, linenum, error)
2901fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
2902fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
2903fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov_RE_PATTERN_INCLUDE_NEW_STYLE = re.compile(r'#include +"[^/]+\.h"')
2904fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov_RE_PATTERN_INCLUDE = re.compile(r'^\s*#\s*include\s*([<"])([^>"]*)[>"].*$')
2905fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# Matches the first component of a filename delimited by -s and _s. That is:
2906fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov#  _RE_FIRST_COMPONENT.match('foo').group(0) == 'foo'
2907fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov#  _RE_FIRST_COMPONENT.match('foo.cc').group(0) == 'foo'
2908fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov#  _RE_FIRST_COMPONENT.match('foo-bar_baz.cc').group(0) == 'foo'
2909fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov#  _RE_FIRST_COMPONENT.match('foo_bar-baz.cc').group(0) == 'foo'
2910fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov_RE_FIRST_COMPONENT = re.compile(r'^[^-_.]+')
2911fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
2912fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
2913fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovdef _DropCommonSuffixes(filename):
2914fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  """Drops common suffixes like _test.cc or -inl.h from filename.
2915fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
2916fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  For example:
2917fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    >>> _DropCommonSuffixes('foo/foo-inl.h')
2918fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    'foo/foo'
2919fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    >>> _DropCommonSuffixes('foo/bar/foo.cc')
2920fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    'foo/bar/foo'
2921fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    >>> _DropCommonSuffixes('foo/foo_internal.h')
2922fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    'foo/foo'
2923fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    >>> _DropCommonSuffixes('foo/foo_unusualinternal.h')
2924fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    'foo/foo_unusualinternal'
2925fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
2926fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  Args:
2927fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    filename: The input filename.
2928fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
2929fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  Returns:
2930fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    The filename with the common suffix removed.
2931fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  """
2932fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  for suffix in ('test.cc', 'regtest.cc', 'unittest.cc',
2933fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov                 'inl.h', 'impl.h', 'internal.h'):
2934fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    if (filename.endswith(suffix) and len(filename) > len(suffix) and
2935fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        filename[-len(suffix) - 1] in ('-', '_')):
2936fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      return filename[:-len(suffix) - 1]
2937fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  return os.path.splitext(filename)[0]
2938fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
2939fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
2940fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovdef _IsTestFilename(filename):
2941fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  """Determines if the given filename has a suffix that identifies it as a test.
2942fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
2943fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  Args:
2944fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    filename: The input filename.
2945fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
2946fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  Returns:
2947fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    True if 'filename' looks like a test, False otherwise.
2948fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  """
2949fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  if (filename.endswith('_test.cc') or
2950fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      filename.endswith('_unittest.cc') or
2951fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      filename.endswith('_regtest.cc')):
2952fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    return True
2953fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  else:
2954fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    return False
2955fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
2956fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
2957fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovdef _ClassifyInclude(fileinfo, include, is_system):
2958fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  """Figures out what kind of header 'include' is.
2959fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
2960fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  Args:
2961fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    fileinfo: The current file cpplint is running over. A FileInfo instance.
2962fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    include: The path to a #included file.
2963fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    is_system: True if the #include used <> rather than "".
2964fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
2965fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  Returns:
2966fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    One of the _XXX_HEADER constants.
2967fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
2968fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  For example:
2969fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    >>> _ClassifyInclude(FileInfo('foo/foo.cc'), 'stdio.h', True)
2970fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    _C_SYS_HEADER
2971fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    >>> _ClassifyInclude(FileInfo('foo/foo.cc'), 'string', True)
2972fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    _CPP_SYS_HEADER
2973fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    >>> _ClassifyInclude(FileInfo('foo/foo.cc'), 'foo/foo.h', False)
2974fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    _LIKELY_MY_HEADER
2975fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    >>> _ClassifyInclude(FileInfo('foo/foo_unknown_extension.cc'),
2976fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    ...                  'bar/foo_other_ext.h', False)
2977fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    _POSSIBLE_MY_HEADER
2978fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    >>> _ClassifyInclude(FileInfo('foo/foo.cc'), 'foo/bar.h', False)
2979fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    _OTHER_HEADER
2980fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  """
2981fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # This is a list of all standard c++ header files, except
2982fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # those already checked for above.
2983fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  is_stl_h = include in _STL_HEADERS
2984fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  is_cpp_h = is_stl_h or include in _CPP_HEADERS
2985fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
2986fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  if is_system:
2987fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    if is_cpp_h:
2988fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      return _CPP_SYS_HEADER
2989fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    else:
2990fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      return _C_SYS_HEADER
2991fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
2992fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # If the target file and the include we're checking share a
2993fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # basename when we drop common extensions, and the include
2994fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # lives in . , then it's likely to be owned by the target file.
2995fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  target_dir, target_base = (
2996fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      os.path.split(_DropCommonSuffixes(fileinfo.RepositoryName())))
2997fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  include_dir, include_base = os.path.split(_DropCommonSuffixes(include))
2998fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  if target_base == include_base and (
2999fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      include_dir == target_dir or
3000fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      include_dir == os.path.normpath(target_dir + '/../public')):
3001fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    return _LIKELY_MY_HEADER
3002fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
3003fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # If the target and include share some initial basename
3004fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # component, it's possible the target is implementing the
3005fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # include, so it's allowed to be first, but we'll never
3006fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # complain if it's not there.
3007fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  target_first_component = _RE_FIRST_COMPONENT.match(target_base)
3008fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  include_first_component = _RE_FIRST_COMPONENT.match(include_base)
3009fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  if (target_first_component and include_first_component and
3010fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      target_first_component.group(0) ==
3011fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      include_first_component.group(0)):
3012fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    return _POSSIBLE_MY_HEADER
3013fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
3014fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  return _OTHER_HEADER
3015fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
3016fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
3017fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
3018fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovdef CheckIncludeLine(filename, clean_lines, linenum, include_state, error):
3019fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  """Check rules that are applicable to #include lines.
3020fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
3021fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  Strings on #include lines are NOT removed from elided line, to make
3022fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  certain tasks easier. However, to prevent false positives, checks
3023fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  applicable to #include lines in CheckLanguage must be put here.
3024fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
3025fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  Args:
3026fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    filename: The name of the current file.
3027fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    clean_lines: A CleansedLines instance containing the file.
3028fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    linenum: The number of the line to check.
3029fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    include_state: An _IncludeState instance in which the headers are inserted.
3030fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    error: The function to call with any errors found.
3031fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  """
3032fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  fileinfo = FileInfo(filename)
3033fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
3034fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  line = clean_lines.lines[linenum]
3035fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
3036fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # "include" should use the new style "foo/bar.h" instead of just "bar.h"
3037fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  if _RE_PATTERN_INCLUDE_NEW_STYLE.search(line):
3038fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    error(filename, linenum, 'build/include', 4,
3039fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          'Include the directory when naming .h files')
3040fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
3041fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # we shouldn't include a file more than once. actually, there are a
3042fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # handful of instances where doing so is okay, but in general it's
3043fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # not.
3044fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  match = _RE_PATTERN_INCLUDE.search(line)
3045fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  if match:
3046fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    include = match.group(2)
3047fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    is_system = (match.group(1) == '<')
3048fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    if include in include_state:
3049fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      error(filename, linenum, 'build/include', 4,
3050fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov            '"%s" already included at %s:%s' %
3051fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov            (include, filename, include_state[include]))
3052fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    else:
3053fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      include_state[include] = linenum
3054fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
3055fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      # We want to ensure that headers appear in the right order:
3056fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      # 1) for foo.cc, foo.h  (preferred location)
3057fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      # 2) c system files
3058fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      # 3) cpp system files
3059fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      # 4) for foo.cc, foo.h  (deprecated location)
3060fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      # 5) other google headers
3061fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      #
3062fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      # We classify each include statement as one of those 5 types
3063fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      # using a number of techniques. The include_state object keeps
3064fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      # track of the highest type seen, and complains if we see a
3065fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      # lower type after that.
3066fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      error_message = include_state.CheckNextIncludeOrder(
3067fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          _ClassifyInclude(fileinfo, include, is_system))
3068fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      if error_message:
3069fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        error(filename, linenum, 'build/include_order', 4,
3070fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov              '%s. Should be: %s.h, c system, c++ system, other.' %
3071fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov              (error_message, fileinfo.BaseName()))
3072fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      if not include_state.IsInAlphabeticalOrder(include):
3073fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        error(filename, linenum, 'build/include_alpha', 4,
3074fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov              'Include "%s" not in alphabetical order' % include)
3075fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
3076fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # Look for any of the stream classes that are part of standard C++.
3077fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  match = _RE_PATTERN_INCLUDE.match(line)
3078fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  if match:
3079fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    include = match.group(2)
3080fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    if Match(r'(f|ind|io|i|o|parse|pf|stdio|str|)?stream$', include):
3081fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      # Many unit tests use cout, so we exempt them.
3082fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      if not _IsTestFilename(filename):
3083fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        error(filename, linenum, 'readability/streams', 3,
3084fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov              'Streams are highly discouraged.')
3085fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
3086fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
3087fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovdef _GetTextInside(text, start_pattern):
3088fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  """Retrieves all the text between matching open and close parentheses.
3089fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
3090fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  Given a string of lines and a regular expression string, retrieve all the text
3091fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  following the expression and between opening punctuation symbols like
3092fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  (, [, or {, and the matching close-punctuation symbol. This properly nested
3093fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  occurrences of the punctuations, so for the text like
3094fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    printf(a(), b(c()));
3095fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  a call to _GetTextInside(text, r'printf\(') will return 'a(), b(c())'.
3096fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  start_pattern must match string having an open punctuation symbol at the end.
3097fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
3098fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  Args:
3099fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    text: The lines to extract text. Its comments and strings must be elided.
3100fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov           It can be single line and can span multiple lines.
3101fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    start_pattern: The regexp string indicating where to start extracting
3102fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov                   the text.
3103fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  Returns:
3104fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    The extracted text.
3105fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    None if either the opening string or ending punctuation could not be found.
3106fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  """
3107fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # TODO(sugawarayu): Audit cpplint.py to see what places could be profitably
3108fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # rewritten to use _GetTextInside (and use inferior regexp matching today).
3109fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
3110fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # Give opening punctuations to get the matching close-punctuations.
3111fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  matching_punctuation = {'(': ')', '{': '}', '[': ']'}
3112fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  closing_punctuation = set(matching_punctuation.itervalues())
3113fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
3114fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # Find the position to start extracting text.
3115fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  match = re.search(start_pattern, text, re.M)
3116fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  if not match:  # start_pattern not found in text.
3117fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    return None
3118fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  start_position = match.end(0)
3119fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
3120fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  assert start_position > 0, (
3121fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      'start_pattern must ends with an opening punctuation.')
3122fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  assert text[start_position - 1] in matching_punctuation, (
3123fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      'start_pattern must ends with an opening punctuation.')
3124fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # Stack of closing punctuations we expect to have in text after position.
3125fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  punctuation_stack = [matching_punctuation[text[start_position - 1]]]
3126fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  position = start_position
3127fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  while punctuation_stack and position < len(text):
3128fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    if text[position] == punctuation_stack[-1]:
3129fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      punctuation_stack.pop()
3130fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    elif text[position] in closing_punctuation:
3131fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      # A closing punctuation without matching opening punctuations.
3132fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      return None
3133fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    elif text[position] in matching_punctuation:
3134fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      punctuation_stack.append(matching_punctuation[text[position]])
3135fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    position += 1
3136fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  if punctuation_stack:
3137fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    # Opening punctuations left without matching close-punctuations.
3138fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    return None
3139fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # punctuations match.
3140fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  return text[start_position:position - 1]
3141fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
3142fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
3143fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovdef CheckLanguage(filename, clean_lines, linenum, file_extension, include_state,
3144fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov                  error):
3145fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  """Checks rules from the 'C++ language rules' section of cppguide.html.
3146fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
3147fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  Some of these rules are hard to test (function overloading, using
3148fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  uint32 inappropriately), but we do the best we can.
3149fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
3150fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  Args:
3151fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    filename: The name of the current file.
3152fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    clean_lines: A CleansedLines instance containing the file.
3153fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    linenum: The number of the line to check.
3154fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    file_extension: The extension (without the dot) of the filename.
3155fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    include_state: An _IncludeState instance in which the headers are inserted.
3156fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    error: The function to call with any errors found.
3157fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  """
3158fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # If the line is empty or consists of entirely a comment, no need to
3159fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # check it.
3160fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  line = clean_lines.elided[linenum]
3161fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  if not line:
3162fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    return
3163fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
3164fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  match = _RE_PATTERN_INCLUDE.search(line)
3165fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  if match:
3166fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    CheckIncludeLine(filename, clean_lines, linenum, include_state, error)
3167fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    return
3168fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
3169fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # Create an extended_line, which is the concatenation of the current and
3170fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # next lines, for more effective checking of code that may span more than one
3171fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # line.
3172fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  if linenum + 1 < clean_lines.NumLines():
3173fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    extended_line = line + clean_lines.elided[linenum + 1]
3174fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  else:
3175fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    extended_line = line
3176fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
3177fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # Make Windows paths like Unix.
3178fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  fullname = os.path.abspath(filename).replace('\\', '/')
3179fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
3180fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # TODO(unknown): figure out if they're using default arguments in fn proto.
3181fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
3182fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # Check for non-const references in functions.  This is tricky because &
3183fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # is also used to take the address of something.  We allow <> for templates,
3184fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # (ignoring whatever is between the braces) and : for classes.
3185fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # These are complicated re's.  They try to capture the following:
3186fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # paren (for fn-prototype start), typename, &, varname.  For the const
3187fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # version, we're willing for const to be before typename or after
3188fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # Don't check the implementation on same line.
3189fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  fnline = line.split('{', 1)[0]
3190fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  if (len(re.findall(r'\([^()]*\b(?:[\w:]|<[^()]*>)+(\s?&|&\s?)\w+', fnline)) >
3191fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      len(re.findall(r'\([^()]*\bconst\s+(?:typename\s+)?(?:struct\s+)?'
3192fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov                     r'(?:[\w:]|<[^()]*>)+(\s?&|&\s?)\w+', fnline)) +
3193fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      len(re.findall(r'\([^()]*\b(?:[\w:]|<[^()]*>)+\s+const(\s?&|&\s?)[\w]+',
3194fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov                     fnline))):
3195fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
3196fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    # We allow non-const references in a few standard places, like functions
3197fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    # called "swap()" or iostream operators like "<<" or ">>". We also filter
3198fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    # out for loops, which lint otherwise mistakenly thinks are functions.
3199fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    if not Search(
3200fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        r'(for|swap|Swap|operator[<>][<>])\s*\(\s*'
3201fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        r'(?:(?:typename\s*)?[\w:]|<.*>)+\s*&',
3202fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        fnline):
3203fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      error(filename, linenum, 'runtime/references', 2,
3204fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov            'Is this a non-const reference? '
3205fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov            'If so, make const or use a pointer.')
3206fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
3207fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # Check to see if they're using an conversion function cast.
3208fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # I just try to capture the most common basic types, though there are more.
3209fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # Parameterless conversion functions, such as bool(), are allowed as they are
3210fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # probably a member operator declaration or default constructor.
3211fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  match = Search(
3212fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      r'(\bnew\s+)?\b'  # Grab 'new' operator, if it's there
3213fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      r'(int|float|double|bool|char|int32|uint32|int64|uint64)\([^)]', line)
3214fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  if match:
3215fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    # gMock methods are defined using some variant of MOCK_METHODx(name, type)
3216fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    # where type may be float(), int(string), etc.  Without context they are
3217fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    # virtually indistinguishable from int(x) casts. Likewise, gMock's
3218fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    # MockCallback takes a template parameter of the form return_type(arg_type),
3219fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    # which looks much like the cast we're trying to detect.
3220fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    if (match.group(1) is None and  # If new operator, then this isn't a cast
3221fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        not (Match(r'^\s*MOCK_(CONST_)?METHOD\d+(_T)?\(', line) or
3222fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov             Match(r'^\s*MockCallback<.*>', line))):
3223fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      # Try a bit harder to catch gmock lines: the only place where
3224fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      # something looks like an old-style cast is where we declare the
3225fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      # return type of the mocked method, and the only time when we
3226fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      # are missing context is if MOCK_METHOD was split across
3227fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      # multiple lines (for example http://go/hrfhr ), so we only need
3228fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      # to check the previous line for MOCK_METHOD.
3229fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      if (linenum == 0 or
3230fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          not Match(r'^\s*MOCK_(CONST_)?METHOD\d+(_T)?\(\S+,\s*$',
3231fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov                    clean_lines.elided[linenum - 1])):
3232fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        error(filename, linenum, 'readability/casting', 4,
3233fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov              'Using deprecated casting style.  '
3234fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov              'Use static_cast<%s>(...) instead' %
3235fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov              match.group(2))
3236fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
3237fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  CheckCStyleCast(filename, linenum, line, clean_lines.raw_lines[linenum],
3238fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov                  'static_cast',
3239fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov                  r'\((int|float|double|bool|char|u?int(16|32|64))\)', error)
3240fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
3241fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # This doesn't catch all cases. Consider (const char * const)"hello".
3242fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  #
3243fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # (char *) "foo" should always be a const_cast (reinterpret_cast won't
3244fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # compile).
3245fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  if CheckCStyleCast(filename, linenum, line, clean_lines.raw_lines[linenum],
3246fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov                     'const_cast', r'\((char\s?\*+\s?)\)\s*"', error):
3247fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    pass
3248fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  else:
3249fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    # Check pointer casts for other than string constants
3250fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    CheckCStyleCast(filename, linenum, line, clean_lines.raw_lines[linenum],
3251fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov                    'reinterpret_cast', r'\((\w+\s?\*+\s?)\)', error)
3252fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
3253fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # In addition, we look for people taking the address of a cast.  This
3254fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # is dangerous -- casts can assign to temporaries, so the pointer doesn't
3255fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # point where you think.
3256fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  if Search(
3257fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      r'(&\([^)]+\)[\w(])|(&(static|dynamic|reinterpret)_cast\b)', line):
3258fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    error(filename, linenum, 'runtime/casting', 4,
3259fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          ('Are you taking an address of a cast?  '
3260fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov           'This is dangerous: could be a temp var.  '
3261fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov           'Take the address before doing the cast, rather than after'))
3262fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
3263fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # Check for people declaring static/global STL strings at the top level.
3264fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # This is dangerous because the C++ language does not guarantee that
3265fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # globals with constructors are initialized before the first access.
3266fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  match = Match(
3267fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      r'((?:|static +)(?:|const +))string +([a-zA-Z0-9_:]+)\b(.*)',
3268fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      line)
3269fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # Make sure it's not a function.
3270fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # Function template specialization looks like: "string foo<Type>(...".
3271fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # Class template definitions look like: "string Foo<Type>::Method(...".
3272fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  if match and not Match(r'\s*(<.*>)?(::[a-zA-Z0-9_]+)?\s*\(([^"]|$)',
3273fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov                         match.group(3)):
3274fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    error(filename, linenum, 'runtime/string', 4,
3275fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          'For a static/global string constant, use a C style string instead: '
3276fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          '"%schar %s[]".' %
3277fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          (match.group(1), match.group(2)))
3278fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
3279fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # Check that we're not using RTTI outside of testing code.
3280fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  if Search(r'\bdynamic_cast<', line) and not _IsTestFilename(filename):
3281fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    error(filename, linenum, 'runtime/rtti', 5,
3282fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          'Do not use dynamic_cast<>.  If you need to cast within a class '
3283fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          "hierarchy, use static_cast<> to upcast.  Google doesn't support "
3284fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          'RTTI.')
3285fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
3286fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  if Search(r'\b([A-Za-z0-9_]*_)\(\1\)', line):
3287fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    error(filename, linenum, 'runtime/init', 4,
3288fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          'You seem to be initializing a member variable with itself.')
3289fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
3290fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  if file_extension == 'h':
3291fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    # TODO(unknown): check that 1-arg constructors are explicit.
3292fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    #                How to tell it's a constructor?
3293fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    #                (handled in CheckForNonStandardConstructs for now)
3294fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    # TODO(unknown): check that classes have DISALLOW_EVIL_CONSTRUCTORS
3295fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    #                (level 1 error)
3296fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    pass
3297fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
3298fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # Check if people are using the verboten C basic types.  The only exception
3299fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # we regularly allow is "unsigned short port" for port.
3300fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  if Search(r'\bshort port\b', line):
3301fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    if not Search(r'\bunsigned short port\b', line):
3302fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      error(filename, linenum, 'runtime/int', 4,
3303fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov            'Use "unsigned short" for ports, not "short"')
3304fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  else:
3305fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    match = Search(r'\b(short|long(?! +double)|long long)\b', line)
3306fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    if match:
3307fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      error(filename, linenum, 'runtime/int', 4,
3308fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov            'Use int16/int64/etc, rather than the C type %s' % match.group(1))
3309fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
3310fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # When snprintf is used, the second argument shouldn't be a literal.
3311fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  match = Search(r'snprintf\s*\(([^,]*),\s*([0-9]*)\s*,', line)
3312fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  if match and match.group(2) != '0':
3313fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    # If 2nd arg is zero, snprintf is used to calculate size.
3314fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    error(filename, linenum, 'runtime/printf', 3,
3315fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          'If you can, use sizeof(%s) instead of %s as the 2nd arg '
3316fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          'to snprintf.' % (match.group(1), match.group(2)))
3317fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
3318fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # Check if some verboten C functions are being used.
3319fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  if Search(r'\bsprintf\b', line):
3320fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    error(filename, linenum, 'runtime/printf', 5,
3321fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          'Never use sprintf.  Use snprintf instead.')
3322fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  match = Search(r'\b(strcpy|strcat)\b', line)
3323fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  if match:
3324fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    error(filename, linenum, 'runtime/printf', 4,
3325fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          'Almost always, snprintf is better than %s' % match.group(1))
3326fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
3327fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  if Search(r'\bsscanf\b', line):
3328fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    error(filename, linenum, 'runtime/printf', 1,
3329fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          'sscanf can be ok, but is slow and can overflow buffers.')
3330fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
3331fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # Check if some verboten operator overloading is going on
3332fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # TODO(unknown): catch out-of-line unary operator&:
3333fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  #   class X {};
3334fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  #   int operator&(const X& x) { return 42; }  // unary operator&
3335fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # The trick is it's hard to tell apart from binary operator&:
3336fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  #   class Y { int operator&(const Y& x) { return 23; } }; // binary operator&
3337fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  if Search(r'\boperator\s*&\s*\(\s*\)', line):
3338fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    error(filename, linenum, 'runtime/operator', 4,
3339fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          'Unary operator& is dangerous.  Do not use it.')
3340fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
3341fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # Check for suspicious usage of "if" like
3342fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # } if (a == b) {
3343fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  if Search(r'\}\s*if\s*\(', line):
3344fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    error(filename, linenum, 'readability/braces', 4,
3345fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          'Did you mean "else if"? If not, start a new line for "if".')
3346fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
3347fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # Check for potential format string bugs like printf(foo).
3348fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # We constrain the pattern not to pick things like DocidForPrintf(foo).
3349fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # Not perfect but it can catch printf(foo.c_str()) and printf(foo->c_str())
3350fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # TODO(sugawarayu): Catch the following case. Need to change the calling
3351fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # convention of the whole function to process multiple line to handle it.
3352fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  #   printf(
3353fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  #       boy_this_is_a_really_long_variable_that_cannot_fit_on_the_prev_line);
3354fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  printf_args = _GetTextInside(line, r'(?i)\b(string)?printf\s*\(')
3355fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  if printf_args:
3356fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    match = Match(r'([\w.\->()]+)$', printf_args)
3357fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    if match and match.group(1) != '__VA_ARGS__':
3358fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      function_name = re.search(r'\b((?:string)?printf)\s*\(',
3359fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov                                line, re.I).group(1)
3360fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      error(filename, linenum, 'runtime/printf', 4,
3361fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov            'Potential format string bug. Do %s("%%s", %s) instead.'
3362fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov            % (function_name, match.group(1)))
3363fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
3364fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # Check for potential memset bugs like memset(buf, sizeof(buf), 0).
3365fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  match = Search(r'memset\s*\(([^,]*),\s*([^,]*),\s*0\s*\)', line)
3366fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  if match and not Match(r"^''|-?[0-9]+|0x[0-9A-Fa-f]$", match.group(2)):
3367fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    error(filename, linenum, 'runtime/memset', 4,
3368fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          'Did you mean "memset(%s, 0, %s)"?'
3369fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          % (match.group(1), match.group(2)))
3370fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
3371fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  if Search(r'\busing namespace\b', line):
3372fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    error(filename, linenum, 'build/namespaces', 5,
3373fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          'Do not use namespace using-directives.  '
3374fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          'Use using-declarations instead.')
3375fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
3376fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # Detect variable-length arrays.
3377fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  match = Match(r'\s*(.+::)?(\w+) [a-z]\w*\[(.+)];', line)
3378fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  if (match and match.group(2) != 'return' and match.group(2) != 'delete' and
3379fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      match.group(3).find(']') == -1):
3380fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    # Split the size using space and arithmetic operators as delimiters.
3381fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    # If any of the resulting tokens are not compile time constants then
3382fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    # report the error.
3383fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    tokens = re.split(r'\s|\+|\-|\*|\/|<<|>>]', match.group(3))
3384fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    is_const = True
3385fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    skip_next = False
3386fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    for tok in tokens:
3387fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      if skip_next:
3388fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        skip_next = False
3389fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        continue
3390fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
3391fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      if Search(r'sizeof\(.+\)', tok): continue
3392fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      if Search(r'arraysize\(\w+\)', tok): continue
3393fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
3394fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      tok = tok.lstrip('(')
3395fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      tok = tok.rstrip(')')
3396fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      if not tok: continue
3397fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      if Match(r'\d+', tok): continue
3398fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      if Match(r'0[xX][0-9a-fA-F]+', tok): continue
3399fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      if Match(r'k[A-Z0-9]\w*', tok): continue
3400fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      if Match(r'(.+::)?k[A-Z0-9]\w*', tok): continue
3401fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      if Match(r'(.+::)?[A-Z][A-Z0-9_]*', tok): continue
3402fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      # A catch all for tricky sizeof cases, including 'sizeof expression',
3403fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      # 'sizeof(*type)', 'sizeof(const type)', 'sizeof(struct StructName)'
3404fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      # requires skipping the next token because we split on ' ' and '*'.
3405fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      if tok.startswith('sizeof'):
3406fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        skip_next = True
3407fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        continue
3408fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      is_const = False
3409fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      break
3410fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    if not is_const:
3411fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      error(filename, linenum, 'runtime/arrays', 1,
3412fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov            'Do not use variable-length arrays.  Use an appropriately named '
3413fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov            "('k' followed by CamelCase) compile-time constant for the size.")
3414fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
3415fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # If DISALLOW_EVIL_CONSTRUCTORS, DISALLOW_COPY_AND_ASSIGN, or
3416fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # DISALLOW_IMPLICIT_CONSTRUCTORS is present, then it should be the last thing
3417fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # in the class declaration.
3418fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  match = Match(
3419fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      (r'\s*'
3420fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov       r'(DISALLOW_(EVIL_CONSTRUCTORS|COPY_AND_ASSIGN|IMPLICIT_CONSTRUCTORS))'
3421fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov       r'\(.*\);$'),
3422fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      line)
3423fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  if match and linenum + 1 < clean_lines.NumLines():
3424fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    next_line = clean_lines.elided[linenum + 1]
3425fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    # We allow some, but not all, declarations of variables to be present
3426fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    # in the statement that defines the class.  The [\w\*,\s]* fragment of
3427fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    # the regular expression below allows users to declare instances of
3428fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    # the class or pointers to instances, but not less common types such
3429fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    # as function pointers or arrays.  It's a tradeoff between allowing
3430fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    # reasonable code and avoiding trying to parse more C++ using regexps.
3431fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    if not Search(r'^\s*}[\w\*,\s]*;', next_line):
3432fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      error(filename, linenum, 'readability/constructors', 3,
3433fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov            match.group(1) + ' should be the last thing in the class')
3434fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
3435fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # Check for use of unnamed namespaces in header files.  Registration
3436fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # macros are typically OK, so we allow use of "namespace {" on lines
3437fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # that end with backslashes.
3438fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  if (file_extension == 'h'
3439fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      and Search(r'\bnamespace\s*{', line)
3440fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      and line[-1] != '\\'):
3441fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    error(filename, linenum, 'build/namespaces', 4,
3442fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          'Do not use unnamed namespaces in header files.  See '
3443fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          'http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml#Namespaces'
3444fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          ' for more information.')
3445fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
3446fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
3447fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovdef CheckCStyleCast(filename, linenum, line, raw_line, cast_type, pattern,
3448fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov                    error):
3449fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  """Checks for a C-style cast by looking for the pattern.
3450fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
3451fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  This also handles sizeof(type) warnings, due to similarity of content.
3452fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
3453fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  Args:
3454fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    filename: The name of the current file.
3455fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    linenum: The number of the line to check.
3456fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    line: The line of code to check.
3457fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    raw_line: The raw line of code to check, with comments.
3458fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    cast_type: The string for the C++ cast to recommend.  This is either
3459fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      reinterpret_cast, static_cast, or const_cast, depending.
3460fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    pattern: The regular expression used to find C-style casts.
3461fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    error: The function to call with any errors found.
3462fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
3463fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  Returns:
3464fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    True if an error was emitted.
3465fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    False otherwise.
3466fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  """
3467fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  match = Search(pattern, line)
3468fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  if not match:
3469fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    return False
3470fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
3471fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # e.g., sizeof(int)
3472fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  sizeof_match = Match(r'.*sizeof\s*$', line[0:match.start(1) - 1])
3473fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  if sizeof_match:
3474fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    error(filename, linenum, 'runtime/sizeof', 1,
3475fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          'Using sizeof(type).  Use sizeof(varname) instead if possible')
3476fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    return True
3477fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
3478fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # operator++(int) and operator--(int)
3479fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  if (line[0:match.start(1) - 1].endswith(' operator++') or
3480fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      line[0:match.start(1) - 1].endswith(' operator--')):
3481fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    return False
3482fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
3483fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  remainder = line[match.end(0):]
3484fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
3485fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # The close paren is for function pointers as arguments to a function.
3486fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # eg, void foo(void (*bar)(int));
3487fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # The semicolon check is a more basic function check; also possibly a
3488fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # function pointer typedef.
3489fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # eg, void foo(int); or void foo(int) const;
3490fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # The equals check is for function pointer assignment.
3491fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # eg, void *(*foo)(int) = ...
3492fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # The > is for MockCallback<...> ...
3493fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  #
3494fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # Right now, this will only catch cases where there's a single argument, and
3495fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # it's unnamed.  It should probably be expanded to check for multiple
3496fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # arguments with some unnamed.
3497fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  function_match = Match(r'\s*(\)|=|(const)?\s*(;|\{|throw\(\)|>))', remainder)
3498fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  if function_match:
3499fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    if (not function_match.group(3) or
3500fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        function_match.group(3) == ';' or
3501fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        ('MockCallback<' not in raw_line and
3502fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov         '/*' not in raw_line)):
3503fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      error(filename, linenum, 'readability/function', 3,
3504fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov            'All parameters should be named in a function')
3505fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    return True
3506fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
3507fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # At this point, all that should be left is actual casts.
3508fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  error(filename, linenum, 'readability/casting', 4,
3509fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        'Using C-style cast.  Use %s<%s>(...) instead' %
3510fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        (cast_type, match.group(1)))
3511fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
3512fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  return True
3513fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
3514fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
3515fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov_HEADERS_CONTAINING_TEMPLATES = (
3516fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    ('<deque>', ('deque',)),
3517fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    ('<functional>', ('unary_function', 'binary_function',
3518fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov                      'plus', 'minus', 'multiplies', 'divides', 'modulus',
3519fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov                      'negate',
3520fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov                      'equal_to', 'not_equal_to', 'greater', 'less',
3521fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov                      'greater_equal', 'less_equal',
3522fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov                      'logical_and', 'logical_or', 'logical_not',
3523fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov                      'unary_negate', 'not1', 'binary_negate', 'not2',
3524fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov                      'bind1st', 'bind2nd',
3525fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov                      'pointer_to_unary_function',
3526fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov                      'pointer_to_binary_function',
3527fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov                      'ptr_fun',
3528fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov                      'mem_fun_t', 'mem_fun', 'mem_fun1_t', 'mem_fun1_ref_t',
3529fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov                      'mem_fun_ref_t',
3530fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov                      'const_mem_fun_t', 'const_mem_fun1_t',
3531fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov                      'const_mem_fun_ref_t', 'const_mem_fun1_ref_t',
3532fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov                      'mem_fun_ref',
3533fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov                     )),
3534fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    ('<limits>', ('numeric_limits',)),
3535fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    ('<list>', ('list',)),
3536fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    ('<map>', ('map', 'multimap',)),
3537fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    ('<memory>', ('allocator',)),
3538fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    ('<queue>', ('queue', 'priority_queue',)),
3539fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    ('<set>', ('set', 'multiset',)),
3540fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    ('<stack>', ('stack',)),
3541fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    ('<string>', ('char_traits', 'basic_string',)),
3542fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    ('<utility>', ('pair',)),
3543fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    ('<vector>', ('vector',)),
3544fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
3545fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    # gcc extensions.
3546fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    # Note: std::hash is their hash, ::hash is our hash
3547fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    ('<hash_map>', ('hash_map', 'hash_multimap',)),
3548fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    ('<hash_set>', ('hash_set', 'hash_multiset',)),
3549fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    ('<slist>', ('slist',)),
3550fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    )
3551fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
3552fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov_RE_PATTERN_STRING = re.compile(r'\bstring\b')
3553fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
3554fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov_re_pattern_algorithm_header = []
3555fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovfor _template in ('copy', 'max', 'min', 'min_element', 'sort', 'swap',
3556fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov                  'transform'):
3557fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # Match max<type>(..., ...), max(..., ...), but not foo->max, foo.max or
3558fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # type::max().
3559fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  _re_pattern_algorithm_header.append(
3560fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      (re.compile(r'[^>.]\b' + _template + r'(<.*?>)?\([^\)]'),
3561fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov       _template,
3562fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov       '<algorithm>'))
3563fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
3564fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov_re_pattern_templates = []
3565fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovfor _header, _templates in _HEADERS_CONTAINING_TEMPLATES:
3566fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  for _template in _templates:
3567fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    _re_pattern_templates.append(
3568fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        (re.compile(r'(\<|\b)' + _template + r'\s*\<'),
3569fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov         _template + '<>',
3570fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov         _header))
3571fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
3572fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
3573fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovdef FilesBelongToSameModule(filename_cc, filename_h):
3574fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  """Check if these two filenames belong to the same module.
3575fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
3576fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  The concept of a 'module' here is a as follows:
3577fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  foo.h, foo-inl.h, foo.cc, foo_test.cc and foo_unittest.cc belong to the
3578fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  same 'module' if they are in the same directory.
3579fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  some/path/public/xyzzy and some/path/internal/xyzzy are also considered
3580fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  to belong to the same module here.
3581fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
3582fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  If the filename_cc contains a longer path than the filename_h, for example,
3583fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  '/absolute/path/to/base/sysinfo.cc', and this file would include
3584fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  'base/sysinfo.h', this function also produces the prefix needed to open the
3585fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  header. This is used by the caller of this function to more robustly open the
3586fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  header file. We don't have access to the real include paths in this context,
3587fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  so we need this guesswork here.
3588fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
3589fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  Known bugs: tools/base/bar.cc and base/bar.h belong to the same module
3590fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  according to this implementation. Because of this, this function gives
3591fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  some false positives. This should be sufficiently rare in practice.
3592fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
3593fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  Args:
3594fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    filename_cc: is the path for the .cc file
3595fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    filename_h: is the path for the header path
3596fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
3597fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  Returns:
3598fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    Tuple with a bool and a string:
3599fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    bool: True if filename_cc and filename_h belong to the same module.
3600fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    string: the additional prefix needed to open the header file.
3601fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  """
3602fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
3603fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  if not filename_cc.endswith('.cc'):
3604fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    return (False, '')
3605fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  filename_cc = filename_cc[:-len('.cc')]
3606fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  if filename_cc.endswith('_unittest'):
3607fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    filename_cc = filename_cc[:-len('_unittest')]
3608fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  elif filename_cc.endswith('_test'):
3609fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    filename_cc = filename_cc[:-len('_test')]
3610fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  filename_cc = filename_cc.replace('/public/', '/')
3611fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  filename_cc = filename_cc.replace('/internal/', '/')
3612fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
3613fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  if not filename_h.endswith('.h'):
3614fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    return (False, '')
3615fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  filename_h = filename_h[:-len('.h')]
3616fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  if filename_h.endswith('-inl'):
3617fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    filename_h = filename_h[:-len('-inl')]
3618fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  filename_h = filename_h.replace('/public/', '/')
3619fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  filename_h = filename_h.replace('/internal/', '/')
3620fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
3621fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  files_belong_to_same_module = filename_cc.endswith(filename_h)
3622fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  common_path = ''
3623fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  if files_belong_to_same_module:
3624fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    common_path = filename_cc[:-len(filename_h)]
3625fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  return files_belong_to_same_module, common_path
3626fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
3627fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
3628fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovdef UpdateIncludeState(filename, include_state, io=codecs):
3629fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  """Fill up the include_state with new includes found from the file.
3630fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
3631fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  Args:
3632fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    filename: the name of the header to read.
3633fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    include_state: an _IncludeState instance in which the headers are inserted.
3634fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    io: The io factory to use to read the file. Provided for testability.
3635fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
3636fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  Returns:
36372d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines    True if a header was successfully added. False otherwise.
3638fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  """
3639fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  headerfile = None
3640fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  try:
3641fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    headerfile = io.open(filename, 'r', 'utf8', 'replace')
3642fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  except IOError:
3643fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    return False
3644fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  linenum = 0
3645fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  for line in headerfile:
3646fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    linenum += 1
3647fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    clean_line = CleanseComments(line)
3648fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    match = _RE_PATTERN_INCLUDE.search(clean_line)
3649fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    if match:
3650fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      include = match.group(2)
3651fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      # The value formatting is cute, but not really used right now.
3652fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      # What matters here is that the key is in include_state.
3653fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      include_state.setdefault(include, '%s:%d' % (filename, linenum))
3654fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  return True
3655fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
3656fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
3657fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovdef CheckForIncludeWhatYouUse(filename, clean_lines, include_state, error,
3658fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov                              io=codecs):
3659fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  """Reports for missing stl includes.
3660fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
3661fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  This function will output warnings to make sure you are including the headers
3662fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  necessary for the stl containers and functions that you use. We only give one
3663fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  reason to include a header. For example, if you use both equal_to<> and
3664fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  less<> in a .h file, only one (the latter in the file) of these will be
3665fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  reported as a reason to include the <functional>.
3666fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
3667fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  Args:
3668fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    filename: The name of the current file.
3669fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    clean_lines: A CleansedLines instance containing the file.
3670fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    include_state: An _IncludeState instance.
3671fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    error: The function to call with any errors found.
3672fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    io: The IO factory to use to read the header file. Provided for unittest
3673fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        injection.
3674fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  """
3675fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  required = {}  # A map of header name to linenumber and the template entity.
3676fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov                 # Example of required: { '<functional>': (1219, 'less<>') }
3677fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
3678fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  for linenum in xrange(clean_lines.NumLines()):
3679fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    line = clean_lines.elided[linenum]
3680fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    if not line or line[0] == '#':
3681fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      continue
3682fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
3683fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    # String is special -- it is a non-templatized type in STL.
3684fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    matched = _RE_PATTERN_STRING.search(line)
3685fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    if matched:
3686fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      # Don't warn about strings in non-STL namespaces:
3687fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      # (We check only the first match per line; good enough.)
3688fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      prefix = line[:matched.start()]
3689fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      if prefix.endswith('std::') or not prefix.endswith('::'):
3690fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        required['<string>'] = (linenum, 'string')
3691fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
3692fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    for pattern, template, header in _re_pattern_algorithm_header:
3693fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      if pattern.search(line):
3694fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        required[header] = (linenum, template)
3695fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
3696fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    # The following function is just a speed up, no semantics are changed.
3697fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    if not '<' in line:  # Reduces the cpu time usage by skipping lines.
3698fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      continue
3699fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
3700fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    for pattern, template, header in _re_pattern_templates:
3701fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      if pattern.search(line):
3702fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        required[header] = (linenum, template)
3703fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
3704fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # The policy is that if you #include something in foo.h you don't need to
3705fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # include it again in foo.cc. Here, we will look at possible includes.
3706fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # Let's copy the include_state so it is only messed up within this function.
3707fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  include_state = include_state.copy()
3708fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
37092d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  # Did we find the header for this file (if any) and successfully load it?
3710fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  header_found = False
3711fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
3712fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # Use the absolute path so that matching works properly.
3713fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  abs_filename = FileInfo(filename).FullName()
3714fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
3715fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # For Emacs's flymake.
3716fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # If cpplint is invoked from Emacs's flymake, a temporary file is generated
3717fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # by flymake and that file name might end with '_flymake.cc'. In that case,
3718fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # restore original file name here so that the corresponding header file can be
3719fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # found.
3720fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # e.g. If the file name is 'foo_flymake.cc', we should search for 'foo.h'
3721fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # instead of 'foo_flymake.h'
3722fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  abs_filename = re.sub(r'_flymake\.cc$', '.cc', abs_filename)
3723fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
3724fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # include_state is modified during iteration, so we iterate over a copy of
3725fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # the keys.
3726fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  header_keys = include_state.keys()
3727fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  for header in header_keys:
3728fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    (same_module, common_path) = FilesBelongToSameModule(abs_filename, header)
3729fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    fullpath = common_path + header
3730fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    if same_module and UpdateIncludeState(fullpath, include_state, io):
3731fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      header_found = True
3732fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
3733fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # If we can't find the header file for a .cc, assume it's because we don't
3734fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # know where to look. In that case we'll give up as we're not sure they
3735fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # didn't include it in the .h file.
3736fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # TODO(unknown): Do a better job of finding .h files so we are confident that
3737fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # not having the .h file means there isn't one.
3738fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  if filename.endswith('.cc') and not header_found:
3739fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    return
3740fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
3741fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # All the lines have been processed, report the errors found.
3742fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  for required_header_unstripped in required:
3743fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    template = required[required_header_unstripped][1]
3744fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    if required_header_unstripped.strip('<>"') not in include_state:
3745fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      error(filename, required[required_header_unstripped][0],
3746fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov            'build/include_what_you_use', 4,
3747fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov            'Add #include ' + required_header_unstripped + ' for ' + template)
3748fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
3749fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
3750fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov_RE_PATTERN_EXPLICIT_MAKEPAIR = re.compile(r'\bmake_pair\s*<')
3751fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
3752fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
3753fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovdef CheckMakePairUsesDeduction(filename, clean_lines, linenum, error):
3754fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  """Check that make_pair's template arguments are deduced.
3755fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
3756fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  G++ 4.6 in C++0x mode fails badly if make_pair's template arguments are
3757fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  specified explicitly, and such use isn't intended in any case.
3758fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
3759fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  Args:
3760fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    filename: The name of the current file.
3761fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    clean_lines: A CleansedLines instance containing the file.
3762fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    linenum: The number of the line to check.
3763fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    error: The function to call with any errors found.
3764fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  """
3765fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  raw = clean_lines.raw_lines
3766fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  line = raw[linenum]
3767fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  match = _RE_PATTERN_EXPLICIT_MAKEPAIR.search(line)
3768fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  if match:
3769fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    error(filename, linenum, 'build/explicit_make_pair',
3770fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          4,  # 4 = high confidence
3771fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          'For C++11-compatibility, omit template arguments from make_pair'
3772fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov          ' OR use pair directly OR if appropriate, construct a pair directly')
3773fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
3774fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
3775fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovdef ProcessLine(filename, file_extension, clean_lines, line,
3776fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov                include_state, function_state, nesting_state, error,
3777fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov                extra_check_functions=[]):
3778fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  """Processes a single line in the file.
3779fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
3780fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  Args:
3781fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    filename: Filename of the file that is being processed.
3782fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    file_extension: The extension (dot not included) of the file.
3783fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    clean_lines: An array of strings, each representing a line of the file,
3784fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov                 with comments stripped.
3785fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    line: Number of line being processed.
3786fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    include_state: An _IncludeState instance in which the headers are inserted.
3787fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    function_state: A _FunctionState instance which counts function lines, etc.
3788fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    nesting_state: A _NestingState instance which maintains information about
3789fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov                   the current stack of nested blocks being parsed.
3790fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    error: A callable to which errors are reported, which takes 4 arguments:
3791fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov           filename, line number, error level, and message
3792fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    extra_check_functions: An array of additional check functions that will be
3793fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov                           run on each source line. Each function takes 4
3794fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov                           arguments: filename, clean_lines, line, error
3795fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  """
3796fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  raw_lines = clean_lines.raw_lines
3797fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  ParseNolintSuppressions(filename, raw_lines[line], line, error)
3798fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  nesting_state.Update(filename, clean_lines, line, error)
3799fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  if nesting_state.stack and nesting_state.stack[-1].inline_asm != _NO_ASM:
3800fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    return
3801fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  CheckForFunctionLengths(filename, clean_lines, line, function_state, error)
3802fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  CheckForMultilineCommentsAndStrings(filename, clean_lines, line, error)
3803fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  CheckStyle(filename, clean_lines, line, file_extension, nesting_state, error)
3804fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  CheckLanguage(filename, clean_lines, line, file_extension, include_state,
3805fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov                error)
3806fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  CheckForNonStandardConstructs(filename, clean_lines, line,
3807fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov                                nesting_state, error)
3808fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  CheckPosixThreading(filename, clean_lines, line, error)
3809fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  CheckInvalidIncrement(filename, clean_lines, line, error)
3810fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  CheckMakePairUsesDeduction(filename, clean_lines, line, error)
3811fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  for check_fn in extra_check_functions:
3812fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    check_fn(filename, clean_lines, line, error)
3813fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
3814fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovdef ProcessFileData(filename, file_extension, lines, error,
3815fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov                    extra_check_functions=[]):
3816fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  """Performs lint checks and reports any errors to the given error function.
3817fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
3818fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  Args:
3819fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    filename: Filename of the file that is being processed.
3820fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    file_extension: The extension (dot not included) of the file.
3821fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    lines: An array of strings, each representing a line of the file, with the
3822fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov           last element being empty if the file is terminated with a newline.
3823fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    error: A callable to which errors are reported, which takes 4 arguments:
3824fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov           filename, line number, error level, and message
3825fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    extra_check_functions: An array of additional check functions that will be
3826fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov                           run on each source line. Each function takes 4
3827fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov                           arguments: filename, clean_lines, line, error
3828fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  """
3829fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  lines = (['// marker so line numbers and indices both start at 1'] + lines +
3830fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov           ['// marker so line numbers end in a known way'])
3831fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
3832fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  include_state = _IncludeState()
3833fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  function_state = _FunctionState()
3834fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  nesting_state = _NestingState()
3835fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
3836fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  ResetNolintSuppressions()
3837fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
3838fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  CheckForCopyright(filename, lines, error)
3839fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
3840fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  if file_extension == 'h':
3841fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    CheckForHeaderGuard(filename, lines, error)
3842fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
3843fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  RemoveMultiLineComments(filename, lines, error)
3844fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  clean_lines = CleansedLines(lines)
3845fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  for line in xrange(clean_lines.NumLines()):
3846fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    ProcessLine(filename, file_extension, clean_lines, line,
3847fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov                include_state, function_state, nesting_state, error,
3848fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov                extra_check_functions)
3849fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  nesting_state.CheckClassFinished(filename, error)
3850fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
3851fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  CheckForIncludeWhatYouUse(filename, clean_lines, include_state, error)
3852fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
3853fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # We check here rather than inside ProcessLine so that we see raw
3854fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # lines rather than "cleaned" lines.
3855fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  CheckForUnicodeReplacementCharacters(filename, lines, error)
3856fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
3857fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  CheckForNewlineAtEOF(filename, lines, error)
3858fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
3859fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovdef ProcessFile(filename, vlevel, extra_check_functions=[]):
3860fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  """Does google-lint on a single file.
3861fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
3862fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  Args:
3863fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    filename: The name of the file to parse.
3864fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
3865fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    vlevel: The level of errors to report.  Every error of confidence
3866fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    >= verbose_level will be reported.  0 is a good default.
3867fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
3868fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    extra_check_functions: An array of additional check functions that will be
3869fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov                           run on each source line. Each function takes 4
3870fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov                           arguments: filename, clean_lines, line, error
3871fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  """
3872fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
3873fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  _SetVerboseLevel(vlevel)
3874fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
3875fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  try:
3876fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    # Support the UNIX convention of using "-" for stdin.  Note that
3877fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    # we are not opening the file with universal newline support
3878fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    # (which codecs doesn't support anyway), so the resulting lines do
3879fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    # contain trailing '\r' characters if we are reading a file that
3880fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    # has CRLF endings.
3881fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    # If after the split a trailing '\r' is present, it is removed
3882fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    # below. If it is not expected to be present (i.e. os.linesep !=
3883fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    # '\r\n' as in Windows), a warning is issued below if this file
3884fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    # is processed.
3885fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
3886fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    if filename == '-':
3887fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      lines = codecs.StreamReaderWriter(sys.stdin,
3888fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov                                        codecs.getreader('utf8'),
3889fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov                                        codecs.getwriter('utf8'),
3890fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov                                        'replace').read().split('\n')
3891fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    else:
3892fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      lines = codecs.open(filename, 'r', 'utf8', 'replace').read().split('\n')
3893fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
3894fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    carriage_return_found = False
3895fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    # Remove trailing '\r'.
3896fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    for linenum in range(len(lines)):
3897fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      if lines[linenum].endswith('\r'):
3898fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        lines[linenum] = lines[linenum].rstrip('\r')
3899fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        carriage_return_found = True
3900fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
3901fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  except IOError:
3902fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    sys.stderr.write(
3903fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        "Skipping input '%s': Can't open for reading\n" % filename)
3904fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    return
3905fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
3906fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # Note, if no dot is found, this will give the entire filename as the ext.
3907fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  file_extension = filename[filename.rfind('.') + 1:]
3908fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
3909fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # When reading from stdin, the extension is unknown, so no cpplint tests
3910fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # should rely on the extension.
3911fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  if (filename != '-' and file_extension != 'cc' and file_extension != 'h'
3912fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      and file_extension != 'cpp'):
3913fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    sys.stderr.write('Ignoring %s; not a .cc or .h file\n' % filename)
3914fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  else:
3915fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    ProcessFileData(filename, file_extension, lines, Error,
3916fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov                    extra_check_functions)
3917fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    if carriage_return_found and os.linesep != '\r\n':
3918fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      # Use 0 for linenum since outputting only one error for potentially
3919fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      # several lines.
3920fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      Error(filename, 0, 'whitespace/newline', 1,
3921fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov            'One or more unexpected \\r (^M) found;'
3922fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov            'better to use only a \\n')
3923fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
3924fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  sys.stderr.write('Done processing %s\n' % filename)
3925fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
3926fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
3927fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovdef PrintUsage(message):
3928fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  """Prints a brief usage string and exits, optionally with an error message.
3929fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
3930fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  Args:
3931fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    message: The optional error message.
3932fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  """
3933fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  sys.stderr.write(_USAGE)
3934fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  if message:
3935fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    sys.exit('\nFATAL ERROR: ' + message)
3936fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  else:
3937fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    sys.exit(1)
3938fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
3939fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
3940fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovdef PrintCategories():
3941fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  """Prints a list of all the error-categories used by error messages.
3942fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
3943fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  These are the categories used to filter messages via --filter.
3944fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  """
3945fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  sys.stderr.write(''.join('  %s\n' % cat for cat in _ERROR_CATEGORIES))
3946fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  sys.exit(0)
3947fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
3948fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
3949fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovdef ParseArguments(args):
3950fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  """Parses the command line arguments.
3951fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
3952fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  This may set the output format and verbosity level as side-effects.
3953fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
3954fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  Args:
3955fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    args: The command line arguments:
3956fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
3957fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  Returns:
3958fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    The list of filenames to lint.
3959fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  """
3960fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  try:
3961fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    (opts, filenames) = getopt.getopt(args, '', ['help', 'output=', 'verbose=',
3962fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov                                                 'counting=',
3963fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov                                                 'filter=',
3964fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov                                                 'root='])
3965fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  except getopt.GetoptError:
3966fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    PrintUsage('Invalid arguments.')
3967fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
3968fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  verbosity = _VerboseLevel()
3969fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  output_format = _OutputFormat()
3970fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  filters = ''
3971fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  counting_style = ''
3972fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
3973fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  for (opt, val) in opts:
3974fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    if opt == '--help':
3975fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      PrintUsage(None)
3976fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    elif opt == '--output':
3977fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      if not val in ('emacs', 'vs7', 'eclipse'):
3978fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        PrintUsage('The only allowed output formats are emacs, vs7 and eclipse.')
3979fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      output_format = val
3980fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    elif opt == '--verbose':
3981fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      verbosity = int(val)
3982fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    elif opt == '--filter':
3983fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      filters = val
3984fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      if not filters:
3985fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        PrintCategories()
3986fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    elif opt == '--counting':
3987fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      if val not in ('total', 'toplevel', 'detailed'):
3988fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov        PrintUsage('Valid counting options are total, toplevel, and detailed')
3989fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      counting_style = val
3990fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    elif opt == '--root':
3991fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      global _root
3992fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov      _root = val
3993fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
3994fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  if not filenames:
3995fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    PrintUsage('No files were specified.')
3996fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
3997fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  _SetOutputFormat(output_format)
3998fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  _SetVerboseLevel(verbosity)
3999fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  _SetFilters(filters)
4000fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  _SetCountingStyle(counting_style)
4001fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
4002fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  return filenames
4003fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
4004fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
4005fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovdef main():
4006fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  filenames = ParseArguments(sys.argv[1:])
4007fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
4008fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # Change stderr to write with replacement characters so we don't die
4009fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  # if we try to print something containing non-ASCII characters.
4010fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  sys.stderr = codecs.StreamReaderWriter(sys.stderr,
4011fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov                                         codecs.getreader('utf8'),
4012fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov                                         codecs.getwriter('utf8'),
4013fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov                                         'replace')
4014fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
4015fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  _cpplint_state.ResetErrorCounts()
4016fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  for filename in filenames:
4017fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov    ProcessFile(filename, _cpplint_state.verbose_level)
4018fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  _cpplint_state.PrintErrorCounts()
4019fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
4020fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  sys.exit(_cpplint_state.error_count > 0)
4021fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
4022fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov
4023fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovif __name__ == '__main__':
4024fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov  main()
4025