10bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch#!/usr/bin/python
20bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch# -*- coding: utf-8 -*-
30bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch#
40bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch# Copyright (C) 2009 Google Inc. All rights reserved.
50bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch# Copyright (C) 2009 Torch Mobile Inc.
6231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block# Copyright (C) 2009 Apple Inc. All rights reserved.
7d0825bca7fe65beaee391d30da42e937db621564Steve Block# Copyright (C) 2010 Chris Jerdonek (cjerdonek@webkit.org)
80bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch#
90bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch# Redistribution and use in source and binary forms, with or without
100bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch# modification, are permitted provided that the following conditions are
110bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch# met:
120bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch#
130bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch#    * Redistributions of source code must retain the above copyright
140bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch# notice, this list of conditions and the following disclaimer.
150bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch#    * Redistributions in binary form must reproduce the above
160bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch# copyright notice, this list of conditions and the following disclaimer
170bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch# in the documentation and/or other materials provided with the
180bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch# distribution.
190bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch#    * Neither the name of Google Inc. nor the names of its
200bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch# contributors may be used to endorse or promote products derived from
210bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch# this software without specific prior written permission.
220bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch#
230bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
240bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
250bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
260bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
270bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
280bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
290bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
300bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
310bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
320bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
330bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
340bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
350bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch# This is the modified version of Google's cpplint. The original code is
360bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch# http://google-styleguide.googlecode.com/svn/trunk/cpplint/cpplint.py
370bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
38d0825bca7fe65beaee391d30da42e937db621564Steve Block"""Support for check-webkit-style."""
390bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
400bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdochimport codecs
410bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdochimport math  # for log
420bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdochimport os
430bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdochimport os.path
440bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdochimport re
450bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdochimport sre_compile
460bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdochimport string
470bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdochimport sys
480bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdochimport unicodedata
490bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
500bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
510bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch# Headers that we consider STL headers.
520bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch_STL_HEADERS = frozenset([
530bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    'algobase.h', 'algorithm', 'alloc.h', 'bitset', 'deque', 'exception',
540bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    'function.h', 'functional', 'hash_map', 'hash_map.h', 'hash_set',
550bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    'hash_set.h', 'iterator', 'list', 'list.h', 'map', 'memory', 'pair.h',
560bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    'pthread_alloc', 'queue', 'set', 'set.h', 'sstream', 'stack',
570bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    'stl_alloc.h', 'stl_relops.h', 'type_traits.h',
580bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    'utility', 'vector', 'vector.h',
590bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    ])
600bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
610bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
620bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch# Non-STL C++ system headers.
630bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch_CPP_HEADERS = frozenset([
640bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    'algo.h', 'builtinbuf.h', 'bvector.h', 'cassert', 'cctype',
650bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    'cerrno', 'cfloat', 'ciso646', 'climits', 'clocale', 'cmath',
660bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    'complex', 'complex.h', 'csetjmp', 'csignal', 'cstdarg', 'cstddef',
670bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    'cstdio', 'cstdlib', 'cstring', 'ctime', 'cwchar', 'cwctype',
680bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    'defalloc.h', 'deque.h', 'editbuf.h', 'exception', 'fstream',
690bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    'fstream.h', 'hashtable.h', 'heap.h', 'indstream.h', 'iomanip',
700bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    'iomanip.h', 'ios', 'iosfwd', 'iostream', 'iostream.h', 'istream.h',
710bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    'iterator.h', 'limits', 'map.h', 'multimap.h', 'multiset.h',
720bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    'numeric', 'ostream.h', 'parsestream.h', 'pfstream.h', 'PlotFile.h',
730bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    'procbuf.h', 'pthread_alloc.h', 'rope', 'rope.h', 'ropeimpl.h',
740bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    'SFile.h', 'slist', 'slist.h', 'stack.h', 'stdexcept',
750bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    'stdiostream.h', 'streambuf.h', 'stream.h', 'strfile.h', 'string',
760bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    'strstream', 'strstream.h', 'tempbuf.h', 'tree.h', 'typeinfo', 'valarray',
770bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    ])
780bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
790bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
800bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch# Assertion macros.  These are defined in base/logging.h and
810bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch# testing/base/gunit.h.  Note that the _M versions need to come first
820bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch# for substring matching to work.
830bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch_CHECK_MACROS = [
840bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    'DCHECK', 'CHECK',
850bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    'EXPECT_TRUE_M', 'EXPECT_TRUE',
860bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    'ASSERT_TRUE_M', 'ASSERT_TRUE',
870bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    'EXPECT_FALSE_M', 'EXPECT_FALSE',
880bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    'ASSERT_FALSE_M', 'ASSERT_FALSE',
890bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    ]
900bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
910bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch# Replacement macros for CHECK/DCHECK/EXPECT_TRUE/EXPECT_FALSE
920bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch_CHECK_REPLACEMENT = dict([(m, {}) for m in _CHECK_MACROS])
930bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
940bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdochfor op, replacement in [('==', 'EQ'), ('!=', 'NE'),
950bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                        ('>=', 'GE'), ('>', 'GT'),
960bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                        ('<=', 'LE'), ('<', 'LT')]:
970bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    _CHECK_REPLACEMENT['DCHECK'][op] = 'DCHECK_%s' % replacement
980bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    _CHECK_REPLACEMENT['CHECK'][op] = 'CHECK_%s' % replacement
990bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    _CHECK_REPLACEMENT['EXPECT_TRUE'][op] = 'EXPECT_%s' % replacement
1000bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    _CHECK_REPLACEMENT['ASSERT_TRUE'][op] = 'ASSERT_%s' % replacement
1010bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    _CHECK_REPLACEMENT['EXPECT_TRUE_M'][op] = 'EXPECT_%s_M' % replacement
1020bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    _CHECK_REPLACEMENT['ASSERT_TRUE_M'][op] = 'ASSERT_%s_M' % replacement
1030bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
1040bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdochfor op, inv_replacement in [('==', 'NE'), ('!=', 'EQ'),
1050bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                            ('>=', 'LT'), ('>', 'LE'),
1060bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                            ('<=', 'GT'), ('<', 'GE')]:
1070bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    _CHECK_REPLACEMENT['EXPECT_FALSE'][op] = 'EXPECT_%s' % inv_replacement
1080bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    _CHECK_REPLACEMENT['ASSERT_FALSE'][op] = 'ASSERT_%s' % inv_replacement
1090bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    _CHECK_REPLACEMENT['EXPECT_FALSE_M'][op] = 'EXPECT_%s_M' % inv_replacement
1100bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    _CHECK_REPLACEMENT['ASSERT_FALSE_M'][op] = 'ASSERT_%s_M' % inv_replacement
1110bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
1120bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
1130bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch# These constants define types of headers for use with
1140bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch# _IncludeState.check_next_include_order().
1150bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch_CONFIG_HEADER = 0
1160bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch_PRIMARY_HEADER = 1
1170bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch_OTHER_HEADER = 2
118d0825bca7fe65beaee391d30da42e937db621564Steve Block_MOC_HEADER = 3
1190bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
1200bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
121643ca7872b450ea4efacab6188849e5aac2ba161Steve Block# The regexp compilation caching is inlined in all regexp functions for
122643ca7872b450ea4efacab6188849e5aac2ba161Steve Block# performance reasons; factoring it out into a separate function turns out
123643ca7872b450ea4efacab6188849e5aac2ba161Steve Block# to be noticeably expensive.
1240bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch_regexp_compile_cache = {}
1250bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
1260bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
1270bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdochdef match(pattern, s):
1280bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """Matches the string with the pattern, caching the compiled regexp."""
1290bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if not pattern in _regexp_compile_cache:
1300bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        _regexp_compile_cache[pattern] = sre_compile.compile(pattern)
1310bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    return _regexp_compile_cache[pattern].match(s)
1320bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
1330bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
1340bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdochdef search(pattern, s):
1350bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """Searches the string for the pattern, caching the compiled regexp."""
1360bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if not pattern in _regexp_compile_cache:
1370bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        _regexp_compile_cache[pattern] = sre_compile.compile(pattern)
1380bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    return _regexp_compile_cache[pattern].search(s)
1390bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
1400bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
141643ca7872b450ea4efacab6188849e5aac2ba161Steve Blockdef sub(pattern, replacement, s):
142643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    """Substitutes occurrences of a pattern, caching the compiled regexp."""
143643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    if not pattern in _regexp_compile_cache:
144643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        _regexp_compile_cache[pattern] = sre_compile.compile(pattern)
145643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    return _regexp_compile_cache[pattern].sub(replacement, s)
146643ca7872b450ea4efacab6188849e5aac2ba161Steve Block
147643ca7872b450ea4efacab6188849e5aac2ba161Steve Block
148643ca7872b450ea4efacab6188849e5aac2ba161Steve Blockdef subn(pattern, replacement, s):
149643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    """Substitutes occurrences of a pattern, caching the compiled regexp."""
150643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    if not pattern in _regexp_compile_cache:
151643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        _regexp_compile_cache[pattern] = sre_compile.compile(pattern)
152643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    return _regexp_compile_cache[pattern].subn(replacement, s)
153643ca7872b450ea4efacab6188849e5aac2ba161Steve Block
154643ca7872b450ea4efacab6188849e5aac2ba161Steve Block
155d0825bca7fe65beaee391d30da42e937db621564Steve Blockdef up_to_unmatched_closing_paren(s):
156d0825bca7fe65beaee391d30da42e937db621564Steve Block    """Splits a string into two parts up to first unmatched ')'.
157d0825bca7fe65beaee391d30da42e937db621564Steve Block
158d0825bca7fe65beaee391d30da42e937db621564Steve Block    Args:
159d0825bca7fe65beaee391d30da42e937db621564Steve Block      s: a string which is a substring of line after '('
160d0825bca7fe65beaee391d30da42e937db621564Steve Block      (e.g., "a == (b + c))").
161d0825bca7fe65beaee391d30da42e937db621564Steve Block
162d0825bca7fe65beaee391d30da42e937db621564Steve Block    Returns:
163d0825bca7fe65beaee391d30da42e937db621564Steve Block      A pair of strings (prefix before first unmatched ')',
164d0825bca7fe65beaee391d30da42e937db621564Steve Block      reminder of s after first unmatched ')'), e.g.,
165d0825bca7fe65beaee391d30da42e937db621564Steve Block      up_to_unmatched_closing_paren("a == (b + c)) { ")
166d0825bca7fe65beaee391d30da42e937db621564Steve Block      returns "a == (b + c)", " {".
167d0825bca7fe65beaee391d30da42e937db621564Steve Block      Returns None, None if there is no unmatched ')'
168d0825bca7fe65beaee391d30da42e937db621564Steve Block
169d0825bca7fe65beaee391d30da42e937db621564Steve Block    """
170d0825bca7fe65beaee391d30da42e937db621564Steve Block    i = 1
171d0825bca7fe65beaee391d30da42e937db621564Steve Block    for pos, c in enumerate(s):
172d0825bca7fe65beaee391d30da42e937db621564Steve Block      if c == '(':
173d0825bca7fe65beaee391d30da42e937db621564Steve Block        i += 1
174d0825bca7fe65beaee391d30da42e937db621564Steve Block      elif c == ')':
175d0825bca7fe65beaee391d30da42e937db621564Steve Block        i -= 1
176d0825bca7fe65beaee391d30da42e937db621564Steve Block        if i == 0:
177d0825bca7fe65beaee391d30da42e937db621564Steve Block          return s[:pos], s[pos + 1:]
178d0825bca7fe65beaee391d30da42e937db621564Steve Block    return None, None
179d0825bca7fe65beaee391d30da42e937db621564Steve Block
1800bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdochclass _IncludeState(dict):
1810bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """Tracks line numbers for includes, and the order in which includes appear.
1820bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
1830bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    As a dict, an _IncludeState object serves as a mapping between include
1840bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    filename and line number on which that file was included.
1850bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
1860bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    Call check_next_include_order() once for each header in the file, passing
1870bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    in the type constants defined above. Calls in an illegal order will
1880bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    raise an _IncludeError with an appropriate error message.
1890bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
1900bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """
1910bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # self._section will move monotonically through this set. If it ever
1920bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # needs to move backwards, check_next_include_order will raise an error.
1930bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    _INITIAL_SECTION = 0
1940bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    _CONFIG_SECTION = 1
1950bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    _PRIMARY_SECTION = 2
1960bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    _OTHER_SECTION = 3
1970bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
1980bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    _TYPE_NAMES = {
1990bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        _CONFIG_HEADER: 'WebCore config.h',
2000bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        _PRIMARY_HEADER: 'header this file implements',
2010bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        _OTHER_HEADER: 'other header',
202d0825bca7fe65beaee391d30da42e937db621564Steve Block        _MOC_HEADER: 'moc file',
2030bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        }
2040bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    _SECTION_NAMES = {
2050bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        _INITIAL_SECTION: "... nothing.",
2060bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        _CONFIG_SECTION: "WebCore config.h.",
2070bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        _PRIMARY_SECTION: 'a header this file implements.',
2080bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        _OTHER_SECTION: 'other header.',
2090bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        }
2100bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
2110bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    def __init__(self):
2120bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        dict.__init__(self)
2130bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        self._section = self._INITIAL_SECTION
2140bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        self._visited_primary_section = False
2150bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        self.header_types = dict();
2160bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
2170bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    def visited_primary_section(self):
2180bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        return self._visited_primary_section
2190bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
2200bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    def check_next_include_order(self, header_type, file_is_header):
2210bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        """Returns a non-empty error message if the next header is out of order.
2220bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
2230bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        This function also updates the internal state to be ready to check
2240bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        the next include.
2250bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
2260bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        Args:
2270bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch          header_type: One of the _XXX_HEADER constants defined above.
2280bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch          file_is_header: Whether the file that owns this _IncludeState is itself a header
2290bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
2300bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        Returns:
2310bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch          The empty string if the header is in the right order, or an
2320bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch          error message describing what's wrong.
2330bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
2340bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        """
2350bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        if header_type == _CONFIG_HEADER and file_is_header:
2360bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            return 'Header file should not contain WebCore config.h.'
2370bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        if header_type == _PRIMARY_HEADER and file_is_header:
2380bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            return 'Header file should not contain itself.'
239d0825bca7fe65beaee391d30da42e937db621564Steve Block        if header_type == _MOC_HEADER:
240d0825bca7fe65beaee391d30da42e937db621564Steve Block            return ''
2410bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
2420bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        error_message = ''
2430bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        if self._section != self._OTHER_SECTION:
2440bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            before_error_message = ('Found %s before %s' %
2450bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                                    (self._TYPE_NAMES[header_type],
2460bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                                     self._SECTION_NAMES[self._section + 1]))
2470bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        after_error_message = ('Found %s after %s' %
2480bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                                (self._TYPE_NAMES[header_type],
2490bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                                 self._SECTION_NAMES[self._section]))
2500bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
2510bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        if header_type == _CONFIG_HEADER:
2520bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            if self._section >= self._CONFIG_SECTION:
2530bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                error_message = after_error_message
2540bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            self._section = self._CONFIG_SECTION
2550bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        elif header_type == _PRIMARY_HEADER:
2560bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            if self._section >= self._PRIMARY_SECTION:
2570bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                error_message = after_error_message
2580bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            elif self._section < self._CONFIG_SECTION:
2590bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                error_message = before_error_message
2600bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            self._section = self._PRIMARY_SECTION
2610bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            self._visited_primary_section = True
2620bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        else:
2630bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            assert header_type == _OTHER_HEADER
2640bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            if not file_is_header and self._section < self._PRIMARY_SECTION:
2650bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                error_message = before_error_message
2660bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            self._section = self._OTHER_SECTION
2670bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
2680bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        return error_message
2690bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
2700bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
271d0825bca7fe65beaee391d30da42e937db621564Steve Blockclass _FunctionState(object):
272d0825bca7fe65beaee391d30da42e937db621564Steve Block    """Tracks current function name and the number of lines in its body.
2730bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
274d0825bca7fe65beaee391d30da42e937db621564Steve Block    Attributes:
275d0825bca7fe65beaee391d30da42e937db621564Steve Block      verbosity: The verbosity level to use while checking style.
2760bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
2770bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """
2780bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
2790bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    _NORMAL_TRIGGER = 250  # for --v=0, 500 for --v=1, etc.
2800bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    _TEST_TRIGGER = 400    # about 50% more than _NORMAL_TRIGGER.
2810bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
282d0825bca7fe65beaee391d30da42e937db621564Steve Block    def __init__(self, verbosity):
283d0825bca7fe65beaee391d30da42e937db621564Steve Block        self.verbosity = verbosity
2840bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        self.in_a_function = False
2850bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        self.lines_in_function = 0
2860bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        self.current_function = ''
2870bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
2880bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    def begin(self, function_name):
2890bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        """Start analyzing function body.
2900bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
2910bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        Args:
2920bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            function_name: The name of the function being tracked.
2930bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        """
2940bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        self.in_a_function = True
2950bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        self.lines_in_function = 0
2960bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        self.current_function = function_name
2970bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
2980bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    def count(self):
2990bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        """Count line in current function body."""
3000bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        if self.in_a_function:
3010bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            self.lines_in_function += 1
3020bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
303d0825bca7fe65beaee391d30da42e937db621564Steve Block    def check(self, error, line_number):
3040bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        """Report if too many lines in function body.
3050bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
3060bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        Args:
3070bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch          error: The function to call with any errors found.
3080bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch          line_number: The number of the line to check.
3090bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        """
3100bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        if match(r'T(EST|est)', self.current_function):
3110bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            base_trigger = self._TEST_TRIGGER
3120bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        else:
3130bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            base_trigger = self._NORMAL_TRIGGER
314d0825bca7fe65beaee391d30da42e937db621564Steve Block        trigger = base_trigger * 2 ** self.verbosity
3150bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
3160bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        if self.lines_in_function > trigger:
3170bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            error_level = int(math.log(self.lines_in_function / base_trigger, 2))
3180bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            # 50 => 0, 100 => 1, 200 => 2, 400 => 3, 800 => 4, 1600 => 5, ...
3190bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            if error_level > 5:
3200bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                error_level = 5
321d0825bca7fe65beaee391d30da42e937db621564Steve Block            error(line_number, 'readability/fn_size', error_level,
3220bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                  'Small and focused functions are preferred:'
3230bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                  ' %s has %d non-comment lines'
3240bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                  ' (error triggered by exceeding %d lines).'  % (
3250bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                      self.current_function, self.lines_in_function, trigger))
3260bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
3270bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    def end(self):
3280bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        """Stop analizing function body."""
3290bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        self.in_a_function = False
3300bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
3310bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
3320bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdochclass _IncludeError(Exception):
3330bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """Indicates a problem with the include order in a file."""
3340bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    pass
3350bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
3360bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
337d0825bca7fe65beaee391d30da42e937db621564Steve Blockdef is_c_or_objective_c(file_extension):
338d0825bca7fe65beaee391d30da42e937db621564Steve Block   """Return whether the file extension corresponds to C or Objective-C.
339d0825bca7fe65beaee391d30da42e937db621564Steve Block
340d0825bca7fe65beaee391d30da42e937db621564Steve Block   Args:
341d0825bca7fe65beaee391d30da42e937db621564Steve Block     file_extension: The file extension without the leading dot.
342d0825bca7fe65beaee391d30da42e937db621564Steve Block
343d0825bca7fe65beaee391d30da42e937db621564Steve Block   """
344d0825bca7fe65beaee391d30da42e937db621564Steve Block   return file_extension in ['c', 'm']
345d0825bca7fe65beaee391d30da42e937db621564Steve Block
346d0825bca7fe65beaee391d30da42e937db621564Steve Block
3470bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdochclass FileInfo:
3480bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """Provides utility functions for filenames.
3490bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
3500bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    FileInfo provides easy access to the components of a file's path
3510bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    relative to the project root.
3520bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """
3530bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
3540bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    def __init__(self, filename):
3550bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        self._filename = filename
3560bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
3570bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    def full_name(self):
3580bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        """Make Windows paths like Unix."""
3590bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        return os.path.abspath(self._filename).replace('\\', '/')
3600bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
3610bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    def repository_name(self):
3620bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        """Full name after removing the local path to the repository.
3630bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
3640bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        If we have a real absolute path name here we can try to do something smart:
3650bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        detecting the root of the checkout and truncating /path/to/checkout from
3660bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        the name so that we get header guards that don't include things like
3670bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        "C:\Documents and Settings\..." or "/home/username/..." in them and thus
3680bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        people on different computers who have checked the source out to different
3690bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        locations won't see bogus errors.
3700bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        """
3710bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        fullname = self.full_name()
3720bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
3730bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        if os.path.exists(fullname):
3740bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            project_dir = os.path.dirname(fullname)
3750bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
3760bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            if os.path.exists(os.path.join(project_dir, ".svn")):
3770bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                # If there's a .svn file in the current directory, we
3780bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                # recursively look up the directory tree for the top
3790bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                # of the SVN checkout
3800bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                root_dir = project_dir
3810bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                one_up_dir = os.path.dirname(root_dir)
3820bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                while os.path.exists(os.path.join(one_up_dir, ".svn")):
3830bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                    root_dir = os.path.dirname(root_dir)
3840bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                    one_up_dir = os.path.dirname(one_up_dir)
3850bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
3860bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                prefix = os.path.commonprefix([root_dir, project_dir])
3870bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                return fullname[len(prefix) + 1:]
3880bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
3890bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            # Not SVN? Try to find a git top level directory by
3900bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            # searching up from the current path.
3910bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            root_dir = os.path.dirname(fullname)
3920bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            while (root_dir != os.path.dirname(root_dir)
3930bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                   and not os.path.exists(os.path.join(root_dir, ".git"))):
3940bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                root_dir = os.path.dirname(root_dir)
3950bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                if os.path.exists(os.path.join(root_dir, ".git")):
3960bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                    prefix = os.path.commonprefix([root_dir, project_dir])
3970bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                    return fullname[len(prefix) + 1:]
3980bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
3990bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # Don't know what to do; header guard warnings may be wrong...
4000bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        return fullname
4010bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
4020bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    def split(self):
4030bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        """Splits the file into the directory, basename, and extension.
4040bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
4050bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        For 'chrome/browser/browser.cpp', Split() would
4060bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        return ('chrome/browser', 'browser', '.cpp')
4070bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
4080bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        Returns:
4090bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch          A tuple of (directory, basename, extension).
4100bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        """
4110bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
4120bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        googlename = self.repository_name()
4130bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        project, rest = os.path.split(googlename)
4140bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        return (project,) + os.path.splitext(rest)
4150bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
4160bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    def base_name(self):
4170bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        """File base name - text after the final slash, before the final period."""
4180bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        return self.split()[1]
4190bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
4200bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    def extension(self):
4210bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        """File extension - text following the final period."""
4220bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        return self.split()[2]
4230bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
4240bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    def no_extension(self):
4250bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        """File has no source file extension."""
4260bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        return '/'.join(self.split()[0:2])
4270bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
4280bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    def is_source(self):
4290bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        """File has a source file extension."""
4300bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        return self.extension()[1:] in ('c', 'cc', 'cpp', 'cxx')
4310bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
4320bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
4330bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch# Matches standard C++ escape esequences per 2.13.2.3 of the C++ standard.
4340bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch_RE_PATTERN_CLEANSE_LINE_ESCAPES = re.compile(
4350bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    r'\\([abfnrtv?"\\\']|\d+|x[0-9a-fA-F]+)')
4360bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch# Matches strings.  Escape codes should already be removed by ESCAPES.
4370bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch_RE_PATTERN_CLEANSE_LINE_DOUBLE_QUOTES = re.compile(r'"[^"]*"')
4380bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch# Matches characters.  Escape codes should already be removed by ESCAPES.
4390bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch_RE_PATTERN_CLEANSE_LINE_SINGLE_QUOTES = re.compile(r"'.'")
4400bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch# Matches multi-line C++ comments.
4410bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch# This RE is a little bit more complicated than one might expect, because we
4420bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch# have to take care of space removals tools so we can handle comments inside
4430bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch# statements better.
4440bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch# The current rule is: We only clear spaces from both sides when we're at the
4450bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch# end of the line. Otherwise, we try to remove spaces from the right side,
4460bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch# if this doesn't work we try on left side but only if there's a non-character
4470bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch# on the right.
4480bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch_RE_PATTERN_CLEANSE_LINE_C_COMMENTS = re.compile(
4490bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    r"""(\s*/\*.*\*/\s*$|
4500bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            /\*.*\*/\s+|
4510bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch         \s+/\*.*\*/(?=\W)|
4520bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            /\*.*\*/)""", re.VERBOSE)
4530bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
4540bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
4550bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdochdef is_cpp_string(line):
4560bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """Does line terminate so, that the next symbol is in string constant.
4570bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
4580bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    This function does not consider single-line nor multi-line comments.
4590bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
4600bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    Args:
4610bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      line: is a partial line of code starting from the 0..n.
4620bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
4630bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    Returns:
4640bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      True, if next character appended to 'line' is inside a
4650bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      string constant.
4660bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """
4670bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
4680bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    line = line.replace(r'\\', 'XX')  # after this, \\" does not match to \"
4690bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    return ((line.count('"') - line.count(r'\"') - line.count("'\"'")) & 1) == 1
4700bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
4710bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
4720bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdochdef find_next_multi_line_comment_start(lines, line_index):
4730bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """Find the beginning marker for a multiline comment."""
4740bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    while line_index < len(lines):
4750bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        if lines[line_index].strip().startswith('/*'):
4760bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            # Only return this marker if the comment goes beyond this line
4770bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            if lines[line_index].strip().find('*/', 2) < 0:
4780bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                return line_index
4790bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        line_index += 1
4800bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    return len(lines)
4810bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
4820bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
4830bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdochdef find_next_multi_line_comment_end(lines, line_index):
4840bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """We are inside a comment, find the end marker."""
4850bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    while line_index < len(lines):
4860bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        if lines[line_index].strip().endswith('*/'):
4870bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            return line_index
4880bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        line_index += 1
4890bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    return len(lines)
4900bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
4910bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
4920bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdochdef remove_multi_line_comments_from_range(lines, begin, end):
4930bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """Clears a range of lines for multi-line comments."""
4940bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # Having // dummy comments makes the lines non-empty, so we will not get
4950bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # unnecessary blank line warnings later in the code.
4960bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    for i in range(begin, end):
4970bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        lines[i] = '// dummy'
4980bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
4990bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
500d0825bca7fe65beaee391d30da42e937db621564Steve Blockdef remove_multi_line_comments(lines, error):
5010bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """Removes multiline (c-style) comments from lines."""
5020bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    line_index = 0
5030bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    while line_index < len(lines):
5040bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        line_index_begin = find_next_multi_line_comment_start(lines, line_index)
5050bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        if line_index_begin >= len(lines):
5060bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            return
5070bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        line_index_end = find_next_multi_line_comment_end(lines, line_index_begin)
5080bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        if line_index_end >= len(lines):
509d0825bca7fe65beaee391d30da42e937db621564Steve Block            error(line_index_begin + 1, 'readability/multiline_comment', 5,
5100bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                  'Could not find end of multi-line comment')
5110bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            return
5120bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        remove_multi_line_comments_from_range(lines, line_index_begin, line_index_end + 1)
5130bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        line_index = line_index_end + 1
5140bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
5150bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
5160bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdochdef cleanse_comments(line):
5170bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """Removes //-comments and single-line C-style /* */ comments.
5180bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
5190bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    Args:
5200bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      line: A line of C++ source.
5210bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
5220bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    Returns:
5230bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      The line with single-line comments removed.
5240bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """
5250bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    comment_position = line.find('//')
5260bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if comment_position != -1 and not is_cpp_string(line[:comment_position]):
5270bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        line = line[:comment_position]
5280bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # get rid of /* ... */
5290bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    return _RE_PATTERN_CLEANSE_LINE_C_COMMENTS.sub('', line)
5300bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
5310bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
5320bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdochclass CleansedLines(object):
5330bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """Holds 3 copies of all lines with different preprocessing applied to them.
5340bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
5350bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    1) elided member contains lines without strings and comments,
5360bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    2) lines member contains lines without comments, and
5370bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    3) raw member contains all the lines without processing.
5380bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    All these three members are of <type 'list'>, and of the same length.
5390bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """
5400bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
5410bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    def __init__(self, lines):
5420bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        self.elided = []
5430bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        self.lines = []
5440bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        self.raw_lines = lines
5450bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        self._num_lines = len(lines)
5460bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        for line_number in range(len(lines)):
5470bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            self.lines.append(cleanse_comments(lines[line_number]))
5480bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            elided = self.collapse_strings(lines[line_number])
5490bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            self.elided.append(cleanse_comments(elided))
5500bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
5510bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    def num_lines(self):
5520bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        """Returns the number of lines represented."""
5530bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        return self._num_lines
5540bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
5550bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    @staticmethod
5560bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    def collapse_strings(elided):
5570bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        """Collapses strings and chars on a line to simple "" or '' blocks.
5580bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
5590bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        We nix strings first so we're not fooled by text like '"http://"'
5600bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
5610bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        Args:
5620bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch          elided: The line being processed.
5630bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
5640bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        Returns:
5650bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch          The line with collapsed strings.
5660bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        """
5670bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        if not _RE_PATTERN_INCLUDE.match(elided):
5680bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            # Remove escaped characters first to make quote/single quote collapsing
5690bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            # basic.  Things that look like escaped characters shouldn't occur
5700bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            # outside of strings and chars.
5710bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            elided = _RE_PATTERN_CLEANSE_LINE_ESCAPES.sub('', elided)
5720bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            elided = _RE_PATTERN_CLEANSE_LINE_SINGLE_QUOTES.sub("''", elided)
5730bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            elided = _RE_PATTERN_CLEANSE_LINE_DOUBLE_QUOTES.sub('""', elided)
5740bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        return elided
5750bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
5760bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
5770bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdochdef close_expression(clean_lines, line_number, pos):
5780bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """If input points to ( or { or [, finds the position that closes it.
5790bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
5800bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    If lines[line_number][pos] points to a '(' or '{' or '[', finds the the
5810bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    line_number/pos that correspond to the closing of the expression.
5820bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
5830bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    Args:
5840bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      clean_lines: A CleansedLines instance containing the file.
5850bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      line_number: The number of the line to check.
5860bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      pos: A position on the line.
5870bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
5880bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    Returns:
5890bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      A tuple (line, line_number, pos) pointer *past* the closing brace, or
5900bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      (line, len(lines), -1) if we never find a close.  Note we ignore
5910bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      strings and comments when matching; and the line we return is the
5920bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      'cleansed' line at line_number.
5930bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """
5940bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
5950bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    line = clean_lines.elided[line_number]
5960bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    start_character = line[pos]
5970bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if start_character not in '({[':
5980bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        return (line, clean_lines.num_lines(), -1)
5990bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if start_character == '(':
6000bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        end_character = ')'
6010bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if start_character == '[':
6020bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        end_character = ']'
6030bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if start_character == '{':
6040bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        end_character = '}'
6050bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
6060bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    num_open = line.count(start_character) - line.count(end_character)
6070bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    while line_number < clean_lines.num_lines() and num_open > 0:
6080bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        line_number += 1
6090bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        line = clean_lines.elided[line_number]
6100bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        num_open += line.count(start_character) - line.count(end_character)
6110bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # OK, now find the end_character that actually got us back to even
6120bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    endpos = len(line)
6130bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    while num_open >= 0:
6140bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        endpos = line.rfind(')', 0, endpos)
6150bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        num_open -= 1                 # chopped off another )
6160bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    return (line, line_number, endpos + 1)
6170bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
6180bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
619d0825bca7fe65beaee391d30da42e937db621564Steve Blockdef check_for_copyright(lines, error):
6200bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """Logs an error if no Copyright message appears at the top of the file."""
6210bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
6220bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # We'll say it should occur by line 10. Don't forget there's a
6230bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # dummy line at the front.
6240bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    for line in xrange(1, min(len(lines), 11)):
6250bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        if re.search(r'Copyright', lines[line], re.I):
6260bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            break
6270bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    else:                       # means no copyright line was found
628d0825bca7fe65beaee391d30da42e937db621564Steve Block        error(0, 'legal/copyright', 5,
6290bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch              'No copyright message found.  '
6300bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch              'You should have a line: "Copyright [year] <Copyright Owner>"')
6310bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
6320bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
6330bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdochdef get_header_guard_cpp_variable(filename):
6340bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """Returns the CPP variable that should be used as a header guard.
6350bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
6360bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    Args:
6370bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      filename: The name of a C++ header file.
6380bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
6390bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    Returns:
6400bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      The CPP variable that should be used as a header guard in the
6410bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      named file.
6420bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
6430bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """
6440bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
645d0825bca7fe65beaee391d30da42e937db621564Steve Block    return sub(r'[-.\s]', '_', os.path.basename(filename))
6460bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
6470bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
6480bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdochdef check_for_header_guard(filename, lines, error):
6490bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """Checks that the file contains a header guard.
6500bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
6510bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    Logs an error if no #ifndef header guard is present.  For other
6520bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    headers, checks that the full pathname is used.
6530bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
6540bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    Args:
6550bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      filename: The name of the C++ header file.
6560bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      lines: An array of strings, each representing a line of the file.
6570bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      error: The function to call with any errors found.
6580bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """
6590bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
6600bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    cppvar = get_header_guard_cpp_variable(filename)
6610bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
6620bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    ifndef = None
6630bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    ifndef_line_number = 0
6640bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    define = None
6650bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    for line_number, line in enumerate(lines):
6660bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        line_split = line.split()
6670bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        if len(line_split) >= 2:
6680bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            # find the first occurrence of #ifndef and #define, save arg
6690bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            if not ifndef and line_split[0] == '#ifndef':
6700bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                # set ifndef to the header guard presented on the #ifndef line.
6710bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                ifndef = line_split[1]
6720bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                ifndef_line_number = line_number
6730bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            if not define and line_split[0] == '#define':
6740bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                define = line_split[1]
675d0825bca7fe65beaee391d30da42e937db621564Steve Block            if define and ifndef:
676d0825bca7fe65beaee391d30da42e937db621564Steve Block                break
6770bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
6780bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if not ifndef or not define or ifndef != define:
679d0825bca7fe65beaee391d30da42e937db621564Steve Block        error(0, 'build/header_guard', 5,
6800bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch              'No #ifndef header guard found, suggested CPP variable is: %s' %
6810bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch              cppvar)
6820bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        return
6830bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
684d0825bca7fe65beaee391d30da42e937db621564Steve Block    # The guard should be File_h.
6850bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if ifndef != cppvar:
686d0825bca7fe65beaee391d30da42e937db621564Steve Block        error(ifndef_line_number, 'build/header_guard', 5,
6870bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch              '#ifndef header guard has wrong style, please use: %s' % cppvar)
6880bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
6890bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
690d0825bca7fe65beaee391d30da42e937db621564Steve Blockdef check_for_unicode_replacement_characters(lines, error):
6910bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """Logs an error for each line containing Unicode replacement characters.
6920bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
6930bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    These indicate that either the file contained invalid UTF-8 (likely)
6940bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    or Unicode replacement characters (which it shouldn't).  Note that
6950bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    it's possible for this to throw off line numbering if the invalid
6960bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    UTF-8 occurred adjacent to a newline.
6970bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
6980bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    Args:
6990bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      lines: An array of strings, each representing a line of the file.
7000bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      error: The function to call with any errors found.
7010bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """
7020bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    for line_number, line in enumerate(lines):
7030bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        if u'\ufffd' in line:
704d0825bca7fe65beaee391d30da42e937db621564Steve Block            error(line_number, 'readability/utf8', 5,
7050bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                  'Line contains invalid UTF-8 (or Unicode replacement character).')
7060bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
7070bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
708d0825bca7fe65beaee391d30da42e937db621564Steve Blockdef check_for_new_line_at_eof(lines, error):
7090bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """Logs an error if there is no newline char at the end of the file.
7100bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
7110bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    Args:
7120bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      lines: An array of strings, each representing a line of the file.
7130bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      error: The function to call with any errors found.
7140bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """
7150bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
7160bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # The array lines() was created by adding two newlines to the
7170bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # original file (go figure), then splitting on \n.
7180bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # To verify that the file ends in \n, we just have to make sure the
7190bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # last-but-two element of lines() exists and is empty.
7200bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if len(lines) < 3 or lines[-2]:
721d0825bca7fe65beaee391d30da42e937db621564Steve Block        error(len(lines) - 2, 'whitespace/ending_newline', 5,
7220bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch              'Could not find a newline character at the end of the file.')
7230bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
7240bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
725d0825bca7fe65beaee391d30da42e937db621564Steve Blockdef check_for_multiline_comments_and_strings(clean_lines, line_number, error):
7260bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """Logs an error if we see /* ... */ or "..." that extend past one line.
7270bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
7280bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    /* ... */ comments are legit inside macros, for one line.
7290bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    Otherwise, we prefer // comments, so it's ok to warn about the
7300bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    other.  Likewise, it's ok for strings to extend across multiple
7310bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    lines, as long as a line continuation character (backslash)
7320bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    terminates each line. Although not currently prohibited by the C++
7330bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    style guide, it's ugly and unnecessary. We don't do well with either
7340bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    in this lint program, so we warn about both.
7350bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
7360bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    Args:
7370bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      clean_lines: A CleansedLines instance containing the file.
7380bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      line_number: The number of the line to check.
7390bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      error: The function to call with any errors found.
7400bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """
7410bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    line = clean_lines.elided[line_number]
7420bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
7430bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # Remove all \\ (escaped backslashes) from the line. They are OK, and the
7440bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # second (escaped) slash may trigger later \" detection erroneously.
7450bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    line = line.replace('\\\\', '')
7460bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
7470bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if line.count('/*') > line.count('*/'):
748d0825bca7fe65beaee391d30da42e937db621564Steve Block        error(line_number, 'readability/multiline_comment', 5,
7490bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch              'Complex multi-line /*...*/-style comment found. '
7500bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch              'Lint may give bogus warnings.  '
7510bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch              'Consider replacing these with //-style comments, '
7520bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch              'with #if 0...#endif, '
7530bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch              'or with more clearly structured multi-line comments.')
7540bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
7550bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if (line.count('"') - line.count('\\"')) % 2:
756d0825bca7fe65beaee391d30da42e937db621564Steve Block        error(line_number, 'readability/multiline_string', 5,
7570bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch              'Multi-line string ("...") found.  This lint script doesn\'t '
7580bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch              'do well with such strings, and may give bogus warnings.  They\'re '
7590bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch              'ugly and unnecessary, and you should use concatenation instead".')
7600bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
7610bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
7620bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch_THREADING_LIST = (
7630bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    ('asctime(', 'asctime_r('),
7640bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    ('ctime(', 'ctime_r('),
7650bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    ('getgrgid(', 'getgrgid_r('),
7660bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    ('getgrnam(', 'getgrnam_r('),
7670bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    ('getlogin(', 'getlogin_r('),
7680bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    ('getpwnam(', 'getpwnam_r('),
7690bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    ('getpwuid(', 'getpwuid_r('),
7700bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    ('gmtime(', 'gmtime_r('),
7710bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    ('localtime(', 'localtime_r('),
7720bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    ('rand(', 'rand_r('),
7730bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    ('readdir(', 'readdir_r('),
7740bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    ('strtok(', 'strtok_r('),
7750bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    ('ttyname(', 'ttyname_r('),
7760bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    )
7770bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
7780bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
779d0825bca7fe65beaee391d30da42e937db621564Steve Blockdef check_posix_threading(clean_lines, line_number, error):
7800bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """Checks for calls to thread-unsafe functions.
7810bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
7820bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    Much code has been originally written without consideration of
7830bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    multi-threading. Also, engineers are relying on their old experience;
7840bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    they have learned posix before threading extensions were added. These
7850bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    tests guide the engineers to use thread-safe functions (when using
7860bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    posix directly).
7870bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
7880bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    Args:
7890bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      clean_lines: A CleansedLines instance containing the file.
7900bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      line_number: The number of the line to check.
7910bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      error: The function to call with any errors found.
7920bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """
7930bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    line = clean_lines.elided[line_number]
7940bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    for single_thread_function, multithread_safe_function in _THREADING_LIST:
7950bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        index = line.find(single_thread_function)
7960bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # Comparisons made explicit for clarity -- pylint: disable-msg=C6403
7970bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        if index >= 0 and (index == 0 or (not line[index - 1].isalnum()
7980bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                                          and line[index - 1] not in ('_', '.', '>'))):
799d0825bca7fe65beaee391d30da42e937db621564Steve Block            error(line_number, 'runtime/threadsafe_fn', 2,
8000bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                  'Consider using ' + multithread_safe_function +
8010bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                  '...) instead of ' + single_thread_function +
8020bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                  '...) for improved thread safety.')
8030bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
8040bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
8050bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch# Matches invalid increment: *count++, which moves pointer instead of
8060bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch# incrementing a value.
8070bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch_RE_PATTERN_INVALID_INCREMENT = re.compile(
8080bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    r'^\s*\*\w+(\+\+|--);')
8090bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
8100bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
811d0825bca7fe65beaee391d30da42e937db621564Steve Blockdef check_invalid_increment(clean_lines, line_number, error):
8120bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """Checks for invalid increment *count++.
8130bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
8140bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    For example following function:
8150bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    void increment_counter(int* count) {
8160bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        *count++;
8170bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    }
8180bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    is invalid, because it effectively does count++, moving pointer, and should
8190bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    be replaced with ++*count, (*count)++ or *count += 1.
8200bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
8210bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    Args:
8220bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      clean_lines: A CleansedLines instance containing the file.
8230bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      line_number: The number of the line to check.
8240bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      error: The function to call with any errors found.
8250bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """
8260bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    line = clean_lines.elided[line_number]
8270bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if _RE_PATTERN_INVALID_INCREMENT.match(line):
828d0825bca7fe65beaee391d30da42e937db621564Steve Block        error(line_number, 'runtime/invalid_increment', 5,
8290bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch              'Changing pointer instead of value (or unused value of operator*).')
8300bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
8310bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
8320bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdochclass _ClassInfo(object):
8330bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """Stores information about a class."""
8340bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
8350bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    def __init__(self, name, line_number):
8360bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        self.name = name
8370bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        self.line_number = line_number
8380bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        self.seen_open_brace = False
8390bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        self.is_derived = False
8400bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        self.virtual_method_line_number = None
8410bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        self.has_virtual_destructor = False
8420bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        self.brace_depth = 0
8430bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
8440bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
8450bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdochclass _ClassState(object):
8460bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """Holds the current state of the parse relating to class declarations.
8470bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
8480bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    It maintains a stack of _ClassInfos representing the parser's guess
8490bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    as to the current nesting of class declarations. The innermost class
8500bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    is at the top (back) of the stack. Typically, the stack will either
8510bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    be empty or have exactly one entry.
8520bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """
8530bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
8540bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    def __init__(self):
8550bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        self.classinfo_stack = []
8560bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
857d0825bca7fe65beaee391d30da42e937db621564Steve Block    def check_finished(self, error):
8580bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        """Checks that all classes have been completely parsed.
8590bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
8600bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        Call this when all lines in a file have been processed.
8610bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        Args:
8620bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch          error: The function to call with any errors found.
8630bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        """
8640bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        if self.classinfo_stack:
8650bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            # Note: This test can result in false positives if #ifdef constructs
8660bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            # get in the way of brace matching. See the testBuildClass test in
8670bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            # cpp_style_unittest.py for an example of this.
868d0825bca7fe65beaee391d30da42e937db621564Steve Block            error(self.classinfo_stack[0].line_number, 'build/class', 5,
8690bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                  'Failed to find complete declaration of class %s' %
8700bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                  self.classinfo_stack[0].name)
8710bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
8720bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
873643ca7872b450ea4efacab6188849e5aac2ba161Steve Blockclass _FileState(object):
874643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    def __init__(self):
875643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        self._did_inside_namespace_indent_warning = False
876643ca7872b450ea4efacab6188849e5aac2ba161Steve Block
877643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    def set_did_inside_namespace_indent_warning(self):
878643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        self._did_inside_namespace_indent_warning = True
879643ca7872b450ea4efacab6188849e5aac2ba161Steve Block
880643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    def did_inside_namespace_indent_warning(self):
881643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        return self._did_inside_namespace_indent_warning
882643ca7872b450ea4efacab6188849e5aac2ba161Steve Block
883d0825bca7fe65beaee391d30da42e937db621564Steve Blockdef check_for_non_standard_constructs(clean_lines, line_number,
8840bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                                      class_state, error):
8850bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """Logs an error if we see certain non-ANSI constructs ignored by gcc-2.
8860bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
8870bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    Complain about several constructs which gcc-2 accepts, but which are
8880bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    not standard C++.  Warning about these in lint is one way to ease the
8890bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    transition to new compilers.
8900bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    - put storage class first (e.g. "static const" instead of "const static").
8910bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    - "%lld" instead of %qd" in printf-type functions.
8920bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    - "%1$d" is non-standard in printf-type functions.
8930bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    - "\%" is an undefined character escape sequence.
8940bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    - text after #endif is not allowed.
8950bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    - invalid inner-style forward declaration.
8960bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    - >? and <? operators, and their >?= and <?= cousins.
8970bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    - classes with virtual methods need virtual destructors (compiler warning
8980bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        available, but not turned on yet.)
8990bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
9000bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    Additionally, check for constructor/destructor style violations as it
9010bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    is very convenient to do so while checking for gcc-2 compliance.
9020bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
9030bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    Args:
9040bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      clean_lines: A CleansedLines instance containing the file.
9050bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      line_number: The number of the line to check.
9060bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      class_state: A _ClassState instance which maintains information about
9070bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                   the current stack of nested class declarations being parsed.
908d0825bca7fe65beaee391d30da42e937db621564Steve Block      error: A callable to which errors are reported, which takes parameters:
909d0825bca7fe65beaee391d30da42e937db621564Steve Block             line number, error level, and message
9100bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """
9110bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
9120bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # Remove comments from the line, but leave in strings for now.
9130bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    line = clean_lines.lines[line_number]
9140bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
9150bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if search(r'printf\s*\(.*".*%[-+ ]?\d*q', line):
916d0825bca7fe65beaee391d30da42e937db621564Steve Block        error(line_number, 'runtime/printf_format', 3,
9170bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch              '%q in format strings is deprecated.  Use %ll instead.')
9180bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
9190bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if search(r'printf\s*\(.*".*%\d+\$', line):
920d0825bca7fe65beaee391d30da42e937db621564Steve Block        error(line_number, 'runtime/printf_format', 2,
9210bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch              '%N$ formats are unconventional.  Try rewriting to avoid them.')
9220bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
9230bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # Remove escaped backslashes before looking for undefined escapes.
9240bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    line = line.replace('\\\\', '')
9250bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
9260bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if search(r'("|\').*\\(%|\[|\(|{)', line):
927d0825bca7fe65beaee391d30da42e937db621564Steve Block        error(line_number, 'build/printf_format', 3,
9280bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch              '%, [, (, and { are undefined character escapes.  Unescape them.')
9290bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
9300bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # For the rest, work with both comments and strings removed.
9310bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    line = clean_lines.elided[line_number]
9320bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
9330bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if search(r'\b(const|volatile|void|char|short|int|long'
9340bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch              r'|float|double|signed|unsigned'
9350bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch              r'|schar|u?int8|u?int16|u?int32|u?int64)'
9360bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch              r'\s+(auto|register|static|extern|typedef)\b',
9370bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch              line):
938d0825bca7fe65beaee391d30da42e937db621564Steve Block        error(line_number, 'build/storage_class', 5,
9390bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch              'Storage class (static, extern, typedef, etc) should be first.')
9400bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
9410bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if match(r'\s*#\s*endif\s*[^/\s]+', line):
942d0825bca7fe65beaee391d30da42e937db621564Steve Block        error(line_number, 'build/endif_comment', 5,
9430bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch              'Uncommented text after #endif is non-standard.  Use a comment.')
9440bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
9450bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if match(r'\s*class\s+(\w+\s*::\s*)+\w+\s*;', line):
946d0825bca7fe65beaee391d30da42e937db621564Steve Block        error(line_number, 'build/forward_decl', 5,
9470bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch              'Inner-style forward declarations are invalid.  Remove this line.')
9480bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
9490bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if search(r'(\w+|[+-]?\d+(\.\d*)?)\s*(<|>)\?=?\s*(\w+|[+-]?\d+)(\.\d*)?', line):
950d0825bca7fe65beaee391d30da42e937db621564Steve Block        error(line_number, 'build/deprecated', 3,
9510bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch              '>? and <? (max and min) operators are non-standard and deprecated.')
9520bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
9530bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # Track class entry and exit, and attempt to find cases within the
9540bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # class declaration that don't meet the C++ style
9550bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # guidelines. Tracking is very dependent on the code matching Google
9560bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # style guidelines, but it seems to perform well enough in testing
9570bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # to be a worthwhile addition to the checks.
9580bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    classinfo_stack = class_state.classinfo_stack
9590bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # Look for a class declaration
9600bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    class_decl_match = match(
9610bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        r'\s*(template\s*<[\w\s<>,:]*>\s*)?(class|struct)\s+(\w+(::\w+)*)', line)
9620bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if class_decl_match:
9630bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        classinfo_stack.append(_ClassInfo(class_decl_match.group(3), line_number))
9640bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
9650bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # Everything else in this function uses the top of the stack if it's
9660bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # not empty.
9670bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if not classinfo_stack:
9680bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        return
9690bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
9700bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    classinfo = classinfo_stack[-1]
9710bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
9720bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # If the opening brace hasn't been seen look for it and also
9730bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # parent class declarations.
9740bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if not classinfo.seen_open_brace:
9750bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # If the line has a ';' in it, assume it's a forward declaration or
9760bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # a single-line class declaration, which we won't process.
9770bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        if line.find(';') != -1:
9780bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            classinfo_stack.pop()
9790bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            return
9800bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        classinfo.seen_open_brace = (line.find('{') != -1)
9810bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # Look for a bare ':'
9820bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        if search('(^|[^:]):($|[^:])', line):
9830bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            classinfo.is_derived = True
9840bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        if not classinfo.seen_open_brace:
9850bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            return  # Everything else in this function is for after open brace
9860bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
9870bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # The class may have been declared with namespace or classname qualifiers.
9880bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # The constructor and destructor will not have those qualifiers.
9890bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    base_classname = classinfo.name.split('::')[-1]
9900bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
9910bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # Look for single-argument constructors that aren't marked explicit.
9920bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # Technically a valid construct, but against style.
9930bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    args = match(r'(?<!explicit)\s+%s\s*\(([^,()]+)\)'
9940bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                 % re.escape(base_classname),
9950bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                 line)
9960bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if (args
9970bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        and args.group(1) != 'void'
9980bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        and not match(r'(const\s+)?%s\s*&' % re.escape(base_classname),
9990bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                      args.group(1).strip())):
1000d0825bca7fe65beaee391d30da42e937db621564Steve Block        error(line_number, 'runtime/explicit', 5,
10010bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch              'Single-argument constructors should be marked explicit.')
10020bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
10030bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # Look for methods declared virtual.
10040bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if search(r'\bvirtual\b', line):
10050bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        classinfo.virtual_method_line_number = line_number
10060bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # Only look for a destructor declaration on the same line. It would
10070bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # be extremely unlikely for the destructor declaration to occupy
10080bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # more than one line.
10090bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        if search(r'~%s\s*\(' % base_classname, line):
10100bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            classinfo.has_virtual_destructor = True
10110bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
10120bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # Look for class end.
10130bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    brace_depth = classinfo.brace_depth
10140bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    brace_depth = brace_depth + line.count('{') - line.count('}')
10150bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if brace_depth <= 0:
10160bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        classinfo = classinfo_stack.pop()
10170bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # Try to detect missing virtual destructor declarations.
10180bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # For now, only warn if a non-derived class with virtual methods lacks
10190bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # a virtual destructor. This is to make it less likely that people will
10200bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # declare derived virtual destructors without declaring the base
10210bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # destructor virtual.
10220bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        if ((classinfo.virtual_method_line_number is not None)
10230bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            and (not classinfo.has_virtual_destructor)
10240bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            and (not classinfo.is_derived)):  # Only warn for base classes
1025d0825bca7fe65beaee391d30da42e937db621564Steve Block            error(classinfo.line_number, 'runtime/virtual', 4,
10260bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                  'The class %s probably needs a virtual destructor due to '
10270bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                  'having virtual method(s), one declared at line %d.'
10280bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                  % (classinfo.name, classinfo.virtual_method_line_number))
10290bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    else:
10300bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        classinfo.brace_depth = brace_depth
10310bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
10320bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
1033d0825bca7fe65beaee391d30da42e937db621564Steve Blockdef check_spacing_for_function_call(line, line_number, error):
10340bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """Checks for the correctness of various spacing around function calls.
10350bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
10360bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    Args:
10370bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      line: The text of the line to check.
10380bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      line_number: The number of the line to check.
10390bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      error: The function to call with any errors found.
10400bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """
10410bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
10420bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # Since function calls often occur inside if/for/foreach/while/switch
10430bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # expressions - which have their own, more liberal conventions - we
10440bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # first see if we should be looking inside such an expression for a
10450bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # function call, to which we can apply more strict standards.
10460bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    function_call = line    # if there's no control flow construct, look at whole line
10470bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    for pattern in (r'\bif\s*\((.*)\)\s*{',
10480bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                    r'\bfor\s*\((.*)\)\s*{',
10490bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                    r'\bforeach\s*\((.*)\)\s*{',
10500bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                    r'\bwhile\s*\((.*)\)\s*[{;]',
10510bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                    r'\bswitch\s*\((.*)\)\s*{'):
10520bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        matched = search(pattern, line)
10530bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        if matched:
10540bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            function_call = matched.group(1)    # look inside the parens for function calls
10550bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            break
10560bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
10570bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # Except in if/for/foreach/while/switch, there should never be space
10580bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # immediately inside parens (eg "f( 3, 4 )").  We make an exception
10590bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # for nested parens ( (a+b) + c ).  Likewise, there should never be
10600bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # a space before a ( when it's a function argument.  I assume it's a
10610bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # function argument when the char before the whitespace is legal in
10620bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # a function name (alnum + _) and we're not starting a macro. Also ignore
10630bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # pointers and references to arrays and functions coz they're too tricky:
10640bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # we use a very simple way to recognize these:
10650bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # " (something)(maybe-something)" or
10660bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # " (something)(maybe-something," or
10670bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # " (something)[something]"
10680bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # Note that we assume the contents of [] to be short enough that
10690bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # they'll never need to wrap.
10700bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if (  # Ignore control structures.
10710bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        not search(r'\b(if|for|foreach|while|switch|return|new|delete)\b', function_call)
10720bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # Ignore pointers/references to functions.
10730bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        and not search(r' \([^)]+\)\([^)]*(\)|,$)', function_call)
10740bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # Ignore pointers/references to arrays.
10750bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        and not search(r' \([^)]+\)\[[^\]]+\]', function_call)):
10760bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        if search(r'\w\s*\([ \t](?!\s*\\$)', function_call):      # a ( used for a fn call
1077d0825bca7fe65beaee391d30da42e937db621564Steve Block            error(line_number, 'whitespace/parens', 4,
10780bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                  'Extra space after ( in function call')
10790bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        elif search(r'\([ \t]+(?!(\s*\\)|\()', function_call):
1080d0825bca7fe65beaee391d30da42e937db621564Steve Block            error(line_number, 'whitespace/parens', 2,
10810bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                  'Extra space after (')
10820bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        if (search(r'\w\s+\(', function_call)
10830bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            and not search(r'#\s*define|typedef', function_call)):
1084d0825bca7fe65beaee391d30da42e937db621564Steve Block            error(line_number, 'whitespace/parens', 4,
10850bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                  'Extra space before ( in function call')
10860bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # If the ) is followed only by a newline or a { + newline, assume it's
10870bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # part of a control statement (if/while/etc), and don't complain
10880bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        if search(r'[^)\s]\s+\)(?!\s*$|{\s*$)', function_call):
1089d0825bca7fe65beaee391d30da42e937db621564Steve Block            error(line_number, 'whitespace/parens', 2,
10900bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                  'Extra space before )')
10910bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
10920bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
10930bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdochdef is_blank_line(line):
10940bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """Returns true if the given line is blank.
10950bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
10960bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    We consider a line to be blank if the line is empty or consists of
10970bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    only white spaces.
10980bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
10990bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    Args:
11000bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      line: A line of a string.
11010bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
11020bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    Returns:
11030bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      True, if the given line is blank.
11040bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """
11050bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    return not line or line.isspace()
11060bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
11070bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
1108d0825bca7fe65beaee391d30da42e937db621564Steve Blockdef check_for_function_lengths(clean_lines, line_number, function_state, error):
11090bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """Reports for long function bodies.
11100bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
11110bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    For an overview why this is done, see:
11120bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml#Write_Short_Functions
11130bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
11140bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    Uses a simplistic algorithm assuming other style guidelines
11150bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    (especially spacing) are followed.
11160bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    Only checks unindented functions, so class members are unchecked.
11170bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    Trivial bodies are unchecked, so constructors with huge initializer lists
11180bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    may be missed.
11190bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    Blank/comment lines are not counted so as to avoid encouraging the removal
11200bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    of vertical space and commments just to get through a lint check.
11210bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    NOLINT *on the last line of a function* disables this check.
11220bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
11230bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    Args:
11240bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      clean_lines: A CleansedLines instance containing the file.
11250bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      line_number: The number of the line to check.
11260bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      function_state: Current function name and lines in body so far.
11270bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      error: The function to call with any errors found.
11280bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """
11290bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    lines = clean_lines.lines
11300bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    line = lines[line_number]
11310bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    raw = clean_lines.raw_lines
11320bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    raw_line = raw[line_number]
11330bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    joined_line = ''
11340bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
11350bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    starting_func = False
11360bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    regexp = r'(\w(\w|::|\*|\&|\s)*)\('  # decls * & space::name( ...
11370bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    match_result = match(regexp, line)
11380bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if match_result:
11390bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # If the name is all caps and underscores, figure it's a macro and
11400bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # ignore it, unless it's TEST or TEST_F.
11410bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        function_name = match_result.group(1).split()[-1]
11420bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        if function_name == 'TEST' or function_name == 'TEST_F' or (not match(r'[A-Z_]+$', function_name)):
11430bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            starting_func = True
11440bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
11450bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if starting_func:
11460bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        body_found = False
11470bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        for start_line_number in xrange(line_number, clean_lines.num_lines()):
11480bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            start_line = lines[start_line_number]
11490bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            joined_line += ' ' + start_line.lstrip()
11500bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            if search(r'(;|})', start_line):  # Declarations and trivial functions
11510bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                body_found = True
11520bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                break                              # ... ignore
11530bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            if search(r'{', start_line):
11540bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                body_found = True
11550bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                function = search(r'((\w|:)*)\(', line).group(1)
11560bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                if match(r'TEST', function):    # Handle TEST... macros
11570bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                    parameter_regexp = search(r'(\(.*\))', joined_line)
11580bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                    if parameter_regexp:             # Ignore bad syntax
11590bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                        function += parameter_regexp.group(1)
11600bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                else:
11610bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                    function += '()'
11620bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                function_state.begin(function)
11630bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                break
11640bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        if not body_found:
11650bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            # No body for the function (or evidence of a non-function) was found.
1166d0825bca7fe65beaee391d30da42e937db621564Steve Block            error(line_number, 'readability/fn_size', 5,
11670bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                  'Lint failed to find start of function body.')
11680bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    elif match(r'^\}\s*$', line):  # function end
11690bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        if not search(r'\bNOLINT\b', raw_line):
1170d0825bca7fe65beaee391d30da42e937db621564Steve Block            function_state.check(error, line_number)
11710bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        function_state.end()
11720bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    elif not match(r'^\s*$', line):
11730bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        function_state.count()  # Count non-blank/non-comment lines.
11740bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
11750bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
1176d0825bca7fe65beaee391d30da42e937db621564Steve Blockdef check_spacing(file_extension, clean_lines, line_number, error):
11770bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """Checks for the correctness of various spacing issues in the code.
11780bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
11790bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    Things we check for: spaces around operators, spaces after
11800bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if/for/while/switch, no spaces around parens in function calls, two
11810bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    spaces between code and comment, don't start a block with a blank
11820bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    line, don't end a function with a blank line, don't have too many
11830bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    blank lines in a row.
11840bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
11850bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    Args:
1186d0825bca7fe65beaee391d30da42e937db621564Steve Block      file_extension: The current file extension, without the leading dot.
11870bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      clean_lines: A CleansedLines instance containing the file.
11880bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      line_number: The number of the line to check.
11890bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      error: The function to call with any errors found.
11900bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """
11910bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
11920bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    raw = clean_lines.raw_lines
11930bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    line = raw[line_number]
11940bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
11950bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # Before nixing comments, check if the line is blank for no good
11960bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # reason.  This includes the first line after a block is opened, and
11970bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # blank lines at the end of a function (ie, right before a line like '}').
11980bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if is_blank_line(line):
11990bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        elided = clean_lines.elided
12000bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        previous_line = elided[line_number - 1]
12010bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        previous_brace = previous_line.rfind('{')
12020bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # FIXME: Don't complain if line before blank line, and line after,
12030bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        #        both start with alnums and are indented the same amount.
12040bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        #        This ignores whitespace at the start of a namespace block
12050bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        #        because those are not usually indented.
12060bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        if (previous_brace != -1 and previous_line[previous_brace:].find('}') == -1
12070bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            and previous_line[:previous_brace].find('namespace') == -1):
12080bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            # OK, we have a blank line at the start of a code block.  Before we
12090bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            # complain, we check if it is an exception to the rule: The previous
12100bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            # non-empty line has the parameters of a function header that are indented
12110bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            # 4 spaces (because they did not fit in a 80 column line when placed on
12120bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            # the same line as the function name).  We also check for the case where
12130bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            # the previous line is indented 6 spaces, which may happen when the
12140bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            # initializers of a constructor do not fit into a 80 column line.
12150bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            exception = False
12160bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            if match(r' {6}\w', previous_line):  # Initializer list?
12170bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                # We are looking for the opening column of initializer list, which
12180bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                # should be indented 4 spaces to cause 6 space indentation afterwards.
12190bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                search_position = line_number - 2
12200bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                while (search_position >= 0
12210bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                       and match(r' {6}\w', elided[search_position])):
12220bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                    search_position -= 1
12230bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                exception = (search_position >= 0
12240bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                             and elided[search_position][:5] == '    :')
12250bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            else:
12260bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                # Search for the function arguments or an initializer list.  We use a
12270bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                # simple heuristic here: If the line is indented 4 spaces; and we have a
12280bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                # closing paren, without the opening paren, followed by an opening brace
12290bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                # or colon (for initializer lists) we assume that it is the last line of
12300bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                # a function header.  If we have a colon indented 4 spaces, it is an
12310bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                # initializer list.
12320bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                exception = (match(r' {4}\w[^\(]*\)\s*(const\s*)?(\{\s*$|:)',
12330bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                                   previous_line)
12340bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                             or match(r' {4}:', previous_line))
12350bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
12360bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            if not exception:
1237d0825bca7fe65beaee391d30da42e937db621564Steve Block                error(line_number, 'whitespace/blank_line', 2,
12380bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                      'Blank line at the start of a code block.  Is this needed?')
12390bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # This doesn't ignore whitespace at the end of a namespace block
12400bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # because that is too hard without pairing open/close braces;
12410bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # however, a special exception is made for namespace closing
12420bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # brackets which have a comment containing "namespace".
12430bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        #
12440bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # Also, ignore blank lines at the end of a block in a long if-else
12450bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # chain, like this:
12460bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        #   if (condition1) {
12470bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        #     // Something followed by a blank line
12480bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        #
12490bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        #   } else if (condition2) {
12500bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        #     // Something else
12510bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        #   }
12520bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        if line_number + 1 < clean_lines.num_lines():
12530bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            next_line = raw[line_number + 1]
12540bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            if (next_line
12550bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                and match(r'\s*}', next_line)
12560bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                and next_line.find('namespace') == -1
12570bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                and next_line.find('} else ') == -1):
1258d0825bca7fe65beaee391d30da42e937db621564Steve Block                error(line_number, 'whitespace/blank_line', 3,
12590bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                      'Blank line at the end of a code block.  Is this needed?')
12600bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
12610bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # Next, we complain if there's a comment too near the text
12620bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    comment_position = line.find('//')
12630bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if comment_position != -1:
12640bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # Check if the // may be in quotes.  If so, ignore it
12650bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # Comparisons made explicit for clarity -- pylint: disable-msg=C6403
12660bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        if (line.count('"', 0, comment_position) - line.count('\\"', 0, comment_position)) % 2 == 0:   # not in quotes
1267d0825bca7fe65beaee391d30da42e937db621564Steve Block            # Allow one space before end of line comment.
1268d0825bca7fe65beaee391d30da42e937db621564Steve Block            if (not match(r'^\s*$', line[:comment_position])
1269d0825bca7fe65beaee391d30da42e937db621564Steve Block                and (comment_position >= 1
1270d0825bca7fe65beaee391d30da42e937db621564Steve Block                and ((line[comment_position - 1] not in string.whitespace)
12710bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                     or (comment_position >= 2
1272d0825bca7fe65beaee391d30da42e937db621564Steve Block                         and line[comment_position - 2] in string.whitespace)))):
1273d0825bca7fe65beaee391d30da42e937db621564Steve Block                error(line_number, 'whitespace/comments', 5,
1274d0825bca7fe65beaee391d30da42e937db621564Steve Block                      'One space before end of line comments')
12750bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            # There should always be a space between the // and the comment
12760bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            commentend = comment_position + 2
12770bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            if commentend < len(line) and not line[commentend] == ' ':
12780bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                # but some lines are exceptions -- e.g. if they're big
12790bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                # comment delimiters like:
12800bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                # //----------------------------------------------------------
12810bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                # or they begin with multiple slashes followed by a space:
12820bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                # //////// Header comment
12830bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                matched = (search(r'[=/-]{4,}\s*$', line[commentend:])
12840bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                           or search(r'^/+ ', line[commentend:]))
12850bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                if not matched:
1286d0825bca7fe65beaee391d30da42e937db621564Steve Block                    error(line_number, 'whitespace/comments', 4,
12870bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                          'Should have a space between // and comment')
12880bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
12890bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    line = clean_lines.elided[line_number]  # get rid of comments and strings
12900bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
12910bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # Don't try to do spacing checks for operator methods
1292643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    line = sub(r'operator(==|!=|<|<<|<=|>=|>>|>)\(', 'operator\(', line)
1293643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    # Don't try to do spacing checks for #include or #import statements at
1294643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    # minimum because it messes up checks for spacing around /
1295643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    if match(r'\s*#\s*(?:include|import)', line):
1296cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block        return
1297cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block    if search(r'[\w.]=[\w.]', line):
1298d0825bca7fe65beaee391d30da42e937db621564Steve Block        error(line_number, 'whitespace/operators', 4,
12990bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch              'Missing spaces around =')
13000bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
1301cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block    # FIXME: It's not ok to have spaces around binary operators like .
13020bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
13030bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # You should always have whitespace around binary operators.
13040bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # Alas, we can't test < or > because they're legitimately used sans spaces
13050bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # (a->b, vector<int> a).  The only time we can tell is a < with no >, and
13060bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # only if it's not template params list spilling into the next line.
1307231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    matched = search(r'[^<>=!\s](==|!=|\+=|-=|\*=|/=|/|\|=|&=|<<=|>>=|<=|>=|\|\||\||&&|>>|<<)[^<>=!\s]', line)
13080bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if not matched:
13090bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # Note that while it seems that the '<[^<]*' term in the following
13100bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # regexp could be simplified to '<.*', which would indeed match
13110bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # the same class of strings, the [^<] means that searching for the
13120bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # regexp takes linear rather than quadratic time.
13130bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        if not search(r'<[^<]*,\s*$', line):  # template params spill
13140bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            matched = search(r'[^<>=!\s](<)[^<>=!\s]([^>]|->)*$', line)
13150bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if matched:
1316d0825bca7fe65beaee391d30da42e937db621564Steve Block        error(line_number, 'whitespace/operators', 3,
13170bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch              'Missing spaces around %s' % matched.group(1))
13180bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
13190bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # There shouldn't be space around unary operators
13200bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    matched = search(r'(!\s|~\s|[\s]--[\s;]|[\s]\+\+[\s;])', line)
13210bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if matched:
1322d0825bca7fe65beaee391d30da42e937db621564Steve Block        error(line_number, 'whitespace/operators', 4,
13230bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch              'Extra space for operator %s' % matched.group(1))
13240bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
13250bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # A pet peeve of mine: no spaces after an if, while, switch, or for
13260bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    matched = search(r' (if\(|for\(|foreach\(|while\(|switch\()', line)
13270bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if matched:
1328d0825bca7fe65beaee391d30da42e937db621564Steve Block        error(line_number, 'whitespace/parens', 5,
13290bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch              'Missing space before ( in %s' % matched.group(1))
13300bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
13310bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # For if/for/foreach/while/switch, the left and right parens should be
13320bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # consistent about how many spaces are inside the parens, and
13330bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # there should either be zero or one spaces inside the parens.
13340bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # We don't want: "if ( foo)" or "if ( foo   )".
13350bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # Exception: "for ( ; foo; bar)" and "for (foo; bar; )" are allowed.
1336d0825bca7fe65beaee391d30da42e937db621564Steve Block    matched = search(r'\b(?P<statement>if|for|foreach|while|switch)\s*\((?P<reminder>.*)$', line)
13370bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if matched:
1338d0825bca7fe65beaee391d30da42e937db621564Steve Block        statement = matched.group('statement')
1339d0825bca7fe65beaee391d30da42e937db621564Steve Block        condition, rest = up_to_unmatched_closing_paren(matched.group('reminder'))
1340d0825bca7fe65beaee391d30da42e937db621564Steve Block        if condition is not None:
1341d0825bca7fe65beaee391d30da42e937db621564Steve Block            condition_match = search(r'(?P<leading>[ ]*)(?P<separator>.).*[^ ]+(?P<trailing>[ ]*)', condition)
1342d0825bca7fe65beaee391d30da42e937db621564Steve Block            if condition_match:
1343d0825bca7fe65beaee391d30da42e937db621564Steve Block                n_leading = len(condition_match.group('leading'))
1344d0825bca7fe65beaee391d30da42e937db621564Steve Block                n_trailing = len(condition_match.group('trailing'))
1345d0825bca7fe65beaee391d30da42e937db621564Steve Block                if n_leading != n_trailing:
1346d0825bca7fe65beaee391d30da42e937db621564Steve Block                    for_exception = statement == 'for' and (
1347d0825bca7fe65beaee391d30da42e937db621564Steve Block                        (condition.startswith(' ;') and n_trailing == 0) or
1348d0825bca7fe65beaee391d30da42e937db621564Steve Block                        (condition.endswith('; ')   and n_leading == 0))
1349d0825bca7fe65beaee391d30da42e937db621564Steve Block                    if not for_exception:
1350d0825bca7fe65beaee391d30da42e937db621564Steve Block                        error(line_number, 'whitespace/parens', 5,
1351d0825bca7fe65beaee391d30da42e937db621564Steve Block                              'Mismatching spaces inside () in %s' % statement)
1352d0825bca7fe65beaee391d30da42e937db621564Steve Block                if n_leading > 1:
1353d0825bca7fe65beaee391d30da42e937db621564Steve Block                    error(line_number, 'whitespace/parens', 5,
1354d0825bca7fe65beaee391d30da42e937db621564Steve Block                          'Should have zero or one spaces inside ( and ) in %s' %
1355d0825bca7fe65beaee391d30da42e937db621564Steve Block                          statement)
1356d0825bca7fe65beaee391d30da42e937db621564Steve Block
1357d0825bca7fe65beaee391d30da42e937db621564Steve Block            # Do not check for more than one command in macros
1358d0825bca7fe65beaee391d30da42e937db621564Steve Block            in_macro = match(r'\s*#define', line)
1359d0825bca7fe65beaee391d30da42e937db621564Steve Block            if not in_macro and not match(r'((\s*{\s*}?)|(\s*;?))\s*\\?$', rest):
1360d0825bca7fe65beaee391d30da42e937db621564Steve Block                error(line_number, 'whitespace/parens', 4,
1361d0825bca7fe65beaee391d30da42e937db621564Steve Block                      'More than one command on the same line in %s' % statement)
13620bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
13630bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # You should always have a space after a comma (either as fn arg or operator)
13640bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if search(r',[^\s]', line):
1365d0825bca7fe65beaee391d30da42e937db621564Steve Block        error(line_number, 'whitespace/comma', 3,
13660bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch              'Missing space after ,')
13670bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
1368d0825bca7fe65beaee391d30da42e937db621564Steve Block    if file_extension == 'cpp':
13690bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # C++ should have the & or * beside the type not the variable name.
13700bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        matched = match(r'\s*\w+(?<!\breturn)\s+(?P<pointer_operator>\*|\&)\w+', line)
13710bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        if matched:
1372d0825bca7fe65beaee391d30da42e937db621564Steve Block            error(line_number, 'whitespace/declaration', 3,
13730bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                  'Declaration has space between type name and %s in %s' % (matched.group('pointer_operator'), matched.group(0).strip()))
13740bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
1375d0825bca7fe65beaee391d30da42e937db621564Steve Block    elif file_extension == 'c':
13760bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # C Pointer declaration should have the * beside the variable not the type name.
13770bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        matched = search(r'^\s*\w+\*\s+\w+', line)
13780bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        if matched:
1379d0825bca7fe65beaee391d30da42e937db621564Steve Block            error(line_number, 'whitespace/declaration', 3,
13800bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                  'Declaration has space between * and variable name in %s' % matched.group(0).strip())
13810bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
13820bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # Next we will look for issues with function calls.
1383d0825bca7fe65beaee391d30da42e937db621564Steve Block    check_spacing_for_function_call(line, line_number, error)
13840bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
13850bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # Except after an opening paren, you should have spaces before your braces.
13860bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # And since you should never have braces at the beginning of a line, this is
13870bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # an easy test.
13880bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if search(r'[^ ({]{', line):
1389d0825bca7fe65beaee391d30da42e937db621564Steve Block        error(line_number, 'whitespace/braces', 5,
13900bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch              'Missing space before {')
13910bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
13920bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # Make sure '} else {' has spaces.
13930bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if search(r'}else', line):
1394d0825bca7fe65beaee391d30da42e937db621564Steve Block        error(line_number, 'whitespace/braces', 5,
13950bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch              'Missing space before else')
13960bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
13970bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # You shouldn't have spaces before your brackets, except maybe after
13980bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # 'delete []' or 'new char * []'.
13990bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if search(r'\w\s+\[', line) and not search(r'delete\s+\[', line):
1400d0825bca7fe65beaee391d30da42e937db621564Steve Block        error(line_number, 'whitespace/braces', 5,
14010bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch              'Extra space before [')
14020bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
14030bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # You shouldn't have a space before a semicolon at the end of the line.
14040bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # There's a special case for "for" since the style guide allows space before
14050bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # the semicolon there.
14060bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if search(r':\s*;\s*$', line):
1407d0825bca7fe65beaee391d30da42e937db621564Steve Block        error(line_number, 'whitespace/semicolon', 5,
14080bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch              'Semicolon defining empty statement. Use { } instead.')
14090bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    elif search(r'^\s*;\s*$', line):
1410d0825bca7fe65beaee391d30da42e937db621564Steve Block        error(line_number, 'whitespace/semicolon', 5,
14110bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch              'Line contains only semicolon. If this should be an empty statement, '
14120bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch              'use { } instead.')
14130bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    elif (search(r'\s+;\s*$', line) and not search(r'\bfor\b', line)):
1414d0825bca7fe65beaee391d30da42e937db621564Steve Block        error(line_number, 'whitespace/semicolon', 5,
14150bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch              'Extra space before last semicolon. If this should be an empty '
14160bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch              'statement, use { } instead.')
14170bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    elif (search(r'\b(for|while)\s*\(.*\)\s*;\s*$', line)
14180bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch          and line.count('(') == line.count(')')
14190bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch          # Allow do {} while();
14200bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch          and not search(r'}\s*while', line)):
1421d0825bca7fe65beaee391d30da42e937db621564Steve Block        error(line_number, 'whitespace/semicolon', 5,
14220bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch              'Semicolon defining empty statement for this loop. Use { } instead.')
14230bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
14240bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
14250bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdochdef get_previous_non_blank_line(clean_lines, line_number):
14260bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """Return the most recent non-blank line and its line number.
14270bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
14280bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    Args:
14290bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      clean_lines: A CleansedLines instance containing the file contents.
14300bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      line_number: The number of the line to check.
14310bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
14320bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    Returns:
14330bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      A tuple with two elements.  The first element is the contents of the last
14340bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      non-blank line before the current line, or the empty string if this is the
14350bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      first non-blank line.  The second is the line number of that line, or -1
14360bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      if this is the first non-blank line.
14370bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """
14380bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
14390bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    previous_line_number = line_number - 1
14400bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    while previous_line_number >= 0:
14410bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        previous_line = clean_lines.elided[previous_line_number]
14420bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        if not is_blank_line(previous_line):     # if not a blank line...
14430bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            return (previous_line, previous_line_number)
14440bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        previous_line_number -= 1
14450bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    return ('', -1)
14460bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
14470bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
1448d0825bca7fe65beaee391d30da42e937db621564Steve Blockdef check_namespace_indentation(clean_lines, line_number, file_extension, file_state, error):
14490bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """Looks for indentation errors inside of namespaces.
14500bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
14510bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    Args:
14520bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      clean_lines: A CleansedLines instance containing the file.
14530bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      line_number: The number of the line to check.
14540bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      file_extension: The extension (dot not included) of the file.
1455643ca7872b450ea4efacab6188849e5aac2ba161Steve Block      file_state: A _FileState instance which maintains information about
1456643ca7872b450ea4efacab6188849e5aac2ba161Steve Block                  the state of things in the file.
14570bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      error: The function to call with any errors found.
14580bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """
14590bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
14600bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    line = clean_lines.elided[line_number] # Get rid of comments and strings.
14610bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
14620bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    namespace_match = match(r'(?P<namespace_indentation>\s*)namespace\s+\S+\s*{\s*$', line)
14630bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if not namespace_match:
14640bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        return
14650bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
1466cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block    current_indentation_level = len(namespace_match.group('namespace_indentation'))
1467cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block    if current_indentation_level > 0:
1468643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        # Don't warn about an indented namespace if we already warned about indented code.
1469643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        if not file_state.did_inside_namespace_indent_warning():
1470d0825bca7fe65beaee391d30da42e937db621564Steve Block            error(line_number, 'whitespace/indent', 4,
1471643ca7872b450ea4efacab6188849e5aac2ba161Steve Block                  'namespace should never be indented.')
1472cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block        return
1473cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block    looking_for_semicolon = False;
14740bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    line_offset = 0
1475cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block    in_preprocessor_directive = False;
1476cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block    for current_line in clean_lines.elided[line_number + 1:]:
1477cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block        line_offset += 1
1478cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block        if not current_line.strip():
1479cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block            continue
1480cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block        if not current_indentation_level:
1481cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block            if not (in_preprocessor_directive or looking_for_semicolon):
1482643ca7872b450ea4efacab6188849e5aac2ba161Steve Block                if not match(r'\S', current_line) and not file_state.did_inside_namespace_indent_warning():
1483643ca7872b450ea4efacab6188849e5aac2ba161Steve Block                    file_state.set_did_inside_namespace_indent_warning()
1484d0825bca7fe65beaee391d30da42e937db621564Steve Block                    error(line_number + line_offset, 'whitespace/indent', 4,
1485cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block                          'Code inside a namespace should not be indented.')
1486cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block            if in_preprocessor_directive or (current_line.strip()[0] == '#'): # This takes care of preprocessor directive syntax.
1487cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block                in_preprocessor_directive = current_line[-1] == '\\'
1488cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block            else:
1489cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block                looking_for_semicolon = ((current_line.find(';') == -1) and (current_line.strip()[-1] != '}')) or (current_line[-1] == '\\')
1490cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block        else:
1491cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block            looking_for_semicolon = False; # If we have a brace we may not need a semicolon.
1492cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block        current_indentation_level += current_line.count('{') - current_line.count('}')
1493cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block        if current_indentation_level < 0:
1494cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block            break;
14950bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
1496d0825bca7fe65beaee391d30da42e937db621564Steve Blockdef check_using_std(file_extension, clean_lines, line_number, error):
1497231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    """Looks for 'using std::foo;' statements which should be replaced with 'using namespace std;'.
1498231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
1499231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    Args:
1500d0825bca7fe65beaee391d30da42e937db621564Steve Block      file_extension: The extension of the current file, without the leading dot.
1501231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block      clean_lines: A CleansedLines instance containing the file.
1502231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block      line_number: The number of the line to check.
1503231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block      error: The function to call with any errors found.
1504231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    """
1505231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
1506231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    # This check doesn't apply to C or Objective-C implementation files.
1507d0825bca7fe65beaee391d30da42e937db621564Steve Block    if is_c_or_objective_c(file_extension):
1508231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        return
1509231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
1510231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    line = clean_lines.elided[line_number] # Get rid of comments and strings.
1511231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
1512231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    using_std_match = match(r'\s*using\s+std::(?P<method_name>\S+)\s*;\s*$', line)
1513231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    if not using_std_match:
1514231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        return
1515231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
1516231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    method_name = using_std_match.group('method_name')
1517d0825bca7fe65beaee391d30da42e937db621564Steve Block    error(line_number, 'build/using_std', 4,
1518231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block          "Use 'using namespace std;' instead of 'using std::%s;'." % method_name)
1519231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
1520231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
1521d0825bca7fe65beaee391d30da42e937db621564Steve Blockdef check_max_min_macros(file_extension, clean_lines, line_number, error):
1522231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    """Looks use of MAX() and MIN() macros that should be replaced with std::max() and std::min().
1523231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
1524231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    Args:
1525d0825bca7fe65beaee391d30da42e937db621564Steve Block      file_extension: The extension of the current file, without the leading dot.
1526231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block      clean_lines: A CleansedLines instance containing the file.
1527231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block      line_number: The number of the line to check.
1528231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block      error: The function to call with any errors found.
1529231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    """
1530231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
1531231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    # This check doesn't apply to C or Objective-C implementation files.
1532d0825bca7fe65beaee391d30da42e937db621564Steve Block    if is_c_or_objective_c(file_extension):
1533231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        return
1534231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
1535231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    line = clean_lines.elided[line_number] # Get rid of comments and strings.
1536231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
1537231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    max_min_macros_search = search(r'\b(?P<max_min_macro>(MAX|MIN))\s*\(', line)
1538231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    if not max_min_macros_search:
1539231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        return
1540231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
1541231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    max_min_macro = max_min_macros_search.group('max_min_macro')
1542231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    max_min_macro_lower = max_min_macro.lower()
1543d0825bca7fe65beaee391d30da42e937db621564Steve Block    error(line_number, 'runtime/max_min_macros', 4,
1544231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block          'Use std::%s() or std::%s<type>() instead of the %s() macro.'
1545231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block          % (max_min_macro_lower, max_min_macro_lower, max_min_macro))
1546231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
1547231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
1548d0825bca7fe65beaee391d30da42e937db621564Steve Blockdef check_switch_indentation(clean_lines, line_number, error):
15490bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """Looks for indentation errors inside of switch statements.
15500bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
15510bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    Args:
15520bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      clean_lines: A CleansedLines instance containing the file.
15530bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      line_number: The number of the line to check.
15540bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      error: The function to call with any errors found.
15550bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """
15560bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
15570bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    line = clean_lines.elided[line_number] # Get rid of comments and strings.
15580bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
15590bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    switch_match = match(r'(?P<switch_indentation>\s*)switch\s*\(.+\)\s*{\s*$', line)
15600bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if not switch_match:
15610bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        return
15620bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
15630bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    switch_indentation = switch_match.group('switch_indentation')
15640bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    inner_indentation = switch_indentation + ' ' * 4
15650bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    line_offset = 0
15660bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    encountered_nested_switch = False
15670bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
15680bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    for current_line in clean_lines.elided[line_number + 1:]:
15690bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        line_offset += 1
15700bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
15710bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # Skip not only empty lines but also those with preprocessor directives.
15720bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        if current_line.strip() == '' or current_line.startswith('#'):
15730bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            continue
15740bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
15750bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        if match(r'\s*switch\s*\(.+\)\s*{\s*$', current_line):
15760bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            # Complexity alarm - another switch statement nested inside the one
15770bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            # that we're currently testing. We'll need to track the extent of
15780bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            # that inner switch if the upcoming label tests are still supposed
15790bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            # to work correctly. Let's not do that; instead, we'll finish
15800bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            # checking this line, and then leave it like that. Assuming the
15810bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            # indentation is done consistently (even if incorrectly), this will
15820bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            # still catch all indentation issues in practice.
15830bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            encountered_nested_switch = True
15840bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
15850bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        current_indentation_match = match(r'(?P<indentation>\s*)(?P<remaining_line>.*)$', current_line);
15860bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        current_indentation = current_indentation_match.group('indentation')
15870bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        remaining_line = current_indentation_match.group('remaining_line')
15880bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
15890bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # End the check at the end of the switch statement.
15900bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        if remaining_line.startswith('}') and current_indentation == switch_indentation:
15910bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            break
15920bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # Case and default branches should not be indented. The regexp also
15930bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # catches single-line cases like "default: break;" but does not trigger
15940bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # on stuff like "Document::Foo();".
15950bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        elif match(r'(default|case\s+.*)\s*:([^:].*)?$', remaining_line):
15960bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            if current_indentation != switch_indentation:
1597d0825bca7fe65beaee391d30da42e937db621564Steve Block                error(line_number + line_offset, 'whitespace/indent', 4,
15980bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                      'A case label should not be indented, but line up with its switch statement.')
15990bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                # Don't throw an error for multiple badly indented labels,
16000bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                # one should be enough to figure out the problem.
16010bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                break
16020bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # We ignore goto labels at the very beginning of a line.
16030bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        elif match(r'\w+\s*:\s*$', remaining_line):
16040bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            continue
16050bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # It's not a goto label, so check if it's indented at least as far as
16060bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # the switch statement plus one more level of indentation.
16070bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        elif not current_indentation.startswith(inner_indentation):
1608d0825bca7fe65beaee391d30da42e937db621564Steve Block            error(line_number + line_offset, 'whitespace/indent', 4,
16090bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                  'Non-label code inside switch statements should be indented.')
16100bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            # Don't throw an error for multiple badly indented statements,
16110bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            # one should be enough to figure out the problem.
16120bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            break
16130bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
16140bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        if encountered_nested_switch:
16150bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            break
16160bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
16170bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
1618d0825bca7fe65beaee391d30da42e937db621564Steve Blockdef check_braces(clean_lines, line_number, error):
16190bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """Looks for misplaced braces (e.g. at the end of line).
16200bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
16210bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    Args:
16220bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      clean_lines: A CleansedLines instance containing the file.
16230bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      line_number: The number of the line to check.
16240bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      error: The function to call with any errors found.
16250bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """
16260bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
16270bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    line = clean_lines.elided[line_number] # Get rid of comments and strings.
16280bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
16290bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if match(r'\s*{\s*$', line):
16300bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # We allow an open brace to start a line in the case where someone
16310bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # is using braces for function definition or in a block to
16320bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # explicitly create a new scope, which is commonly used to control
16330bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # the lifetime of stack-allocated variables.  We don't detect this
16340bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # perfectly: we just don't complain if the last non-whitespace
16350bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # character on the previous non-blank line is ';', ':', '{', '}',
16360bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # ')', or ') const' and doesn't begin with 'if|for|while|switch|else'.
16370bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # We also allow '#' for #endif and '=' for array initialization.
16380bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        previous_line = get_previous_non_blank_line(clean_lines, line_number)[0]
16390bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        if ((not search(r'[;:}{)=]\s*$|\)\s*const\s*$', previous_line)
16400bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch             or search(r'\b(if|for|foreach|while|switch|else)\b', previous_line))
16410bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            and previous_line.find('#') < 0):
1642d0825bca7fe65beaee391d30da42e937db621564Steve Block            error(line_number, 'whitespace/braces', 4,
16430bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                  'This { should be at the end of the previous line')
16440bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    elif (search(r'\)\s*(const\s*)?{\s*$', line)
16450bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch          and line.count('(') == line.count(')')
1646643ca7872b450ea4efacab6188849e5aac2ba161Steve Block          and not search(r'\b(if|for|foreach|while|switch)\b', line)
1647643ca7872b450ea4efacab6188849e5aac2ba161Steve Block          and not match(r'\s+[A-Z_][A-Z_0-9]+\b', line)):
1648d0825bca7fe65beaee391d30da42e937db621564Steve Block        error(line_number, 'whitespace/braces', 4,
16490bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch              'Place brace on its own line for function definitions.')
16500bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
16510bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if (match(r'\s*}\s*(else\s*({\s*)?)?$', line) and line_number > 1):
16520bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # We check if a closed brace has started a line to see if a
16530bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # one line control statement was previous.
16540bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        previous_line = clean_lines.elided[line_number - 2]
16550bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        if (previous_line.find('{') > 0
16560bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            and search(r'\b(if|for|foreach|while|else)\b', previous_line)):
1657d0825bca7fe65beaee391d30da42e937db621564Steve Block            error(line_number, 'whitespace/braces', 4,
16580bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                  'One line control clauses should not use braces.')
16590bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
16600bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # An else clause should be on the same line as the preceding closing brace.
16610bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if match(r'\s*else\s*', line):
16620bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        previous_line = get_previous_non_blank_line(clean_lines, line_number)[0]
16630bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        if match(r'\s*}\s*$', previous_line):
1664d0825bca7fe65beaee391d30da42e937db621564Steve Block            error(line_number, 'whitespace/newline', 4,
16650bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                  'An else should appear on the same line as the preceding }')
16660bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
16670bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # Likewise, an else should never have the else clause on the same line
16680bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if search(r'\belse [^\s{]', line) and not search(r'\belse if\b', line):
1669d0825bca7fe65beaee391d30da42e937db621564Steve Block        error(line_number, 'whitespace/newline', 4,
16700bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch              'Else clause should never be on same line as else (use 2 lines)')
16710bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
16720bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # In the same way, a do/while should never be on one line
16730bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if match(r'\s*do [^\s{]', line):
1674d0825bca7fe65beaee391d30da42e937db621564Steve Block        error(line_number, 'whitespace/newline', 4,
16750bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch              'do/while clauses should not be on a single line')
16760bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
16770bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # Braces shouldn't be followed by a ; unless they're defining a struct
16780bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # or initializing an array.
16790bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # We can't tell in general, but we can for some common cases.
16800bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    previous_line_number = line_number
16810bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    while True:
16820bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        (previous_line, previous_line_number) = get_previous_non_blank_line(clean_lines, previous_line_number)
16830bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        if match(r'\s+{.*}\s*;', line) and not previous_line.count(';'):
16840bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            line = previous_line + line
16850bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        else:
16860bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            break
16870bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if (search(r'{.*}\s*;', line)
16880bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        and line.count('{') == line.count('}')
16890bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        and not search(r'struct|class|enum|\s*=\s*{', line)):
1690d0825bca7fe65beaee391d30da42e937db621564Steve Block        error(line_number, 'readability/braces', 4,
16910bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch              "You don't need a ; after a }")
16920bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
16930bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
1694d0825bca7fe65beaee391d30da42e937db621564Steve Blockdef check_exit_statement_simplifications(clean_lines, line_number, error):
16950bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """Looks for else or else-if statements that should be written as an
16960bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if statement when the prior if concludes with a return, break, continue or
16970bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    goto statement.
16980bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
16990bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    Args:
17000bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      clean_lines: A CleansedLines instance containing the file.
17010bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      line_number: The number of the line to check.
17020bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      error: The function to call with any errors found.
17030bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """
17040bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
17050bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    line = clean_lines.elided[line_number] # Get rid of comments and strings.
17060bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
17070bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    else_match = match(r'(?P<else_indentation>\s*)(\}\s*)?else(\s+if\s*\(|(?P<else>\s*(\{\s*)?\Z))', line)
17080bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if not else_match:
17090bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        return
17100bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
17110bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    else_indentation = else_match.group('else_indentation')
17120bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    inner_indentation = else_indentation + ' ' * 4
17130bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
17140bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    previous_lines = clean_lines.elided[:line_number]
17150bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    previous_lines.reverse()
17160bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    line_offset = 0
17170bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    encountered_exit_statement = False
17180bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
17190bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    for current_line in previous_lines:
17200bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        line_offset -= 1
17210bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
17220bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # Skip not only empty lines but also those with preprocessor directives
17230bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # and goto labels.
17240bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        if current_line.strip() == '' or current_line.startswith('#') or match(r'\w+\s*:\s*$', current_line):
17250bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            continue
17260bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
17270bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # Skip lines with closing braces on the original indentation level.
17280bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # Even though the styleguide says they should be on the same line as
17290bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # the "else if" statement, we also want to check for instances where
17300bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # the current code does not comply with the coding style. Thus, ignore
17310bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # these lines and proceed to the line before that.
17320bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        if current_line == else_indentation + '}':
17330bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            continue
17340bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
17350bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        current_indentation_match = match(r'(?P<indentation>\s*)(?P<remaining_line>.*)$', current_line);
17360bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        current_indentation = current_indentation_match.group('indentation')
17370bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        remaining_line = current_indentation_match.group('remaining_line')
17380bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
17390bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # As we're going up the lines, the first real statement to encounter
17400bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # has to be an exit statement (return, break, continue or goto) -
17410bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # otherwise, this check doesn't apply.
17420bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        if not encountered_exit_statement:
17430bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            # We only want to find exit statements if they are on exactly
17440bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            # the same level of indentation as expected from the code inside
17450bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            # the block. If the indentation doesn't strictly match then we
17460bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            # might have a nested if or something, which must be ignored.
17470bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            if current_indentation != inner_indentation:
17480bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                break
17490bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            if match(r'(return(\W+.*)|(break|continue)\s*;|goto\s*\w+;)$', remaining_line):
17500bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                encountered_exit_statement = True
17510bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                continue
17520bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            break
17530bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
17540bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # When code execution reaches this point, we've found an exit statement
17550bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # as last statement of the previous block. Now we only need to make
17560bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # sure that the block belongs to an "if", then we can throw an error.
17570bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
17580bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # Skip lines with opening braces on the original indentation level,
17590bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # similar to the closing braces check above. ("if (condition)\n{")
17600bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        if current_line == else_indentation + '{':
17610bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            continue
17620bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
17630bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # Skip everything that's further indented than our "else" or "else if".
17640bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        if current_indentation.startswith(else_indentation) and current_indentation != else_indentation:
17650bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            continue
17660bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
17670bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # So we've got a line with same (or less) indentation. Is it an "if"?
17680bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # If yes: throw an error. If no: don't throw an error.
17690bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # Whatever the outcome, this is the end of our loop.
17700bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        if match(r'if\s*\(', remaining_line):
17710bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            if else_match.start('else') != -1:
1772d0825bca7fe65beaee391d30da42e937db621564Steve Block                error(line_number + line_offset, 'readability/control_flow', 4,
17730bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                      'An else statement can be removed when the prior "if" '
17740bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                      'concludes with a return, break, continue or goto statement.')
17750bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            else:
1776d0825bca7fe65beaee391d30da42e937db621564Steve Block                error(line_number + line_offset, 'readability/control_flow', 4,
17770bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                      'An else if statement should be written as an if statement '
17780bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                      'when the prior "if" concludes with a return, break, '
17790bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                      'continue or goto statement.')
17800bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        break
17810bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
17820bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
17830bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdochdef replaceable_check(operator, macro, line):
17840bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """Determine whether a basic CHECK can be replaced with a more specific one.
17850bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
17860bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    For example suggest using CHECK_EQ instead of CHECK(a == b) and
17870bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    similarly for CHECK_GE, CHECK_GT, CHECK_LE, CHECK_LT, CHECK_NE.
17880bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
17890bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    Args:
17900bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      operator: The C++ operator used in the CHECK.
17910bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      macro: The CHECK or EXPECT macro being called.
17920bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      line: The current source line.
17930bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
17940bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    Returns:
17950bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      True if the CHECK can be replaced with a more specific one.
17960bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """
17970bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
17980bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # This matches decimal and hex integers, strings, and chars (in that order).
17990bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    match_constant = r'([-+]?(\d+|0[xX][0-9a-fA-F]+)[lLuU]{0,3}|".*"|\'.*\')'
18000bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
18010bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # Expression to match two sides of the operator with something that
18020bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # looks like a literal, since CHECK(x == iterator) won't compile.
18030bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # This means we can't catch all the cases where a more specific
18040bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # CHECK is possible, but it's less annoying than dealing with
18050bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # extraneous warnings.
18060bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    match_this = (r'\s*' + macro + r'\((\s*' +
18070bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                  match_constant + r'\s*' + operator + r'[^<>].*|'
18080bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                  r'.*[^<>]' + operator + r'\s*' + match_constant +
18090bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                  r'\s*\))')
18100bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
18110bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # Don't complain about CHECK(x == NULL) or similar because
18120bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # CHECK_EQ(x, NULL) won't compile (requires a cast).
18130bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # Also, don't complain about more complex boolean expressions
18140bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # involving && or || such as CHECK(a == b || c == d).
18150bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    return match(match_this, line) and not search(r'NULL|&&|\|\|', line)
18160bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
18170bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
1818d0825bca7fe65beaee391d30da42e937db621564Steve Blockdef check_check(clean_lines, line_number, error):
18190bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """Checks the use of CHECK and EXPECT macros.
18200bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
18210bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    Args:
18220bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      clean_lines: A CleansedLines instance containing the file.
18230bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      line_number: The number of the line to check.
18240bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      error: The function to call with any errors found.
18250bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """
18260bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
18270bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # Decide the set of replacement macros that should be suggested
18280bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    raw_lines = clean_lines.raw_lines
18290bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    current_macro = ''
18300bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    for macro in _CHECK_MACROS:
18310bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        if raw_lines[line_number].find(macro) >= 0:
18320bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            current_macro = macro
18330bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            break
18340bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if not current_macro:
18350bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # Don't waste time here if line doesn't contain 'CHECK' or 'EXPECT'
18360bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        return
18370bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
18380bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    line = clean_lines.elided[line_number]        # get rid of comments and strings
18390bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
18400bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # Encourage replacing plain CHECKs with CHECK_EQ/CHECK_NE/etc.
18410bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    for operator in ['==', '!=', '>=', '>', '<=', '<']:
18420bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        if replaceable_check(operator, current_macro, line):
1843d0825bca7fe65beaee391d30da42e937db621564Steve Block            error(line_number, 'readability/check', 2,
18440bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                  'Consider using %s instead of %s(a %s b)' % (
18450bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                      _CHECK_REPLACEMENT[current_macro][operator],
18460bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                      current_macro, operator))
18470bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            break
18480bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
18490bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
1850d0825bca7fe65beaee391d30da42e937db621564Steve Blockdef check_for_comparisons_to_zero(clean_lines, line_number, error):
18510bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # Get the line without comments and strings.
18520bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    line = clean_lines.elided[line_number]
18530bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
18540bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # Include NULL here so that users don't have to convert NULL to 0 first and then get this error.
18550bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if search(r'[=!]=\s*(NULL|0|true|false)\W', line) or search(r'\W(NULL|0|true|false)\s*[=!]=', line):
1856d0825bca7fe65beaee391d30da42e937db621564Steve Block        error(line_number, 'readability/comparison_to_zero', 5,
18570bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch              'Tests for true/false, null/non-null, and zero/non-zero should all be done without equality comparisons.')
18580bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
18590bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
1860d0825bca7fe65beaee391d30da42e937db621564Steve Blockdef check_for_null(file_extension, clean_lines, line_number, error):
18610bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # This check doesn't apply to C or Objective-C implementation files.
1862d0825bca7fe65beaee391d30da42e937db621564Steve Block    if is_c_or_objective_c(file_extension):
18630bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        return
18640bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
18650bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    line = clean_lines.elided[line_number]
1866d0825bca7fe65beaee391d30da42e937db621564Steve Block
1867d0825bca7fe65beaee391d30da42e937db621564Steve Block    # Don't warn about NULL usage in g_object_{get,set}(). See Bug 32858
1868d0825bca7fe65beaee391d30da42e937db621564Steve Block    if search(r'\bg_object_[sg]et\b', line):
1869d0825bca7fe65beaee391d30da42e937db621564Steve Block        return
1870d0825bca7fe65beaee391d30da42e937db621564Steve Block
18710bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if search(r'\bNULL\b', line):
1872d0825bca7fe65beaee391d30da42e937db621564Steve Block        error(line_number, 'readability/null', 5, 'Use 0 instead of NULL.')
18730bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        return
18740bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
18750bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    line = clean_lines.raw_lines[line_number]
18760bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # See if NULL occurs in any comments in the line. If the search for NULL using the raw line
18770bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # matches, then do the check with strings collapsed to avoid giving errors for
18780bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # NULLs occurring in strings.
18790bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if search(r'\bNULL\b', line) and search(r'\bNULL\b', CleansedLines.collapse_strings(line)):
1880d0825bca7fe65beaee391d30da42e937db621564Steve Block        error(line_number, 'readability/null', 4, 'Use 0 instead of NULL.')
18810bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
18820bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdochdef get_line_width(line):
18830bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """Determines the width of the line in column positions.
18840bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
18850bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    Args:
18860bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      line: A string, which may be a Unicode string.
18870bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
18880bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    Returns:
18890bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      The width of the line in column positions, accounting for Unicode
18900bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      combining characters and wide characters.
18910bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """
18920bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if isinstance(line, unicode):
18930bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        width = 0
18940bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        for c in unicodedata.normalize('NFC', line):
18950bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            if unicodedata.east_asian_width(c) in ('W', 'F'):
18960bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                width += 2
18970bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            elif not unicodedata.combining(c):
18980bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                width += 1
18990bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        return width
19000bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    return len(line)
19010bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
19020bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
1903d0825bca7fe65beaee391d30da42e937db621564Steve Blockdef check_style(clean_lines, line_number, file_extension, file_state, error):
19040bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """Checks rules from the 'C++ style rules' section of cppguide.html.
19050bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
19060bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    Most of these rules are hard to test (naming, comment style), but we
19070bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    do what we can.  In particular we check for 4-space indents, line lengths,
19080bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    tab usage, spaces inside code, etc.
19090bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
19100bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    Args:
19110bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      clean_lines: A CleansedLines instance containing the file.
19120bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      line_number: The number of the line to check.
19130bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      file_extension: The extension (without the dot) of the filename.
1914643ca7872b450ea4efacab6188849e5aac2ba161Steve Block      file_state: A _FileState instance which maintains information about
1915643ca7872b450ea4efacab6188849e5aac2ba161Steve Block                  the state of things in the file.
19160bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      error: The function to call with any errors found.
19170bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """
19180bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
19190bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    raw_lines = clean_lines.raw_lines
19200bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    line = raw_lines[line_number]
19210bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
19220bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if line.find('\t') != -1:
1923d0825bca7fe65beaee391d30da42e937db621564Steve Block        error(line_number, 'whitespace/tab', 1,
19240bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch              'Tab found; better to use spaces')
19250bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
19260bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # One or three blank spaces at the beginning of the line is weird; it's
19270bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # hard to reconcile that with 4-space indents.
19280bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # NOTE: here are the conditions rob pike used for his tests.  Mine aren't
19290bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # as sophisticated, but it may be worth becoming so:  RLENGTH==initial_spaces
19300bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # if(RLENGTH > 20) complain = 0;
19310bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # if(match($0, " +(error|private|public|protected):")) complain = 0;
19320bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # if(match(prev, "&& *$")) complain = 0;
19330bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # if(match(prev, "\\|\\| *$")) complain = 0;
19340bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # if(match(prev, "[\",=><] *$")) complain = 0;
19350bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # if(match($0, " <<")) complain = 0;
19360bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # if(match(prev, " +for \\(")) complain = 0;
19370bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # if(prevodd && match(prevprev, " +for \\(")) complain = 0;
19380bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    initial_spaces = 0
19390bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    cleansed_line = clean_lines.elided[line_number]
19400bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    while initial_spaces < len(line) and line[initial_spaces] == ' ':
19410bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        initial_spaces += 1
19420bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if line and line[-1].isspace():
1943d0825bca7fe65beaee391d30da42e937db621564Steve Block        error(line_number, 'whitespace/end_of_line', 4,
19440bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch              'Line ends in whitespace.  Consider deleting these extra spaces.')
19450bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # There are certain situations we allow one space, notably for labels
19460bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    elif ((initial_spaces >= 1 and initial_spaces <= 3)
19470bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch          and not match(r'\s*\w+\s*:\s*$', cleansed_line)):
1948d0825bca7fe65beaee391d30da42e937db621564Steve Block        error(line_number, 'whitespace/indent', 3,
19490bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch              'Weird number of spaces at line-start.  '
19500bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch              'Are you using a 4-space indent?')
19510bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # Labels should always be indented at least one space.
19520bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    elif not initial_spaces and line[:2] != '//':
19530bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        label_match = match(r'(?P<label>[^:]+):\s*$', line)
19540bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
19550bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        if label_match:
19560bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            label = label_match.group('label')
19570bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            # Only throw errors for stuff that is definitely not a goto label,
19580bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            # because goto labels can in fact occur at the start of the line.
19590bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            if label in ['public', 'private', 'protected'] or label.find(' ') != -1:
1960d0825bca7fe65beaee391d30da42e937db621564Steve Block                error(line_number, 'whitespace/labels', 4,
19610bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                      'Labels should always be indented at least one space.  '
19620bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                      'If this is a member-initializer list in a constructor, '
19630bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                      'the colon should be on the line after the definition header.')
19640bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
19650bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if (cleansed_line.count(';') > 1
19660bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # for loops are allowed two ;'s (and may run over two lines).
19670bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        and cleansed_line.find('for') == -1
19680bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        and (get_previous_non_blank_line(clean_lines, line_number)[0].find('for') == -1
19690bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch             or get_previous_non_blank_line(clean_lines, line_number)[0].find(';') != -1)
19700bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # It's ok to have many commands in a switch case that fits in 1 line
19710bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        and not ((cleansed_line.find('case ') != -1
19720bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                  or cleansed_line.find('default:') != -1)
1973d0825bca7fe65beaee391d30da42e937db621564Steve Block                 and cleansed_line.find('break;') != -1)
1974d0825bca7fe65beaee391d30da42e937db621564Steve Block        and not cleansed_line.startswith('#define ')):
1975d0825bca7fe65beaee391d30da42e937db621564Steve Block        error(line_number, 'whitespace/newline', 4,
19760bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch              'More than one command on the same line')
19770bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
19780bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if cleansed_line.strip().endswith('||') or cleansed_line.strip().endswith('&&'):
1979d0825bca7fe65beaee391d30da42e937db621564Steve Block        error(line_number, 'whitespace/operators', 4,
19800bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch              'Boolean expressions that span multiple lines should have their '
19810bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch              'operators on the left side of the line instead of the right side.')
19820bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
19830bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # Some more style checks
1984d0825bca7fe65beaee391d30da42e937db621564Steve Block    check_namespace_indentation(clean_lines, line_number, file_extension, file_state, error)
1985d0825bca7fe65beaee391d30da42e937db621564Steve Block    check_using_std(file_extension, clean_lines, line_number, error)
1986d0825bca7fe65beaee391d30da42e937db621564Steve Block    check_max_min_macros(file_extension, clean_lines, line_number, error)
1987d0825bca7fe65beaee391d30da42e937db621564Steve Block    check_switch_indentation(clean_lines, line_number, error)
1988d0825bca7fe65beaee391d30da42e937db621564Steve Block    check_braces(clean_lines, line_number, error)
1989d0825bca7fe65beaee391d30da42e937db621564Steve Block    check_exit_statement_simplifications(clean_lines, line_number, error)
1990d0825bca7fe65beaee391d30da42e937db621564Steve Block    check_spacing(file_extension, clean_lines, line_number, error)
1991d0825bca7fe65beaee391d30da42e937db621564Steve Block    check_check(clean_lines, line_number, error)
1992d0825bca7fe65beaee391d30da42e937db621564Steve Block    check_for_comparisons_to_zero(clean_lines, line_number, error)
1993d0825bca7fe65beaee391d30da42e937db621564Steve Block    check_for_null(file_extension, clean_lines, line_number, error)
19940bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
19950bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
19960bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch_RE_PATTERN_INCLUDE_NEW_STYLE = re.compile(r'#include +"[^/]+\.h"')
19970bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch_RE_PATTERN_INCLUDE = re.compile(r'^\s*#\s*include\s*([<"])([^>"]*)[>"].*$')
19980bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch# Matches the first component of a filename delimited by -s and _s. That is:
19990bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch#  _RE_FIRST_COMPONENT.match('foo').group(0) == 'foo'
20000bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch#  _RE_FIRST_COMPONENT.match('foo.cpp').group(0) == 'foo'
20010bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch#  _RE_FIRST_COMPONENT.match('foo-bar_baz.cpp').group(0) == 'foo'
20020bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch#  _RE_FIRST_COMPONENT.match('foo_bar-baz.cpp').group(0) == 'foo'
20030bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch_RE_FIRST_COMPONENT = re.compile(r'^[^-_.]+')
20040bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
20050bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
20060bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdochdef _drop_common_suffixes(filename):
20070bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """Drops common suffixes like _test.cpp or -inl.h from filename.
20080bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
20090bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    For example:
20100bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      >>> _drop_common_suffixes('foo/foo-inl.h')
20110bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      'foo/foo'
20120bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      >>> _drop_common_suffixes('foo/bar/foo.cpp')
20130bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      'foo/bar/foo'
20140bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      >>> _drop_common_suffixes('foo/foo_internal.h')
20150bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      'foo/foo'
20160bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      >>> _drop_common_suffixes('foo/foo_unusualinternal.h')
20170bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      'foo/foo_unusualinternal'
20180bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
20190bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    Args:
20200bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      filename: The input filename.
20210bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
20220bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    Returns:
20230bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      The filename with the common suffix removed.
20240bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """
20250bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    for suffix in ('test.cpp', 'regtest.cpp', 'unittest.cpp',
20260bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                   'inl.h', 'impl.h', 'internal.h'):
20270bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        if (filename.endswith(suffix) and len(filename) > len(suffix)
20280bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            and filename[-len(suffix) - 1] in ('-', '_')):
20290bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            return filename[:-len(suffix) - 1]
20300bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    return os.path.splitext(filename)[0]
20310bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
20320bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
20330bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdochdef _classify_include(filename, include, is_system, include_state):
20340bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """Figures out what kind of header 'include' is.
20350bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
20360bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    Args:
20370bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      filename: The current file cpp_style is running over.
20380bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      include: The path to a #included file.
20390bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      is_system: True if the #include used <> rather than "".
20400bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      include_state: An _IncludeState instance in which the headers are inserted.
20410bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
20420bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    Returns:
20430bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      One of the _XXX_HEADER constants.
20440bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
20450bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    For example:
20460bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      >>> _classify_include('foo.cpp', 'config.h', False)
20470bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      _CONFIG_HEADER
20480bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      >>> _classify_include('foo.cpp', 'foo.h', False)
20490bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      _PRIMARY_HEADER
20500bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      >>> _classify_include('foo.cpp', 'bar.h', False)
20510bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      _OTHER_HEADER
20520bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """
20530bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
20540bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # If it is a system header we know it is classified as _OTHER_HEADER.
20550bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if is_system:
20560bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        return _OTHER_HEADER
20570bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
20580bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # If the include is named config.h then this is WebCore/config.h.
20590bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if include == "config.h":
20600bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        return _CONFIG_HEADER
20610bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
20620bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # There cannot be primary includes in header files themselves. Only an
20630bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # include exactly matches the header filename will be is flagged as
20640bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # primary, so that it triggers the "don't include yourself" check.
20650bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if filename.endswith('.h') and filename != include:
20660bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        return _OTHER_HEADER;
20670bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
2068d0825bca7fe65beaee391d30da42e937db621564Steve Block    # Qt's moc files do not follow the naming and ordering rules, so they should be skipped
2069d0825bca7fe65beaee391d30da42e937db621564Steve Block    if include.startswith('moc_') and include.endswith('.cpp'):
2070d0825bca7fe65beaee391d30da42e937db621564Steve Block        return _MOC_HEADER
2071d0825bca7fe65beaee391d30da42e937db621564Steve Block
2072d0825bca7fe65beaee391d30da42e937db621564Steve Block    if include.endswith('.moc'):
2073d0825bca7fe65beaee391d30da42e937db621564Steve Block        return _MOC_HEADER
2074d0825bca7fe65beaee391d30da42e937db621564Steve Block
20750bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # If the target file basename starts with the include we're checking
20760bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # then we consider it the primary header.
20770bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    target_base = FileInfo(filename).base_name()
20780bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    include_base = FileInfo(include).base_name()
20790bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
20800bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # If we haven't encountered a primary header, then be lenient in checking.
2081643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    if not include_state.visited_primary_section() and target_base.find(include_base) != -1:
20820bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        return _PRIMARY_HEADER
20830bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # If we already encountered a primary header, perform a strict comparison.
20840bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # In case the two filename bases are the same then the above lenient check
20850bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # probably was a false positive.
20860bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    elif include_state.visited_primary_section() and target_base == include_base:
2087d0825bca7fe65beaee391d30da42e937db621564Steve Block        if include == "ResourceHandleWin.h":
2088d0825bca7fe65beaee391d30da42e937db621564Steve Block            # FIXME: Thus far, we've only seen one example of these, but if we
2089d0825bca7fe65beaee391d30da42e937db621564Steve Block            # start to see more, please consider generalizing this check
2090d0825bca7fe65beaee391d30da42e937db621564Steve Block            # somehow.
2091d0825bca7fe65beaee391d30da42e937db621564Steve Block            return _OTHER_HEADER
20920bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        return _PRIMARY_HEADER
20930bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
20940bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    return _OTHER_HEADER
20950bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
20960bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
2097d0825bca7fe65beaee391d30da42e937db621564Steve Blockdef check_include_line(filename, file_extension, clean_lines, line_number, include_state, error):
20980bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """Check rules that are applicable to #include lines.
20990bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
21000bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    Strings on #include lines are NOT removed from elided line, to make
21010bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    certain tasks easier. However, to prevent false positives, checks
21020bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    applicable to #include lines in CheckLanguage must be put here.
21030bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
21040bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    Args:
21050bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      filename: The name of the current file.
2106d0825bca7fe65beaee391d30da42e937db621564Steve Block      file_extension: The current file extension, without the leading dot.
21070bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      clean_lines: A CleansedLines instance containing the file.
21080bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      line_number: The number of the line to check.
21090bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      include_state: An _IncludeState instance in which the headers are inserted.
21100bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      error: The function to call with any errors found.
21110bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """
21128a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block    # FIXME: For readability or as a possible optimization, consider
21138a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block    #        exiting early here by checking whether the "build/include"
21148a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block    #        category should be checked for the given filename.  This
21158a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block    #        may involve having the error handler classes expose a
21168a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block    #        should_check() method, in addition to the usual __call__
21178a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block    #        method.
21180bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    line = clean_lines.lines[line_number]
21190bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
21200bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    matched = _RE_PATTERN_INCLUDE.search(line)
21210bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if not matched:
21220bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        return
21230bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
21240bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    include = matched.group(2)
21250bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    is_system = (matched.group(1) == '<')
21260bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
21270bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # Look for any of the stream classes that are part of standard C++.
21280bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if match(r'(f|ind|io|i|o|parse|pf|stdio|str|)?stream$', include):
21298a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        error(line_number, 'readability/streams', 3,
21308a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block              'Streams are highly discouraged.')
21310bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
21320bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # Look for specific includes to fix.
21330bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if include.startswith('wtf/') and not is_system:
2134d0825bca7fe65beaee391d30da42e937db621564Steve Block        error(line_number, 'build/include', 4,
21350bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch              'wtf includes should be <wtf/file.h> instead of "wtf/file.h".')
21360bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
21370bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    duplicate_header = include in include_state
21380bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if duplicate_header:
2139d0825bca7fe65beaee391d30da42e937db621564Steve Block        error(line_number, 'build/include', 4,
21400bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch              '"%s" already included at %s:%s' %
21410bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch              (include, filename, include_state[include]))
21420bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    else:
21430bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        include_state[include] = line_number
21440bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
21450bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    header_type = _classify_include(filename, include, is_system, include_state)
21460bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    include_state.header_types[line_number] = header_type
21470bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
21480bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # Only proceed if this isn't a duplicate header.
21490bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if duplicate_header:
21500bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        return
21510bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
21520bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # We want to ensure that headers appear in the right order:
21530bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # 1) for implementation files: config.h, primary header, blank line, alphabetically sorted
21540bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # 2) for header files: alphabetically sorted
21550bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # The include_state object keeps track of the last type seen
21560bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # and complains if the header types are out of order or missing.
2157d0825bca7fe65beaee391d30da42e937db621564Steve Block    error_message = include_state.check_next_include_order(header_type, file_extension == "h")
21580bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
21590bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # Check to make sure we have a blank line after primary header.
21600bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if not error_message and header_type == _PRIMARY_HEADER:
21610bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch         next_line = clean_lines.raw_lines[line_number + 1]
21620bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch         if not is_blank_line(next_line):
2163d0825bca7fe65beaee391d30da42e937db621564Steve Block            error(line_number, 'build/include_order', 4,
21640bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                  'You should add a blank line after implementation file\'s own header.')
21650bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
21660bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # Check to make sure all headers besides config.h and the primary header are
2167d0825bca7fe65beaee391d30da42e937db621564Steve Block    # alphabetically sorted. Skip Qt's moc files.
21680bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if not error_message and header_type == _OTHER_HEADER:
21690bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch         previous_line_number = line_number - 1;
21700bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch         previous_line = clean_lines.lines[previous_line_number]
21710bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch         previous_match = _RE_PATTERN_INCLUDE.search(previous_line)
21720bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch         while (not previous_match and previous_line_number > 0
21730bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                and not search(r'\A(#if|#ifdef|#ifndef|#else|#elif|#endif)', previous_line)):
21740bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            previous_line_number -= 1;
21750bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            previous_line = clean_lines.lines[previous_line_number]
21760bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            previous_match = _RE_PATTERN_INCLUDE.search(previous_line)
21770bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch         if previous_match:
21780bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            previous_header_type = include_state.header_types[previous_line_number]
21790bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            if previous_header_type == _OTHER_HEADER and previous_line.strip() > line.strip():
2180d0825bca7fe65beaee391d30da42e937db621564Steve Block                error(line_number, 'build/include_order', 4,
21810bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                      'Alphabetical sorting problem.')
21820bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
21830bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if error_message:
2184d0825bca7fe65beaee391d30da42e937db621564Steve Block        if file_extension == 'h':
2185d0825bca7fe65beaee391d30da42e937db621564Steve Block            error(line_number, 'build/include_order', 4,
21860bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                  '%s Should be: alphabetically sorted.' %
21870bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                  error_message)
21880bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        else:
2189d0825bca7fe65beaee391d30da42e937db621564Steve Block            error(line_number, 'build/include_order', 4,
21900bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                  '%s Should be: config.h, primary header, blank line, and then alphabetically sorted.' %
21910bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                  error_message)
21920bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
21930bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
21940bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdochdef check_language(filename, clean_lines, line_number, file_extension, include_state,
21950bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                   error):
21960bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """Checks rules from the 'C++ language rules' section of cppguide.html.
21970bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
21980bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    Some of these rules are hard to test (function overloading, using
21990bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    uint32 inappropriately), but we do the best we can.
22000bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
22010bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    Args:
22020bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      filename: The name of the current file.
22030bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      clean_lines: A CleansedLines instance containing the file.
22040bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      line_number: The number of the line to check.
22050bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      file_extension: The extension (without the dot) of the filename.
22060bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      include_state: An _IncludeState instance in which the headers are inserted.
22070bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      error: The function to call with any errors found.
22080bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """
22090bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # If the line is empty or consists of entirely a comment, no need to
22100bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # check it.
22110bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    line = clean_lines.elided[line_number]
22120bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if not line:
22130bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        return
22140bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
22150bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    matched = _RE_PATTERN_INCLUDE.search(line)
22160bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if matched:
2217d0825bca7fe65beaee391d30da42e937db621564Steve Block        check_include_line(filename, file_extension, clean_lines, line_number, include_state, error)
22180bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        return
22190bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
22200bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # FIXME: figure out if they're using default arguments in fn proto.
22210bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
22220bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # Check to see if they're using an conversion function cast.
22230bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # I just try to capture the most common basic types, though there are more.
22240bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # Parameterless conversion functions, such as bool(), are allowed as they are
22250bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # probably a member operator declaration or default constructor.
22260bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    matched = search(
22270bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        r'\b(int|float|double|bool|char|int32|uint32|int64|uint64)\([^)]', line)
22280bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if matched:
22290bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # gMock methods are defined using some variant of MOCK_METHODx(name, type)
22300bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # where type may be float(), int(string), etc.  Without context they are
22310bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # virtually indistinguishable from int(x) casts.
22320bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        if not match(r'^\s*MOCK_(CONST_)?METHOD\d+(_T)?\(', line):
2233d0825bca7fe65beaee391d30da42e937db621564Steve Block            error(line_number, 'readability/casting', 4,
22340bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                  'Using deprecated casting style.  '
22350bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                  'Use static_cast<%s>(...) instead' %
22360bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                  matched.group(1))
22370bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
2238d0825bca7fe65beaee391d30da42e937db621564Steve Block    check_c_style_cast(line_number, line, clean_lines.raw_lines[line_number],
22390bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                       'static_cast',
22400bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                       r'\((int|float|double|bool|char|u?int(16|32|64))\)',
22410bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                       error)
22420bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # This doesn't catch all cases.  Consider (const char * const)"hello".
2243d0825bca7fe65beaee391d30da42e937db621564Steve Block    check_c_style_cast(line_number, line, clean_lines.raw_lines[line_number],
22440bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                       'reinterpret_cast', r'\((\w+\s?\*+\s?)\)', error)
22450bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
22460bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # In addition, we look for people taking the address of a cast.  This
22470bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # is dangerous -- casts can assign to temporaries, so the pointer doesn't
22480bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # point where you think.
22490bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if search(
22500bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        r'(&\([^)]+\)[\w(])|(&(static|dynamic|reinterpret)_cast\b)', line):
2251d0825bca7fe65beaee391d30da42e937db621564Steve Block        error(line_number, 'runtime/casting', 4,
22520bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch              ('Are you taking an address of a cast?  '
22530bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch               'This is dangerous: could be a temp var.  '
22540bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch               'Take the address before doing the cast, rather than after'))
22550bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
22560bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # Check for people declaring static/global STL strings at the top level.
22570bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # This is dangerous because the C++ language does not guarantee that
22580bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # globals with constructors are initialized before the first access.
22590bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    matched = match(
22600bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        r'((?:|static +)(?:|const +))string +([a-zA-Z0-9_:]+)\b(.*)',
22610bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        line)
22620bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # Make sure it's not a function.
22630bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # Function template specialization looks like: "string foo<Type>(...".
22640bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # Class template definitions look like: "string Foo<Type>::Method(...".
22650bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if matched and not match(r'\s*(<.*>)?(::[a-zA-Z0-9_]+)?\s*\(([^"]|$)',
22660bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                             matched.group(3)):
2267d0825bca7fe65beaee391d30da42e937db621564Steve Block        error(line_number, 'runtime/string', 4,
22680bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch              'For a static/global string constant, use a C style string instead: '
22690bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch              '"%schar %s[]".' %
22700bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch              (matched.group(1), matched.group(2)))
22710bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
22720bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # Check that we're not using RTTI outside of testing code.
22738a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block    if search(r'\bdynamic_cast<', line):
2274d0825bca7fe65beaee391d30da42e937db621564Steve Block        error(line_number, 'runtime/rtti', 5,
22750bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch              'Do not use dynamic_cast<>.  If you need to cast within a class '
22760bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch              "hierarchy, use static_cast<> to upcast.  Google doesn't support "
22770bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch              'RTTI.')
22780bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
22790bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if search(r'\b([A-Za-z0-9_]*_)\(\1\)', line):
2280d0825bca7fe65beaee391d30da42e937db621564Steve Block        error(line_number, 'runtime/init', 4,
22810bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch              'You seem to be initializing a member variable with itself.')
22820bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
22830bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if file_extension == 'h':
22840bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # FIXME: check that 1-arg constructors are explicit.
22850bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        #        How to tell it's a constructor?
22860bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        #        (handled in check_for_non_standard_constructs for now)
22870bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        pass
22880bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
22890bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # Check if people are using the verboten C basic types.  The only exception
22900bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # we regularly allow is "unsigned short port" for port.
22910bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if search(r'\bshort port\b', line):
22920bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        if not search(r'\bunsigned short port\b', line):
2293d0825bca7fe65beaee391d30da42e937db621564Steve Block            error(line_number, 'runtime/int', 4,
22940bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                  'Use "unsigned short" for ports, not "short"')
22950bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
22960bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # When snprintf is used, the second argument shouldn't be a literal.
22970bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    matched = search(r'snprintf\s*\(([^,]*),\s*([0-9]*)\s*,', line)
22980bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if matched:
2299d0825bca7fe65beaee391d30da42e937db621564Steve Block        error(line_number, 'runtime/printf', 3,
23000bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch              'If you can, use sizeof(%s) instead of %s as the 2nd arg '
23010bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch              'to snprintf.' % (matched.group(1), matched.group(2)))
23020bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
23030bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # Check if some verboten C functions are being used.
23040bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if search(r'\bsprintf\b', line):
2305d0825bca7fe65beaee391d30da42e937db621564Steve Block        error(line_number, 'runtime/printf', 5,
23060bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch              'Never use sprintf.  Use snprintf instead.')
23070bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    matched = search(r'\b(strcpy|strcat)\b', line)
23080bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if matched:
2309d0825bca7fe65beaee391d30da42e937db621564Steve Block        error(line_number, 'runtime/printf', 4,
23100bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch              'Almost always, snprintf is better than %s' % matched.group(1))
23110bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
23120bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if search(r'\bsscanf\b', line):
2313d0825bca7fe65beaee391d30da42e937db621564Steve Block        error(line_number, 'runtime/printf', 1,
23140bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch              'sscanf can be ok, but is slow and can overflow buffers.')
23150bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
23160bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # Check for suspicious usage of "if" like
23170bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # } if (a == b) {
23180bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if search(r'\}\s*if\s*\(', line):
2319d0825bca7fe65beaee391d30da42e937db621564Steve Block        error(line_number, 'readability/braces', 4,
23200bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch              'Did you mean "else if"? If not, start a new line for "if".')
23210bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
23220bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # Check for potential format string bugs like printf(foo).
23230bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # We constrain the pattern not to pick things like DocidForPrintf(foo).
23240bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # Not perfect but it can catch printf(foo.c_str()) and printf(foo->c_str())
23250bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    matched = re.search(r'\b((?:string)?printf)\s*\(([\w.\->()]+)\)', line, re.I)
23260bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if matched:
2327d0825bca7fe65beaee391d30da42e937db621564Steve Block        error(line_number, 'runtime/printf', 4,
23280bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch              'Potential format string bug. Do %s("%%s", %s) instead.'
23290bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch              % (matched.group(1), matched.group(2)))
23300bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
23310bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # Check for potential memset bugs like memset(buf, sizeof(buf), 0).
23320bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    matched = search(r'memset\s*\(([^,]*),\s*([^,]*),\s*0\s*\)', line)
23330bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if matched and not match(r"^''|-?[0-9]+|0x[0-9A-Fa-f]$", matched.group(2)):
2334d0825bca7fe65beaee391d30da42e937db621564Steve Block        error(line_number, 'runtime/memset', 4,
23350bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch              'Did you mean "memset(%s, 0, %s)"?'
23360bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch              % (matched.group(1), matched.group(2)))
23370bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
23380bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # Detect variable-length arrays.
23390bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    matched = match(r'\s*(.+::)?(\w+) [a-z]\w*\[(.+)];', line)
23400bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if (matched and matched.group(2) != 'return' and matched.group(2) != 'delete' and
23410bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        matched.group(3).find(']') == -1):
23420bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # Split the size using space and arithmetic operators as delimiters.
23430bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # If any of the resulting tokens are not compile time constants then
23440bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # report the error.
23450bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        tokens = re.split(r'\s|\+|\-|\*|\/|<<|>>]', matched.group(3))
23460bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        is_const = True
23470bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        skip_next = False
23480bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        for tok in tokens:
23490bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            if skip_next:
23500bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                skip_next = False
23510bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                continue
23520bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
23530bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            if search(r'sizeof\(.+\)', tok):
23540bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                continue
23550bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            if search(r'arraysize\(\w+\)', tok):
23560bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                continue
23570bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
23580bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            tok = tok.lstrip('(')
23590bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            tok = tok.rstrip(')')
23600bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            if not tok:
23610bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                continue
23620bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            if match(r'\d+', tok):
23630bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                continue
23640bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            if match(r'0[xX][0-9a-fA-F]+', tok):
23650bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                continue
23660bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            if match(r'k[A-Z0-9]\w*', tok):
23670bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                continue
23680bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            if match(r'(.+::)?k[A-Z0-9]\w*', tok):
23690bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                continue
23700bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            if match(r'(.+::)?[A-Z][A-Z0-9_]*', tok):
23710bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                continue
23720bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            # A catch all for tricky sizeof cases, including 'sizeof expression',
23730bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            # 'sizeof(*type)', 'sizeof(const type)', 'sizeof(struct StructName)'
23740bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            # requires skipping the next token becasue we split on ' ' and '*'.
23750bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            if tok.startswith('sizeof'):
23760bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                skip_next = True
23770bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                continue
23780bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            is_const = False
23790bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            break
23800bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        if not is_const:
2381d0825bca7fe65beaee391d30da42e937db621564Steve Block            error(line_number, 'runtime/arrays', 1,
23820bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                  'Do not use variable-length arrays.  Use an appropriately named '
23830bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                  "('k' followed by CamelCase) compile-time constant for the size.")
23840bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
23850bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # Check for use of unnamed namespaces in header files.  Registration
23860bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # macros are typically OK, so we allow use of "namespace {" on lines
23870bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # that end with backslashes.
23880bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if (file_extension == 'h'
23890bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        and search(r'\bnamespace\s*{', line)
23900bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        and line[-1] != '\\'):
2391d0825bca7fe65beaee391d30da42e937db621564Steve Block        error(line_number, 'build/namespaces', 4,
23920bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch              'Do not use unnamed namespaces in header files.  See '
23930bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch              'http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml#Namespaces'
23940bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch              ' for more information.')
23950bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
2396643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    check_identifier_name_in_declaration(filename, line_number, line, error)
2397643ca7872b450ea4efacab6188849e5aac2ba161Steve Block
2398643ca7872b450ea4efacab6188849e5aac2ba161Steve Block
2399643ca7872b450ea4efacab6188849e5aac2ba161Steve Blockdef check_identifier_name_in_declaration(filename, line_number, line, error):
2400643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    """Checks if identifier names contain any underscores.
2401643ca7872b450ea4efacab6188849e5aac2ba161Steve Block
2402643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    As identifiers in libraries we are using have a bunch of
2403643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    underscores, we only warn about the declarations of identifiers
2404643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    and don't check use of identifiers.
2405643ca7872b450ea4efacab6188849e5aac2ba161Steve Block
2406643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    Args:
2407643ca7872b450ea4efacab6188849e5aac2ba161Steve Block      filename: The name of the current file.
2408643ca7872b450ea4efacab6188849e5aac2ba161Steve Block      line_number: The number of the line to check.
2409643ca7872b450ea4efacab6188849e5aac2ba161Steve Block      line: The line of code to check.
2410643ca7872b450ea4efacab6188849e5aac2ba161Steve Block      error: The function to call with any errors found.
2411643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    """
2412643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    # We don't check a return statement.
2413d0825bca7fe65beaee391d30da42e937db621564Steve Block    if match(r'\s*(return|delete)\b', line):
2414643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        return
2415643ca7872b450ea4efacab6188849e5aac2ba161Steve Block
2416643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    # Basically, a declaration is a type name followed by whitespaces
2417643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    # followed by an identifier. The type name can be complicated
2418643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    # due to type adjectives and templates. We remove them first to
2419643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    # simplify the process to find declarations of identifiers.
2420643ca7872b450ea4efacab6188849e5aac2ba161Steve Block
2421643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    # Convert "long long", "long double", and "long long int" to
2422643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    # simple types, but don't remove simple "long".
2423643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    line = sub(r'long (long )?(?=long|double|int)', '', line)
2424643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    line = sub(r'\b(unsigned|signed|inline|using|static|const|volatile|auto|register|extern|typedef|restrict|struct|class|virtual)(?=\W)', '', line)
2425643ca7872b450ea4efacab6188849e5aac2ba161Steve Block
2426643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    # Remove all template parameters by removing matching < and >.
2427643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    # Loop until no templates are removed to remove nested templates.
2428643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    while True:
2429643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        line, number_of_replacements = subn(r'<([\w\s:]|::)+\s*[*&]*\s*>', '', line)
2430643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        if not number_of_replacements:
2431643ca7872b450ea4efacab6188849e5aac2ba161Steve Block            break
2432643ca7872b450ea4efacab6188849e5aac2ba161Steve Block
2433643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    # Declarations of local variables can be in condition expressions
2434643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    # of control flow statements (e.g., "if (RenderObject* p = o->parent())").
2435643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    # We remove the keywords and the first parenthesis.
2436643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    #
2437643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    # Declarations in "while", "if", and "switch" are different from
2438643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    # other declarations in two aspects:
2439643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    #
2440643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    # - There can be only one declaration between the parentheses.
2441643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    #   (i.e., you cannot write "if (int i = 0, j = 1) {}")
2442643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    # - The variable must be initialized.
2443643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    #   (i.e., you cannot write "if (int i) {}")
2444643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    #
2445643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    # and we will need different treatments for them.
2446643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    line = sub(r'^\s*for\s*\(', '', line)
2447643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    line, control_statement = subn(r'^\s*(while|else if|if|switch)\s*\(', '', line)
2448643ca7872b450ea4efacab6188849e5aac2ba161Steve Block
2449643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    # Detect variable and functions.
2450643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    type_regexp = r'\w([\w]|\s*[*&]\s*|::)+'
2451643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    identifier_regexp = r'(?P<identifier>[\w:]+)'
2452643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    character_after_identifier_regexp = r'(?P<character_after_identifier>[[;()=,])(?!=)'
2453643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    declaration_without_type_regexp = r'\s*' + identifier_regexp + r'\s*' + character_after_identifier_regexp
2454643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    declaration_with_type_regexp = r'\s*' + type_regexp + r'\s' + declaration_without_type_regexp
2455643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    is_function_arguments = False
2456643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    number_of_identifiers = 0
2457643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    while True:
2458643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        # If we are seeing the first identifier or arguments of a
2459643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        # function, there should be a type name before an identifier.
2460643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        if not number_of_identifiers or is_function_arguments:
2461643ca7872b450ea4efacab6188849e5aac2ba161Steve Block            declaration_regexp = declaration_with_type_regexp
2462643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        else:
2463643ca7872b450ea4efacab6188849e5aac2ba161Steve Block            declaration_regexp = declaration_without_type_regexp
2464643ca7872b450ea4efacab6188849e5aac2ba161Steve Block
2465643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        matched = match(declaration_regexp, line)
2466643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        if not matched:
2467643ca7872b450ea4efacab6188849e5aac2ba161Steve Block            return
2468643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        identifier = matched.group('identifier')
2469643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        character_after_identifier = matched.group('character_after_identifier')
2470643ca7872b450ea4efacab6188849e5aac2ba161Steve Block
2471643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        # If we removed a non-for-control statement, the character after
2472643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        # the identifier should be '='. With this rule, we can avoid
2473643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        # warning for cases like "if (val & INT_MAX) {".
2474643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        if control_statement and character_after_identifier != '=':
2475643ca7872b450ea4efacab6188849e5aac2ba161Steve Block            return
2476643ca7872b450ea4efacab6188849e5aac2ba161Steve Block
2477643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        is_function_arguments = is_function_arguments or character_after_identifier == '('
2478643ca7872b450ea4efacab6188849e5aac2ba161Steve Block
2479643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        # Remove "m_" and "s_" to allow them.
2480643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        modified_identifier = sub(r'(^|(?<=::))[ms]_', '', identifier)
2481643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        if modified_identifier.find('_') >= 0:
2482643ca7872b450ea4efacab6188849e5aac2ba161Steve Block            # Various exceptions to the rule: JavaScript op codes functions, const_iterator.
2483643ca7872b450ea4efacab6188849e5aac2ba161Steve Block            if (not (filename.find('JavaScriptCore') >= 0 and modified_identifier.find('_op_') >= 0)
2484d0825bca7fe65beaee391d30da42e937db621564Steve Block                and not modified_identifier.startswith('tst_')
2485d0825bca7fe65beaee391d30da42e937db621564Steve Block                and not modified_identifier.startswith('webkit_dom_object_')
2486d0825bca7fe65beaee391d30da42e937db621564Steve Block                and not modified_identifier.startswith('qt_')
2487d0825bca7fe65beaee391d30da42e937db621564Steve Block                and not modified_identifier.find('::qt_') >= 0
2488643ca7872b450ea4efacab6188849e5aac2ba161Steve Block                and not modified_identifier == "const_iterator"):
2489d0825bca7fe65beaee391d30da42e937db621564Steve Block                error(line_number, 'readability/naming', 4, identifier + " is incorrectly named. Don't use underscores in your identifier names.")
2490643ca7872b450ea4efacab6188849e5aac2ba161Steve Block
2491643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        # There can be only one declaration in non-for-control statements.
2492643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        if control_statement:
2493643ca7872b450ea4efacab6188849e5aac2ba161Steve Block            return
2494643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        # We should continue checking if this is a function
2495643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        # declaration because we need to check its arguments.
2496643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        # Also, we need to check multiple declarations.
2497643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        if character_after_identifier != '(' and character_after_identifier != ',':
2498643ca7872b450ea4efacab6188849e5aac2ba161Steve Block            return
2499643ca7872b450ea4efacab6188849e5aac2ba161Steve Block
2500643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        number_of_identifiers += 1
2501643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        line = line[matched.end():]
2502643ca7872b450ea4efacab6188849e5aac2ba161Steve Block
25030bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
2504d0825bca7fe65beaee391d30da42e937db621564Steve Blockdef check_c_style_cast(line_number, line, raw_line, cast_type, pattern,
25050bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                       error):
25060bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """Checks for a C-style cast by looking for the pattern.
25070bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
25080bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    This also handles sizeof(type) warnings, due to similarity of content.
25090bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
25100bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    Args:
25110bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      line_number: The number of the line to check.
25120bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      line: The line of code to check.
25130bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      raw_line: The raw line of code to check, with comments.
25140bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      cast_type: The string for the C++ cast to recommend.  This is either
25150bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                 reinterpret_cast or static_cast, depending.
25160bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      pattern: The regular expression used to find C-style casts.
25170bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      error: The function to call with any errors found.
25180bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """
25190bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    matched = search(pattern, line)
25200bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if not matched:
25210bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        return
25220bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
25230bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # e.g., sizeof(int)
25240bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    sizeof_match = match(r'.*sizeof\s*$', line[0:matched.start(1) - 1])
25250bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if sizeof_match:
2526d0825bca7fe65beaee391d30da42e937db621564Steve Block        error(line_number, 'runtime/sizeof', 1,
25270bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch              'Using sizeof(type).  Use sizeof(varname) instead if possible')
25280bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        return
25290bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
25300bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    remainder = line[matched.end(0):]
25310bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
25320bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # The close paren is for function pointers as arguments to a function.
25330bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # eg, void foo(void (*bar)(int));
25340bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # The semicolon check is a more basic function check; also possibly a
25350bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # function pointer typedef.
25360bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # eg, void foo(int); or void foo(int) const;
25370bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # The equals check is for function pointer assignment.
25380bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # eg, void *(*foo)(int) = ...
25390bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    #
25400bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # Right now, this will only catch cases where there's a single argument, and
25410bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # it's unnamed.  It should probably be expanded to check for multiple
25420bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # arguments with some unnamed.
25430bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    function_match = match(r'\s*(\)|=|(const)?\s*(;|\{|throw\(\)))', remainder)
25440bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if function_match:
25450bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        if (not function_match.group(3)
25460bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            or function_match.group(3) == ';'
25470bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            or raw_line.find('/*') < 0):
2548d0825bca7fe65beaee391d30da42e937db621564Steve Block            error(line_number, 'readability/function', 3,
25490bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                  'All parameters should be named in a function')
25500bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        return
25510bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
25520bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # At this point, all that should be left is actual casts.
2553d0825bca7fe65beaee391d30da42e937db621564Steve Block    error(line_number, 'readability/casting', 4,
25540bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch          'Using C-style cast.  Use %s<%s>(...) instead' %
25550bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch          (cast_type, matched.group(1)))
25560bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
25570bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
25580bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch_HEADERS_CONTAINING_TEMPLATES = (
25590bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    ('<deque>', ('deque',)),
25600bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    ('<functional>', ('unary_function', 'binary_function',
25610bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                      'plus', 'minus', 'multiplies', 'divides', 'modulus',
25620bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                      'negate',
25630bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                      'equal_to', 'not_equal_to', 'greater', 'less',
25640bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                      'greater_equal', 'less_equal',
25650bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                      'logical_and', 'logical_or', 'logical_not',
25660bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                      'unary_negate', 'not1', 'binary_negate', 'not2',
25670bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                      'bind1st', 'bind2nd',
25680bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                      'pointer_to_unary_function',
25690bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                      'pointer_to_binary_function',
25700bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                      'ptr_fun',
25710bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                      'mem_fun_t', 'mem_fun', 'mem_fun1_t', 'mem_fun1_ref_t',
25720bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                      'mem_fun_ref_t',
25730bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                      'const_mem_fun_t', 'const_mem_fun1_t',
25740bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                      'const_mem_fun_ref_t', 'const_mem_fun1_ref_t',
25750bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                      'mem_fun_ref',
25760bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                     )),
25770bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    ('<limits>', ('numeric_limits',)),
25780bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    ('<list>', ('list',)),
25790bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    ('<map>', ('map', 'multimap',)),
25800bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    ('<memory>', ('allocator',)),
25810bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    ('<queue>', ('queue', 'priority_queue',)),
25820bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    ('<set>', ('set', 'multiset',)),
25830bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    ('<stack>', ('stack',)),
25840bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    ('<string>', ('char_traits', 'basic_string',)),
25850bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    ('<utility>', ('pair',)),
25860bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    ('<vector>', ('vector',)),
25870bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
25880bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # gcc extensions.
25890bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # Note: std::hash is their hash, ::hash is our hash
25900bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    ('<hash_map>', ('hash_map', 'hash_multimap',)),
25910bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    ('<hash_set>', ('hash_set', 'hash_multiset',)),
25920bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    ('<slist>', ('slist',)),
25930bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    )
25940bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
25950bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch_HEADERS_ACCEPTED_BUT_NOT_PROMOTED = {
25960bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # We can trust with reasonable confidence that map gives us pair<>, too.
25970bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    'pair<>': ('map', 'multimap', 'hash_map', 'hash_multimap')
25980bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch}
25990bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
26000bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch_RE_PATTERN_STRING = re.compile(r'\bstring\b')
26010bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
26020bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch_re_pattern_algorithm_header = []
26030bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdochfor _template in ('copy', 'max', 'min', 'min_element', 'sort', 'swap',
26040bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                  'transform'):
26050bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # Match max<type>(..., ...), max(..., ...), but not foo->max, foo.max or
26060bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # type::max().
26070bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    _re_pattern_algorithm_header.append(
26080bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        (re.compile(r'[^>.]\b' + _template + r'(<.*?>)?\([^\)]'),
26090bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch         _template,
26100bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch         '<algorithm>'))
26110bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
26120bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch_re_pattern_templates = []
26130bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdochfor _header, _templates in _HEADERS_CONTAINING_TEMPLATES:
26140bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    for _template in _templates:
26150bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        _re_pattern_templates.append(
26160bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            (re.compile(r'(\<|\b)' + _template + r'\s*\<'),
26170bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch             _template + '<>',
26180bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch             _header))
26190bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
26200bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
26210bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdochdef files_belong_to_same_module(filename_cpp, filename_h):
26220bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """Check if these two filenames belong to the same module.
26230bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
26240bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    The concept of a 'module' here is a as follows:
26250bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    foo.h, foo-inl.h, foo.cpp, foo_test.cpp and foo_unittest.cpp belong to the
26260bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    same 'module' if they are in the same directory.
26270bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    some/path/public/xyzzy and some/path/internal/xyzzy are also considered
26280bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    to belong to the same module here.
26290bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
26300bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    If the filename_cpp contains a longer path than the filename_h, for example,
26310bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    '/absolute/path/to/base/sysinfo.cpp', and this file would include
26320bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    'base/sysinfo.h', this function also produces the prefix needed to open the
26330bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    header. This is used by the caller of this function to more robustly open the
26340bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    header file. We don't have access to the real include paths in this context,
26350bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    so we need this guesswork here.
26360bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
26370bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    Known bugs: tools/base/bar.cpp and base/bar.h belong to the same module
26380bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    according to this implementation. Because of this, this function gives
26390bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    some false positives. This should be sufficiently rare in practice.
26400bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
26410bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    Args:
26420bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      filename_cpp: is the path for the .cpp file
26430bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      filename_h: is the path for the header path
26440bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
26450bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    Returns:
26460bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      Tuple with a bool and a string:
26470bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      bool: True if filename_cpp and filename_h belong to the same module.
26480bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      string: the additional prefix needed to open the header file.
26490bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """
26500bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
26510bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if not filename_cpp.endswith('.cpp'):
26520bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        return (False, '')
26530bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    filename_cpp = filename_cpp[:-len('.cpp')]
26540bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if filename_cpp.endswith('_unittest'):
26550bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        filename_cpp = filename_cpp[:-len('_unittest')]
26560bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    elif filename_cpp.endswith('_test'):
26570bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        filename_cpp = filename_cpp[:-len('_test')]
26580bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    filename_cpp = filename_cpp.replace('/public/', '/')
26590bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    filename_cpp = filename_cpp.replace('/internal/', '/')
26600bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
26610bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if not filename_h.endswith('.h'):
26620bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        return (False, '')
26630bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    filename_h = filename_h[:-len('.h')]
26640bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if filename_h.endswith('-inl'):
26650bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        filename_h = filename_h[:-len('-inl')]
26660bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    filename_h = filename_h.replace('/public/', '/')
26670bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    filename_h = filename_h.replace('/internal/', '/')
26680bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
26690bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    files_belong_to_same_module = filename_cpp.endswith(filename_h)
26700bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    common_path = ''
26710bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if files_belong_to_same_module:
26720bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        common_path = filename_cpp[:-len(filename_h)]
26730bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    return files_belong_to_same_module, common_path
26740bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
26750bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
26760bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdochdef update_include_state(filename, include_state, io=codecs):
26770bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """Fill up the include_state with new includes found from the file.
26780bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
26790bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    Args:
26800bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      filename: the name of the header to read.
26810bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      include_state: an _IncludeState instance in which the headers are inserted.
26820bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      io: The io factory to use to read the file. Provided for testability.
26830bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
26840bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    Returns:
26850bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      True if a header was succesfully added. False otherwise.
26860bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """
26870bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    header_file = None
26880bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    try:
26890bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        header_file = io.open(filename, 'r', 'utf8', 'replace')
26900bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    except IOError:
26910bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        return False
26920bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    line_number = 0
26930bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    for line in header_file:
26940bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        line_number += 1
26950bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        clean_line = cleanse_comments(line)
26960bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        matched = _RE_PATTERN_INCLUDE.search(clean_line)
26970bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        if matched:
26980bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            include = matched.group(2)
26990bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            # The value formatting is cute, but not really used right now.
27000bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            # What matters here is that the key is in include_state.
27010bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            include_state.setdefault(include, '%s:%d' % (filename, line_number))
27020bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    return True
27030bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
27040bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
27050bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdochdef check_for_include_what_you_use(filename, clean_lines, include_state, error,
27060bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                                   io=codecs):
27070bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """Reports for missing stl includes.
27080bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
27090bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    This function will output warnings to make sure you are including the headers
27100bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    necessary for the stl containers and functions that you use. We only give one
27110bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    reason to include a header. For example, if you use both equal_to<> and
27120bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    less<> in a .h file, only one (the latter in the file) of these will be
27130bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    reported as a reason to include the <functional>.
27140bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
27150bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    Args:
27160bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      filename: The name of the current file.
27170bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      clean_lines: A CleansedLines instance containing the file.
27180bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      include_state: An _IncludeState instance.
27190bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      error: The function to call with any errors found.
27200bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      io: The IO factory to use to read the header file. Provided for unittest
27210bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch          injection.
27220bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """
27230bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    required = {}  # A map of header name to line_number and the template entity.
27240bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # Example of required: { '<functional>': (1219, 'less<>') }
27250bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
27260bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    for line_number in xrange(clean_lines.num_lines()):
27270bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        line = clean_lines.elided[line_number]
27280bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        if not line or line[0] == '#':
27290bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            continue
27300bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
27310bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # String is special -- it is a non-templatized type in STL.
27320bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        if _RE_PATTERN_STRING.search(line):
27330bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            required['<string>'] = (line_number, 'string')
27340bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
27350bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        for pattern, template, header in _re_pattern_algorithm_header:
27360bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            if pattern.search(line):
27370bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                required[header] = (line_number, template)
27380bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
27390bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # The following function is just a speed up, no semantics are changed.
27400bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        if not '<' in line:  # Reduces the cpu time usage by skipping lines.
27410bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            continue
27420bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
27430bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        for pattern, template, header in _re_pattern_templates:
27440bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            if pattern.search(line):
27450bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                required[header] = (line_number, template)
27460bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
27470bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # The policy is that if you #include something in foo.h you don't need to
27480bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # include it again in foo.cpp. Here, we will look at possible includes.
27490bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # Let's copy the include_state so it is only messed up within this function.
27500bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    include_state = include_state.copy()
27510bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
27520bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # Did we find the header for this file (if any) and succesfully load it?
27530bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    header_found = False
27540bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
27550bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # Use the absolute path so that matching works properly.
27560bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    abs_filename = os.path.abspath(filename)
27570bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
27580bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # For Emacs's flymake.
27590bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # If cpp_style is invoked from Emacs's flymake, a temporary file is generated
27600bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # by flymake and that file name might end with '_flymake.cpp'. In that case,
27610bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # restore original file name here so that the corresponding header file can be
27620bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # found.
27630bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # e.g. If the file name is 'foo_flymake.cpp', we should search for 'foo.h'
27640bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # instead of 'foo_flymake.h'
27650bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    emacs_flymake_suffix = '_flymake.cpp'
27660bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if abs_filename.endswith(emacs_flymake_suffix):
27670bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        abs_filename = abs_filename[:-len(emacs_flymake_suffix)] + '.cpp'
27680bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
27690bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # include_state is modified during iteration, so we iterate over a copy of
27700bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # the keys.
27710bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    for header in include_state.keys():  #NOLINT
27720bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        (same_module, common_path) = files_belong_to_same_module(abs_filename, header)
27730bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        fullpath = common_path + header
27740bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        if same_module and update_include_state(fullpath, include_state, io):
27750bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            header_found = True
27760bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
27770bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # If we can't find the header file for a .cpp, assume it's because we don't
27780bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # know where to look. In that case we'll give up as we're not sure they
27790bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # didn't include it in the .h file.
27800bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # FIXME: Do a better job of finding .h files so we are confident that
27810bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    #        not having the .h file means there isn't one.
27820bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if filename.endswith('.cpp') and not header_found:
27830bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        return
27840bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
27850bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # All the lines have been processed, report the errors found.
27860bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    for required_header_unstripped in required:
27870bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        template = required[required_header_unstripped][1]
27880bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        if template in _HEADERS_ACCEPTED_BUT_NOT_PROMOTED:
27890bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            headers = _HEADERS_ACCEPTED_BUT_NOT_PROMOTED[template]
27900bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            if [True for header in headers if header in include_state]:
27910bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                continue
27920bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        if required_header_unstripped.strip('<>"') not in include_state:
2793d0825bca7fe65beaee391d30da42e937db621564Steve Block            error(required[required_header_unstripped][0],
27940bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                  'build/include_what_you_use', 4,
27950bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                  'Add #include ' + required_header_unstripped + ' for ' + template)
27960bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
27970bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
27980bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdochdef process_line(filename, file_extension,
27990bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                 clean_lines, line, include_state, function_state,
2800643ca7872b450ea4efacab6188849e5aac2ba161Steve Block                 class_state, file_state, error):
28010bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """Processes a single line in the file.
28020bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
28030bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    Args:
28040bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      filename: Filename of the file that is being processed.
28050bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      file_extension: The extension (dot not included) of the file.
28060bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      clean_lines: An array of strings, each representing a line of the file,
28070bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                   with comments stripped.
28080bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      line: Number of line being processed.
28090bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      include_state: An _IncludeState instance in which the headers are inserted.
28100bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      function_state: A _FunctionState instance which counts function lines, etc.
28110bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      class_state: A _ClassState instance which maintains information about
28120bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                   the current stack of nested class declarations being parsed.
2813643ca7872b450ea4efacab6188849e5aac2ba161Steve Block      file_state: A _FileState instance which maintains information about
2814643ca7872b450ea4efacab6188849e5aac2ba161Steve Block                  the state of things in the file.
2815d0825bca7fe65beaee391d30da42e937db621564Steve Block      error: A callable to which errors are reported, which takes arguments:
2816d0825bca7fe65beaee391d30da42e937db621564Steve Block             line number, error level, and message
28170bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
28180bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """
28190bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    raw_lines = clean_lines.raw_lines
2820d0825bca7fe65beaee391d30da42e937db621564Steve Block    check_for_function_lengths(clean_lines, line, function_state, error)
28210bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if search(r'\bNOLINT\b', raw_lines[line]):  # ignore nolint lines
28220bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        return
2823d0825bca7fe65beaee391d30da42e937db621564Steve Block    check_for_multiline_comments_and_strings(clean_lines, line, error)
2824d0825bca7fe65beaee391d30da42e937db621564Steve Block    check_style(clean_lines, line, file_extension, file_state, error)
28250bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    check_language(filename, clean_lines, line, file_extension, include_state,
28260bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                   error)
2827d0825bca7fe65beaee391d30da42e937db621564Steve Block    check_for_non_standard_constructs(clean_lines, line, class_state, error)
2828d0825bca7fe65beaee391d30da42e937db621564Steve Block    check_posix_threading(clean_lines, line, error)
2829d0825bca7fe65beaee391d30da42e937db621564Steve Block    check_invalid_increment(clean_lines, line, error)
28300bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
28310bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
2832d0825bca7fe65beaee391d30da42e937db621564Steve Blockdef _process_lines(filename, file_extension, lines, error, verbosity):
28330bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """Performs lint checks and reports any errors to the given error function.
28340bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
28350bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    Args:
28360bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      filename: Filename of the file that is being processed.
28370bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      file_extension: The extension (dot not included) of the file.
28380bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      lines: An array of strings, each representing a line of the file, with the
28390bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch             last element being empty if the file is termined with a newline.
28400bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      error: A callable to which errors are reported, which takes 4 arguments:
28410bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """
28420bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    lines = (['// marker so line numbers and indices both start at 1'] + lines +
28430bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch             ['// marker so line numbers end in a known way'])
28440bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
28450bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    include_state = _IncludeState()
2846d0825bca7fe65beaee391d30da42e937db621564Steve Block    function_state = _FunctionState(verbosity)
28470bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    class_state = _ClassState()
2848643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    file_state = _FileState()
28490bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
2850d0825bca7fe65beaee391d30da42e937db621564Steve Block    check_for_copyright(lines, error)
28510bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
28520bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if file_extension == 'h':
28530bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        check_for_header_guard(filename, lines, error)
28540bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
2855d0825bca7fe65beaee391d30da42e937db621564Steve Block    remove_multi_line_comments(lines, error)
28560bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    clean_lines = CleansedLines(lines)
28570bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    for line in xrange(clean_lines.num_lines()):
28580bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        process_line(filename, file_extension, clean_lines, line,
2859643ca7872b450ea4efacab6188849e5aac2ba161Steve Block                     include_state, function_state, class_state, file_state, error)
2860d0825bca7fe65beaee391d30da42e937db621564Steve Block    class_state.check_finished(error)
28610bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
28620bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    check_for_include_what_you_use(filename, clean_lines, include_state, error)
28630bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
28640bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # We check here rather than inside process_line so that we see raw
28650bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # lines rather than "cleaned" lines.
2866d0825bca7fe65beaee391d30da42e937db621564Steve Block    check_for_unicode_replacement_characters(lines, error)
28670bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
2868d0825bca7fe65beaee391d30da42e937db621564Steve Block    check_for_new_line_at_eof(lines, error)
28690bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
28700bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
2871d0825bca7fe65beaee391d30da42e937db621564Steve Blockclass CppProcessor(object):
28720bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
2873d0825bca7fe65beaee391d30da42e937db621564Steve Block    """Processes C++ lines for checking style."""
28740bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
2875d0825bca7fe65beaee391d30da42e937db621564Steve Block    # This list is used to--
2876d0825bca7fe65beaee391d30da42e937db621564Steve Block    #
2877d0825bca7fe65beaee391d30da42e937db621564Steve Block    # (1) generate an explicit list of all possible categories,
2878d0825bca7fe65beaee391d30da42e937db621564Steve Block    # (2) unit test that all checked categories have valid names, and
2879d0825bca7fe65beaee391d30da42e937db621564Steve Block    # (3) unit test that all categories are getting unit tested.
2880d0825bca7fe65beaee391d30da42e937db621564Steve Block    #
2881d0825bca7fe65beaee391d30da42e937db621564Steve Block    categories = set([
2882d0825bca7fe65beaee391d30da42e937db621564Steve Block        'build/class',
2883d0825bca7fe65beaee391d30da42e937db621564Steve Block        'build/deprecated',
2884d0825bca7fe65beaee391d30da42e937db621564Steve Block        'build/endif_comment',
2885d0825bca7fe65beaee391d30da42e937db621564Steve Block        'build/forward_decl',
2886d0825bca7fe65beaee391d30da42e937db621564Steve Block        'build/header_guard',
2887d0825bca7fe65beaee391d30da42e937db621564Steve Block        'build/include',
2888d0825bca7fe65beaee391d30da42e937db621564Steve Block        'build/include_order',
2889d0825bca7fe65beaee391d30da42e937db621564Steve Block        'build/include_what_you_use',
2890d0825bca7fe65beaee391d30da42e937db621564Steve Block        'build/namespaces',
2891d0825bca7fe65beaee391d30da42e937db621564Steve Block        'build/printf_format',
2892d0825bca7fe65beaee391d30da42e937db621564Steve Block        'build/storage_class',
2893d0825bca7fe65beaee391d30da42e937db621564Steve Block        'build/using_std',
2894d0825bca7fe65beaee391d30da42e937db621564Steve Block        'legal/copyright',
2895d0825bca7fe65beaee391d30da42e937db621564Steve Block        'readability/braces',
2896d0825bca7fe65beaee391d30da42e937db621564Steve Block        'readability/casting',
2897d0825bca7fe65beaee391d30da42e937db621564Steve Block        'readability/check',
2898d0825bca7fe65beaee391d30da42e937db621564Steve Block        'readability/comparison_to_zero',
2899d0825bca7fe65beaee391d30da42e937db621564Steve Block        'readability/constructors',
2900d0825bca7fe65beaee391d30da42e937db621564Steve Block        'readability/control_flow',
2901d0825bca7fe65beaee391d30da42e937db621564Steve Block        'readability/fn_size',
2902d0825bca7fe65beaee391d30da42e937db621564Steve Block        'readability/function',
2903d0825bca7fe65beaee391d30da42e937db621564Steve Block        'readability/multiline_comment',
2904d0825bca7fe65beaee391d30da42e937db621564Steve Block        'readability/multiline_string',
2905d0825bca7fe65beaee391d30da42e937db621564Steve Block        'readability/naming',
2906d0825bca7fe65beaee391d30da42e937db621564Steve Block        'readability/null',
2907d0825bca7fe65beaee391d30da42e937db621564Steve Block        'readability/streams',
2908d0825bca7fe65beaee391d30da42e937db621564Steve Block        'readability/todo',
2909d0825bca7fe65beaee391d30da42e937db621564Steve Block        'readability/utf8',
2910d0825bca7fe65beaee391d30da42e937db621564Steve Block        'runtime/arrays',
2911d0825bca7fe65beaee391d30da42e937db621564Steve Block        'runtime/casting',
2912d0825bca7fe65beaee391d30da42e937db621564Steve Block        'runtime/explicit',
2913d0825bca7fe65beaee391d30da42e937db621564Steve Block        'runtime/init',
2914d0825bca7fe65beaee391d30da42e937db621564Steve Block        'runtime/int',
2915d0825bca7fe65beaee391d30da42e937db621564Steve Block        'runtime/invalid_increment',
2916d0825bca7fe65beaee391d30da42e937db621564Steve Block        'runtime/max_min_macros',
2917d0825bca7fe65beaee391d30da42e937db621564Steve Block        'runtime/memset',
2918d0825bca7fe65beaee391d30da42e937db621564Steve Block        'runtime/printf',
2919d0825bca7fe65beaee391d30da42e937db621564Steve Block        'runtime/printf_format',
2920d0825bca7fe65beaee391d30da42e937db621564Steve Block        'runtime/references',
2921d0825bca7fe65beaee391d30da42e937db621564Steve Block        'runtime/rtti',
2922d0825bca7fe65beaee391d30da42e937db621564Steve Block        'runtime/sizeof',
2923d0825bca7fe65beaee391d30da42e937db621564Steve Block        'runtime/string',
2924d0825bca7fe65beaee391d30da42e937db621564Steve Block        'runtime/threadsafe_fn',
2925d0825bca7fe65beaee391d30da42e937db621564Steve Block        'runtime/virtual',
2926d0825bca7fe65beaee391d30da42e937db621564Steve Block        'whitespace/blank_line',
2927d0825bca7fe65beaee391d30da42e937db621564Steve Block        'whitespace/braces',
2928d0825bca7fe65beaee391d30da42e937db621564Steve Block        'whitespace/comma',
2929d0825bca7fe65beaee391d30da42e937db621564Steve Block        'whitespace/comments',
2930d0825bca7fe65beaee391d30da42e937db621564Steve Block        'whitespace/declaration',
2931d0825bca7fe65beaee391d30da42e937db621564Steve Block        'whitespace/end_of_line',
2932d0825bca7fe65beaee391d30da42e937db621564Steve Block        'whitespace/ending_newline',
2933d0825bca7fe65beaee391d30da42e937db621564Steve Block        'whitespace/indent',
2934d0825bca7fe65beaee391d30da42e937db621564Steve Block        'whitespace/labels',
2935d0825bca7fe65beaee391d30da42e937db621564Steve Block        'whitespace/line_length',
2936d0825bca7fe65beaee391d30da42e937db621564Steve Block        'whitespace/newline',
2937d0825bca7fe65beaee391d30da42e937db621564Steve Block        'whitespace/operators',
2938d0825bca7fe65beaee391d30da42e937db621564Steve Block        'whitespace/parens',
2939d0825bca7fe65beaee391d30da42e937db621564Steve Block        'whitespace/semicolon',
2940d0825bca7fe65beaee391d30da42e937db621564Steve Block        'whitespace/tab',
2941d0825bca7fe65beaee391d30da42e937db621564Steve Block        'whitespace/todo',
2942d0825bca7fe65beaee391d30da42e937db621564Steve Block        ])
2943d0825bca7fe65beaee391d30da42e937db621564Steve Block
2944d0825bca7fe65beaee391d30da42e937db621564Steve Block    def __init__(self, file_path, file_extension, handle_style_error, verbosity):
2945d0825bca7fe65beaee391d30da42e937db621564Steve Block        """Create a CppProcessor instance.
29460bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
2947d0825bca7fe65beaee391d30da42e937db621564Steve Block        Args:
2948d0825bca7fe65beaee391d30da42e937db621564Steve Block          file_extension: A string that is the file extension, without
2949d0825bca7fe65beaee391d30da42e937db621564Steve Block                          the leading dot.
29500bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
2951d0825bca7fe65beaee391d30da42e937db621564Steve Block        """
2952d0825bca7fe65beaee391d30da42e937db621564Steve Block        self.file_extension = file_extension
2953d0825bca7fe65beaee391d30da42e937db621564Steve Block        self.file_path = file_path
2954d0825bca7fe65beaee391d30da42e937db621564Steve Block        self.handle_style_error = handle_style_error
2955d0825bca7fe65beaee391d30da42e937db621564Steve Block        self.verbosity = verbosity
2956d0825bca7fe65beaee391d30da42e937db621564Steve Block
2957d0825bca7fe65beaee391d30da42e937db621564Steve Block    # Useful for unit testing.
2958d0825bca7fe65beaee391d30da42e937db621564Steve Block    def __eq__(self, other):
2959d0825bca7fe65beaee391d30da42e937db621564Steve Block        """Return whether this CppProcessor instance is equal to another."""
2960d0825bca7fe65beaee391d30da42e937db621564Steve Block        if self.file_extension != other.file_extension:
2961d0825bca7fe65beaee391d30da42e937db621564Steve Block            return False
2962d0825bca7fe65beaee391d30da42e937db621564Steve Block        if self.file_path != other.file_path:
2963d0825bca7fe65beaee391d30da42e937db621564Steve Block            return False
2964d0825bca7fe65beaee391d30da42e937db621564Steve Block        if self.handle_style_error != other.handle_style_error:
2965d0825bca7fe65beaee391d30da42e937db621564Steve Block            return False
2966d0825bca7fe65beaee391d30da42e937db621564Steve Block        if self.verbosity != other.verbosity:
2967d0825bca7fe65beaee391d30da42e937db621564Steve Block            return False
29680bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
2969d0825bca7fe65beaee391d30da42e937db621564Steve Block        return True
29700bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
2971d0825bca7fe65beaee391d30da42e937db621564Steve Block    # Useful for unit testing.
2972d0825bca7fe65beaee391d30da42e937db621564Steve Block    def __ne__(self, other):
2973d0825bca7fe65beaee391d30da42e937db621564Steve Block        # Python does not automatically deduce __ne__() from __eq__().
2974d0825bca7fe65beaee391d30da42e937db621564Steve Block        return not self.__eq__(other)
29750bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
2976d0825bca7fe65beaee391d30da42e937db621564Steve Block    def process(self, lines):
2977d0825bca7fe65beaee391d30da42e937db621564Steve Block        _process_lines(self.file_path, self.file_extension, lines,
2978d0825bca7fe65beaee391d30da42e937db621564Steve Block                       self.handle_style_error, self.verbosity)
29790bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
29800bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
2981d0825bca7fe65beaee391d30da42e937db621564Steve Block# FIXME: Remove this function (requires refactoring unit tests).
2982d0825bca7fe65beaee391d30da42e937db621564Steve Blockdef process_file_data(filename, file_extension, lines, error, verbosity):
2983d0825bca7fe65beaee391d30da42e937db621564Steve Block    processor = CppProcessor(filename, file_extension, error, verbosity)
2984d0825bca7fe65beaee391d30da42e937db621564Steve Block    processor.process(lines)
29850bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
2986