10bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch#!/usr/bin/python
20bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch# -*- coding: utf-8 -*-
30bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch#
4cad810f21b803229eb11403f9209855525a25d57Steve Block# Copyright (C) 2009, 2010 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
50cad810f21b803229eb11403f9209855525a25d57Steve Blockfrom webkitpy.common.memoized import memoized
51cad810f21b803229eb11403f9209855525a25d57Steve Block
52f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch# The key to use to provide a class to fake loading a header file.
53f05b935882198ccf7d81675736e3aeb089c5113aBen MurdochINCLUDE_IO_INJECTION_KEY = 'include_header_io'
540bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
550bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch# Headers that we consider STL headers.
560bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch_STL_HEADERS = frozenset([
570bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    'algobase.h', 'algorithm', 'alloc.h', 'bitset', 'deque', 'exception',
580bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    'function.h', 'functional', 'hash_map', 'hash_map.h', 'hash_set',
590bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    'hash_set.h', 'iterator', 'list', 'list.h', 'map', 'memory', 'pair.h',
600bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    'pthread_alloc', 'queue', 'set', 'set.h', 'sstream', 'stack',
610bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    'stl_alloc.h', 'stl_relops.h', 'type_traits.h',
620bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    'utility', 'vector', 'vector.h',
630bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    ])
640bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
650bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
660bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch# Non-STL C++ system headers.
670bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch_CPP_HEADERS = frozenset([
680bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    'algo.h', 'builtinbuf.h', 'bvector.h', 'cassert', 'cctype',
690bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    'cerrno', 'cfloat', 'ciso646', 'climits', 'clocale', 'cmath',
700bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    'complex', 'complex.h', 'csetjmp', 'csignal', 'cstdarg', 'cstddef',
710bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    'cstdio', 'cstdlib', 'cstring', 'ctime', 'cwchar', 'cwctype',
720bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    'defalloc.h', 'deque.h', 'editbuf.h', 'exception', 'fstream',
730bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    'fstream.h', 'hashtable.h', 'heap.h', 'indstream.h', 'iomanip',
740bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    'iomanip.h', 'ios', 'iosfwd', 'iostream', 'iostream.h', 'istream.h',
750bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    'iterator.h', 'limits', 'map.h', 'multimap.h', 'multiset.h',
760bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    'numeric', 'ostream.h', 'parsestream.h', 'pfstream.h', 'PlotFile.h',
770bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    'procbuf.h', 'pthread_alloc.h', 'rope', 'rope.h', 'ropeimpl.h',
780bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    'SFile.h', 'slist', 'slist.h', 'stack.h', 'stdexcept',
790bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    'stdiostream.h', 'streambuf.h', 'stream.h', 'strfile.h', 'string',
800bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    'strstream', 'strstream.h', 'tempbuf.h', 'tree.h', 'typeinfo', 'valarray',
810bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    ])
820bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
830bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
840bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch# Assertion macros.  These are defined in base/logging.h and
850bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch# testing/base/gunit.h.  Note that the _M versions need to come first
860bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch# for substring matching to work.
870bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch_CHECK_MACROS = [
880bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    'DCHECK', 'CHECK',
890bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    'EXPECT_TRUE_M', 'EXPECT_TRUE',
900bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    'ASSERT_TRUE_M', 'ASSERT_TRUE',
910bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    'EXPECT_FALSE_M', 'EXPECT_FALSE',
920bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    'ASSERT_FALSE_M', 'ASSERT_FALSE',
930bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    ]
940bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
950bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch# Replacement macros for CHECK/DCHECK/EXPECT_TRUE/EXPECT_FALSE
960bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch_CHECK_REPLACEMENT = dict([(m, {}) for m in _CHECK_MACROS])
970bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
980bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdochfor op, replacement in [('==', 'EQ'), ('!=', 'NE'),
990bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                        ('>=', 'GE'), ('>', 'GT'),
1000bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                        ('<=', 'LE'), ('<', 'LT')]:
1010bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    _CHECK_REPLACEMENT['DCHECK'][op] = 'DCHECK_%s' % replacement
1020bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    _CHECK_REPLACEMENT['CHECK'][op] = 'CHECK_%s' % replacement
1030bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    _CHECK_REPLACEMENT['EXPECT_TRUE'][op] = 'EXPECT_%s' % replacement
1040bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    _CHECK_REPLACEMENT['ASSERT_TRUE'][op] = 'ASSERT_%s' % replacement
1050bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    _CHECK_REPLACEMENT['EXPECT_TRUE_M'][op] = 'EXPECT_%s_M' % replacement
1060bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    _CHECK_REPLACEMENT['ASSERT_TRUE_M'][op] = 'ASSERT_%s_M' % replacement
1070bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
1080bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdochfor op, inv_replacement in [('==', 'NE'), ('!=', 'EQ'),
1090bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                            ('>=', 'LT'), ('>', 'LE'),
1100bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                            ('<=', 'GT'), ('<', 'GE')]:
1110bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    _CHECK_REPLACEMENT['EXPECT_FALSE'][op] = 'EXPECT_%s' % inv_replacement
1120bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    _CHECK_REPLACEMENT['ASSERT_FALSE'][op] = 'ASSERT_%s' % inv_replacement
1130bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    _CHECK_REPLACEMENT['EXPECT_FALSE_M'][op] = 'EXPECT_%s_M' % inv_replacement
1140bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    _CHECK_REPLACEMENT['ASSERT_FALSE_M'][op] = 'ASSERT_%s_M' % inv_replacement
1150bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
1160bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
1170bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch# These constants define types of headers for use with
1180bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch# _IncludeState.check_next_include_order().
1190bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch_CONFIG_HEADER = 0
1200bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch_PRIMARY_HEADER = 1
1210bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch_OTHER_HEADER = 2
122d0825bca7fe65beaee391d30da42e937db621564Steve Block_MOC_HEADER = 3
1230bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
1240bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
125f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch# A dictionary of items customize behavior for unit test. For example,
126f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch# INCLUDE_IO_INJECTION_KEY allows providing a custom io class which allows
127f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch# for faking a header file.
128f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch_unit_test_config = {}
129f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch
130f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch
131643ca7872b450ea4efacab6188849e5aac2ba161Steve Block# The regexp compilation caching is inlined in all regexp functions for
132643ca7872b450ea4efacab6188849e5aac2ba161Steve Block# performance reasons; factoring it out into a separate function turns out
133643ca7872b450ea4efacab6188849e5aac2ba161Steve Block# to be noticeably expensive.
1340bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch_regexp_compile_cache = {}
1350bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
1360bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
1370bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdochdef match(pattern, s):
1380bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """Matches the string with the pattern, caching the compiled regexp."""
1390bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if not pattern in _regexp_compile_cache:
1400bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        _regexp_compile_cache[pattern] = sre_compile.compile(pattern)
1410bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    return _regexp_compile_cache[pattern].match(s)
1420bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
1430bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
1440bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdochdef search(pattern, s):
1450bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """Searches the string for the pattern, caching the compiled regexp."""
1460bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if not pattern in _regexp_compile_cache:
1470bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        _regexp_compile_cache[pattern] = sre_compile.compile(pattern)
1480bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    return _regexp_compile_cache[pattern].search(s)
1490bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
1500bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
151643ca7872b450ea4efacab6188849e5aac2ba161Steve Blockdef sub(pattern, replacement, s):
152643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    """Substitutes occurrences of a pattern, caching the compiled regexp."""
153643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    if not pattern in _regexp_compile_cache:
154643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        _regexp_compile_cache[pattern] = sre_compile.compile(pattern)
155643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    return _regexp_compile_cache[pattern].sub(replacement, s)
156643ca7872b450ea4efacab6188849e5aac2ba161Steve Block
157643ca7872b450ea4efacab6188849e5aac2ba161Steve Block
158643ca7872b450ea4efacab6188849e5aac2ba161Steve Blockdef subn(pattern, replacement, s):
159643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    """Substitutes occurrences of a pattern, caching the compiled regexp."""
160643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    if not pattern in _regexp_compile_cache:
161643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        _regexp_compile_cache[pattern] = sre_compile.compile(pattern)
162643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    return _regexp_compile_cache[pattern].subn(replacement, s)
163643ca7872b450ea4efacab6188849e5aac2ba161Steve Block
164643ca7872b450ea4efacab6188849e5aac2ba161Steve Block
1656b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brennerdef iteratively_replace_matches_with_char(pattern, char_replacement, s):
1666b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner    """Returns the string with replacement done.
1676b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner
1686b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner    Every character in the match is replaced with char.
1696b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner    Due to the iterative nature, pattern should not match char or
1706b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner    there will be an infinite loop.
1716b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner
1726b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner    Example:
1736b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner      pattern = r'<[^>]>' # template parameters
1746b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner      char_replacement =  '_'
1756b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner      s =     'A<B<C, D>>'
1766b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner      Returns 'A_________'
1776b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner
1786b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner    Args:
1796b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner      pattern: The regex to match.
1806b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner      char_replacement: The character to put in place of every
1816b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner                        character of the match.
1826b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner      s: The string on which to do the replacements.
1836b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner
1846b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner    Returns:
1856b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner      True, if the given line is blank.
1866b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner    """
1876b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner    while True:
1886b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner        matched = search(pattern, s)
1896b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner        if not matched:
1906b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner            return s
1916b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner        start_match_index = matched.start(0)
1926b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner        end_match_index = matched.end(0)
1936b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner        match_length = end_match_index - start_match_index
1946b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner        s = s[:start_match_index] + char_replacement * match_length + s[end_match_index:]
1956b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner
1966b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner
1972fc2651226baac27029e38c9d6ef883fa32084dbSteve Blockdef _rfind_in_lines(regex, lines, start_position, not_found_position):
1982fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    """Does a reverse find starting at start position and going backwards until
1992fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    a match is found.
2002fc2651226baac27029e38c9d6ef883fa32084dbSteve Block
2012fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    Returns the position where the regex ended.
2022fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    """
2032fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    # Put the regex in a group and proceed it with a greedy expression that
2042fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    # matches anything to ensure that we get the last possible match in a line.
2052fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    last_in_line_regex = r'.*(' + regex + ')'
2062fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    current_row = start_position.row
2072fc2651226baac27029e38c9d6ef883fa32084dbSteve Block
2082fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    # Start with the given row and trim off everything past what may be matched.
2092fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    current_line = lines[start_position.row][:start_position.column]
2102fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    while True:
2112fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        found_match = match(last_in_line_regex, current_line)
2122fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        if found_match:
2132fc2651226baac27029e38c9d6ef883fa32084dbSteve Block            return Position(current_row, found_match.end(1))
2142fc2651226baac27029e38c9d6ef883fa32084dbSteve Block
2152fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        # A match was not found so continue backward.
2162fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        current_row -= 1
2172fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        if current_row < 0:
2182fc2651226baac27029e38c9d6ef883fa32084dbSteve Block            return not_found_position
2192fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        current_line = lines[current_row]
2202fc2651226baac27029e38c9d6ef883fa32084dbSteve Block
2212fc2651226baac27029e38c9d6ef883fa32084dbSteve Block
222cad810f21b803229eb11403f9209855525a25d57Steve Blockdef _convert_to_lower_with_underscores(text):
223cad810f21b803229eb11403f9209855525a25d57Steve Block    """Converts all text strings in camelCase or PascalCase to lowers with underscores."""
224cad810f21b803229eb11403f9209855525a25d57Steve Block
225cad810f21b803229eb11403f9209855525a25d57Steve Block    # First add underscores before any capital letter followed by a lower case letter
226cad810f21b803229eb11403f9209855525a25d57Steve Block    # as long as it is in a word.
227cad810f21b803229eb11403f9209855525a25d57Steve Block    # (This put an underscore before Password but not P and A in WPAPassword).
228cad810f21b803229eb11403f9209855525a25d57Steve Block    text = sub(r'(?<=[A-Za-z0-9])([A-Z])(?=[a-z])', r'_\1', text)
229cad810f21b803229eb11403f9209855525a25d57Steve Block
230cad810f21b803229eb11403f9209855525a25d57Steve Block    # Next add underscores before capitals at the end of words if it was
231cad810f21b803229eb11403f9209855525a25d57Steve Block    # preceeded by lower case letter or number.
232cad810f21b803229eb11403f9209855525a25d57Steve Block    # (This puts an underscore before A in isA but not A in CBA).
233cad810f21b803229eb11403f9209855525a25d57Steve Block    text = sub(r'(?<=[a-z0-9])([A-Z])(?=\b)', r'_\1', text)
234cad810f21b803229eb11403f9209855525a25d57Steve Block
235cad810f21b803229eb11403f9209855525a25d57Steve Block    # Next add underscores when you have a captial letter which is followed by a capital letter
236cad810f21b803229eb11403f9209855525a25d57Steve Block    # but is not proceeded by one. (This puts an underscore before A in 'WordADay').
237cad810f21b803229eb11403f9209855525a25d57Steve Block    text = sub(r'(?<=[a-z0-9])([A-Z][A-Z_])', r'_\1', text)
238cad810f21b803229eb11403f9209855525a25d57Steve Block
239cad810f21b803229eb11403f9209855525a25d57Steve Block    return text.lower()
240cad810f21b803229eb11403f9209855525a25d57Steve Block
241cad810f21b803229eb11403f9209855525a25d57Steve Block
242cad810f21b803229eb11403f9209855525a25d57Steve Block
243cad810f21b803229eb11403f9209855525a25d57Steve Blockdef _create_acronym(text):
244cad810f21b803229eb11403f9209855525a25d57Steve Block    """Creates an acronym for the given text."""
245cad810f21b803229eb11403f9209855525a25d57Steve Block    # Removes all lower case letters except those starting words.
246cad810f21b803229eb11403f9209855525a25d57Steve Block    text = sub(r'(?<!\b)[a-z]', '', text)
247cad810f21b803229eb11403f9209855525a25d57Steve Block    return text.upper()
248cad810f21b803229eb11403f9209855525a25d57Steve Block
249cad810f21b803229eb11403f9209855525a25d57Steve Block
250d0825bca7fe65beaee391d30da42e937db621564Steve Blockdef up_to_unmatched_closing_paren(s):
251d0825bca7fe65beaee391d30da42e937db621564Steve Block    """Splits a string into two parts up to first unmatched ')'.
252d0825bca7fe65beaee391d30da42e937db621564Steve Block
253d0825bca7fe65beaee391d30da42e937db621564Steve Block    Args:
254d0825bca7fe65beaee391d30da42e937db621564Steve Block      s: a string which is a substring of line after '('
255d0825bca7fe65beaee391d30da42e937db621564Steve Block      (e.g., "a == (b + c))").
256d0825bca7fe65beaee391d30da42e937db621564Steve Block
257d0825bca7fe65beaee391d30da42e937db621564Steve Block    Returns:
258d0825bca7fe65beaee391d30da42e937db621564Steve Block      A pair of strings (prefix before first unmatched ')',
25906ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen      remainder of s after first unmatched ')'), e.g.,
260d0825bca7fe65beaee391d30da42e937db621564Steve Block      up_to_unmatched_closing_paren("a == (b + c)) { ")
261d0825bca7fe65beaee391d30da42e937db621564Steve Block      returns "a == (b + c)", " {".
262d0825bca7fe65beaee391d30da42e937db621564Steve Block      Returns None, None if there is no unmatched ')'
263d0825bca7fe65beaee391d30da42e937db621564Steve Block
264d0825bca7fe65beaee391d30da42e937db621564Steve Block    """
265d0825bca7fe65beaee391d30da42e937db621564Steve Block    i = 1
266d0825bca7fe65beaee391d30da42e937db621564Steve Block    for pos, c in enumerate(s):
267d0825bca7fe65beaee391d30da42e937db621564Steve Block      if c == '(':
268d0825bca7fe65beaee391d30da42e937db621564Steve Block        i += 1
269d0825bca7fe65beaee391d30da42e937db621564Steve Block      elif c == ')':
270d0825bca7fe65beaee391d30da42e937db621564Steve Block        i -= 1
271d0825bca7fe65beaee391d30da42e937db621564Steve Block        if i == 0:
272d0825bca7fe65beaee391d30da42e937db621564Steve Block          return s[:pos], s[pos + 1:]
273d0825bca7fe65beaee391d30da42e937db621564Steve Block    return None, None
274d0825bca7fe65beaee391d30da42e937db621564Steve Block
2750bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdochclass _IncludeState(dict):
2760bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """Tracks line numbers for includes, and the order in which includes appear.
2770bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
2780bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    As a dict, an _IncludeState object serves as a mapping between include
2790bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    filename and line number on which that file was included.
2800bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
2810bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    Call check_next_include_order() once for each header in the file, passing
2820bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    in the type constants defined above. Calls in an illegal order will
2830bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    raise an _IncludeError with an appropriate error message.
2840bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
2850bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """
2860bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # self._section will move monotonically through this set. If it ever
2870bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # needs to move backwards, check_next_include_order will raise an error.
2880bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    _INITIAL_SECTION = 0
2890bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    _CONFIG_SECTION = 1
2900bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    _PRIMARY_SECTION = 2
2910bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    _OTHER_SECTION = 3
2920bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
2930bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    _TYPE_NAMES = {
2940bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        _CONFIG_HEADER: 'WebCore config.h',
2950bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        _PRIMARY_HEADER: 'header this file implements',
2960bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        _OTHER_HEADER: 'other header',
297d0825bca7fe65beaee391d30da42e937db621564Steve Block        _MOC_HEADER: 'moc file',
2980bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        }
2990bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    _SECTION_NAMES = {
3000bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        _INITIAL_SECTION: "... nothing.",
3010bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        _CONFIG_SECTION: "WebCore config.h.",
3020bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        _PRIMARY_SECTION: 'a header this file implements.',
3030bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        _OTHER_SECTION: 'other header.',
3040bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        }
3050bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
3060bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    def __init__(self):
3070bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        dict.__init__(self)
3080bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        self._section = self._INITIAL_SECTION
3090bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        self._visited_primary_section = False
3100bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        self.header_types = dict();
3110bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
3120bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    def visited_primary_section(self):
3130bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        return self._visited_primary_section
3140bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
3152daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    def check_next_include_order(self, header_type, file_is_header, primary_header_exists):
3160bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        """Returns a non-empty error message if the next header is out of order.
3170bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
3180bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        This function also updates the internal state to be ready to check
3190bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        the next include.
3200bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
3210bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        Args:
3220bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch          header_type: One of the _XXX_HEADER constants defined above.
3230bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch          file_is_header: Whether the file that owns this _IncludeState is itself a header
3240bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
3250bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        Returns:
3260bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch          The empty string if the header is in the right order, or an
3270bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch          error message describing what's wrong.
3280bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
3290bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        """
3300bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        if header_type == _CONFIG_HEADER and file_is_header:
3310bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            return 'Header file should not contain WebCore config.h.'
3320bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        if header_type == _PRIMARY_HEADER and file_is_header:
3330bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            return 'Header file should not contain itself.'
334d0825bca7fe65beaee391d30da42e937db621564Steve Block        if header_type == _MOC_HEADER:
335d0825bca7fe65beaee391d30da42e937db621564Steve Block            return ''
3360bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
3370bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        error_message = ''
3380bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        if self._section != self._OTHER_SECTION:
3390bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            before_error_message = ('Found %s before %s' %
3400bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                                    (self._TYPE_NAMES[header_type],
3410bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                                     self._SECTION_NAMES[self._section + 1]))
3420bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        after_error_message = ('Found %s after %s' %
3430bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                                (self._TYPE_NAMES[header_type],
3440bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                                 self._SECTION_NAMES[self._section]))
3450bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
3460bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        if header_type == _CONFIG_HEADER:
3470bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            if self._section >= self._CONFIG_SECTION:
3480bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                error_message = after_error_message
3490bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            self._section = self._CONFIG_SECTION
3500bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        elif header_type == _PRIMARY_HEADER:
3510bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            if self._section >= self._PRIMARY_SECTION:
3520bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                error_message = after_error_message
3530bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            elif self._section < self._CONFIG_SECTION:
3540bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                error_message = before_error_message
3550bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            self._section = self._PRIMARY_SECTION
3560bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            self._visited_primary_section = True
3570bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        else:
3580bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            assert header_type == _OTHER_HEADER
3590bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            if not file_is_header and self._section < self._PRIMARY_SECTION:
3602daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch                if primary_header_exists:
3612daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch                    error_message = before_error_message
3620bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            self._section = self._OTHER_SECTION
3630bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
3640bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        return error_message
3650bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
3660bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
367cad810f21b803229eb11403f9209855525a25d57Steve Blockclass Position(object):
368cad810f21b803229eb11403f9209855525a25d57Steve Block    """Holds the position of something."""
369cad810f21b803229eb11403f9209855525a25d57Steve Block    def __init__(self, row, column):
370cad810f21b803229eb11403f9209855525a25d57Steve Block        self.row = row
371cad810f21b803229eb11403f9209855525a25d57Steve Block        self.column = column
372cad810f21b803229eb11403f9209855525a25d57Steve Block
37365f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch    def __str__(self):
37465f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch        return '(%s, %s)' % (self.row, self.column)
37565f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch
37665f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch    def __cmp__(self, other):
37765f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch        return self.row.__cmp__(other.row) or self.column.__cmp__(other.column)
37865f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch
379cad810f21b803229eb11403f9209855525a25d57Steve Block
380cad810f21b803229eb11403f9209855525a25d57Steve Blockclass Parameter(object):
381cad810f21b803229eb11403f9209855525a25d57Steve Block    """Information about one function parameter."""
382cad810f21b803229eb11403f9209855525a25d57Steve Block    def __init__(self, parameter, parameter_name_index, row):
383cad810f21b803229eb11403f9209855525a25d57Steve Block        self.type = parameter[:parameter_name_index].strip()
384cad810f21b803229eb11403f9209855525a25d57Steve Block        # Remove any initializers from the parameter name (e.g. int i = 5).
385cad810f21b803229eb11403f9209855525a25d57Steve Block        self.name = sub(r'=.*', '', parameter[parameter_name_index:]).strip()
386cad810f21b803229eb11403f9209855525a25d57Steve Block        self.row = row
387cad810f21b803229eb11403f9209855525a25d57Steve Block
388cad810f21b803229eb11403f9209855525a25d57Steve Block    @memoized
389cad810f21b803229eb11403f9209855525a25d57Steve Block    def lower_with_underscores_name(self):
390cad810f21b803229eb11403f9209855525a25d57Steve Block        """Returns the parameter name in the lower with underscores format."""
391cad810f21b803229eb11403f9209855525a25d57Steve Block        return _convert_to_lower_with_underscores(self.name)
392cad810f21b803229eb11403f9209855525a25d57Steve Block
393cad810f21b803229eb11403f9209855525a25d57Steve Block
394cad810f21b803229eb11403f9209855525a25d57Steve Blockclass SingleLineView(object):
395cad810f21b803229eb11403f9209855525a25d57Steve Block    """Converts multiple lines into a single line (with line breaks replaced by a
396cad810f21b803229eb11403f9209855525a25d57Steve Block       space) to allow for easier searching."""
397cad810f21b803229eb11403f9209855525a25d57Steve Block    def __init__(self, lines, start_position, end_position):
398cad810f21b803229eb11403f9209855525a25d57Steve Block        """Create a SingleLineView instance.
399cad810f21b803229eb11403f9209855525a25d57Steve Block
400cad810f21b803229eb11403f9209855525a25d57Steve Block        Args:
401cad810f21b803229eb11403f9209855525a25d57Steve Block          lines: a list of multiple lines to combine into a single line.
402cad810f21b803229eb11403f9209855525a25d57Steve Block          start_position: offset within lines of where to start the single line.
403cad810f21b803229eb11403f9209855525a25d57Steve Block          end_position: just after where to end (like a slice operation).
404cad810f21b803229eb11403f9209855525a25d57Steve Block        """
405cad810f21b803229eb11403f9209855525a25d57Steve Block        # Get the rows of interest.
406cad810f21b803229eb11403f9209855525a25d57Steve Block        trimmed_lines = lines[start_position.row:end_position.row + 1]
407cad810f21b803229eb11403f9209855525a25d57Steve Block
408cad810f21b803229eb11403f9209855525a25d57Steve Block        # Remove the columns on the last line that aren't included.
409cad810f21b803229eb11403f9209855525a25d57Steve Block        trimmed_lines[-1] = trimmed_lines[-1][:end_position.column]
410cad810f21b803229eb11403f9209855525a25d57Steve Block
411cad810f21b803229eb11403f9209855525a25d57Steve Block        # Remove the columns on the first line that aren't included.
412cad810f21b803229eb11403f9209855525a25d57Steve Block        trimmed_lines[0] = trimmed_lines[0][start_position.column:]
413cad810f21b803229eb11403f9209855525a25d57Steve Block
414cad810f21b803229eb11403f9209855525a25d57Steve Block        # Create a single line with all of the parameters.
415cad810f21b803229eb11403f9209855525a25d57Steve Block        self.single_line = ' '.join(trimmed_lines)
416cad810f21b803229eb11403f9209855525a25d57Steve Block
417cad810f21b803229eb11403f9209855525a25d57Steve Block        # Keep the row lengths, so we can calculate the original row number
418cad810f21b803229eb11403f9209855525a25d57Steve Block        # given a column in the single line (adding 1 due to the space added
419cad810f21b803229eb11403f9209855525a25d57Steve Block        # during the join).
420cad810f21b803229eb11403f9209855525a25d57Steve Block        self._row_lengths = [len(line) + 1 for line in trimmed_lines]
421cad810f21b803229eb11403f9209855525a25d57Steve Block        self._starting_row = start_position.row
422cad810f21b803229eb11403f9209855525a25d57Steve Block
423cad810f21b803229eb11403f9209855525a25d57Steve Block    def convert_column_to_row(self, single_line_column_number):
424cad810f21b803229eb11403f9209855525a25d57Steve Block        """Convert the column number from the single line into the original
425cad810f21b803229eb11403f9209855525a25d57Steve Block        line number.
426cad810f21b803229eb11403f9209855525a25d57Steve Block
427cad810f21b803229eb11403f9209855525a25d57Steve Block        Special cases:
428cad810f21b803229eb11403f9209855525a25d57Steve Block        * Columns in the added spaces are considered part of the previous line.
429cad810f21b803229eb11403f9209855525a25d57Steve Block        * Columns beyond the end of the line are consider part the last line
430cad810f21b803229eb11403f9209855525a25d57Steve Block        in the view."""
431cad810f21b803229eb11403f9209855525a25d57Steve Block        total_columns = 0
432cad810f21b803229eb11403f9209855525a25d57Steve Block        row_offset = 0
433cad810f21b803229eb11403f9209855525a25d57Steve Block        while row_offset < len(self._row_lengths) - 1 and single_line_column_number >= total_columns + self._row_lengths[row_offset]:
434cad810f21b803229eb11403f9209855525a25d57Steve Block            total_columns += self._row_lengths[row_offset]
435cad810f21b803229eb11403f9209855525a25d57Steve Block            row_offset += 1
436cad810f21b803229eb11403f9209855525a25d57Steve Block        return self._starting_row + row_offset
437cad810f21b803229eb11403f9209855525a25d57Steve Block
438cad810f21b803229eb11403f9209855525a25d57Steve Block
439cad810f21b803229eb11403f9209855525a25d57Steve Blockdef create_skeleton_parameters(all_parameters):
440cad810f21b803229eb11403f9209855525a25d57Steve Block    """Converts a parameter list to a skeleton version.
441cad810f21b803229eb11403f9209855525a25d57Steve Block
442cad810f21b803229eb11403f9209855525a25d57Steve Block    The skeleton only has one word for the parameter name, one word for the type,
443cad810f21b803229eb11403f9209855525a25d57Steve Block    and commas after each parameter and only there. Everything in the skeleton
444cad810f21b803229eb11403f9209855525a25d57Steve Block    remains in the same columns as the original."""
445cad810f21b803229eb11403f9209855525a25d57Steve Block    all_simplifications = (
446cad810f21b803229eb11403f9209855525a25d57Steve Block        # Remove template parameters, function declaration parameters, etc.
447cad810f21b803229eb11403f9209855525a25d57Steve Block        r'(<[^<>]*?>)|(\([^\(\)]*?\))|(\{[^\{\}]*?\})',
448cad810f21b803229eb11403f9209855525a25d57Steve Block        # Remove all initializers.
449cad810f21b803229eb11403f9209855525a25d57Steve Block        r'=[^,]*',
450cad810f21b803229eb11403f9209855525a25d57Steve Block        # Remove :: and everything before it.
451cad810f21b803229eb11403f9209855525a25d57Steve Block        r'[^,]*::',
452cad810f21b803229eb11403f9209855525a25d57Steve Block        # Remove modifiers like &, *.
453cad810f21b803229eb11403f9209855525a25d57Steve Block        r'[&*]',
454cad810f21b803229eb11403f9209855525a25d57Steve Block        # Remove const modifiers.
455cad810f21b803229eb11403f9209855525a25d57Steve Block        r'\bconst\s+(?=[A-Za-z])',
456cad810f21b803229eb11403f9209855525a25d57Steve Block        # Remove numerical modifiers like long.
457cad810f21b803229eb11403f9209855525a25d57Steve Block        r'\b(unsigned|long|short)\s+(?=unsigned|long|short|int|char|double|float)')
458cad810f21b803229eb11403f9209855525a25d57Steve Block
459cad810f21b803229eb11403f9209855525a25d57Steve Block    skeleton_parameters = all_parameters
460cad810f21b803229eb11403f9209855525a25d57Steve Block    for simplification in all_simplifications:
461cad810f21b803229eb11403f9209855525a25d57Steve Block        skeleton_parameters = iteratively_replace_matches_with_char(simplification, ' ', skeleton_parameters)
462cad810f21b803229eb11403f9209855525a25d57Steve Block    # If there are any parameters, then add a , after the last one to
463cad810f21b803229eb11403f9209855525a25d57Steve Block    # make a regular pattern of a , following every parameter.
464cad810f21b803229eb11403f9209855525a25d57Steve Block    if skeleton_parameters.strip():
465cad810f21b803229eb11403f9209855525a25d57Steve Block        skeleton_parameters += ','
466cad810f21b803229eb11403f9209855525a25d57Steve Block    return skeleton_parameters
467cad810f21b803229eb11403f9209855525a25d57Steve Block
468cad810f21b803229eb11403f9209855525a25d57Steve Block
469cad810f21b803229eb11403f9209855525a25d57Steve Blockdef find_parameter_name_index(skeleton_parameter):
470cad810f21b803229eb11403f9209855525a25d57Steve Block    """Determines where the parametere name starts given the skeleton parameter."""
471cad810f21b803229eb11403f9209855525a25d57Steve Block    # The first space from the right in the simplified parameter is where the parameter
472cad810f21b803229eb11403f9209855525a25d57Steve Block    # name starts unless the first space is before any content in the simplified parameter.
473cad810f21b803229eb11403f9209855525a25d57Steve Block    before_name_index = skeleton_parameter.rstrip().rfind(' ')
474cad810f21b803229eb11403f9209855525a25d57Steve Block    if before_name_index != -1 and skeleton_parameter[:before_name_index].strip():
475cad810f21b803229eb11403f9209855525a25d57Steve Block        return before_name_index + 1
476cad810f21b803229eb11403f9209855525a25d57Steve Block    return len(skeleton_parameter)
477cad810f21b803229eb11403f9209855525a25d57Steve Block
478cad810f21b803229eb11403f9209855525a25d57Steve Block
479cad810f21b803229eb11403f9209855525a25d57Steve Blockdef parameter_list(elided_lines, start_position, end_position):
480cad810f21b803229eb11403f9209855525a25d57Steve Block    """Generator for a function's parameters."""
481cad810f21b803229eb11403f9209855525a25d57Steve Block    # Create new positions that omit the outer parenthesis of the parameters.
482cad810f21b803229eb11403f9209855525a25d57Steve Block    start_position = Position(row=start_position.row, column=start_position.column + 1)
483cad810f21b803229eb11403f9209855525a25d57Steve Block    end_position = Position(row=end_position.row, column=end_position.column - 1)
484cad810f21b803229eb11403f9209855525a25d57Steve Block    single_line_view = SingleLineView(elided_lines, start_position, end_position)
485cad810f21b803229eb11403f9209855525a25d57Steve Block    skeleton_parameters = create_skeleton_parameters(single_line_view.single_line)
486cad810f21b803229eb11403f9209855525a25d57Steve Block    end_index = -1
487cad810f21b803229eb11403f9209855525a25d57Steve Block
488cad810f21b803229eb11403f9209855525a25d57Steve Block    while True:
489cad810f21b803229eb11403f9209855525a25d57Steve Block        # Find the end of the next parameter.
490cad810f21b803229eb11403f9209855525a25d57Steve Block        start_index = end_index + 1
491cad810f21b803229eb11403f9209855525a25d57Steve Block        end_index = skeleton_parameters.find(',', start_index)
492cad810f21b803229eb11403f9209855525a25d57Steve Block
493cad810f21b803229eb11403f9209855525a25d57Steve Block        # No comma means that all parameters have been parsed.
494cad810f21b803229eb11403f9209855525a25d57Steve Block        if end_index == -1:
495cad810f21b803229eb11403f9209855525a25d57Steve Block            return
496cad810f21b803229eb11403f9209855525a25d57Steve Block        row = single_line_view.convert_column_to_row(end_index)
497cad810f21b803229eb11403f9209855525a25d57Steve Block
498cad810f21b803229eb11403f9209855525a25d57Steve Block        # Parse the parameter into a type and parameter name.
499cad810f21b803229eb11403f9209855525a25d57Steve Block        skeleton_parameter = skeleton_parameters[start_index:end_index]
500cad810f21b803229eb11403f9209855525a25d57Steve Block        name_offset = find_parameter_name_index(skeleton_parameter)
501cad810f21b803229eb11403f9209855525a25d57Steve Block        parameter = single_line_view.single_line[start_index:end_index]
502cad810f21b803229eb11403f9209855525a25d57Steve Block        yield Parameter(parameter, name_offset, row)
503cad810f21b803229eb11403f9209855525a25d57Steve Block
504cad810f21b803229eb11403f9209855525a25d57Steve Block
505d0825bca7fe65beaee391d30da42e937db621564Steve Blockclass _FunctionState(object):
506d0825bca7fe65beaee391d30da42e937db621564Steve Block    """Tracks current function name and the number of lines in its body.
5070bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
508d0825bca7fe65beaee391d30da42e937db621564Steve Block    Attributes:
509dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block      min_confidence: The minimum confidence level to use while checking style.
5100bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
5110bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """
5120bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
5130bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    _NORMAL_TRIGGER = 250  # for --v=0, 500 for --v=1, etc.
5140bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    _TEST_TRIGGER = 400    # about 50% more than _NORMAL_TRIGGER.
5150bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
516dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    def __init__(self, min_confidence):
517dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        self.min_confidence = min_confidence
518dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        self.current_function = ''
5190bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        self.in_a_function = False
5200bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        self.lines_in_function = 0
52165f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch        # Make sure these will not be mistaken for real positions (even when a
5226b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner        # small amount is added to them).
52365f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch        self.body_start_position = Position(-1000, 0)
52465f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch        self.end_position = Position(-1000, 0)
5250bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
52665f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch    def begin(self, function_name, function_name_start_position, body_start_position, end_position,
527cad810f21b803229eb11403f9209855525a25d57Steve Block              parameter_start_position, parameter_end_position, clean_lines):
5280bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        """Start analyzing function body.
5290bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
5300bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        Args:
5310bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            function_name: The name of the function being tracked.
53265f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch            function_name_start_position: Position in elided where the function name starts.
53365f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch            body_start_position: Position in elided of the { or the ; for a prototype.
53465f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch            end_position: Position in elided just after the final } (or ; is.
53565f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch            parameter_start_position: Position in elided of the '(' for the parameters.
53665f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch            parameter_end_position: Position in elided just after the ')' for the parameters.
537cad810f21b803229eb11403f9209855525a25d57Steve Block            clean_lines: A CleansedLines instance containing the file.
5380bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        """
5390bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        self.in_a_function = True
540f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch        self.lines_in_function = -1  # Don't count the open brace line.
5410bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        self.current_function = function_name
54265f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch        self.function_name_start_position = function_name_start_position
54365f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch        self.body_start_position = body_start_position
54465f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch        self.end_position = end_position
54565f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch        self.is_declaration = clean_lines.elided[body_start_position.row][body_start_position.column] == ';'
546cad810f21b803229eb11403f9209855525a25d57Steve Block        self.parameter_start_position = parameter_start_position
547cad810f21b803229eb11403f9209855525a25d57Steve Block        self.parameter_end_position = parameter_end_position
54865f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch        self.is_pure = False
54965f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch        if self.is_declaration:
55065f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch            characters_after_parameters = SingleLineView(clean_lines.elided, parameter_end_position, body_start_position).single_line
55165f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch            self.is_pure = bool(match(r'\s*=\s*0\s*', characters_after_parameters))
552cad810f21b803229eb11403f9209855525a25d57Steve Block        self._clean_lines = clean_lines
553cad810f21b803229eb11403f9209855525a25d57Steve Block        self._parameter_list = None
554cad810f21b803229eb11403f9209855525a25d57Steve Block
5552fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    def modifiers_and_return_type(self):
5562fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        """Returns the modifiers and the return type."""
5572fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        # Go backwards from where the function name is until we encounter one of several things:
5582fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        #   ';' or '{' or '}' or 'private:', etc. or '#' or return Position(0, 0)
5592fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        elided = self._clean_lines.elided
5602fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        start_modifiers = _rfind_in_lines(r';|\{|\}|((private|public|protected):)|(#.*)',
5612fc2651226baac27029e38c9d6ef883fa32084dbSteve Block                                          elided, self.parameter_start_position, Position(0, 0))
5622fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        return SingleLineView(elided, start_modifiers, self.function_name_start_position).single_line.strip()
5632fc2651226baac27029e38c9d6ef883fa32084dbSteve Block
564cad810f21b803229eb11403f9209855525a25d57Steve Block    def parameter_list(self):
565cad810f21b803229eb11403f9209855525a25d57Steve Block        if not self._parameter_list:
566cad810f21b803229eb11403f9209855525a25d57Steve Block            # Store the final result as a tuple since that is immutable.
567cad810f21b803229eb11403f9209855525a25d57Steve Block            self._parameter_list = tuple(parameter_list(self._clean_lines.elided, self.parameter_start_position, self.parameter_end_position))
568cad810f21b803229eb11403f9209855525a25d57Steve Block
569cad810f21b803229eb11403f9209855525a25d57Steve Block        return self._parameter_list
5700bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
5716b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner    def count(self, line_number):
5720bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        """Count line in current function body."""
57365f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch        if self.in_a_function and line_number >= self.body_start_position.row:
5740bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            self.lines_in_function += 1
5750bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
576d0825bca7fe65beaee391d30da42e937db621564Steve Block    def check(self, error, line_number):
5770bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        """Report if too many lines in function body.
5780bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
5790bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        Args:
5800bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch          error: The function to call with any errors found.
5810bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch          line_number: The number of the line to check.
5820bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        """
5830bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        if match(r'T(EST|est)', self.current_function):
5840bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            base_trigger = self._TEST_TRIGGER
5850bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        else:
5860bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            base_trigger = self._NORMAL_TRIGGER
587dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        trigger = base_trigger * 2 ** self.min_confidence
5880bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
5890bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        if self.lines_in_function > trigger:
5900bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            error_level = int(math.log(self.lines_in_function / base_trigger, 2))
5910bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            # 50 => 0, 100 => 1, 200 => 2, 400 => 3, 800 => 4, 1600 => 5, ...
5920bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            if error_level > 5:
5930bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                error_level = 5
594d0825bca7fe65beaee391d30da42e937db621564Steve Block            error(line_number, 'readability/fn_size', error_level,
5950bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                  'Small and focused functions are preferred:'
5960bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                  ' %s has %d non-comment lines'
5970bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                  ' (error triggered by exceeding %d lines).'  % (
5980bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                      self.current_function, self.lines_in_function, trigger))
5990bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
6000bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    def end(self):
6016b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner        """Stop analyzing function body."""
6020bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        self.in_a_function = False
6030bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
6040bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
6050bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdochclass _IncludeError(Exception):
6060bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """Indicates a problem with the include order in a file."""
6070bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    pass
6080bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
6090bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
6100bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdochclass FileInfo:
6110bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """Provides utility functions for filenames.
6120bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
6130bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    FileInfo provides easy access to the components of a file's path
6140bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    relative to the project root.
6150bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """
6160bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
6170bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    def __init__(self, filename):
6180bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        self._filename = filename
6190bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
6200bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    def full_name(self):
6210bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        """Make Windows paths like Unix."""
6220bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        return os.path.abspath(self._filename).replace('\\', '/')
6230bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
6240bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    def repository_name(self):
6250bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        """Full name after removing the local path to the repository.
6260bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
6270bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        If we have a real absolute path name here we can try to do something smart:
6280bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        detecting the root of the checkout and truncating /path/to/checkout from
6290bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        the name so that we get header guards that don't include things like
6300bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        "C:\Documents and Settings\..." or "/home/username/..." in them and thus
6310bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        people on different computers who have checked the source out to different
6320bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        locations won't see bogus errors.
6330bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        """
6340bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        fullname = self.full_name()
6350bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
6360bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        if os.path.exists(fullname):
6370bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            project_dir = os.path.dirname(fullname)
6380bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
6390bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            if os.path.exists(os.path.join(project_dir, ".svn")):
6400bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                # If there's a .svn file in the current directory, we
6410bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                # recursively look up the directory tree for the top
6420bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                # of the SVN checkout
6430bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                root_dir = project_dir
6440bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                one_up_dir = os.path.dirname(root_dir)
6450bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                while os.path.exists(os.path.join(one_up_dir, ".svn")):
6460bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                    root_dir = os.path.dirname(root_dir)
6470bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                    one_up_dir = os.path.dirname(one_up_dir)
6480bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
6490bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                prefix = os.path.commonprefix([root_dir, project_dir])
6500bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                return fullname[len(prefix) + 1:]
6510bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
6520bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            # Not SVN? Try to find a git top level directory by
6530bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            # searching up from the current path.
6540bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            root_dir = os.path.dirname(fullname)
6550bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            while (root_dir != os.path.dirname(root_dir)
6560bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                   and not os.path.exists(os.path.join(root_dir, ".git"))):
6570bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                root_dir = os.path.dirname(root_dir)
6580bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                if os.path.exists(os.path.join(root_dir, ".git")):
6590bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                    prefix = os.path.commonprefix([root_dir, project_dir])
6600bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                    return fullname[len(prefix) + 1:]
6610bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
6620bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # Don't know what to do; header guard warnings may be wrong...
6630bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        return fullname
6640bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
6650bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    def split(self):
6660bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        """Splits the file into the directory, basename, and extension.
6670bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
6680bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        For 'chrome/browser/browser.cpp', Split() would
6690bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        return ('chrome/browser', 'browser', '.cpp')
6700bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
6710bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        Returns:
6720bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch          A tuple of (directory, basename, extension).
6730bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        """
6740bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
6750bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        googlename = self.repository_name()
6760bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        project, rest = os.path.split(googlename)
6770bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        return (project,) + os.path.splitext(rest)
6780bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
6790bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    def base_name(self):
6800bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        """File base name - text after the final slash, before the final period."""
6810bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        return self.split()[1]
6820bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
6830bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    def extension(self):
6840bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        """File extension - text following the final period."""
6850bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        return self.split()[2]
6860bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
6870bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    def no_extension(self):
6880bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        """File has no source file extension."""
6890bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        return '/'.join(self.split()[0:2])
6900bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
6910bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    def is_source(self):
6920bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        """File has a source file extension."""
6930bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        return self.extension()[1:] in ('c', 'cc', 'cpp', 'cxx')
6940bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
6950bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
6960bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch# Matches standard C++ escape esequences per 2.13.2.3 of the C++ standard.
6970bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch_RE_PATTERN_CLEANSE_LINE_ESCAPES = re.compile(
6980bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    r'\\([abfnrtv?"\\\']|\d+|x[0-9a-fA-F]+)')
6990bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch# Matches strings.  Escape codes should already be removed by ESCAPES.
7000bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch_RE_PATTERN_CLEANSE_LINE_DOUBLE_QUOTES = re.compile(r'"[^"]*"')
7010bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch# Matches characters.  Escape codes should already be removed by ESCAPES.
7020bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch_RE_PATTERN_CLEANSE_LINE_SINGLE_QUOTES = re.compile(r"'.'")
7030bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch# Matches multi-line C++ comments.
7040bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch# This RE is a little bit more complicated than one might expect, because we
7050bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch# have to take care of space removals tools so we can handle comments inside
7060bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch# statements better.
7070bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch# The current rule is: We only clear spaces from both sides when we're at the
7080bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch# end of the line. Otherwise, we try to remove spaces from the right side,
7090bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch# if this doesn't work we try on left side but only if there's a non-character
7100bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch# on the right.
7110bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch_RE_PATTERN_CLEANSE_LINE_C_COMMENTS = re.compile(
7120bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    r"""(\s*/\*.*\*/\s*$|
7130bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            /\*.*\*/\s+|
7140bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch         \s+/\*.*\*/(?=\W)|
7150bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            /\*.*\*/)""", re.VERBOSE)
7160bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
7170bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
7180bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdochdef is_cpp_string(line):
7190bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """Does line terminate so, that the next symbol is in string constant.
7200bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
7210bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    This function does not consider single-line nor multi-line comments.
7220bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
7230bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    Args:
7240bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      line: is a partial line of code starting from the 0..n.
7250bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
7260bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    Returns:
7270bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      True, if next character appended to 'line' is inside a
7280bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      string constant.
7290bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """
7300bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
7310bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    line = line.replace(r'\\', 'XX')  # after this, \\" does not match to \"
7320bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    return ((line.count('"') - line.count(r'\"') - line.count("'\"'")) & 1) == 1
7330bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
7340bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
7350bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdochdef find_next_multi_line_comment_start(lines, line_index):
7360bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """Find the beginning marker for a multiline comment."""
7370bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    while line_index < len(lines):
7380bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        if lines[line_index].strip().startswith('/*'):
7390bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            # Only return this marker if the comment goes beyond this line
7400bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            if lines[line_index].strip().find('*/', 2) < 0:
7410bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                return line_index
7420bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        line_index += 1
7430bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    return len(lines)
7440bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
7450bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
7460bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdochdef find_next_multi_line_comment_end(lines, line_index):
7470bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """We are inside a comment, find the end marker."""
7480bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    while line_index < len(lines):
7490bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        if lines[line_index].strip().endswith('*/'):
7500bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            return line_index
7510bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        line_index += 1
7520bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    return len(lines)
7530bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
7540bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
7550bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdochdef remove_multi_line_comments_from_range(lines, begin, end):
7560bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """Clears a range of lines for multi-line comments."""
7570bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # Having // dummy comments makes the lines non-empty, so we will not get
7580bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # unnecessary blank line warnings later in the code.
7590bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    for i in range(begin, end):
7600bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        lines[i] = '// dummy'
7610bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
7620bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
763d0825bca7fe65beaee391d30da42e937db621564Steve Blockdef remove_multi_line_comments(lines, error):
7640bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """Removes multiline (c-style) comments from lines."""
7650bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    line_index = 0
7660bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    while line_index < len(lines):
7670bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        line_index_begin = find_next_multi_line_comment_start(lines, line_index)
7680bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        if line_index_begin >= len(lines):
7690bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            return
7700bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        line_index_end = find_next_multi_line_comment_end(lines, line_index_begin)
7710bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        if line_index_end >= len(lines):
772d0825bca7fe65beaee391d30da42e937db621564Steve Block            error(line_index_begin + 1, 'readability/multiline_comment', 5,
7730bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                  'Could not find end of multi-line comment')
7740bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            return
7750bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        remove_multi_line_comments_from_range(lines, line_index_begin, line_index_end + 1)
7760bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        line_index = line_index_end + 1
7770bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
7780bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
7790bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdochdef cleanse_comments(line):
7800bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """Removes //-comments and single-line C-style /* */ comments.
7810bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
7820bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    Args:
7830bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      line: A line of C++ source.
7840bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
7850bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    Returns:
7860bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      The line with single-line comments removed.
7870bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """
7880bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    comment_position = line.find('//')
7890bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if comment_position != -1 and not is_cpp_string(line[:comment_position]):
7900bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        line = line[:comment_position]
7910bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # get rid of /* ... */
7920bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    return _RE_PATTERN_CLEANSE_LINE_C_COMMENTS.sub('', line)
7930bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
7940bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
7950bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdochclass CleansedLines(object):
7960bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """Holds 3 copies of all lines with different preprocessing applied to them.
7970bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
7980bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    1) elided member contains lines without strings and comments,
7990bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    2) lines member contains lines without comments, and
8000bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    3) raw member contains all the lines without processing.
8010bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    All these three members are of <type 'list'>, and of the same length.
8020bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """
8030bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
8040bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    def __init__(self, lines):
8050bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        self.elided = []
8060bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        self.lines = []
8070bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        self.raw_lines = lines
8080bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        self._num_lines = len(lines)
8090bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        for line_number in range(len(lines)):
8100bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            self.lines.append(cleanse_comments(lines[line_number]))
8110bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            elided = self.collapse_strings(lines[line_number])
8120bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            self.elided.append(cleanse_comments(elided))
8130bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
8140bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    def num_lines(self):
8150bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        """Returns the number of lines represented."""
8160bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        return self._num_lines
8170bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
8180bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    @staticmethod
8190bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    def collapse_strings(elided):
8200bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        """Collapses strings and chars on a line to simple "" or '' blocks.
8210bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
8220bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        We nix strings first so we're not fooled by text like '"http://"'
8230bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
8240bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        Args:
8250bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch          elided: The line being processed.
8260bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
8270bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        Returns:
8280bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch          The line with collapsed strings.
8290bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        """
8300bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        if not _RE_PATTERN_INCLUDE.match(elided):
8310bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            # Remove escaped characters first to make quote/single quote collapsing
8320bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            # basic.  Things that look like escaped characters shouldn't occur
8330bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            # outside of strings and chars.
8340bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            elided = _RE_PATTERN_CLEANSE_LINE_ESCAPES.sub('', elided)
8350bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            elided = _RE_PATTERN_CLEANSE_LINE_SINGLE_QUOTES.sub("''", elided)
8360bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            elided = _RE_PATTERN_CLEANSE_LINE_DOUBLE_QUOTES.sub('""', elided)
8370bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        return elided
8380bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
8390bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
84065f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdochdef close_expression(elided, position):
8410bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """If input points to ( or { or [, finds the position that closes it.
8420bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
84365f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch    If elided[position.row][position.column] points to a '(' or '{' or '[',
84465f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch    finds the line_number/pos that correspond to the closing of the expression.
8450bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
84665f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch     Args:
84765f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch       elided: A CleansedLines.elided instance containing the file.
84865f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch       position: The position of the opening item.
8490bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
85065f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch     Returns:
85165f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch      The Position *past* the closing brace, or Position(len(elided), -1)
85265f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch      if we never find a close. Note we ignore strings and comments when matching.
8530bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """
85465f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch    line = elided[position.row]
85565f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch    start_character = line[position.column]
8560bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if start_character == '(':
85765f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch        enclosing_character_regex = r'[\(\)]'
85865f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch    elif start_character == '[':
85965f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch        enclosing_character_regex = r'[\[\]]'
86065f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch    elif start_character == '{':
86165f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch        enclosing_character_regex = r'[\{\}]'
86265f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch    else:
86365f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch        return Position(len(elided), -1)
86465f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch
86565f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch    current_column = position.column + 1
86665f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch    line_number = position.row
86765f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch    net_open = 1
86865f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch    for line in elided[position.row:]:
86965f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch        line = line[current_column:]
87065f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch
87165f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch        # Search the current line for opening and closing characters.
87265f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch        while True:
87365f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch            next_enclosing_character = search(enclosing_character_regex, line)
87465f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch            # No more on this line.
87565f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch            if not next_enclosing_character:
87665f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch                break
87765f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch            current_column += next_enclosing_character.end(0)
87865f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch            line = line[next_enclosing_character.end(0):]
87965f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch            if next_enclosing_character.group(0) == start_character:
88065f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch                net_open += 1
88165f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch            else:
88265f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch                net_open -= 1
88365f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch                if not net_open:
88465f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch                    return Position(line_number, current_column)
88565f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch
88665f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch        # Proceed to the next line.
8870bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        line_number += 1
88865f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch        current_column = 0
8890bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
89065f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch    # The given item was not closed.
89165f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch    return Position(len(elided), -1)
8920bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
893d0825bca7fe65beaee391d30da42e937db621564Steve Blockdef check_for_copyright(lines, error):
8940bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """Logs an error if no Copyright message appears at the top of the file."""
8950bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
8960bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # We'll say it should occur by line 10. Don't forget there's a
8970bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # dummy line at the front.
8980bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    for line in xrange(1, min(len(lines), 11)):
8990bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        if re.search(r'Copyright', lines[line], re.I):
9000bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            break
9010bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    else:                       # means no copyright line was found
902d0825bca7fe65beaee391d30da42e937db621564Steve Block        error(0, 'legal/copyright', 5,
9030bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch              'No copyright message found.  '
9040bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch              'You should have a line: "Copyright [year] <Copyright Owner>"')
9050bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
9060bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
9070bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdochdef get_header_guard_cpp_variable(filename):
9080bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """Returns the CPP variable that should be used as a header guard.
9090bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
9100bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    Args:
9110bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      filename: The name of a C++ header file.
9120bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
9130bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    Returns:
9140bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      The CPP variable that should be used as a header guard in the
9150bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      named file.
9160bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
9170bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """
9180bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
919dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    # Restores original filename in case that style checker is invoked from Emacs's
920dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    # flymake.
921dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    filename = re.sub(r'_flymake\.h$', '.h', filename)
922dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
923f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch    standard_name = sub(r'[-.\s]', '_', os.path.basename(filename))
924f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch
925f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch    # Files under WTF typically have header guards that start with WTF_.
926f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch    if filename.find('/wtf/'):
927f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch        special_name = "WTF_" + standard_name
928f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch    else:
929f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch        special_name = standard_name
930f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch    return (special_name, standard_name)
9310bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
9320bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
9330bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdochdef check_for_header_guard(filename, lines, error):
9340bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """Checks that the file contains a header guard.
9350bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
9360bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    Logs an error if no #ifndef header guard is present.  For other
9370bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    headers, checks that the full pathname is used.
9380bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
9390bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    Args:
9400bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      filename: The name of the C++ header file.
9410bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      lines: An array of strings, each representing a line of the file.
9420bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      error: The function to call with any errors found.
9430bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """
9440bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
9450bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    cppvar = get_header_guard_cpp_variable(filename)
9460bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
9470bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    ifndef = None
9480bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    ifndef_line_number = 0
9490bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    define = None
9500bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    for line_number, line in enumerate(lines):
9510bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        line_split = line.split()
9520bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        if len(line_split) >= 2:
9530bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            # find the first occurrence of #ifndef and #define, save arg
9540bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            if not ifndef and line_split[0] == '#ifndef':
9550bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                # set ifndef to the header guard presented on the #ifndef line.
9560bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                ifndef = line_split[1]
9570bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                ifndef_line_number = line_number
9580bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            if not define and line_split[0] == '#define':
9590bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                define = line_split[1]
960d0825bca7fe65beaee391d30da42e937db621564Steve Block            if define and ifndef:
961d0825bca7fe65beaee391d30da42e937db621564Steve Block                break
9620bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
9630bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if not ifndef or not define or ifndef != define:
964d0825bca7fe65beaee391d30da42e937db621564Steve Block        error(0, 'build/header_guard', 5,
9650bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch              'No #ifndef header guard found, suggested CPP variable is: %s' %
966f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch              cppvar[0])
9670bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        return
9680bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
969d0825bca7fe65beaee391d30da42e937db621564Steve Block    # The guard should be File_h.
970f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch    if ifndef not in cppvar:
971d0825bca7fe65beaee391d30da42e937db621564Steve Block        error(ifndef_line_number, 'build/header_guard', 5,
972f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch              '#ifndef header guard has wrong style, please use: %s' % cppvar[0])
9730bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
9740bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
975d0825bca7fe65beaee391d30da42e937db621564Steve Blockdef check_for_unicode_replacement_characters(lines, error):
9760bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """Logs an error for each line containing Unicode replacement characters.
9770bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
9780bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    These indicate that either the file contained invalid UTF-8 (likely)
9790bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    or Unicode replacement characters (which it shouldn't).  Note that
9800bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    it's possible for this to throw off line numbering if the invalid
9810bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    UTF-8 occurred adjacent to a newline.
9820bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
9830bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    Args:
9840bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      lines: An array of strings, each representing a line of the file.
9850bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      error: The function to call with any errors found.
9860bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """
9870bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    for line_number, line in enumerate(lines):
9880bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        if u'\ufffd' in line:
989d0825bca7fe65beaee391d30da42e937db621564Steve Block            error(line_number, 'readability/utf8', 5,
9900bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                  'Line contains invalid UTF-8 (or Unicode replacement character).')
9910bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
9920bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
993d0825bca7fe65beaee391d30da42e937db621564Steve Blockdef check_for_new_line_at_eof(lines, error):
9940bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """Logs an error if there is no newline char at the end of the file.
9950bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
9960bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    Args:
9970bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      lines: An array of strings, each representing a line of the file.
9980bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      error: The function to call with any errors found.
9990bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """
10000bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
10010bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # The array lines() was created by adding two newlines to the
10020bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # original file (go figure), then splitting on \n.
10030bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # To verify that the file ends in \n, we just have to make sure the
10040bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # last-but-two element of lines() exists and is empty.
10050bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if len(lines) < 3 or lines[-2]:
1006d0825bca7fe65beaee391d30da42e937db621564Steve Block        error(len(lines) - 2, 'whitespace/ending_newline', 5,
10070bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch              'Could not find a newline character at the end of the file.')
10080bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
10090bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
1010d0825bca7fe65beaee391d30da42e937db621564Steve Blockdef check_for_multiline_comments_and_strings(clean_lines, line_number, error):
10110bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """Logs an error if we see /* ... */ or "..." that extend past one line.
10120bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
10130bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    /* ... */ comments are legit inside macros, for one line.
10140bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    Otherwise, we prefer // comments, so it's ok to warn about the
10150bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    other.  Likewise, it's ok for strings to extend across multiple
10160bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    lines, as long as a line continuation character (backslash)
10170bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    terminates each line. Although not currently prohibited by the C++
10180bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    style guide, it's ugly and unnecessary. We don't do well with either
10190bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    in this lint program, so we warn about both.
10200bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
10210bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    Args:
10220bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      clean_lines: A CleansedLines instance containing the file.
10230bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      line_number: The number of the line to check.
10240bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      error: The function to call with any errors found.
10250bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """
10260bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    line = clean_lines.elided[line_number]
10270bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
10280bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # Remove all \\ (escaped backslashes) from the line. They are OK, and the
10290bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # second (escaped) slash may trigger later \" detection erroneously.
10300bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    line = line.replace('\\\\', '')
10310bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
10320bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if line.count('/*') > line.count('*/'):
1033d0825bca7fe65beaee391d30da42e937db621564Steve Block        error(line_number, 'readability/multiline_comment', 5,
10340bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch              'Complex multi-line /*...*/-style comment found. '
10350bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch              'Lint may give bogus warnings.  '
10360bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch              'Consider replacing these with //-style comments, '
10370bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch              'with #if 0...#endif, '
10380bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch              'or with more clearly structured multi-line comments.')
10390bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
10400bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if (line.count('"') - line.count('\\"')) % 2:
1041d0825bca7fe65beaee391d30da42e937db621564Steve Block        error(line_number, 'readability/multiline_string', 5,
10420bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch              'Multi-line string ("...") found.  This lint script doesn\'t '
10430bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch              'do well with such strings, and may give bogus warnings.  They\'re '
10440bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch              'ugly and unnecessary, and you should use concatenation instead".')
10450bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
10460bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
10470bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch_THREADING_LIST = (
10480bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    ('asctime(', 'asctime_r('),
10490bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    ('ctime(', 'ctime_r('),
10500bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    ('getgrgid(', 'getgrgid_r('),
10510bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    ('getgrnam(', 'getgrnam_r('),
10520bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    ('getlogin(', 'getlogin_r('),
10530bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    ('getpwnam(', 'getpwnam_r('),
10540bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    ('getpwuid(', 'getpwuid_r('),
10550bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    ('gmtime(', 'gmtime_r('),
10560bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    ('localtime(', 'localtime_r('),
10570bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    ('rand(', 'rand_r('),
10580bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    ('readdir(', 'readdir_r('),
10590bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    ('strtok(', 'strtok_r('),
10600bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    ('ttyname(', 'ttyname_r('),
10610bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    )
10620bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
10630bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
1064d0825bca7fe65beaee391d30da42e937db621564Steve Blockdef check_posix_threading(clean_lines, line_number, error):
10650bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """Checks for calls to thread-unsafe functions.
10660bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
10670bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    Much code has been originally written without consideration of
10680bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    multi-threading. Also, engineers are relying on their old experience;
10690bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    they have learned posix before threading extensions were added. These
10700bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    tests guide the engineers to use thread-safe functions (when using
10710bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    posix directly).
10720bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
10730bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    Args:
10740bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      clean_lines: A CleansedLines instance containing the file.
10750bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      line_number: The number of the line to check.
10760bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      error: The function to call with any errors found.
10770bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """
10780bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    line = clean_lines.elided[line_number]
10790bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    for single_thread_function, multithread_safe_function in _THREADING_LIST:
10800bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        index = line.find(single_thread_function)
10810bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # Comparisons made explicit for clarity -- pylint: disable-msg=C6403
10820bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        if index >= 0 and (index == 0 or (not line[index - 1].isalnum()
10830bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                                          and line[index - 1] not in ('_', '.', '>'))):
1084d0825bca7fe65beaee391d30da42e937db621564Steve Block            error(line_number, 'runtime/threadsafe_fn', 2,
10850bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                  'Consider using ' + multithread_safe_function +
10860bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                  '...) instead of ' + single_thread_function +
10870bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                  '...) for improved thread safety.')
10880bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
10890bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
10900bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch# Matches invalid increment: *count++, which moves pointer instead of
10910bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch# incrementing a value.
10920bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch_RE_PATTERN_INVALID_INCREMENT = re.compile(
10930bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    r'^\s*\*\w+(\+\+|--);')
10940bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
10950bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
1096d0825bca7fe65beaee391d30da42e937db621564Steve Blockdef check_invalid_increment(clean_lines, line_number, error):
10970bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """Checks for invalid increment *count++.
10980bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
10990bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    For example following function:
11000bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    void increment_counter(int* count) {
11010bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        *count++;
11020bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    }
11030bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    is invalid, because it effectively does count++, moving pointer, and should
11040bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    be replaced with ++*count, (*count)++ or *count += 1.
11050bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
11060bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    Args:
11070bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      clean_lines: A CleansedLines instance containing the file.
11080bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      line_number: The number of the line to check.
11090bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      error: The function to call with any errors found.
11100bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """
11110bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    line = clean_lines.elided[line_number]
11120bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if _RE_PATTERN_INVALID_INCREMENT.match(line):
1113d0825bca7fe65beaee391d30da42e937db621564Steve Block        error(line_number, 'runtime/invalid_increment', 5,
11140bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch              'Changing pointer instead of value (or unused value of operator*).')
11150bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
11160bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
11170bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdochclass _ClassInfo(object):
11180bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """Stores information about a class."""
11190bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
11200bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    def __init__(self, name, line_number):
11210bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        self.name = name
11220bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        self.line_number = line_number
11230bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        self.seen_open_brace = False
11240bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        self.is_derived = False
11250bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        self.virtual_method_line_number = None
11260bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        self.has_virtual_destructor = False
11270bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        self.brace_depth = 0
11280bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
11290bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
11300bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdochclass _ClassState(object):
11310bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """Holds the current state of the parse relating to class declarations.
11320bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
11330bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    It maintains a stack of _ClassInfos representing the parser's guess
11340bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    as to the current nesting of class declarations. The innermost class
11350bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    is at the top (back) of the stack. Typically, the stack will either
11360bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    be empty or have exactly one entry.
11370bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """
11380bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
11390bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    def __init__(self):
11400bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        self.classinfo_stack = []
11410bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
1142d0825bca7fe65beaee391d30da42e937db621564Steve Block    def check_finished(self, error):
11430bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        """Checks that all classes have been completely parsed.
11440bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
11450bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        Call this when all lines in a file have been processed.
11460bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        Args:
11470bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch          error: The function to call with any errors found.
11480bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        """
11490bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        if self.classinfo_stack:
11500bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            # Note: This test can result in false positives if #ifdef constructs
11510bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            # get in the way of brace matching. See the testBuildClass test in
11520bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            # cpp_style_unittest.py for an example of this.
1153d0825bca7fe65beaee391d30da42e937db621564Steve Block            error(self.classinfo_stack[0].line_number, 'build/class', 5,
11540bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                  'Failed to find complete declaration of class %s' %
11550bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                  self.classinfo_stack[0].name)
11560bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
11570bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
1158643ca7872b450ea4efacab6188849e5aac2ba161Steve Blockclass _FileState(object):
1159f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch    def __init__(self, clean_lines, file_extension):
1160643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        self._did_inside_namespace_indent_warning = False
1161f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch        self._clean_lines = clean_lines
1162f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch        if file_extension in ['m', 'mm']:
1163f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch            self._is_objective_c = True
1164f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch        elif file_extension == 'h':
1165f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch            # In the case of header files, it is unknown if the file
1166f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch            # is objective c or not, so set this value to None and then
1167f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch            # if it is requested, use heuristics to guess the value.
1168f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch            self._is_objective_c = None
1169f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch        else:
1170f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch            self._is_objective_c = False
1171f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch        self._is_c = file_extension == 'c'
1172643ca7872b450ea4efacab6188849e5aac2ba161Steve Block
1173643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    def set_did_inside_namespace_indent_warning(self):
1174643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        self._did_inside_namespace_indent_warning = True
1175643ca7872b450ea4efacab6188849e5aac2ba161Steve Block
1176643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    def did_inside_namespace_indent_warning(self):
1177643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        return self._did_inside_namespace_indent_warning
1178643ca7872b450ea4efacab6188849e5aac2ba161Steve Block
1179f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch    def is_objective_c(self):
1180f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch        if self._is_objective_c is None:
1181f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch            for line in self._clean_lines.elided:
1182f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch                # Starting with @ or #import seem like the best indications
1183f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch                # that we have an Objective C file.
1184f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch                if line.startswith("@") or line.startswith("#import"):
1185f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch                    self._is_objective_c = True
1186f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch                    break
1187f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch            else:
1188f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch                self._is_objective_c = False
1189f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch        return self._is_objective_c
1190f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch
1191f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch    def is_c_or_objective_c(self):
1192f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch        """Return whether the file extension corresponds to C or Objective-C."""
1193f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch        return self._is_c or self.is_objective_c()
1194f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch
1195f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch
1196d0825bca7fe65beaee391d30da42e937db621564Steve Blockdef check_for_non_standard_constructs(clean_lines, line_number,
11970bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                                      class_state, error):
11980bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """Logs an error if we see certain non-ANSI constructs ignored by gcc-2.
11990bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
12000bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    Complain about several constructs which gcc-2 accepts, but which are
12010bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    not standard C++.  Warning about these in lint is one way to ease the
12020bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    transition to new compilers.
12030bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    - put storage class first (e.g. "static const" instead of "const static").
12040bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    - "%lld" instead of %qd" in printf-type functions.
12050bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    - "%1$d" is non-standard in printf-type functions.
12060bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    - "\%" is an undefined character escape sequence.
12070bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    - text after #endif is not allowed.
12080bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    - invalid inner-style forward declaration.
12090bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    - >? and <? operators, and their >?= and <?= cousins.
12100bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    - classes with virtual methods need virtual destructors (compiler warning
12110bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        available, but not turned on yet.)
12120bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
12130bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    Additionally, check for constructor/destructor style violations as it
12140bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    is very convenient to do so while checking for gcc-2 compliance.
12150bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
12160bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    Args:
12170bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      clean_lines: A CleansedLines instance containing the file.
12180bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      line_number: The number of the line to check.
12190bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      class_state: A _ClassState instance which maintains information about
12200bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                   the current stack of nested class declarations being parsed.
1221d0825bca7fe65beaee391d30da42e937db621564Steve Block      error: A callable to which errors are reported, which takes parameters:
1222d0825bca7fe65beaee391d30da42e937db621564Steve Block             line number, error level, and message
12230bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """
12240bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
12250bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # Remove comments from the line, but leave in strings for now.
12260bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    line = clean_lines.lines[line_number]
12270bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
12280bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if search(r'printf\s*\(.*".*%[-+ ]?\d*q', line):
1229d0825bca7fe65beaee391d30da42e937db621564Steve Block        error(line_number, 'runtime/printf_format', 3,
12300bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch              '%q in format strings is deprecated.  Use %ll instead.')
12310bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
12320bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if search(r'printf\s*\(.*".*%\d+\$', line):
1233d0825bca7fe65beaee391d30da42e937db621564Steve Block        error(line_number, 'runtime/printf_format', 2,
12340bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch              '%N$ formats are unconventional.  Try rewriting to avoid them.')
12350bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
12360bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # Remove escaped backslashes before looking for undefined escapes.
12370bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    line = line.replace('\\\\', '')
12380bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
12390bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if search(r'("|\').*\\(%|\[|\(|{)', line):
1240d0825bca7fe65beaee391d30da42e937db621564Steve Block        error(line_number, 'build/printf_format', 3,
12410bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch              '%, [, (, and { are undefined character escapes.  Unescape them.')
12420bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
12430bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # For the rest, work with both comments and strings removed.
12440bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    line = clean_lines.elided[line_number]
12450bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
12460bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if search(r'\b(const|volatile|void|char|short|int|long'
12470bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch              r'|float|double|signed|unsigned'
12480bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch              r'|schar|u?int8|u?int16|u?int32|u?int64)'
12490bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch              r'\s+(auto|register|static|extern|typedef)\b',
12500bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch              line):
1251d0825bca7fe65beaee391d30da42e937db621564Steve Block        error(line_number, 'build/storage_class', 5,
12520bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch              'Storage class (static, extern, typedef, etc) should be first.')
12530bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
12540bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if match(r'\s*#\s*endif\s*[^/\s]+', line):
1255d0825bca7fe65beaee391d30da42e937db621564Steve Block        error(line_number, 'build/endif_comment', 5,
12560bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch              'Uncommented text after #endif is non-standard.  Use a comment.')
12570bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
12580bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if match(r'\s*class\s+(\w+\s*::\s*)+\w+\s*;', line):
1259d0825bca7fe65beaee391d30da42e937db621564Steve Block        error(line_number, 'build/forward_decl', 5,
12600bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch              'Inner-style forward declarations are invalid.  Remove this line.')
12610bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
12620bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if search(r'(\w+|[+-]?\d+(\.\d*)?)\s*(<|>)\?=?\s*(\w+|[+-]?\d+)(\.\d*)?', line):
1263d0825bca7fe65beaee391d30da42e937db621564Steve Block        error(line_number, 'build/deprecated', 3,
12640bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch              '>? and <? (max and min) operators are non-standard and deprecated.')
12650bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
12660bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # Track class entry and exit, and attempt to find cases within the
12670bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # class declaration that don't meet the C++ style
12680bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # guidelines. Tracking is very dependent on the code matching Google
12690bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # style guidelines, but it seems to perform well enough in testing
12700bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # to be a worthwhile addition to the checks.
12710bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    classinfo_stack = class_state.classinfo_stack
12720bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # Look for a class declaration
12730bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    class_decl_match = match(
12740bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        r'\s*(template\s*<[\w\s<>,:]*>\s*)?(class|struct)\s+(\w+(::\w+)*)', line)
12750bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if class_decl_match:
12760bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        classinfo_stack.append(_ClassInfo(class_decl_match.group(3), line_number))
12770bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
12780bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # Everything else in this function uses the top of the stack if it's
12790bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # not empty.
12800bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if not classinfo_stack:
12810bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        return
12820bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
12830bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    classinfo = classinfo_stack[-1]
12840bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
12850bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # If the opening brace hasn't been seen look for it and also
12860bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # parent class declarations.
12870bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if not classinfo.seen_open_brace:
12880bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # If the line has a ';' in it, assume it's a forward declaration or
12890bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # a single-line class declaration, which we won't process.
12900bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        if line.find(';') != -1:
12910bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            classinfo_stack.pop()
12920bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            return
12930bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        classinfo.seen_open_brace = (line.find('{') != -1)
12940bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # Look for a bare ':'
12950bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        if search('(^|[^:]):($|[^:])', line):
12960bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            classinfo.is_derived = True
12970bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        if not classinfo.seen_open_brace:
12980bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            return  # Everything else in this function is for after open brace
12990bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
13000bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # The class may have been declared with namespace or classname qualifiers.
13010bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # The constructor and destructor will not have those qualifiers.
13020bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    base_classname = classinfo.name.split('::')[-1]
13030bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
13040bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # Look for single-argument constructors that aren't marked explicit.
13050bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # Technically a valid construct, but against style.
13060bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    args = match(r'(?<!explicit)\s+%s\s*\(([^,()]+)\)'
13070bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                 % re.escape(base_classname),
13080bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                 line)
13090bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if (args
13100bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        and args.group(1) != 'void'
13110bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        and not match(r'(const\s+)?%s\s*&' % re.escape(base_classname),
13120bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                      args.group(1).strip())):
1313d0825bca7fe65beaee391d30da42e937db621564Steve Block        error(line_number, 'runtime/explicit', 5,
13140bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch              'Single-argument constructors should be marked explicit.')
13150bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
13160bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # Look for methods declared virtual.
13170bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if search(r'\bvirtual\b', line):
13180bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        classinfo.virtual_method_line_number = line_number
13190bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # Only look for a destructor declaration on the same line. It would
13200bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # be extremely unlikely for the destructor declaration to occupy
13210bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # more than one line.
13220bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        if search(r'~%s\s*\(' % base_classname, line):
13230bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            classinfo.has_virtual_destructor = True
13240bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
13250bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # Look for class end.
13260bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    brace_depth = classinfo.brace_depth
13270bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    brace_depth = brace_depth + line.count('{') - line.count('}')
13280bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if brace_depth <= 0:
13290bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        classinfo = classinfo_stack.pop()
13300bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # Try to detect missing virtual destructor declarations.
13310bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # For now, only warn if a non-derived class with virtual methods lacks
13320bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # a virtual destructor. This is to make it less likely that people will
13330bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # declare derived virtual destructors without declaring the base
13340bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # destructor virtual.
13350bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        if ((classinfo.virtual_method_line_number is not None)
13360bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            and (not classinfo.has_virtual_destructor)
13370bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            and (not classinfo.is_derived)):  # Only warn for base classes
1338d0825bca7fe65beaee391d30da42e937db621564Steve Block            error(classinfo.line_number, 'runtime/virtual', 4,
13390bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                  'The class %s probably needs a virtual destructor due to '
13400bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                  'having virtual method(s), one declared at line %d.'
13410bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                  % (classinfo.name, classinfo.virtual_method_line_number))
13420bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    else:
13430bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        classinfo.brace_depth = brace_depth
13440bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
13450bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
1346d0825bca7fe65beaee391d30da42e937db621564Steve Blockdef check_spacing_for_function_call(line, line_number, error):
13470bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """Checks for the correctness of various spacing around function calls.
13480bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
13490bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    Args:
13500bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      line: The text of the line to check.
13510bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      line_number: The number of the line to check.
13520bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      error: The function to call with any errors found.
13530bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """
13540bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
13550bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # Since function calls often occur inside if/for/foreach/while/switch
13560bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # expressions - which have their own, more liberal conventions - we
13570bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # first see if we should be looking inside such an expression for a
13580bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # function call, to which we can apply more strict standards.
13590bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    function_call = line    # if there's no control flow construct, look at whole line
13600bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    for pattern in (r'\bif\s*\((.*)\)\s*{',
13610bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                    r'\bfor\s*\((.*)\)\s*{',
13620bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                    r'\bforeach\s*\((.*)\)\s*{',
13630bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                    r'\bwhile\s*\((.*)\)\s*[{;]',
13640bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                    r'\bswitch\s*\((.*)\)\s*{'):
13650bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        matched = search(pattern, line)
13660bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        if matched:
13670bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            function_call = matched.group(1)    # look inside the parens for function calls
13680bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            break
13690bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
13700bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # Except in if/for/foreach/while/switch, there should never be space
13710bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # immediately inside parens (eg "f( 3, 4 )").  We make an exception
13720bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # for nested parens ( (a+b) + c ).  Likewise, there should never be
13730bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # a space before a ( when it's a function argument.  I assume it's a
13740bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # function argument when the char before the whitespace is legal in
13750bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # a function name (alnum + _) and we're not starting a macro. Also ignore
13760bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # pointers and references to arrays and functions coz they're too tricky:
13770bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # we use a very simple way to recognize these:
13780bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # " (something)(maybe-something)" or
13790bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # " (something)(maybe-something," or
13800bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # " (something)[something]"
13810bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # Note that we assume the contents of [] to be short enough that
13820bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # they'll never need to wrap.
13830bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if (  # Ignore control structures.
13840bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        not search(r'\b(if|for|foreach|while|switch|return|new|delete)\b', function_call)
13850bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # Ignore pointers/references to functions.
13860bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        and not search(r' \([^)]+\)\([^)]*(\)|,$)', function_call)
13870bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # Ignore pointers/references to arrays.
13880bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        and not search(r' \([^)]+\)\[[^\]]+\]', function_call)):
13890bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        if search(r'\w\s*\([ \t](?!\s*\\$)', function_call):      # a ( used for a fn call
1390d0825bca7fe65beaee391d30da42e937db621564Steve Block            error(line_number, 'whitespace/parens', 4,
13910bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                  'Extra space after ( in function call')
13920bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        elif search(r'\([ \t]+(?!(\s*\\)|\()', function_call):
1393d0825bca7fe65beaee391d30da42e937db621564Steve Block            error(line_number, 'whitespace/parens', 2,
13940bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                  'Extra space after (')
13950bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        if (search(r'\w\s+\(', function_call)
1396cad810f21b803229eb11403f9209855525a25d57Steve Block            and not match(r'\s*(#|typedef)', function_call)):
1397d0825bca7fe65beaee391d30da42e937db621564Steve Block            error(line_number, 'whitespace/parens', 4,
13980bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                  'Extra space before ( in function call')
13990bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # If the ) is followed only by a newline or a { + newline, assume it's
14000bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # part of a control statement (if/while/etc), and don't complain
14010bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        if search(r'[^)\s]\s+\)(?!\s*$|{\s*$)', function_call):
1402d0825bca7fe65beaee391d30da42e937db621564Steve Block            error(line_number, 'whitespace/parens', 2,
14030bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                  'Extra space before )')
14040bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
14050bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
14060bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdochdef is_blank_line(line):
14070bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """Returns true if the given line is blank.
14080bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
14090bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    We consider a line to be blank if the line is empty or consists of
14100bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    only white spaces.
14110bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
14120bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    Args:
14130bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      line: A line of a string.
14140bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
14150bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    Returns:
14160bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      True, if the given line is blank.
14170bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """
14180bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    return not line or line.isspace()
14190bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
14200bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
14216b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brennerdef detect_functions(clean_lines, line_number, function_state, error):
14226b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner    """Finds where functions start and end.
14236b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner
14246b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner    Uses a simplistic algorithm assuming other style guidelines
14256b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner    (especially spacing) are followed.
14266b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner    Trivial bodies are unchecked, so constructors with huge initializer lists
14276b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner    may be missed.
14286b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner
14296b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner    Args:
14306b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner      clean_lines: A CleansedLines instance containing the file.
14316b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner      line_number: The number of the line to check.
14326b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner      function_state: Current function name and lines in body so far.
14336b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner      error: The function to call with any errors found.
14346b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner    """
14356b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner    # Are we now past the end of a function?
143665f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch    if function_state.end_position.row + 1 == line_number:
14376b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner        function_state.end()
14386b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner
14396b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner    # If we're in a function, don't try to detect a new one.
14406b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner    if function_state.in_a_function:
14416b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner        return
14426b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner
14436b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner    lines = clean_lines.lines
14446b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner    line = lines[line_number]
14456b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner    raw = clean_lines.raw_lines
14466b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner    raw_line = raw[line_number]
14476b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner
1448cad810f21b803229eb11403f9209855525a25d57Steve Block    # Lines ending with a \ indicate a macro. Don't try to check them.
1449cad810f21b803229eb11403f9209855525a25d57Steve Block    if raw_line.endswith('\\'):
1450cad810f21b803229eb11403f9209855525a25d57Steve Block        return
1451cad810f21b803229eb11403f9209855525a25d57Steve Block
1452cad810f21b803229eb11403f9209855525a25d57Steve Block    regexp = r'\s*(\w(\w|::|\*|\&|\s|<|>|,|~|(operator\s*(/|-|=|!|\+)+))*)\('  # decls * & space::name( ...
14536b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner    match_result = match(regexp, line)
14546b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner    if not match_result:
14556b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner        return
14566b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner
14576b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner    # If the name is all caps and underscores, figure it's a macro and
14586b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner    # ignore it, unless it's TEST or TEST_F.
14596b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner    function_name = match_result.group(1).split()[-1]
14606b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner    if function_name != 'TEST' and function_name != 'TEST_F' and match(r'[A-Z_]+$', function_name):
14616b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner        return
14626b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner
14636b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner    joined_line = ''
14646b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner    for start_line_number in xrange(line_number, clean_lines.num_lines()):
1465f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch        start_line = clean_lines.elided[start_line_number]
14666b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner        joined_line += ' ' + start_line.lstrip()
146765f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch        body_match = search(r'{|;', start_line)
146865f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch        if body_match:
146965f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch            body_start_position = Position(start_line_number, body_match.start(0))
147065f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch
14716b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner            # Replace template constructs with _ so that no spaces remain in the function name,
14726b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner            # while keeping the column numbers of other characters the same as "line".
14736b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner            line_with_no_templates = iteratively_replace_matches_with_char(r'<[^<>]*>', '_', line)
1474cad810f21b803229eb11403f9209855525a25d57Steve Block            match_function = search(r'((\w|:|<|>|,|~|(operator\s*(/|-|=|!|\+)+))*)\(', line_with_no_templates)
14756b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner            if not match_function:
14766b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner                return  # The '(' must have been inside of a template.
14776b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner
14786b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner            # Use the column numbers from the modified line to find the
14796b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner            # function name in the original line.
14806b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner            function = line[match_function.start(1):match_function.end(1)]
148165f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch            function_name_start_position = Position(line_number, match_function.start(1))
14826b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner
14836b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner            if match(r'TEST', function):    # Handle TEST... macros
14846b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner                parameter_regexp = search(r'(\(.*\))', joined_line)
14856b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner                if parameter_regexp:             # Ignore bad syntax
14866b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner                    function += parameter_regexp.group(1)
14876b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner            else:
14886b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner                function += '()'
1489cad810f21b803229eb11403f9209855525a25d57Steve Block
1490cad810f21b803229eb11403f9209855525a25d57Steve Block            parameter_start_position = Position(line_number, match_function.end(1))
149165f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch            parameter_end_position = close_expression(clean_lines.elided, parameter_start_position)
149265f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch            if parameter_end_position.row == len(clean_lines.elided):
1493cad810f21b803229eb11403f9209855525a25d57Steve Block                # No end was found.
1494cad810f21b803229eb11403f9209855525a25d57Steve Block                return
1495cad810f21b803229eb11403f9209855525a25d57Steve Block
149665f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch            if start_line[body_start_position.column] == ';':
149765f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch                end_position = Position(body_start_position.row, body_start_position.column + 1)
1498f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch            else:
149965f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch                end_position = close_expression(clean_lines.elided, body_start_position)
150065f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch
150165f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch            # Check for nonsensical positions. (This happens in test cases which check code snippets.)
150265f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch            if parameter_end_position > body_start_position:
150365f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch                return
150465f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch
150565f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch            function_state.begin(function, function_name_start_position, body_start_position, end_position,
1506cad810f21b803229eb11403f9209855525a25d57Steve Block                                 parameter_start_position, parameter_end_position, clean_lines)
15076b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner            return
15086b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner
15096b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner    # No body for the function (or evidence of a non-function) was found.
15106b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner    error(line_number, 'readability/fn_size', 5,
15116b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner          'Lint failed to find start of function body.')
15126b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner
15136b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner
1514d0825bca7fe65beaee391d30da42e937db621564Steve Blockdef check_for_function_lengths(clean_lines, line_number, function_state, error):
15150bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """Reports for long function bodies.
15160bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
15170bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    For an overview why this is done, see:
15180bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml#Write_Short_Functions
15190bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
15200bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    Blank/comment lines are not counted so as to avoid encouraging the removal
15210bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    of vertical space and commments just to get through a lint check.
15220bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    NOLINT *on the last line of a function* disables this check.
15230bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
15240bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    Args:
15250bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      clean_lines: A CleansedLines instance containing the file.
15260bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      line_number: The number of the line to check.
15270bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      function_state: Current function name and lines in body so far.
15280bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      error: The function to call with any errors found.
15290bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """
15300bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    lines = clean_lines.lines
15310bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    line = lines[line_number]
15320bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    raw = clean_lines.raw_lines
15330bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    raw_line = raw[line_number]
15340bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
153565f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch    if function_state.end_position.row == line_number:  # last line
15360bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        if not search(r'\bNOLINT\b', raw_line):
1537d0825bca7fe65beaee391d30da42e937db621564Steve Block            function_state.check(error, line_number)
15380bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    elif not match(r'^\s*$', line):
15396b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner        function_state.count(line_number)  # Count non-blank/non-comment lines.
15406b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner
15416b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner
1542cad810f21b803229eb11403f9209855525a25d57Steve Blockdef _check_parameter_name_against_text(parameter, text, error):
1543cad810f21b803229eb11403f9209855525a25d57Steve Block    """Checks to see if the parameter name is contained within the text.
1544cad810f21b803229eb11403f9209855525a25d57Steve Block
1545cad810f21b803229eb11403f9209855525a25d57Steve Block    Return false if the check failed (i.e. an error was produced).
1546cad810f21b803229eb11403f9209855525a25d57Steve Block    """
1547cad810f21b803229eb11403f9209855525a25d57Steve Block
1548cad810f21b803229eb11403f9209855525a25d57Steve Block    # Treat 'lower with underscores' as a canonical form because it is
1549cad810f21b803229eb11403f9209855525a25d57Steve Block    # case insensitive while still retaining word breaks. (This ensures that
1550cad810f21b803229eb11403f9209855525a25d57Steve Block    # 'elate' doesn't look like it is duplicating of 'NateLate'.)
1551cad810f21b803229eb11403f9209855525a25d57Steve Block    canonical_parameter_name = parameter.lower_with_underscores_name()
1552cad810f21b803229eb11403f9209855525a25d57Steve Block
1553cad810f21b803229eb11403f9209855525a25d57Steve Block    # Appends "object" to all text to catch variables that did the same (but only
1554cad810f21b803229eb11403f9209855525a25d57Steve Block    # do this when the parameter name is more than a single character to avoid
1555cad810f21b803229eb11403f9209855525a25d57Steve Block    # flagging 'b' which may be an ok variable when used in an rgba function).
1556cad810f21b803229eb11403f9209855525a25d57Steve Block    if len(canonical_parameter_name) > 1:
1557cad810f21b803229eb11403f9209855525a25d57Steve Block        text = sub(r'(\w)\b', r'\1Object', text)
1558cad810f21b803229eb11403f9209855525a25d57Steve Block    canonical_text = _convert_to_lower_with_underscores(text)
1559cad810f21b803229eb11403f9209855525a25d57Steve Block
1560cad810f21b803229eb11403f9209855525a25d57Steve Block    # Used to detect cases like ec for ExceptionCode.
1561cad810f21b803229eb11403f9209855525a25d57Steve Block    acronym = _create_acronym(text).lower()
1562cad810f21b803229eb11403f9209855525a25d57Steve Block    if canonical_text.find(canonical_parameter_name) != -1 or acronym.find(canonical_parameter_name) != -1:
1563cad810f21b803229eb11403f9209855525a25d57Steve Block        error(parameter.row, 'readability/parameter_name', 5,
1564cad810f21b803229eb11403f9209855525a25d57Steve Block              'The parameter name "%s" adds no information, so it should be removed.' % parameter.name)
1565cad810f21b803229eb11403f9209855525a25d57Steve Block        return False
1566cad810f21b803229eb11403f9209855525a25d57Steve Block    return True
1567cad810f21b803229eb11403f9209855525a25d57Steve Block
1568cad810f21b803229eb11403f9209855525a25d57Steve Block
156981bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdochdef check_function_definition(filename, file_extension, clean_lines, line_number, function_state, error):
1570cad810f21b803229eb11403f9209855525a25d57Steve Block    """Check that function definitions for style issues.
1571cad810f21b803229eb11403f9209855525a25d57Steve Block
1572cad810f21b803229eb11403f9209855525a25d57Steve Block    Specifically, check that parameter names in declarations add information.
1573cad810f21b803229eb11403f9209855525a25d57Steve Block
1574cad810f21b803229eb11403f9209855525a25d57Steve Block    Args:
157581bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch       filename: Filename of the file that is being processed.
157681bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch       file_extension: The current file extension, without the leading dot.
1577cad810f21b803229eb11403f9209855525a25d57Steve Block       clean_lines: A CleansedLines instance containing the file.
1578cad810f21b803229eb11403f9209855525a25d57Steve Block       line_number: The number of the line to check.
1579cad810f21b803229eb11403f9209855525a25d57Steve Block       function_state: Current function name and lines in body so far.
1580cad810f21b803229eb11403f9209855525a25d57Steve Block       error: The function to call with any errors found.
1581cad810f21b803229eb11403f9209855525a25d57Steve Block    """
158281bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    if line_number != function_state.body_start_position.row:
1583cad810f21b803229eb11403f9209855525a25d57Steve Block        return
1584cad810f21b803229eb11403f9209855525a25d57Steve Block
158581bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    modifiers_and_return_type = function_state.modifiers_and_return_type()
158681bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    if filename.find('/chromium/') != -1 and search(r'\bWEBKIT_API\b', modifiers_and_return_type):
158781bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch        if filename.find('/chromium/public/') == -1:
158881bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch            error(function_state.function_name_start_position.row, 'readability/webkit_api', 5,
158981bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch                  'WEBKIT_API should only appear in the chromium public directory.')
159081bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch        elif not file_extension == "h":
159181bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch            error(function_state.function_name_start_position.row, 'readability/webkit_api', 5,
159281bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch                  'WEBKIT_API should only be used in header files.')
159381bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch        elif not function_state.is_declaration or search(r'\binline\b', modifiers_and_return_type):
159481bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch            error(function_state.function_name_start_position.row, 'readability/webkit_api', 5,
159581bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch                  'WEBKIT_API should not be used on a function with a body.')
159681bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch        elif function_state.is_pure:
159781bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch            error(function_state.function_name_start_position.row, 'readability/webkit_api', 5,
159881bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch                  'WEBKIT_API should not be used with a pure virtual function.')
159981bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch
160081bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    # Do checks specific to function declaractions.
160181bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    if not function_state.is_declaration:
160281bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch        return
1603cad810f21b803229eb11403f9209855525a25d57Steve Block    parameter_list = function_state.parameter_list()
1604cad810f21b803229eb11403f9209855525a25d57Steve Block    for parameter in parameter_list:
1605cad810f21b803229eb11403f9209855525a25d57Steve Block        if not parameter.name:
1606cad810f21b803229eb11403f9209855525a25d57Steve Block            continue
1607cad810f21b803229eb11403f9209855525a25d57Steve Block
1608cad810f21b803229eb11403f9209855525a25d57Steve Block        # Check the parameter name against the function name for single parameter set functions.
1609cad810f21b803229eb11403f9209855525a25d57Steve Block        if len(parameter_list) == 1 and match('set[A-Z]', function_state.current_function):
1610cad810f21b803229eb11403f9209855525a25d57Steve Block            trimmed_function_name = function_state.current_function[len('set'):]
1611cad810f21b803229eb11403f9209855525a25d57Steve Block            if not _check_parameter_name_against_text(parameter, trimmed_function_name, error):
1612cad810f21b803229eb11403f9209855525a25d57Steve Block                continue  # Since an error was noted for this name, move to the next parameter.
1613cad810f21b803229eb11403f9209855525a25d57Steve Block
1614cad810f21b803229eb11403f9209855525a25d57Steve Block        # Check the parameter name against the type.
1615cad810f21b803229eb11403f9209855525a25d57Steve Block        if not _check_parameter_name_against_text(parameter, parameter.type, error):
1616cad810f21b803229eb11403f9209855525a25d57Steve Block            continue  # Since an error was noted for this name, move to the next parameter.
1617cad810f21b803229eb11403f9209855525a25d57Steve Block
1618cad810f21b803229eb11403f9209855525a25d57Steve Block
16196b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brennerdef check_pass_ptr_usage(clean_lines, line_number, function_state, error):
16206b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner    """Check for proper usage of Pass*Ptr.
16216b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner
16226b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner    Currently this is limited to detecting declarations of Pass*Ptr
16236b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner    variables inside of functions.
16246b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner
16256b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner    Args:
16266b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner      clean_lines: A CleansedLines instance containing the file.
16276b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner      line_number: The number of the line to check.
16286b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner      function_state: Current function name and lines in body so far.
16296b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner      error: The function to call with any errors found.
16306b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner    """
16316b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner    if not function_state.in_a_function:
16326b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner        return
16336b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner
16346b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner    lines = clean_lines.lines
16356b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner    line = lines[line_number]
163665f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch    if line_number > function_state.body_start_position.row:
16376b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner        matched_pass_ptr = match(r'^\s*Pass([A-Z][A-Za-z]*)Ptr<', line)
16386b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner        if matched_pass_ptr:
16396b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner            type_name = 'Pass%sPtr' % matched_pass_ptr.group(1)
16406b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner            error(line_number, 'readability/pass_ptr', 5,
16416b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner                  'Local variables should never be %s (see '
16426b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner                  'http://webkit.org/coding/RefPtr.html).' % type_name)
16430bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
16440bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
1645d0825bca7fe65beaee391d30da42e937db621564Steve Blockdef check_spacing(file_extension, clean_lines, line_number, error):
16460bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """Checks for the correctness of various spacing issues in the code.
16470bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
16480bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    Things we check for: spaces around operators, spaces after
16490bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if/for/while/switch, no spaces around parens in function calls, two
16500bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    spaces between code and comment, don't start a block with a blank
16510bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    line, don't end a function with a blank line, don't have too many
16520bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    blank lines in a row.
16530bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
16540bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    Args:
1655d0825bca7fe65beaee391d30da42e937db621564Steve Block      file_extension: The current file extension, without the leading dot.
16560bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      clean_lines: A CleansedLines instance containing the file.
16570bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      line_number: The number of the line to check.
16580bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      error: The function to call with any errors found.
16590bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """
16600bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
16610bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    raw = clean_lines.raw_lines
16620bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    line = raw[line_number]
16630bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
16640bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # Before nixing comments, check if the line is blank for no good
16650bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # reason.  This includes the first line after a block is opened, and
16660bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # blank lines at the end of a function (ie, right before a line like '}').
16670bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if is_blank_line(line):
16680bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        elided = clean_lines.elided
16690bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        previous_line = elided[line_number - 1]
16700bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        previous_brace = previous_line.rfind('{')
16710bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # FIXME: Don't complain if line before blank line, and line after,
16720bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        #        both start with alnums and are indented the same amount.
16730bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        #        This ignores whitespace at the start of a namespace block
16740bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        #        because those are not usually indented.
16750bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        if (previous_brace != -1 and previous_line[previous_brace:].find('}') == -1
16760bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            and previous_line[:previous_brace].find('namespace') == -1):
16770bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            # OK, we have a blank line at the start of a code block.  Before we
16780bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            # complain, we check if it is an exception to the rule: The previous
16790bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            # non-empty line has the parameters of a function header that are indented
16800bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            # 4 spaces (because they did not fit in a 80 column line when placed on
16810bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            # the same line as the function name).  We also check for the case where
16820bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            # the previous line is indented 6 spaces, which may happen when the
16830bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            # initializers of a constructor do not fit into a 80 column line.
16840bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            exception = False
16850bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            if match(r' {6}\w', previous_line):  # Initializer list?
16860bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                # We are looking for the opening column of initializer list, which
16870bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                # should be indented 4 spaces to cause 6 space indentation afterwards.
16880bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                search_position = line_number - 2
16890bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                while (search_position >= 0
16900bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                       and match(r' {6}\w', elided[search_position])):
16910bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                    search_position -= 1
16920bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                exception = (search_position >= 0
16930bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                             and elided[search_position][:5] == '    :')
16940bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            else:
16950bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                # Search for the function arguments or an initializer list.  We use a
16960bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                # simple heuristic here: If the line is indented 4 spaces; and we have a
16970bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                # closing paren, without the opening paren, followed by an opening brace
16980bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                # or colon (for initializer lists) we assume that it is the last line of
16990bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                # a function header.  If we have a colon indented 4 spaces, it is an
17000bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                # initializer list.
17010bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                exception = (match(r' {4}\w[^\(]*\)\s*(const\s*)?(\{\s*$|:)',
17020bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                                   previous_line)
17030bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                             or match(r' {4}:', previous_line))
17040bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
17050bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            if not exception:
1706d0825bca7fe65beaee391d30da42e937db621564Steve Block                error(line_number, 'whitespace/blank_line', 2,
17070bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                      'Blank line at the start of a code block.  Is this needed?')
17080bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # This doesn't ignore whitespace at the end of a namespace block
17090bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # because that is too hard without pairing open/close braces;
17100bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # however, a special exception is made for namespace closing
17110bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # brackets which have a comment containing "namespace".
17120bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        #
17130bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # Also, ignore blank lines at the end of a block in a long if-else
17140bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # chain, like this:
17150bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        #   if (condition1) {
17160bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        #     // Something followed by a blank line
17170bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        #
17180bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        #   } else if (condition2) {
17190bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        #     // Something else
17200bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        #   }
17210bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        if line_number + 1 < clean_lines.num_lines():
17220bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            next_line = raw[line_number + 1]
17230bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            if (next_line
17240bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                and match(r'\s*}', next_line)
17250bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                and next_line.find('namespace') == -1
17260bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                and next_line.find('} else ') == -1):
1727d0825bca7fe65beaee391d30da42e937db621564Steve Block                error(line_number, 'whitespace/blank_line', 3,
17280bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                      'Blank line at the end of a code block.  Is this needed?')
17290bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
173081bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    # Next, we check for proper spacing with respect to comments.
17310bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    comment_position = line.find('//')
17320bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if comment_position != -1:
17330bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # Check if the // may be in quotes.  If so, ignore it
17340bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # Comparisons made explicit for clarity -- pylint: disable-msg=C6403
17350bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        if (line.count('"', 0, comment_position) - line.count('\\"', 0, comment_position)) % 2 == 0:   # not in quotes
1736d0825bca7fe65beaee391d30da42e937db621564Steve Block            # Allow one space before end of line comment.
1737d0825bca7fe65beaee391d30da42e937db621564Steve Block            if (not match(r'^\s*$', line[:comment_position])
1738d0825bca7fe65beaee391d30da42e937db621564Steve Block                and (comment_position >= 1
1739d0825bca7fe65beaee391d30da42e937db621564Steve Block                and ((line[comment_position - 1] not in string.whitespace)
17400bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                     or (comment_position >= 2
1741d0825bca7fe65beaee391d30da42e937db621564Steve Block                         and line[comment_position - 2] in string.whitespace)))):
1742d0825bca7fe65beaee391d30da42e937db621564Steve Block                error(line_number, 'whitespace/comments', 5,
1743d0825bca7fe65beaee391d30da42e937db621564Steve Block                      'One space before end of line comments')
17440bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            # There should always be a space between the // and the comment
17450bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            commentend = comment_position + 2
17460bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            if commentend < len(line) and not line[commentend] == ' ':
17470bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                # but some lines are exceptions -- e.g. if they're big
17480bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                # comment delimiters like:
17490bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                # //----------------------------------------------------------
17500bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                # or they begin with multiple slashes followed by a space:
17510bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                # //////// Header comment
17520bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                matched = (search(r'[=/-]{4,}\s*$', line[commentend:])
17530bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                           or search(r'^/+ ', line[commentend:]))
17540bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                if not matched:
1755d0825bca7fe65beaee391d30da42e937db621564Steve Block                    error(line_number, 'whitespace/comments', 4,
17560bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                          'Should have a space between // and comment')
17570bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
175881bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch            # There should only be one space after punctuation in a comment.
175981bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch            if search('[.!?,;:]\s\s', line[comment_position:]):
176081bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch                error(line_number, 'whitespace/comments', 5,
176181bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch                      'Should only a single space after a punctuation in a comment.')
176281bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch
17630bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    line = clean_lines.elided[line_number]  # get rid of comments and strings
17640bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
17650bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # Don't try to do spacing checks for operator methods
1766e14391e94c850b8bd03680c23b38978db68687a8John Reck    line = sub(r'operator(==|!=|<|<<|<=|>=|>>|>|\+=|-=|\*=|/=|%=|&=|\|=|^=|<<=|>>=)\(', 'operator\(', line)
1767643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    # Don't try to do spacing checks for #include or #import statements at
1768643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    # minimum because it messes up checks for spacing around /
1769643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    if match(r'\s*#\s*(?:include|import)', line):
1770cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block        return
1771cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block    if search(r'[\w.]=[\w.]', line):
1772d0825bca7fe65beaee391d30da42e937db621564Steve Block        error(line_number, 'whitespace/operators', 4,
17730bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch              'Missing spaces around =')
17740bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
1775cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block    # FIXME: It's not ok to have spaces around binary operators like .
17760bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
17770bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # You should always have whitespace around binary operators.
17780bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # Alas, we can't test < or > because they're legitimately used sans spaces
17790bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # (a->b, vector<int> a).  The only time we can tell is a < with no >, and
17800bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # only if it's not template params list spilling into the next line.
1781231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    matched = search(r'[^<>=!\s](==|!=|\+=|-=|\*=|/=|/|\|=|&=|<<=|>>=|<=|>=|\|\||\||&&|>>|<<)[^<>=!\s]', line)
17820bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if not matched:
17830bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # Note that while it seems that the '<[^<]*' term in the following
17840bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # regexp could be simplified to '<.*', which would indeed match
17850bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # the same class of strings, the [^<] means that searching for the
17860bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # regexp takes linear rather than quadratic time.
17870bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        if not search(r'<[^<]*,\s*$', line):  # template params spill
17880bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            matched = search(r'[^<>=!\s](<)[^<>=!\s]([^>]|->)*$', line)
17890bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if matched:
1790d0825bca7fe65beaee391d30da42e937db621564Steve Block        error(line_number, 'whitespace/operators', 3,
17910bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch              'Missing spaces around %s' % matched.group(1))
17920bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
17930bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # There shouldn't be space around unary operators
17940bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    matched = search(r'(!\s|~\s|[\s]--[\s;]|[\s]\+\+[\s;])', line)
17950bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if matched:
1796d0825bca7fe65beaee391d30da42e937db621564Steve Block        error(line_number, 'whitespace/operators', 4,
17970bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch              'Extra space for operator %s' % matched.group(1))
17980bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
17990bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # A pet peeve of mine: no spaces after an if, while, switch, or for
18000bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    matched = search(r' (if\(|for\(|foreach\(|while\(|switch\()', line)
18010bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if matched:
1802d0825bca7fe65beaee391d30da42e937db621564Steve Block        error(line_number, 'whitespace/parens', 5,
18030bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch              'Missing space before ( in %s' % matched.group(1))
18040bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
18050bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # For if/for/foreach/while/switch, the left and right parens should be
18060bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # consistent about how many spaces are inside the parens, and
18070bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # there should either be zero or one spaces inside the parens.
18080bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # We don't want: "if ( foo)" or "if ( foo   )".
18090bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # Exception: "for ( ; foo; bar)" and "for (foo; bar; )" are allowed.
181006ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen    matched = search(r'\b(?P<statement>if|for|foreach|while|switch)\s*\((?P<remainder>.*)$', line)
18110bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if matched:
1812d0825bca7fe65beaee391d30da42e937db621564Steve Block        statement = matched.group('statement')
181306ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen        condition, rest = up_to_unmatched_closing_paren(matched.group('remainder'))
1814d0825bca7fe65beaee391d30da42e937db621564Steve Block        if condition is not None:
1815d0825bca7fe65beaee391d30da42e937db621564Steve Block            condition_match = search(r'(?P<leading>[ ]*)(?P<separator>.).*[^ ]+(?P<trailing>[ ]*)', condition)
1816d0825bca7fe65beaee391d30da42e937db621564Steve Block            if condition_match:
1817d0825bca7fe65beaee391d30da42e937db621564Steve Block                n_leading = len(condition_match.group('leading'))
1818d0825bca7fe65beaee391d30da42e937db621564Steve Block                n_trailing = len(condition_match.group('trailing'))
181906ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen                if n_leading != 0:
182006ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen                    for_exception = statement == 'for' and condition.startswith(' ;')
1821d0825bca7fe65beaee391d30da42e937db621564Steve Block                    if not for_exception:
1822d0825bca7fe65beaee391d30da42e937db621564Steve Block                        error(line_number, 'whitespace/parens', 5,
182306ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen                              'Extra space after ( in %s' % statement)
182406ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen                if n_trailing != 0:
182506ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen                    for_exception = statement == 'for' and condition.endswith('; ')
182606ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen                    if not for_exception:
182706ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen                        error(line_number, 'whitespace/parens', 5,
182806ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen                              'Extra space before ) in %s' % statement)
1829d0825bca7fe65beaee391d30da42e937db621564Steve Block
1830d0825bca7fe65beaee391d30da42e937db621564Steve Block            # Do not check for more than one command in macros
1831f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch            in_preprocessor_directive = match(r'\s*#', line)
1832f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch            if not in_preprocessor_directive and not match(r'((\s*{\s*}?)|(\s*;?))\s*\\?$', rest):
1833d0825bca7fe65beaee391d30da42e937db621564Steve Block                error(line_number, 'whitespace/parens', 4,
1834d0825bca7fe65beaee391d30da42e937db621564Steve Block                      'More than one command on the same line in %s' % statement)
18350bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
18360bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # You should always have a space after a comma (either as fn arg or operator)
18370bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if search(r',[^\s]', line):
1838d0825bca7fe65beaee391d30da42e937db621564Steve Block        error(line_number, 'whitespace/comma', 3,
18390bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch              'Missing space after ,')
18400bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
184106ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen    matched = search(r'^\s*(?P<token1>[a-zA-Z0-9_\*&]+)\s\s+(?P<token2>[a-zA-Z0-9_\*&]+)', line)
184206ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen    if matched:
184306ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen        error(line_number, 'whitespace/declaration', 3,
184406ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen              'Extra space between %s and %s' % (matched.group('token1'), matched.group('token2')))
184506ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen
1846d0825bca7fe65beaee391d30da42e937db621564Steve Block    if file_extension == 'cpp':
18470bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # C++ should have the & or * beside the type not the variable name.
1848dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        matched = match(r'\s*\w+(?<!\breturn|\bdelete)\s+(?P<pointer_operator>\*|\&)\w+', line)
18490bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        if matched:
1850d0825bca7fe65beaee391d30da42e937db621564Steve Block            error(line_number, 'whitespace/declaration', 3,
18510bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                  'Declaration has space between type name and %s in %s' % (matched.group('pointer_operator'), matched.group(0).strip()))
18520bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
1853d0825bca7fe65beaee391d30da42e937db621564Steve Block    elif file_extension == 'c':
18540bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # C Pointer declaration should have the * beside the variable not the type name.
18550bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        matched = search(r'^\s*\w+\*\s+\w+', line)
18560bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        if matched:
1857d0825bca7fe65beaee391d30da42e937db621564Steve Block            error(line_number, 'whitespace/declaration', 3,
18580bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                  'Declaration has space between * and variable name in %s' % matched.group(0).strip())
18590bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
18600bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # Next we will look for issues with function calls.
1861d0825bca7fe65beaee391d30da42e937db621564Steve Block    check_spacing_for_function_call(line, line_number, error)
18620bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
18630bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # Except after an opening paren, you should have spaces before your braces.
18640bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # And since you should never have braces at the beginning of a line, this is
18650bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # an easy test.
18660bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if search(r'[^ ({]{', line):
1867d0825bca7fe65beaee391d30da42e937db621564Steve Block        error(line_number, 'whitespace/braces', 5,
18680bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch              'Missing space before {')
18690bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
18700bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # Make sure '} else {' has spaces.
18710bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if search(r'}else', line):
1872d0825bca7fe65beaee391d30da42e937db621564Steve Block        error(line_number, 'whitespace/braces', 5,
18730bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch              'Missing space before else')
18740bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
18750bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # You shouldn't have spaces before your brackets, except maybe after
18760bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # 'delete []' or 'new char * []'.
18770bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if search(r'\w\s+\[', line) and not search(r'delete\s+\[', line):
1878d0825bca7fe65beaee391d30da42e937db621564Steve Block        error(line_number, 'whitespace/braces', 5,
18790bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch              'Extra space before [')
18800bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
18810bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # You shouldn't have a space before a semicolon at the end of the line.
18820bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # There's a special case for "for" since the style guide allows space before
18830bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # the semicolon there.
18840bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if search(r':\s*;\s*$', line):
1885d0825bca7fe65beaee391d30da42e937db621564Steve Block        error(line_number, 'whitespace/semicolon', 5,
18860bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch              'Semicolon defining empty statement. Use { } instead.')
18870bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    elif search(r'^\s*;\s*$', line):
1888d0825bca7fe65beaee391d30da42e937db621564Steve Block        error(line_number, 'whitespace/semicolon', 5,
18890bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch              'Line contains only semicolon. If this should be an empty statement, '
18900bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch              'use { } instead.')
18910bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    elif (search(r'\s+;\s*$', line) and not search(r'\bfor\b', line)):
1892d0825bca7fe65beaee391d30da42e937db621564Steve Block        error(line_number, 'whitespace/semicolon', 5,
18930bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch              'Extra space before last semicolon. If this should be an empty '
18940bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch              'statement, use { } instead.')
18950bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    elif (search(r'\b(for|while)\s*\(.*\)\s*;\s*$', line)
18960bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch          and line.count('(') == line.count(')')
18970bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch          # Allow do {} while();
18980bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch          and not search(r'}\s*while', line)):
1899d0825bca7fe65beaee391d30da42e937db621564Steve Block        error(line_number, 'whitespace/semicolon', 5,
19000bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch              'Semicolon defining empty statement for this loop. Use { } instead.')
19010bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
19020bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
19030bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdochdef get_previous_non_blank_line(clean_lines, line_number):
19040bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """Return the most recent non-blank line and its line number.
19050bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
19060bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    Args:
19070bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      clean_lines: A CleansedLines instance containing the file contents.
19080bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      line_number: The number of the line to check.
19090bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
19100bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    Returns:
19110bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      A tuple with two elements.  The first element is the contents of the last
19120bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      non-blank line before the current line, or the empty string if this is the
19130bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      first non-blank line.  The second is the line number of that line, or -1
19140bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      if this is the first non-blank line.
19150bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """
19160bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
19170bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    previous_line_number = line_number - 1
19180bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    while previous_line_number >= 0:
19190bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        previous_line = clean_lines.elided[previous_line_number]
19200bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        if not is_blank_line(previous_line):     # if not a blank line...
19210bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            return (previous_line, previous_line_number)
19220bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        previous_line_number -= 1
19230bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    return ('', -1)
19240bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
19250bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
1926d0825bca7fe65beaee391d30da42e937db621564Steve Blockdef check_namespace_indentation(clean_lines, line_number, file_extension, file_state, error):
19270bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """Looks for indentation errors inside of namespaces.
19280bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
19290bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    Args:
19300bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      clean_lines: A CleansedLines instance containing the file.
19310bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      line_number: The number of the line to check.
19320bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      file_extension: The extension (dot not included) of the file.
1933643ca7872b450ea4efacab6188849e5aac2ba161Steve Block      file_state: A _FileState instance which maintains information about
1934643ca7872b450ea4efacab6188849e5aac2ba161Steve Block                  the state of things in the file.
19350bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      error: The function to call with any errors found.
19360bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """
19370bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
19380bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    line = clean_lines.elided[line_number] # Get rid of comments and strings.
19390bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
19400bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    namespace_match = match(r'(?P<namespace_indentation>\s*)namespace\s+\S+\s*{\s*$', line)
19410bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if not namespace_match:
19420bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        return
19430bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
1944cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block    current_indentation_level = len(namespace_match.group('namespace_indentation'))
1945cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block    if current_indentation_level > 0:
1946643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        # Don't warn about an indented namespace if we already warned about indented code.
1947643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        if not file_state.did_inside_namespace_indent_warning():
1948d0825bca7fe65beaee391d30da42e937db621564Steve Block            error(line_number, 'whitespace/indent', 4,
1949643ca7872b450ea4efacab6188849e5aac2ba161Steve Block                  'namespace should never be indented.')
1950cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block        return
1951cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block    looking_for_semicolon = False;
19520bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    line_offset = 0
1953cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block    in_preprocessor_directive = False;
1954cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block    for current_line in clean_lines.elided[line_number + 1:]:
1955cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block        line_offset += 1
1956cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block        if not current_line.strip():
1957cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block            continue
1958cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block        if not current_indentation_level:
1959cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block            if not (in_preprocessor_directive or looking_for_semicolon):
1960643ca7872b450ea4efacab6188849e5aac2ba161Steve Block                if not match(r'\S', current_line) and not file_state.did_inside_namespace_indent_warning():
1961643ca7872b450ea4efacab6188849e5aac2ba161Steve Block                    file_state.set_did_inside_namespace_indent_warning()
1962d0825bca7fe65beaee391d30da42e937db621564Steve Block                    error(line_number + line_offset, 'whitespace/indent', 4,
1963cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block                          'Code inside a namespace should not be indented.')
1964cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block            if in_preprocessor_directive or (current_line.strip()[0] == '#'): # This takes care of preprocessor directive syntax.
1965cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block                in_preprocessor_directive = current_line[-1] == '\\'
1966cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block            else:
1967cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block                looking_for_semicolon = ((current_line.find(';') == -1) and (current_line.strip()[-1] != '}')) or (current_line[-1] == '\\')
1968cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block        else:
1969cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block            looking_for_semicolon = False; # If we have a brace we may not need a semicolon.
1970cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block        current_indentation_level += current_line.count('{') - current_line.count('}')
1971cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block        if current_indentation_level < 0:
1972cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block            break;
19730bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
1974f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch
1975f05b935882198ccf7d81675736e3aeb089c5113aBen Murdochdef check_using_std(clean_lines, line_number, file_state, error):
1976231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    """Looks for 'using std::foo;' statements which should be replaced with 'using namespace std;'.
1977231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
1978231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    Args:
1979231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block      clean_lines: A CleansedLines instance containing the file.
1980231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block      line_number: The number of the line to check.
1981f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch      file_state: A _FileState instance which maintains information about
1982f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch                  the state of things in the file.
1983231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block      error: The function to call with any errors found.
1984231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    """
1985231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
1986231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    # This check doesn't apply to C or Objective-C implementation files.
1987f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch    if file_state.is_c_or_objective_c():
1988231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        return
1989231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
1990231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    line = clean_lines.elided[line_number] # Get rid of comments and strings.
1991231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
1992231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    using_std_match = match(r'\s*using\s+std::(?P<method_name>\S+)\s*;\s*$', line)
1993231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    if not using_std_match:
1994231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        return
1995231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
1996231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    method_name = using_std_match.group('method_name')
1997d0825bca7fe65beaee391d30da42e937db621564Steve Block    error(line_number, 'build/using_std', 4,
1998231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block          "Use 'using namespace std;' instead of 'using std::%s;'." % method_name)
1999231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
2000231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
2001f05b935882198ccf7d81675736e3aeb089c5113aBen Murdochdef check_max_min_macros(clean_lines, line_number, file_state, error):
2002231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    """Looks use of MAX() and MIN() macros that should be replaced with std::max() and std::min().
2003231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
2004231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    Args:
2005231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block      clean_lines: A CleansedLines instance containing the file.
2006231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block      line_number: The number of the line to check.
2007f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch      file_state: A _FileState instance which maintains information about
2008f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch                  the state of things in the file.
2009231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block      error: The function to call with any errors found.
2010231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    """
2011231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
2012231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    # This check doesn't apply to C or Objective-C implementation files.
2013f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch    if file_state.is_c_or_objective_c():
2014231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        return
2015231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
2016231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    line = clean_lines.elided[line_number] # Get rid of comments and strings.
2017231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
2018231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    max_min_macros_search = search(r'\b(?P<max_min_macro>(MAX|MIN))\s*\(', line)
2019231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    if not max_min_macros_search:
2020231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        return
2021231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
2022231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    max_min_macro = max_min_macros_search.group('max_min_macro')
2023231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    max_min_macro_lower = max_min_macro.lower()
2024d0825bca7fe65beaee391d30da42e937db621564Steve Block    error(line_number, 'runtime/max_min_macros', 4,
2025231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block          'Use std::%s() or std::%s<type>() instead of the %s() macro.'
2026231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block          % (max_min_macro_lower, max_min_macro_lower, max_min_macro))
2027231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
2028231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
2029d0825bca7fe65beaee391d30da42e937db621564Steve Blockdef check_switch_indentation(clean_lines, line_number, error):
20300bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """Looks for indentation errors inside of switch statements.
20310bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
20320bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    Args:
20330bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      clean_lines: A CleansedLines instance containing the file.
20340bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      line_number: The number of the line to check.
20350bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      error: The function to call with any errors found.
20360bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """
20370bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
20380bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    line = clean_lines.elided[line_number] # Get rid of comments and strings.
20390bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
20400bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    switch_match = match(r'(?P<switch_indentation>\s*)switch\s*\(.+\)\s*{\s*$', line)
20410bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if not switch_match:
20420bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        return
20430bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
20440bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    switch_indentation = switch_match.group('switch_indentation')
20450bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    inner_indentation = switch_indentation + ' ' * 4
20460bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    line_offset = 0
20470bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    encountered_nested_switch = False
20480bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
20490bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    for current_line in clean_lines.elided[line_number + 1:]:
20500bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        line_offset += 1
20510bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
20520bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # Skip not only empty lines but also those with preprocessor directives.
20530bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        if current_line.strip() == '' or current_line.startswith('#'):
20540bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            continue
20550bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
20560bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        if match(r'\s*switch\s*\(.+\)\s*{\s*$', current_line):
20570bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            # Complexity alarm - another switch statement nested inside the one
20580bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            # that we're currently testing. We'll need to track the extent of
20590bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            # that inner switch if the upcoming label tests are still supposed
20600bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            # to work correctly. Let's not do that; instead, we'll finish
20610bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            # checking this line, and then leave it like that. Assuming the
20620bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            # indentation is done consistently (even if incorrectly), this will
20630bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            # still catch all indentation issues in practice.
20640bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            encountered_nested_switch = True
20650bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
20660bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        current_indentation_match = match(r'(?P<indentation>\s*)(?P<remaining_line>.*)$', current_line);
20670bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        current_indentation = current_indentation_match.group('indentation')
20680bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        remaining_line = current_indentation_match.group('remaining_line')
20690bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
20700bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # End the check at the end of the switch statement.
20710bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        if remaining_line.startswith('}') and current_indentation == switch_indentation:
20720bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            break
20730bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # Case and default branches should not be indented. The regexp also
20740bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # catches single-line cases like "default: break;" but does not trigger
20750bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # on stuff like "Document::Foo();".
20760bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        elif match(r'(default|case\s+.*)\s*:([^:].*)?$', remaining_line):
20770bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            if current_indentation != switch_indentation:
2078d0825bca7fe65beaee391d30da42e937db621564Steve Block                error(line_number + line_offset, 'whitespace/indent', 4,
20790bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                      'A case label should not be indented, but line up with its switch statement.')
20800bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                # Don't throw an error for multiple badly indented labels,
20810bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                # one should be enough to figure out the problem.
20820bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                break
20830bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # We ignore goto labels at the very beginning of a line.
20840bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        elif match(r'\w+\s*:\s*$', remaining_line):
20850bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            continue
20860bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # It's not a goto label, so check if it's indented at least as far as
20870bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # the switch statement plus one more level of indentation.
20880bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        elif not current_indentation.startswith(inner_indentation):
2089d0825bca7fe65beaee391d30da42e937db621564Steve Block            error(line_number + line_offset, 'whitespace/indent', 4,
20900bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                  'Non-label code inside switch statements should be indented.')
20910bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            # Don't throw an error for multiple badly indented statements,
20920bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            # one should be enough to figure out the problem.
20930bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            break
20940bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
20950bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        if encountered_nested_switch:
20960bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            break
20970bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
20980bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
2099d0825bca7fe65beaee391d30da42e937db621564Steve Blockdef check_braces(clean_lines, line_number, error):
21000bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """Looks for misplaced braces (e.g. at the end of line).
21010bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
21020bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    Args:
21030bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      clean_lines: A CleansedLines instance containing the file.
21040bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      line_number: The number of the line to check.
21050bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      error: The function to call with any errors found.
21060bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """
21070bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
21080bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    line = clean_lines.elided[line_number] # Get rid of comments and strings.
21090bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
21100bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if match(r'\s*{\s*$', line):
21110bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # We allow an open brace to start a line in the case where someone
21120bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # is using braces for function definition or in a block to
21130bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # explicitly create a new scope, which is commonly used to control
21140bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # the lifetime of stack-allocated variables.  We don't detect this
21150bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # perfectly: we just don't complain if the last non-whitespace
21160bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # character on the previous non-blank line is ';', ':', '{', '}',
21170bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # ')', or ') const' and doesn't begin with 'if|for|while|switch|else'.
21180bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # We also allow '#' for #endif and '=' for array initialization.
21190bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        previous_line = get_previous_non_blank_line(clean_lines, line_number)[0]
21200bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        if ((not search(r'[;:}{)=]\s*$|\)\s*const\s*$', previous_line)
21210bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch             or search(r'\b(if|for|foreach|while|switch|else)\b', previous_line))
21220bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            and previous_line.find('#') < 0):
2123d0825bca7fe65beaee391d30da42e937db621564Steve Block            error(line_number, 'whitespace/braces', 4,
21240bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                  'This { should be at the end of the previous line')
21250bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    elif (search(r'\)\s*(const\s*)?{\s*$', line)
21260bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch          and line.count('(') == line.count(')')
2127643ca7872b450ea4efacab6188849e5aac2ba161Steve Block          and not search(r'\b(if|for|foreach|while|switch)\b', line)
2128643ca7872b450ea4efacab6188849e5aac2ba161Steve Block          and not match(r'\s+[A-Z_][A-Z_0-9]+\b', line)):
2129d0825bca7fe65beaee391d30da42e937db621564Steve Block        error(line_number, 'whitespace/braces', 4,
21300bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch              'Place brace on its own line for function definitions.')
21310bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
21320bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if (match(r'\s*}\s*(else\s*({\s*)?)?$', line) and line_number > 1):
21330bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # We check if a closed brace has started a line to see if a
21340bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # one line control statement was previous.
21350bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        previous_line = clean_lines.elided[line_number - 2]
213681bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch        last_open_brace = previous_line.rfind('{')
213781bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch        if (last_open_brace != -1 and previous_line.find('}', last_open_brace) == -1
21380bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            and search(r'\b(if|for|foreach|while|else)\b', previous_line)):
2139d0825bca7fe65beaee391d30da42e937db621564Steve Block            error(line_number, 'whitespace/braces', 4,
21400bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                  'One line control clauses should not use braces.')
21410bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
21420bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # An else clause should be on the same line as the preceding closing brace.
21430bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if match(r'\s*else\s*', line):
21440bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        previous_line = get_previous_non_blank_line(clean_lines, line_number)[0]
21450bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        if match(r'\s*}\s*$', previous_line):
2146d0825bca7fe65beaee391d30da42e937db621564Steve Block            error(line_number, 'whitespace/newline', 4,
21470bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                  'An else should appear on the same line as the preceding }')
21480bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
21490bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # Likewise, an else should never have the else clause on the same line
21500bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if search(r'\belse [^\s{]', line) and not search(r'\belse if\b', line):
2151d0825bca7fe65beaee391d30da42e937db621564Steve Block        error(line_number, 'whitespace/newline', 4,
21520bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch              'Else clause should never be on same line as else (use 2 lines)')
21530bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
21540bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # In the same way, a do/while should never be on one line
21550bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if match(r'\s*do [^\s{]', line):
2156d0825bca7fe65beaee391d30da42e937db621564Steve Block        error(line_number, 'whitespace/newline', 4,
21570bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch              'do/while clauses should not be on a single line')
21580bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
21590bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # Braces shouldn't be followed by a ; unless they're defining a struct
21600bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # or initializing an array.
21610bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # We can't tell in general, but we can for some common cases.
21620bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    previous_line_number = line_number
21630bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    while True:
21640bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        (previous_line, previous_line_number) = get_previous_non_blank_line(clean_lines, previous_line_number)
21650bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        if match(r'\s+{.*}\s*;', line) and not previous_line.count(';'):
21660bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            line = previous_line + line
21670bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        else:
21680bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            break
21690bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if (search(r'{.*}\s*;', line)
21700bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        and line.count('{') == line.count('}')
21710bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        and not search(r'struct|class|enum|\s*=\s*{', line)):
2172d0825bca7fe65beaee391d30da42e937db621564Steve Block        error(line_number, 'readability/braces', 4,
21730bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch              "You don't need a ; after a }")
21740bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
21750bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
2176d0825bca7fe65beaee391d30da42e937db621564Steve Blockdef check_exit_statement_simplifications(clean_lines, line_number, error):
21770bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """Looks for else or else-if statements that should be written as an
21780bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if statement when the prior if concludes with a return, break, continue or
21790bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    goto statement.
21800bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
21810bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    Args:
21820bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      clean_lines: A CleansedLines instance containing the file.
21830bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      line_number: The number of the line to check.
21840bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      error: The function to call with any errors found.
21850bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """
21860bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
21870bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    line = clean_lines.elided[line_number] # Get rid of comments and strings.
21880bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
21890bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    else_match = match(r'(?P<else_indentation>\s*)(\}\s*)?else(\s+if\s*\(|(?P<else>\s*(\{\s*)?\Z))', line)
21900bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if not else_match:
21910bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        return
21920bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
21930bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    else_indentation = else_match.group('else_indentation')
21940bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    inner_indentation = else_indentation + ' ' * 4
21950bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
21960bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    previous_lines = clean_lines.elided[:line_number]
21970bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    previous_lines.reverse()
21980bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    line_offset = 0
21990bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    encountered_exit_statement = False
22000bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
22010bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    for current_line in previous_lines:
22020bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        line_offset -= 1
22030bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
22040bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # Skip not only empty lines but also those with preprocessor directives
22050bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # and goto labels.
22060bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        if current_line.strip() == '' or current_line.startswith('#') or match(r'\w+\s*:\s*$', current_line):
22070bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            continue
22080bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
22090bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # Skip lines with closing braces on the original indentation level.
22100bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # Even though the styleguide says they should be on the same line as
22110bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # the "else if" statement, we also want to check for instances where
22120bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # the current code does not comply with the coding style. Thus, ignore
22130bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # these lines and proceed to the line before that.
22140bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        if current_line == else_indentation + '}':
22150bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            continue
22160bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
22170bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        current_indentation_match = match(r'(?P<indentation>\s*)(?P<remaining_line>.*)$', current_line);
22180bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        current_indentation = current_indentation_match.group('indentation')
22190bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        remaining_line = current_indentation_match.group('remaining_line')
22200bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
22210bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # As we're going up the lines, the first real statement to encounter
22220bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # has to be an exit statement (return, break, continue or goto) -
22230bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # otherwise, this check doesn't apply.
22240bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        if not encountered_exit_statement:
22250bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            # We only want to find exit statements if they are on exactly
22260bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            # the same level of indentation as expected from the code inside
22270bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            # the block. If the indentation doesn't strictly match then we
22280bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            # might have a nested if or something, which must be ignored.
22290bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            if current_indentation != inner_indentation:
22300bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                break
22310bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            if match(r'(return(\W+.*)|(break|continue)\s*;|goto\s*\w+;)$', remaining_line):
22320bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                encountered_exit_statement = True
22330bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                continue
22340bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            break
22350bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
22360bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # When code execution reaches this point, we've found an exit statement
22370bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # as last statement of the previous block. Now we only need to make
22380bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # sure that the block belongs to an "if", then we can throw an error.
22390bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
22400bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # Skip lines with opening braces on the original indentation level,
22410bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # similar to the closing braces check above. ("if (condition)\n{")
22420bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        if current_line == else_indentation + '{':
22430bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            continue
22440bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
22450bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # Skip everything that's further indented than our "else" or "else if".
22460bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        if current_indentation.startswith(else_indentation) and current_indentation != else_indentation:
22470bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            continue
22480bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
22490bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # So we've got a line with same (or less) indentation. Is it an "if"?
22500bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # If yes: throw an error. If no: don't throw an error.
22510bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # Whatever the outcome, this is the end of our loop.
22520bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        if match(r'if\s*\(', remaining_line):
22530bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            if else_match.start('else') != -1:
2254d0825bca7fe65beaee391d30da42e937db621564Steve Block                error(line_number + line_offset, 'readability/control_flow', 4,
22550bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                      'An else statement can be removed when the prior "if" '
22560bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                      'concludes with a return, break, continue or goto statement.')
22570bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            else:
2258d0825bca7fe65beaee391d30da42e937db621564Steve Block                error(line_number + line_offset, 'readability/control_flow', 4,
22590bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                      'An else if statement should be written as an if statement '
22600bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                      'when the prior "if" concludes with a return, break, '
22610bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                      'continue or goto statement.')
22620bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        break
22630bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
22640bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
22650bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdochdef replaceable_check(operator, macro, line):
22660bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """Determine whether a basic CHECK can be replaced with a more specific one.
22670bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
22680bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    For example suggest using CHECK_EQ instead of CHECK(a == b) and
22690bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    similarly for CHECK_GE, CHECK_GT, CHECK_LE, CHECK_LT, CHECK_NE.
22700bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
22710bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    Args:
22720bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      operator: The C++ operator used in the CHECK.
22730bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      macro: The CHECK or EXPECT macro being called.
22740bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      line: The current source line.
22750bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
22760bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    Returns:
22770bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      True if the CHECK can be replaced with a more specific one.
22780bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """
22790bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
22800bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # This matches decimal and hex integers, strings, and chars (in that order).
22810bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    match_constant = r'([-+]?(\d+|0[xX][0-9a-fA-F]+)[lLuU]{0,3}|".*"|\'.*\')'
22820bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
22830bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # Expression to match two sides of the operator with something that
22840bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # looks like a literal, since CHECK(x == iterator) won't compile.
22850bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # This means we can't catch all the cases where a more specific
22860bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # CHECK is possible, but it's less annoying than dealing with
22870bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # extraneous warnings.
22880bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    match_this = (r'\s*' + macro + r'\((\s*' +
22890bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                  match_constant + r'\s*' + operator + r'[^<>].*|'
22900bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                  r'.*[^<>]' + operator + r'\s*' + match_constant +
22910bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                  r'\s*\))')
22920bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
22930bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # Don't complain about CHECK(x == NULL) or similar because
22940bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # CHECK_EQ(x, NULL) won't compile (requires a cast).
22950bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # Also, don't complain about more complex boolean expressions
22960bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # involving && or || such as CHECK(a == b || c == d).
22970bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    return match(match_this, line) and not search(r'NULL|&&|\|\|', line)
22980bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
22990bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
2300d0825bca7fe65beaee391d30da42e937db621564Steve Blockdef check_check(clean_lines, line_number, error):
23010bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """Checks the use of CHECK and EXPECT macros.
23020bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
23030bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    Args:
23040bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      clean_lines: A CleansedLines instance containing the file.
23050bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      line_number: The number of the line to check.
23060bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      error: The function to call with any errors found.
23070bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """
23080bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
23090bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # Decide the set of replacement macros that should be suggested
23100bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    raw_lines = clean_lines.raw_lines
23110bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    current_macro = ''
23120bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    for macro in _CHECK_MACROS:
23130bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        if raw_lines[line_number].find(macro) >= 0:
23140bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            current_macro = macro
23150bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            break
23160bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if not current_macro:
23170bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # Don't waste time here if line doesn't contain 'CHECK' or 'EXPECT'
23180bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        return
23190bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
23200bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    line = clean_lines.elided[line_number]        # get rid of comments and strings
23210bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
23220bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # Encourage replacing plain CHECKs with CHECK_EQ/CHECK_NE/etc.
23230bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    for operator in ['==', '!=', '>=', '>', '<=', '<']:
23240bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        if replaceable_check(operator, current_macro, line):
2325d0825bca7fe65beaee391d30da42e937db621564Steve Block            error(line_number, 'readability/check', 2,
23260bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                  'Consider using %s instead of %s(a %s b)' % (
23270bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                      _CHECK_REPLACEMENT[current_macro][operator],
23280bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                      current_macro, operator))
23290bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            break
23300bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
23310bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
2332d0825bca7fe65beaee391d30da42e937db621564Steve Blockdef check_for_comparisons_to_zero(clean_lines, line_number, error):
23330bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # Get the line without comments and strings.
23340bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    line = clean_lines.elided[line_number]
23350bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
23360bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # Include NULL here so that users don't have to convert NULL to 0 first and then get this error.
23370bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if search(r'[=!]=\s*(NULL|0|true|false)\W', line) or search(r'\W(NULL|0|true|false)\s*[=!]=', line):
2338d0825bca7fe65beaee391d30da42e937db621564Steve Block        error(line_number, 'readability/comparison_to_zero', 5,
23390bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch              'Tests for true/false, null/non-null, and zero/non-zero should all be done without equality comparisons.')
23400bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
23410bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
2342f05b935882198ccf7d81675736e3aeb089c5113aBen Murdochdef check_for_null(clean_lines, line_number, file_state, error):
23430bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # This check doesn't apply to C or Objective-C implementation files.
2344f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch    if file_state.is_c_or_objective_c():
23450bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        return
23460bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
23470bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    line = clean_lines.elided[line_number]
2348d0825bca7fe65beaee391d30da42e937db621564Steve Block
23495af96e2c7b73ebc627c6894727826a7576d31758Leon Clarke    # Don't warn about NULL usage in g_*(). See Bug 32858 and 39372.
23505af96e2c7b73ebc627c6894727826a7576d31758Leon Clarke    if search(r'\bg(_[a-z]+)+\b', line):
23515af96e2c7b73ebc627c6894727826a7576d31758Leon Clarke        return
23525af96e2c7b73ebc627c6894727826a7576d31758Leon Clarke
23535af96e2c7b73ebc627c6894727826a7576d31758Leon Clarke    # Don't warn about NULL usage in gst_*_many(). See Bug 39740
23545af96e2c7b73ebc627c6894727826a7576d31758Leon Clarke    if search(r'\bgst_\w+_many\b', line):
2355d0825bca7fe65beaee391d30da42e937db621564Steve Block        return
2356d0825bca7fe65beaee391d30da42e937db621564Steve Block
2357692e5dbf12901edacf14812a6fae25462920af42Steve Block    # Don't warn about NULL usage in g_str{join,concat}(). See Bug 34834
2358692e5dbf12901edacf14812a6fae25462920af42Steve Block    if search(r'\bg_str(join|concat)\b', line):
2359692e5dbf12901edacf14812a6fae25462920af42Steve Block        return
2360692e5dbf12901edacf14812a6fae25462920af42Steve Block
23610617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen    # Don't warn about NULL usage in gdk_pixbuf_save_to_*{join,concat}(). See Bug 43090.
23620617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen    if search(r'\bgdk_pixbuf_save_to\w+\b', line):
23630617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen        return
23640617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen
2365cad810f21b803229eb11403f9209855525a25d57Steve Block    # Don't warn about NULL usage in gtk_widget_style_get(). See Bug 51758.
2366cad810f21b803229eb11403f9209855525a25d57Steve Block    if search(r'\bgtk_widget_style_get\(\w+\b', line):
2367cad810f21b803229eb11403f9209855525a25d57Steve Block        return
2368cad810f21b803229eb11403f9209855525a25d57Steve Block
23690bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if search(r'\bNULL\b', line):
2370d0825bca7fe65beaee391d30da42e937db621564Steve Block        error(line_number, 'readability/null', 5, 'Use 0 instead of NULL.')
23710bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        return
23720bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
23730bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    line = clean_lines.raw_lines[line_number]
23740bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # See if NULL occurs in any comments in the line. If the search for NULL using the raw line
23750bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # matches, then do the check with strings collapsed to avoid giving errors for
23760bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # NULLs occurring in strings.
23770bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if search(r'\bNULL\b', line) and search(r'\bNULL\b', CleansedLines.collapse_strings(line)):
23782fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        error(line_number, 'readability/null', 4, 'Use 0 or null instead of NULL (even in *comments*).')
23790bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
23800bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdochdef get_line_width(line):
23810bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """Determines the width of the line in column positions.
23820bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
23830bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    Args:
23840bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      line: A string, which may be a Unicode string.
23850bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
23860bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    Returns:
23870bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      The width of the line in column positions, accounting for Unicode
23880bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      combining characters and wide characters.
23890bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """
23900bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if isinstance(line, unicode):
23910bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        width = 0
23920bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        for c in unicodedata.normalize('NFC', line):
23930bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            if unicodedata.east_asian_width(c) in ('W', 'F'):
23940bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                width += 2
23950bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            elif not unicodedata.combining(c):
23960bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                width += 1
23970bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        return width
23980bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    return len(line)
23990bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
24000bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
24010617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsendef check_style(clean_lines, line_number, file_extension, class_state, file_state, error):
24020bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """Checks rules from the 'C++ style rules' section of cppguide.html.
24030bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
24040bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    Most of these rules are hard to test (naming, comment style), but we
24050bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    do what we can.  In particular we check for 4-space indents, line lengths,
24060bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    tab usage, spaces inside code, etc.
24070bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
24080bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    Args:
24090bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      clean_lines: A CleansedLines instance containing the file.
24100bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      line_number: The number of the line to check.
24110bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      file_extension: The extension (without the dot) of the filename.
24120617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen      class_state: A _ClassState instance which maintains information about
24130617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen                   the current stack of nested class declarations being parsed.
2414643ca7872b450ea4efacab6188849e5aac2ba161Steve Block      file_state: A _FileState instance which maintains information about
2415643ca7872b450ea4efacab6188849e5aac2ba161Steve Block                  the state of things in the file.
24160bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      error: The function to call with any errors found.
24170bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """
24180bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
24190bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    raw_lines = clean_lines.raw_lines
24200bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    line = raw_lines[line_number]
24210bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
24220bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if line.find('\t') != -1:
2423d0825bca7fe65beaee391d30da42e937db621564Steve Block        error(line_number, 'whitespace/tab', 1,
24240bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch              'Tab found; better to use spaces')
24250bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
24260bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # One or three blank spaces at the beginning of the line is weird; it's
24270bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # hard to reconcile that with 4-space indents.
24280bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # NOTE: here are the conditions rob pike used for his tests.  Mine aren't
24290bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # as sophisticated, but it may be worth becoming so:  RLENGTH==initial_spaces
24300bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # if(RLENGTH > 20) complain = 0;
24310bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # if(match($0, " +(error|private|public|protected):")) complain = 0;
24320bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # if(match(prev, "&& *$")) complain = 0;
24330bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # if(match(prev, "\\|\\| *$")) complain = 0;
24340bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # if(match(prev, "[\",=><] *$")) complain = 0;
24350bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # if(match($0, " <<")) complain = 0;
24360bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # if(match(prev, " +for \\(")) complain = 0;
24370bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # if(prevodd && match(prevprev, " +for \\(")) complain = 0;
24380bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    initial_spaces = 0
24390bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    cleansed_line = clean_lines.elided[line_number]
24400bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    while initial_spaces < len(line) and line[initial_spaces] == ' ':
24410bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        initial_spaces += 1
24420bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if line and line[-1].isspace():
2443d0825bca7fe65beaee391d30da42e937db621564Steve Block        error(line_number, 'whitespace/end_of_line', 4,
24440bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch              'Line ends in whitespace.  Consider deleting these extra spaces.')
24450bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # There are certain situations we allow one space, notably for labels
24460bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    elif ((initial_spaces >= 1 and initial_spaces <= 3)
24470bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch          and not match(r'\s*\w+\s*:\s*$', cleansed_line)):
2448d0825bca7fe65beaee391d30da42e937db621564Steve Block        error(line_number, 'whitespace/indent', 3,
24490bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch              'Weird number of spaces at line-start.  '
24500bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch              'Are you using a 4-space indent?')
24510bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # Labels should always be indented at least one space.
24520bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    elif not initial_spaces and line[:2] != '//':
24530bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        label_match = match(r'(?P<label>[^:]+):\s*$', line)
24540bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
24550bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        if label_match:
24560bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            label = label_match.group('label')
24570bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            # Only throw errors for stuff that is definitely not a goto label,
24580bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            # because goto labels can in fact occur at the start of the line.
24590bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            if label in ['public', 'private', 'protected'] or label.find(' ') != -1:
2460d0825bca7fe65beaee391d30da42e937db621564Steve Block                error(line_number, 'whitespace/labels', 4,
24610bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                      'Labels should always be indented at least one space.  '
24620bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                      'If this is a member-initializer list in a constructor, '
24630bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                      'the colon should be on the line after the definition header.')
24640bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
24650bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if (cleansed_line.count(';') > 1
24660bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # for loops are allowed two ;'s (and may run over two lines).
24670bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        and cleansed_line.find('for') == -1
24680bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        and (get_previous_non_blank_line(clean_lines, line_number)[0].find('for') == -1
24690bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch             or get_previous_non_blank_line(clean_lines, line_number)[0].find(';') != -1)
24700bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # It's ok to have many commands in a switch case that fits in 1 line
24710bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        and not ((cleansed_line.find('case ') != -1
24720bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                  or cleansed_line.find('default:') != -1)
2473d0825bca7fe65beaee391d30da42e937db621564Steve Block                 and cleansed_line.find('break;') != -1)
24740617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen        # Also it's ok to have many commands in trivial single-line accessors in class definitions.
24750617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen        and not (match(r'.*\(.*\).*{.*.}', line)
24760617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen                 and class_state.classinfo_stack
24770617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen                 and line.count('{') == line.count('}'))
2478d0825bca7fe65beaee391d30da42e937db621564Steve Block        and not cleansed_line.startswith('#define ')):
2479d0825bca7fe65beaee391d30da42e937db621564Steve Block        error(line_number, 'whitespace/newline', 4,
24800bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch              'More than one command on the same line')
24810bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
24820bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if cleansed_line.strip().endswith('||') or cleansed_line.strip().endswith('&&'):
2483d0825bca7fe65beaee391d30da42e937db621564Steve Block        error(line_number, 'whitespace/operators', 4,
24840bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch              'Boolean expressions that span multiple lines should have their '
24850bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch              'operators on the left side of the line instead of the right side.')
24860bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
24870bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # Some more style checks
2488d0825bca7fe65beaee391d30da42e937db621564Steve Block    check_namespace_indentation(clean_lines, line_number, file_extension, file_state, error)
2489f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch    check_using_std(clean_lines, line_number, file_state, error)
2490f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch    check_max_min_macros(clean_lines, line_number, file_state, error)
2491d0825bca7fe65beaee391d30da42e937db621564Steve Block    check_switch_indentation(clean_lines, line_number, error)
2492d0825bca7fe65beaee391d30da42e937db621564Steve Block    check_braces(clean_lines, line_number, error)
2493d0825bca7fe65beaee391d30da42e937db621564Steve Block    check_exit_statement_simplifications(clean_lines, line_number, error)
2494d0825bca7fe65beaee391d30da42e937db621564Steve Block    check_spacing(file_extension, clean_lines, line_number, error)
2495d0825bca7fe65beaee391d30da42e937db621564Steve Block    check_check(clean_lines, line_number, error)
2496d0825bca7fe65beaee391d30da42e937db621564Steve Block    check_for_comparisons_to_zero(clean_lines, line_number, error)
2497f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch    check_for_null(clean_lines, line_number, file_state, error)
24980bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
24990bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
25000bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch_RE_PATTERN_INCLUDE_NEW_STYLE = re.compile(r'#include +"[^/]+\.h"')
25010bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch_RE_PATTERN_INCLUDE = re.compile(r'^\s*#\s*include\s*([<"])([^>"]*)[>"].*$')
25020bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch# Matches the first component of a filename delimited by -s and _s. That is:
25030bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch#  _RE_FIRST_COMPONENT.match('foo').group(0) == 'foo'
25040bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch#  _RE_FIRST_COMPONENT.match('foo.cpp').group(0) == 'foo'
25050bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch#  _RE_FIRST_COMPONENT.match('foo-bar_baz.cpp').group(0) == 'foo'
25060bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch#  _RE_FIRST_COMPONENT.match('foo_bar-baz.cpp').group(0) == 'foo'
25070bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch_RE_FIRST_COMPONENT = re.compile(r'^[^-_.]+')
25080bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
25090bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
25100bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdochdef _drop_common_suffixes(filename):
25110bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """Drops common suffixes like _test.cpp or -inl.h from filename.
25120bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
25130bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    For example:
25140bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      >>> _drop_common_suffixes('foo/foo-inl.h')
25150bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      'foo/foo'
25160bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      >>> _drop_common_suffixes('foo/bar/foo.cpp')
25170bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      'foo/bar/foo'
25180bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      >>> _drop_common_suffixes('foo/foo_internal.h')
25190bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      'foo/foo'
25200bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      >>> _drop_common_suffixes('foo/foo_unusualinternal.h')
25210bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      'foo/foo_unusualinternal'
25220bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
25230bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    Args:
25240bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      filename: The input filename.
25250bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
25260bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    Returns:
25270bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      The filename with the common suffix removed.
25280bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """
25290bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    for suffix in ('test.cpp', 'regtest.cpp', 'unittest.cpp',
25300bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                   'inl.h', 'impl.h', 'internal.h'):
25310bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        if (filename.endswith(suffix) and len(filename) > len(suffix)
25320bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            and filename[-len(suffix) - 1] in ('-', '_')):
25330bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            return filename[:-len(suffix) - 1]
25340bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    return os.path.splitext(filename)[0]
25350bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
25360bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
25370bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdochdef _classify_include(filename, include, is_system, include_state):
25380bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """Figures out what kind of header 'include' is.
25390bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
25400bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    Args:
25410bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      filename: The current file cpp_style is running over.
25420bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      include: The path to a #included file.
25430bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      is_system: True if the #include used <> rather than "".
25440bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      include_state: An _IncludeState instance in which the headers are inserted.
25450bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
25460bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    Returns:
25470bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      One of the _XXX_HEADER constants.
25480bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
25490bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    For example:
25500bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      >>> _classify_include('foo.cpp', 'config.h', False)
25510bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      _CONFIG_HEADER
25520bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      >>> _classify_include('foo.cpp', 'foo.h', False)
25530bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      _PRIMARY_HEADER
25540bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      >>> _classify_include('foo.cpp', 'bar.h', False)
25550bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      _OTHER_HEADER
25560bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """
25570bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
25580bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # If it is a system header we know it is classified as _OTHER_HEADER.
25590bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if is_system:
25600bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        return _OTHER_HEADER
25610bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
25620bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # If the include is named config.h then this is WebCore/config.h.
25630bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if include == "config.h":
25640bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        return _CONFIG_HEADER
25650bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
25660bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # There cannot be primary includes in header files themselves. Only an
25670bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # include exactly matches the header filename will be is flagged as
25680bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # primary, so that it triggers the "don't include yourself" check.
25690bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if filename.endswith('.h') and filename != include:
25700bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        return _OTHER_HEADER;
25710bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
2572d0825bca7fe65beaee391d30da42e937db621564Steve Block    # Qt's moc files do not follow the naming and ordering rules, so they should be skipped
2573d0825bca7fe65beaee391d30da42e937db621564Steve Block    if include.startswith('moc_') and include.endswith('.cpp'):
2574d0825bca7fe65beaee391d30da42e937db621564Steve Block        return _MOC_HEADER
2575d0825bca7fe65beaee391d30da42e937db621564Steve Block
2576d0825bca7fe65beaee391d30da42e937db621564Steve Block    if include.endswith('.moc'):
2577d0825bca7fe65beaee391d30da42e937db621564Steve Block        return _MOC_HEADER
2578d0825bca7fe65beaee391d30da42e937db621564Steve Block
25790bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # If the target file basename starts with the include we're checking
25800bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # then we consider it the primary header.
25810bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    target_base = FileInfo(filename).base_name()
25820bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    include_base = FileInfo(include).base_name()
25830bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
25840bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # If we haven't encountered a primary header, then be lenient in checking.
2585643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    if not include_state.visited_primary_section() and target_base.find(include_base) != -1:
25860bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        return _PRIMARY_HEADER
25870bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # If we already encountered a primary header, perform a strict comparison.
25880bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # In case the two filename bases are the same then the above lenient check
25890bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # probably was a false positive.
25900bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    elif include_state.visited_primary_section() and target_base == include_base:
2591d0825bca7fe65beaee391d30da42e937db621564Steve Block        if include == "ResourceHandleWin.h":
2592d0825bca7fe65beaee391d30da42e937db621564Steve Block            # FIXME: Thus far, we've only seen one example of these, but if we
2593d0825bca7fe65beaee391d30da42e937db621564Steve Block            # start to see more, please consider generalizing this check
2594d0825bca7fe65beaee391d30da42e937db621564Steve Block            # somehow.
2595d0825bca7fe65beaee391d30da42e937db621564Steve Block            return _OTHER_HEADER
25960bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        return _PRIMARY_HEADER
25970bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
25980bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    return _OTHER_HEADER
25990bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
26000bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
26012daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdochdef _does_primary_header_exist(filename):
26022daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    """Return a primary header file name for a file, or empty string
26032daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    if the file is not source file or primary header does not exist.
26042daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    """
26052daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    fileinfo = FileInfo(filename)
26062daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    if not fileinfo.is_source():
26072daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        return False
26082daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    primary_header = fileinfo.no_extension() + ".h"
26092daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    return os.path.isfile(primary_header)
26102daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch
26112daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch
2612d0825bca7fe65beaee391d30da42e937db621564Steve Blockdef check_include_line(filename, file_extension, clean_lines, line_number, include_state, error):
26130bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """Check rules that are applicable to #include lines.
26140bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
26150bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    Strings on #include lines are NOT removed from elided line, to make
26160bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    certain tasks easier. However, to prevent false positives, checks
26170bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    applicable to #include lines in CheckLanguage must be put here.
26180bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
26190bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    Args:
26200bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      filename: The name of the current file.
2621d0825bca7fe65beaee391d30da42e937db621564Steve Block      file_extension: The current file extension, without the leading dot.
26220bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      clean_lines: A CleansedLines instance containing the file.
26230bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      line_number: The number of the line to check.
26240bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      include_state: An _IncludeState instance in which the headers are inserted.
26250bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      error: The function to call with any errors found.
26260bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """
26278a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block    # FIXME: For readability or as a possible optimization, consider
26288a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block    #        exiting early here by checking whether the "build/include"
26298a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block    #        category should be checked for the given filename.  This
26308a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block    #        may involve having the error handler classes expose a
26318a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block    #        should_check() method, in addition to the usual __call__
26328a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block    #        method.
26330bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    line = clean_lines.lines[line_number]
26340bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
26350bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    matched = _RE_PATTERN_INCLUDE.search(line)
26360bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if not matched:
26370bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        return
26380bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
26390bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    include = matched.group(2)
26400bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    is_system = (matched.group(1) == '<')
26410bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
26420bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # Look for any of the stream classes that are part of standard C++.
26430bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if match(r'(f|ind|io|i|o|parse|pf|stdio|str|)?stream$', include):
26448a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        error(line_number, 'readability/streams', 3,
26458a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block              'Streams are highly discouraged.')
26460bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
26470bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # Look for specific includes to fix.
26480bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if include.startswith('wtf/') and not is_system:
2649d0825bca7fe65beaee391d30da42e937db621564Steve Block        error(line_number, 'build/include', 4,
26500bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch              'wtf includes should be <wtf/file.h> instead of "wtf/file.h".')
26510bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
26520bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    duplicate_header = include in include_state
26530bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if duplicate_header:
2654d0825bca7fe65beaee391d30da42e937db621564Steve Block        error(line_number, 'build/include', 4,
26550bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch              '"%s" already included at %s:%s' %
26560bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch              (include, filename, include_state[include]))
26570bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    else:
26580bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        include_state[include] = line_number
26590bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
26600bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    header_type = _classify_include(filename, include, is_system, include_state)
26612daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    primary_header_exists = _does_primary_header_exist(filename)
26620bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    include_state.header_types[line_number] = header_type
26630bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
26640bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # Only proceed if this isn't a duplicate header.
26650bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if duplicate_header:
26660bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        return
26670bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
26680bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # We want to ensure that headers appear in the right order:
26690bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # 1) for implementation files: config.h, primary header, blank line, alphabetically sorted
26700bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # 2) for header files: alphabetically sorted
26710bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # The include_state object keeps track of the last type seen
26720bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # and complains if the header types are out of order or missing.
26732daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    error_message = include_state.check_next_include_order(header_type,
26742daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch                                                           file_extension == "h",
26752daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch                                                           primary_header_exists)
26760bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
26770bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # Check to make sure we have a blank line after primary header.
26780bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if not error_message and header_type == _PRIMARY_HEADER:
26790bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch         next_line = clean_lines.raw_lines[line_number + 1]
26800bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch         if not is_blank_line(next_line):
2681d0825bca7fe65beaee391d30da42e937db621564Steve Block            error(line_number, 'build/include_order', 4,
26820bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                  'You should add a blank line after implementation file\'s own header.')
26830bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
26840bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # Check to make sure all headers besides config.h and the primary header are
2685d0825bca7fe65beaee391d30da42e937db621564Steve Block    # alphabetically sorted. Skip Qt's moc files.
26860bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if not error_message and header_type == _OTHER_HEADER:
26870bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch         previous_line_number = line_number - 1;
26880bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch         previous_line = clean_lines.lines[previous_line_number]
26890bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch         previous_match = _RE_PATTERN_INCLUDE.search(previous_line)
26900bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch         while (not previous_match and previous_line_number > 0
26910bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                and not search(r'\A(#if|#ifdef|#ifndef|#else|#elif|#endif)', previous_line)):
26920bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            previous_line_number -= 1;
26930bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            previous_line = clean_lines.lines[previous_line_number]
26940bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            previous_match = _RE_PATTERN_INCLUDE.search(previous_line)
26950bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch         if previous_match:
26960bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            previous_header_type = include_state.header_types[previous_line_number]
26970bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            if previous_header_type == _OTHER_HEADER and previous_line.strip() > line.strip():
2698d0825bca7fe65beaee391d30da42e937db621564Steve Block                error(line_number, 'build/include_order', 4,
26990bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                      'Alphabetical sorting problem.')
27000bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
27010bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if error_message:
2702d0825bca7fe65beaee391d30da42e937db621564Steve Block        if file_extension == 'h':
2703d0825bca7fe65beaee391d30da42e937db621564Steve Block            error(line_number, 'build/include_order', 4,
27040bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                  '%s Should be: alphabetically sorted.' %
27050bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                  error_message)
27060bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        else:
2707d0825bca7fe65beaee391d30da42e937db621564Steve Block            error(line_number, 'build/include_order', 4,
27080bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                  '%s Should be: config.h, primary header, blank line, and then alphabetically sorted.' %
27090bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                  error_message)
27100bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
27110bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
27120bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdochdef check_language(filename, clean_lines, line_number, file_extension, include_state,
2713f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch                   file_state, error):
27140bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """Checks rules from the 'C++ language rules' section of cppguide.html.
27150bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
27160bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    Some of these rules are hard to test (function overloading, using
27170bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    uint32 inappropriately), but we do the best we can.
27180bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
27190bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    Args:
27200bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      filename: The name of the current file.
27210bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      clean_lines: A CleansedLines instance containing the file.
27220bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      line_number: The number of the line to check.
27230bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      file_extension: The extension (without the dot) of the filename.
27240bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      include_state: An _IncludeState instance in which the headers are inserted.
2725f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch      file_state: A _FileState instance which maintains information about
2726f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch                  the state of things in the file.
27270bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      error: The function to call with any errors found.
27280bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """
27290bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # If the line is empty or consists of entirely a comment, no need to
27300bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # check it.
27310bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    line = clean_lines.elided[line_number]
27320bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if not line:
27330bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        return
27340bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
27350bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    matched = _RE_PATTERN_INCLUDE.search(line)
27360bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if matched:
2737d0825bca7fe65beaee391d30da42e937db621564Steve Block        check_include_line(filename, file_extension, clean_lines, line_number, include_state, error)
27380bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        return
27390bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
27400bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # FIXME: figure out if they're using default arguments in fn proto.
27410bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
27420bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # Check to see if they're using an conversion function cast.
27430bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # I just try to capture the most common basic types, though there are more.
27440bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # Parameterless conversion functions, such as bool(), are allowed as they are
27450bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # probably a member operator declaration or default constructor.
27460bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    matched = search(
27470bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        r'\b(int|float|double|bool|char|int32|uint32|int64|uint64)\([^)]', line)
27480bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if matched:
27490bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # gMock methods are defined using some variant of MOCK_METHODx(name, type)
27500bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # where type may be float(), int(string), etc.  Without context they are
27510bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # virtually indistinguishable from int(x) casts.
27520bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        if not match(r'^\s*MOCK_(CONST_)?METHOD\d+(_T)?\(', line):
2753d0825bca7fe65beaee391d30da42e937db621564Steve Block            error(line_number, 'readability/casting', 4,
27540bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                  'Using deprecated casting style.  '
27550bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                  'Use static_cast<%s>(...) instead' %
27560bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                  matched.group(1))
27570bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
2758d0825bca7fe65beaee391d30da42e937db621564Steve Block    check_c_style_cast(line_number, line, clean_lines.raw_lines[line_number],
27590bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                       'static_cast',
27600bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                       r'\((int|float|double|bool|char|u?int(16|32|64))\)',
27610bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                       error)
27620bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # This doesn't catch all cases.  Consider (const char * const)"hello".
2763d0825bca7fe65beaee391d30da42e937db621564Steve Block    check_c_style_cast(line_number, line, clean_lines.raw_lines[line_number],
27640bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                       'reinterpret_cast', r'\((\w+\s?\*+\s?)\)', error)
27650bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
27660bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # In addition, we look for people taking the address of a cast.  This
27670bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # is dangerous -- casts can assign to temporaries, so the pointer doesn't
27680bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # point where you think.
27690bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if search(
27700bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        r'(&\([^)]+\)[\w(])|(&(static|dynamic|reinterpret)_cast\b)', line):
2771d0825bca7fe65beaee391d30da42e937db621564Steve Block        error(line_number, 'runtime/casting', 4,
27720bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch              ('Are you taking an address of a cast?  '
27730bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch               'This is dangerous: could be a temp var.  '
27740bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch               'Take the address before doing the cast, rather than after'))
27750bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
27760bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # Check for people declaring static/global STL strings at the top level.
27770bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # This is dangerous because the C++ language does not guarantee that
27780bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # globals with constructors are initialized before the first access.
27790bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    matched = match(
27800bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        r'((?:|static +)(?:|const +))string +([a-zA-Z0-9_:]+)\b(.*)',
27810bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        line)
27820bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # Make sure it's not a function.
27830bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # Function template specialization looks like: "string foo<Type>(...".
27840bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # Class template definitions look like: "string Foo<Type>::Method(...".
27850bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if matched and not match(r'\s*(<.*>)?(::[a-zA-Z0-9_]+)?\s*\(([^"]|$)',
27860bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                             matched.group(3)):
2787d0825bca7fe65beaee391d30da42e937db621564Steve Block        error(line_number, 'runtime/string', 4,
27880bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch              'For a static/global string constant, use a C style string instead: '
27890bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch              '"%schar %s[]".' %
27900bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch              (matched.group(1), matched.group(2)))
27910bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
27920bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # Check that we're not using RTTI outside of testing code.
27938a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block    if search(r'\bdynamic_cast<', line):
2794d0825bca7fe65beaee391d30da42e937db621564Steve Block        error(line_number, 'runtime/rtti', 5,
27950bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch              'Do not use dynamic_cast<>.  If you need to cast within a class '
27960bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch              "hierarchy, use static_cast<> to upcast.  Google doesn't support "
27970bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch              'RTTI.')
27980bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
27990bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if search(r'\b([A-Za-z0-9_]*_)\(\1\)', line):
2800d0825bca7fe65beaee391d30da42e937db621564Steve Block        error(line_number, 'runtime/init', 4,
28010bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch              'You seem to be initializing a member variable with itself.')
28020bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
28030bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if file_extension == 'h':
28040bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # FIXME: check that 1-arg constructors are explicit.
28050bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        #        How to tell it's a constructor?
28060bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        #        (handled in check_for_non_standard_constructs for now)
28070bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        pass
28080bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
28090bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # Check if people are using the verboten C basic types.  The only exception
28100bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # we regularly allow is "unsigned short port" for port.
28110bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if search(r'\bshort port\b', line):
28120bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        if not search(r'\bunsigned short port\b', line):
2813d0825bca7fe65beaee391d30da42e937db621564Steve Block            error(line_number, 'runtime/int', 4,
28140bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                  'Use "unsigned short" for ports, not "short"')
28150bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
28160bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # When snprintf is used, the second argument shouldn't be a literal.
28170bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    matched = search(r'snprintf\s*\(([^,]*),\s*([0-9]*)\s*,', line)
28180bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if matched:
2819d0825bca7fe65beaee391d30da42e937db621564Steve Block        error(line_number, 'runtime/printf', 3,
28200bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch              'If you can, use sizeof(%s) instead of %s as the 2nd arg '
28210bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch              'to snprintf.' % (matched.group(1), matched.group(2)))
28220bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
28230bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # Check if some verboten C functions are being used.
28240bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if search(r'\bsprintf\b', line):
2825d0825bca7fe65beaee391d30da42e937db621564Steve Block        error(line_number, 'runtime/printf', 5,
28260bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch              'Never use sprintf.  Use snprintf instead.')
28270bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    matched = search(r'\b(strcpy|strcat)\b', line)
28280bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if matched:
2829d0825bca7fe65beaee391d30da42e937db621564Steve Block        error(line_number, 'runtime/printf', 4,
28300bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch              'Almost always, snprintf is better than %s' % matched.group(1))
28310bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
28320bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if search(r'\bsscanf\b', line):
2833d0825bca7fe65beaee391d30da42e937db621564Steve Block        error(line_number, 'runtime/printf', 1,
28340bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch              'sscanf can be ok, but is slow and can overflow buffers.')
28350bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
28360bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # Check for suspicious usage of "if" like
28370bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # } if (a == b) {
28380bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if search(r'\}\s*if\s*\(', line):
2839d0825bca7fe65beaee391d30da42e937db621564Steve Block        error(line_number, 'readability/braces', 4,
28400bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch              'Did you mean "else if"? If not, start a new line for "if".')
28410bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
28420bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # Check for potential format string bugs like printf(foo).
28430bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # We constrain the pattern not to pick things like DocidForPrintf(foo).
28440bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # Not perfect but it can catch printf(foo.c_str()) and printf(foo->c_str())
28450bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    matched = re.search(r'\b((?:string)?printf)\s*\(([\w.\->()]+)\)', line, re.I)
28460bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if matched:
2847d0825bca7fe65beaee391d30da42e937db621564Steve Block        error(line_number, 'runtime/printf', 4,
28480bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch              'Potential format string bug. Do %s("%%s", %s) instead.'
28490bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch              % (matched.group(1), matched.group(2)))
28500bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
28510bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # Check for potential memset bugs like memset(buf, sizeof(buf), 0).
28520bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    matched = search(r'memset\s*\(([^,]*),\s*([^,]*),\s*0\s*\)', line)
28530bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if matched and not match(r"^''|-?[0-9]+|0x[0-9A-Fa-f]$", matched.group(2)):
2854d0825bca7fe65beaee391d30da42e937db621564Steve Block        error(line_number, 'runtime/memset', 4,
28550bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch              'Did you mean "memset(%s, 0, %s)"?'
28560bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch              % (matched.group(1), matched.group(2)))
28570bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
28580bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # Detect variable-length arrays.
28590bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    matched = match(r'\s*(.+::)?(\w+) [a-z]\w*\[(.+)];', line)
28600bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if (matched and matched.group(2) != 'return' and matched.group(2) != 'delete' and
28610bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        matched.group(3).find(']') == -1):
28620bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # Split the size using space and arithmetic operators as delimiters.
28630bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # If any of the resulting tokens are not compile time constants then
28640bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # report the error.
28650bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        tokens = re.split(r'\s|\+|\-|\*|\/|<<|>>]', matched.group(3))
28660bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        is_const = True
28670bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        skip_next = False
28680bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        for tok in tokens:
28690bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            if skip_next:
28700bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                skip_next = False
28710bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                continue
28720bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
28730bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            if search(r'sizeof\(.+\)', tok):
28740bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                continue
28750bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            if search(r'arraysize\(\w+\)', tok):
28760bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                continue
28770bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
28780bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            tok = tok.lstrip('(')
28790bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            tok = tok.rstrip(')')
28800bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            if not tok:
28810bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                continue
28820bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            if match(r'\d+', tok):
28830bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                continue
28840bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            if match(r'0[xX][0-9a-fA-F]+', tok):
28850bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                continue
28860bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            if match(r'k[A-Z0-9]\w*', tok):
28870bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                continue
28880bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            if match(r'(.+::)?k[A-Z0-9]\w*', tok):
28890bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                continue
28900bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            if match(r'(.+::)?[A-Z][A-Z0-9_]*', tok):
28910bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                continue
28920bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            # A catch all for tricky sizeof cases, including 'sizeof expression',
28930bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            # 'sizeof(*type)', 'sizeof(const type)', 'sizeof(struct StructName)'
28940bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            # requires skipping the next token becasue we split on ' ' and '*'.
28950bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            if tok.startswith('sizeof'):
28960bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                skip_next = True
28970bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                continue
28980bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            is_const = False
28990bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            break
29000bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        if not is_const:
2901d0825bca7fe65beaee391d30da42e937db621564Steve Block            error(line_number, 'runtime/arrays', 1,
29020bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                  'Do not use variable-length arrays.  Use an appropriately named '
29030bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                  "('k' followed by CamelCase) compile-time constant for the size.")
29040bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
29050bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # Check for use of unnamed namespaces in header files.  Registration
29060bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # macros are typically OK, so we allow use of "namespace {" on lines
29070bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # that end with backslashes.
29080bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if (file_extension == 'h'
29090bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        and search(r'\bnamespace\s*{', line)
29100bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        and line[-1] != '\\'):
2911d0825bca7fe65beaee391d30da42e937db621564Steve Block        error(line_number, 'build/namespaces', 4,
29120bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch              'Do not use unnamed namespaces in header files.  See '
29130bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch              'http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml#Namespaces'
29140bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch              ' for more information.')
29150bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
2916f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch    check_identifier_name_in_declaration(filename, line_number, line, file_state, error)
2917643ca7872b450ea4efacab6188849e5aac2ba161Steve Block
2918643ca7872b450ea4efacab6188849e5aac2ba161Steve Block
2919f05b935882198ccf7d81675736e3aeb089c5113aBen Murdochdef check_identifier_name_in_declaration(filename, line_number, line, file_state, error):
2920643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    """Checks if identifier names contain any underscores.
2921643ca7872b450ea4efacab6188849e5aac2ba161Steve Block
2922643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    As identifiers in libraries we are using have a bunch of
2923643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    underscores, we only warn about the declarations of identifiers
2924643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    and don't check use of identifiers.
2925643ca7872b450ea4efacab6188849e5aac2ba161Steve Block
2926643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    Args:
2927643ca7872b450ea4efacab6188849e5aac2ba161Steve Block      filename: The name of the current file.
2928643ca7872b450ea4efacab6188849e5aac2ba161Steve Block      line_number: The number of the line to check.
2929643ca7872b450ea4efacab6188849e5aac2ba161Steve Block      line: The line of code to check.
2930f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch      file_state: A _FileState instance which maintains information about
2931f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch                  the state of things in the file.
2932643ca7872b450ea4efacab6188849e5aac2ba161Steve Block      error: The function to call with any errors found.
2933643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    """
2934643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    # We don't check a return statement.
2935d0825bca7fe65beaee391d30da42e937db621564Steve Block    if match(r'\s*(return|delete)\b', line):
2936643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        return
2937643ca7872b450ea4efacab6188849e5aac2ba161Steve Block
2938643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    # Basically, a declaration is a type name followed by whitespaces
2939643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    # followed by an identifier. The type name can be complicated
2940643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    # due to type adjectives and templates. We remove them first to
2941643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    # simplify the process to find declarations of identifiers.
2942643ca7872b450ea4efacab6188849e5aac2ba161Steve Block
2943643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    # Convert "long long", "long double", and "long long int" to
2944643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    # simple types, but don't remove simple "long".
2945643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    line = sub(r'long (long )?(?=long|double|int)', '', line)
2946692e5dbf12901edacf14812a6fae25462920af42Steve Block    # Convert unsigned/signed types to simple types, too.
2947692e5dbf12901edacf14812a6fae25462920af42Steve Block    line = sub(r'(unsigned|signed) (?=char|short|int|long)', '', line)
2948692e5dbf12901edacf14812a6fae25462920af42Steve Block    line = sub(r'\b(inline|using|static|const|volatile|auto|register|extern|typedef|restrict|struct|class|virtual)(?=\W)', '', line)
2949643ca7872b450ea4efacab6188849e5aac2ba161Steve Block
2950dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch    # Remove "new" and "new (expr)" to simplify, too.
2951dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch    line = sub(r'new\s*(\([^)]*\))?', '', line)
2952dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch
2953643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    # Remove all template parameters by removing matching < and >.
2954643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    # Loop until no templates are removed to remove nested templates.
2955643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    while True:
2956643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        line, number_of_replacements = subn(r'<([\w\s:]|::)+\s*[*&]*\s*>', '', line)
2957643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        if not number_of_replacements:
2958643ca7872b450ea4efacab6188849e5aac2ba161Steve Block            break
2959643ca7872b450ea4efacab6188849e5aac2ba161Steve Block
2960643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    # Declarations of local variables can be in condition expressions
2961643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    # of control flow statements (e.g., "if (RenderObject* p = o->parent())").
2962643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    # We remove the keywords and the first parenthesis.
2963643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    #
2964643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    # Declarations in "while", "if", and "switch" are different from
2965643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    # other declarations in two aspects:
2966643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    #
2967643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    # - There can be only one declaration between the parentheses.
2968643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    #   (i.e., you cannot write "if (int i = 0, j = 1) {}")
2969643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    # - The variable must be initialized.
2970643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    #   (i.e., you cannot write "if (int i) {}")
2971643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    #
2972643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    # and we will need different treatments for them.
2973643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    line = sub(r'^\s*for\s*\(', '', line)
2974643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    line, control_statement = subn(r'^\s*(while|else if|if|switch)\s*\(', '', line)
2975643ca7872b450ea4efacab6188849e5aac2ba161Steve Block
2976643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    # Detect variable and functions.
2977643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    type_regexp = r'\w([\w]|\s*[*&]\s*|::)+'
2978643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    identifier_regexp = r'(?P<identifier>[\w:]+)'
2979692e5dbf12901edacf14812a6fae25462920af42Steve Block    maybe_bitfield_regexp = r'(:\s*\d+\s*)?'
2980643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    character_after_identifier_regexp = r'(?P<character_after_identifier>[[;()=,])(?!=)'
2981692e5dbf12901edacf14812a6fae25462920af42Steve Block    declaration_without_type_regexp = r'\s*' + identifier_regexp + r'\s*' + maybe_bitfield_regexp + character_after_identifier_regexp
2982643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    declaration_with_type_regexp = r'\s*' + type_regexp + r'\s' + declaration_without_type_regexp
2983643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    is_function_arguments = False
2984643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    number_of_identifiers = 0
2985643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    while True:
2986643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        # If we are seeing the first identifier or arguments of a
2987643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        # function, there should be a type name before an identifier.
2988643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        if not number_of_identifiers or is_function_arguments:
2989643ca7872b450ea4efacab6188849e5aac2ba161Steve Block            declaration_regexp = declaration_with_type_regexp
2990643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        else:
2991643ca7872b450ea4efacab6188849e5aac2ba161Steve Block            declaration_regexp = declaration_without_type_regexp
2992643ca7872b450ea4efacab6188849e5aac2ba161Steve Block
2993643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        matched = match(declaration_regexp, line)
2994643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        if not matched:
2995643ca7872b450ea4efacab6188849e5aac2ba161Steve Block            return
2996643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        identifier = matched.group('identifier')
2997643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        character_after_identifier = matched.group('character_after_identifier')
2998643ca7872b450ea4efacab6188849e5aac2ba161Steve Block
2999643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        # If we removed a non-for-control statement, the character after
3000643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        # the identifier should be '='. With this rule, we can avoid
3001643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        # warning for cases like "if (val & INT_MAX) {".
3002643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        if control_statement and character_after_identifier != '=':
3003643ca7872b450ea4efacab6188849e5aac2ba161Steve Block            return
3004643ca7872b450ea4efacab6188849e5aac2ba161Steve Block
3005643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        is_function_arguments = is_function_arguments or character_after_identifier == '('
3006643ca7872b450ea4efacab6188849e5aac2ba161Steve Block
3007643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        # Remove "m_" and "s_" to allow them.
3008643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        modified_identifier = sub(r'(^|(?<=::))[ms]_', '', identifier)
3009f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch        if not file_state.is_objective_c() and modified_identifier.find('_') >= 0:
3010643ca7872b450ea4efacab6188849e5aac2ba161Steve Block            # Various exceptions to the rule: JavaScript op codes functions, const_iterator.
3011a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch            if (not (filename.find('JavaScriptCore') >= 0 and modified_identifier.find('op_') >= 0)
3012d0825bca7fe65beaee391d30da42e937db621564Steve Block                and not modified_identifier.startswith('tst_')
3013d0825bca7fe65beaee391d30da42e937db621564Steve Block                and not modified_identifier.startswith('webkit_dom_object_')
3014db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Block                and not modified_identifier.startswith('NPN_')
3015db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Block                and not modified_identifier.startswith('NPP_')
3016db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Block                and not modified_identifier.startswith('NP_')
3017d0825bca7fe65beaee391d30da42e937db621564Steve Block                and not modified_identifier.startswith('qt_')
301868513a70bcd92384395513322f1b801e7bf9c729Steve Block                and not modified_identifier.startswith('cairo_')
3019d0825bca7fe65beaee391d30da42e937db621564Steve Block                and not modified_identifier.find('::qt_') >= 0
3020a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch                and not modified_identifier == "const_iterator"
3021a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch                and not modified_identifier == "vm_throw"):
3022d0825bca7fe65beaee391d30da42e937db621564Steve Block                error(line_number, 'readability/naming', 4, identifier + " is incorrectly named. Don't use underscores in your identifier names.")
3023643ca7872b450ea4efacab6188849e5aac2ba161Steve Block
302421939df44de1705786c545cd1bf519d47250322dBen Murdoch        # Check for variables named 'l', these are too easy to confuse with '1' in some fonts
302521939df44de1705786c545cd1bf519d47250322dBen Murdoch        if modified_identifier == 'l':
302621939df44de1705786c545cd1bf519d47250322dBen Murdoch            error(line_number, 'readability/naming', 4, identifier + " is incorrectly named. Don't use the single letter 'l' as an identifier name.")
302721939df44de1705786c545cd1bf519d47250322dBen Murdoch
3028643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        # There can be only one declaration in non-for-control statements.
3029643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        if control_statement:
3030643ca7872b450ea4efacab6188849e5aac2ba161Steve Block            return
3031643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        # We should continue checking if this is a function
3032643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        # declaration because we need to check its arguments.
3033643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        # Also, we need to check multiple declarations.
3034643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        if character_after_identifier != '(' and character_after_identifier != ',':
3035643ca7872b450ea4efacab6188849e5aac2ba161Steve Block            return
3036643ca7872b450ea4efacab6188849e5aac2ba161Steve Block
3037643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        number_of_identifiers += 1
3038643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        line = line[matched.end():]
3039643ca7872b450ea4efacab6188849e5aac2ba161Steve Block
3040d0825bca7fe65beaee391d30da42e937db621564Steve Blockdef check_c_style_cast(line_number, line, raw_line, cast_type, pattern,
30410bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                       error):
30420bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """Checks for a C-style cast by looking for the pattern.
30430bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
30440bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    This also handles sizeof(type) warnings, due to similarity of content.
30450bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
30460bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    Args:
30470bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      line_number: The number of the line to check.
30480bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      line: The line of code to check.
30490bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      raw_line: The raw line of code to check, with comments.
30500bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      cast_type: The string for the C++ cast to recommend.  This is either
30510bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                 reinterpret_cast or static_cast, depending.
30520bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      pattern: The regular expression used to find C-style casts.
30530bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      error: The function to call with any errors found.
30540bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """
30550bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    matched = search(pattern, line)
30560bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if not matched:
30570bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        return
30580bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
30590bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # e.g., sizeof(int)
30600bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    sizeof_match = match(r'.*sizeof\s*$', line[0:matched.start(1) - 1])
30610bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if sizeof_match:
3062d0825bca7fe65beaee391d30da42e937db621564Steve Block        error(line_number, 'runtime/sizeof', 1,
30630bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch              'Using sizeof(type).  Use sizeof(varname) instead if possible')
30640bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        return
30650bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
30660bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    remainder = line[matched.end(0):]
30670bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
30680bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # The close paren is for function pointers as arguments to a function.
30690bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # eg, void foo(void (*bar)(int));
30700bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # The semicolon check is a more basic function check; also possibly a
30710bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # function pointer typedef.
30720bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # eg, void foo(int); or void foo(int) const;
30730bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # The equals check is for function pointer assignment.
30740bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # eg, void *(*foo)(int) = ...
30750bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    #
30760bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # Right now, this will only catch cases where there's a single argument, and
30770bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # it's unnamed.  It should probably be expanded to check for multiple
30780bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # arguments with some unnamed.
30790bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    function_match = match(r'\s*(\)|=|(const)?\s*(;|\{|throw\(\)))', remainder)
30800bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if function_match:
30810bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        if (not function_match.group(3)
30820bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            or function_match.group(3) == ';'
30830bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            or raw_line.find('/*') < 0):
3084d0825bca7fe65beaee391d30da42e937db621564Steve Block            error(line_number, 'readability/function', 3,
30850bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                  'All parameters should be named in a function')
30860bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        return
30870bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
30880bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # At this point, all that should be left is actual casts.
3089d0825bca7fe65beaee391d30da42e937db621564Steve Block    error(line_number, 'readability/casting', 4,
30900bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch          'Using C-style cast.  Use %s<%s>(...) instead' %
30910bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch          (cast_type, matched.group(1)))
30920bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
30930bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
30940bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch_HEADERS_CONTAINING_TEMPLATES = (
30950bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    ('<deque>', ('deque',)),
30960bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    ('<functional>', ('unary_function', 'binary_function',
30970bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                      'plus', 'minus', 'multiplies', 'divides', 'modulus',
30980bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                      'negate',
30990bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                      'equal_to', 'not_equal_to', 'greater', 'less',
31000bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                      'greater_equal', 'less_equal',
31010bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                      'logical_and', 'logical_or', 'logical_not',
31020bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                      'unary_negate', 'not1', 'binary_negate', 'not2',
31030bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                      'bind1st', 'bind2nd',
31040bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                      'pointer_to_unary_function',
31050bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                      'pointer_to_binary_function',
31060bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                      'ptr_fun',
31070bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                      'mem_fun_t', 'mem_fun', 'mem_fun1_t', 'mem_fun1_ref_t',
31080bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                      'mem_fun_ref_t',
31090bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                      'const_mem_fun_t', 'const_mem_fun1_t',
31100bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                      'const_mem_fun_ref_t', 'const_mem_fun1_ref_t',
31110bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                      'mem_fun_ref',
31120bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                     )),
31130bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    ('<limits>', ('numeric_limits',)),
31140bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    ('<list>', ('list',)),
31150bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    ('<map>', ('map', 'multimap',)),
31160bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    ('<memory>', ('allocator',)),
31170bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    ('<queue>', ('queue', 'priority_queue',)),
31180bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    ('<set>', ('set', 'multiset',)),
31190bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    ('<stack>', ('stack',)),
31200bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    ('<string>', ('char_traits', 'basic_string',)),
31210bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    ('<utility>', ('pair',)),
31220bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    ('<vector>', ('vector',)),
31230bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
31240bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # gcc extensions.
31250bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # Note: std::hash is their hash, ::hash is our hash
31260bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    ('<hash_map>', ('hash_map', 'hash_multimap',)),
31270bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    ('<hash_set>', ('hash_set', 'hash_multiset',)),
31280bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    ('<slist>', ('slist',)),
31290bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    )
31300bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
31310bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch_HEADERS_ACCEPTED_BUT_NOT_PROMOTED = {
31320bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # We can trust with reasonable confidence that map gives us pair<>, too.
31330bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    'pair<>': ('map', 'multimap', 'hash_map', 'hash_multimap')
31340bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch}
31350bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
31360bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch_RE_PATTERN_STRING = re.compile(r'\bstring\b')
31370bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
31380bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch_re_pattern_algorithm_header = []
31390bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdochfor _template in ('copy', 'max', 'min', 'min_element', 'sort', 'swap',
31400bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                  'transform'):
31410bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # Match max<type>(..., ...), max(..., ...), but not foo->max, foo.max or
31420bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # type::max().
31430bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    _re_pattern_algorithm_header.append(
31440bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        (re.compile(r'[^>.]\b' + _template + r'(<.*?>)?\([^\)]'),
31450bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch         _template,
31460bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch         '<algorithm>'))
31470bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
31480bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch_re_pattern_templates = []
31490bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdochfor _header, _templates in _HEADERS_CONTAINING_TEMPLATES:
31500bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    for _template in _templates:
31510bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        _re_pattern_templates.append(
31520bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            (re.compile(r'(\<|\b)' + _template + r'\s*\<'),
31530bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch             _template + '<>',
31540bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch             _header))
31550bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
31560bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
31570bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdochdef files_belong_to_same_module(filename_cpp, filename_h):
31580bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """Check if these two filenames belong to the same module.
31590bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
31600bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    The concept of a 'module' here is a as follows:
31610bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    foo.h, foo-inl.h, foo.cpp, foo_test.cpp and foo_unittest.cpp belong to the
31620bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    same 'module' if they are in the same directory.
31630bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    some/path/public/xyzzy and some/path/internal/xyzzy are also considered
31640bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    to belong to the same module here.
31650bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
31660bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    If the filename_cpp contains a longer path than the filename_h, for example,
31670bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    '/absolute/path/to/base/sysinfo.cpp', and this file would include
31680bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    'base/sysinfo.h', this function also produces the prefix needed to open the
31690bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    header. This is used by the caller of this function to more robustly open the
31700bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    header file. We don't have access to the real include paths in this context,
31710bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    so we need this guesswork here.
31720bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
31730bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    Known bugs: tools/base/bar.cpp and base/bar.h belong to the same module
31740bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    according to this implementation. Because of this, this function gives
31750bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    some false positives. This should be sufficiently rare in practice.
31760bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
31770bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    Args:
31780bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      filename_cpp: is the path for the .cpp file
31790bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      filename_h: is the path for the header path
31800bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
31810bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    Returns:
31820bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      Tuple with a bool and a string:
31830bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      bool: True if filename_cpp and filename_h belong to the same module.
31840bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      string: the additional prefix needed to open the header file.
31850bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """
31860bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
31870bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if not filename_cpp.endswith('.cpp'):
31880bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        return (False, '')
31890bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    filename_cpp = filename_cpp[:-len('.cpp')]
31900bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if filename_cpp.endswith('_unittest'):
31910bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        filename_cpp = filename_cpp[:-len('_unittest')]
31920bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    elif filename_cpp.endswith('_test'):
31930bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        filename_cpp = filename_cpp[:-len('_test')]
31940bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    filename_cpp = filename_cpp.replace('/public/', '/')
31950bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    filename_cpp = filename_cpp.replace('/internal/', '/')
31960bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
31970bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if not filename_h.endswith('.h'):
31980bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        return (False, '')
31990bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    filename_h = filename_h[:-len('.h')]
32000bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if filename_h.endswith('-inl'):
32010bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        filename_h = filename_h[:-len('-inl')]
32020bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    filename_h = filename_h.replace('/public/', '/')
32030bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    filename_h = filename_h.replace('/internal/', '/')
32040bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
32050bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    files_belong_to_same_module = filename_cpp.endswith(filename_h)
32060bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    common_path = ''
32070bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if files_belong_to_same_module:
32080bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        common_path = filename_cpp[:-len(filename_h)]
32090bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    return files_belong_to_same_module, common_path
32100bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
32110bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
32120bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdochdef update_include_state(filename, include_state, io=codecs):
32130bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """Fill up the include_state with new includes found from the file.
32140bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
32150bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    Args:
32160bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      filename: the name of the header to read.
32170bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      include_state: an _IncludeState instance in which the headers are inserted.
32180bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      io: The io factory to use to read the file. Provided for testability.
32190bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
32200bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    Returns:
32210bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      True if a header was succesfully added. False otherwise.
32220bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """
3223f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch    io = _unit_test_config.get(INCLUDE_IO_INJECTION_KEY, codecs)
32240bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    header_file = None
32250bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    try:
32260bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        header_file = io.open(filename, 'r', 'utf8', 'replace')
32270bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    except IOError:
32280bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        return False
32290bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    line_number = 0
32300bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    for line in header_file:
32310bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        line_number += 1
32320bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        clean_line = cleanse_comments(line)
32330bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        matched = _RE_PATTERN_INCLUDE.search(clean_line)
32340bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        if matched:
32350bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            include = matched.group(2)
32360bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            # The value formatting is cute, but not really used right now.
32370bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            # What matters here is that the key is in include_state.
32380bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            include_state.setdefault(include, '%s:%d' % (filename, line_number))
32390bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    return True
32400bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
32410bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
3242f05b935882198ccf7d81675736e3aeb089c5113aBen Murdochdef check_for_include_what_you_use(filename, clean_lines, include_state, error):
32430bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """Reports for missing stl includes.
32440bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
32450bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    This function will output warnings to make sure you are including the headers
32460bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    necessary for the stl containers and functions that you use. We only give one
32470bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    reason to include a header. For example, if you use both equal_to<> and
32480bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    less<> in a .h file, only one (the latter in the file) of these will be
32490bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    reported as a reason to include the <functional>.
32500bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
32510bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    Args:
32520bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      filename: The name of the current file.
32530bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      clean_lines: A CleansedLines instance containing the file.
32540bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      include_state: An _IncludeState instance.
32550bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      error: The function to call with any errors found.
32560bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """
32570bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    required = {}  # A map of header name to line_number and the template entity.
32580bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # Example of required: { '<functional>': (1219, 'less<>') }
32590bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
32600bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    for line_number in xrange(clean_lines.num_lines()):
32610bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        line = clean_lines.elided[line_number]
32620bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        if not line or line[0] == '#':
32630bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            continue
32640bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
32650bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # String is special -- it is a non-templatized type in STL.
32660bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        if _RE_PATTERN_STRING.search(line):
32670bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            required['<string>'] = (line_number, 'string')
32680bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
32690bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        for pattern, template, header in _re_pattern_algorithm_header:
32700bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            if pattern.search(line):
32710bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                required[header] = (line_number, template)
32720bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
32730bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # The following function is just a speed up, no semantics are changed.
32740bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        if not '<' in line:  # Reduces the cpu time usage by skipping lines.
32750bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            continue
32760bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
32770bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        for pattern, template, header in _re_pattern_templates:
32780bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            if pattern.search(line):
32790bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                required[header] = (line_number, template)
32800bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
32810bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # The policy is that if you #include something in foo.h you don't need to
32820bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # include it again in foo.cpp. Here, we will look at possible includes.
32830bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # Let's copy the include_state so it is only messed up within this function.
32840bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    include_state = include_state.copy()
32850bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
32860bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # Did we find the header for this file (if any) and succesfully load it?
32870bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    header_found = False
32880bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
32890bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # Use the absolute path so that matching works properly.
32900bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    abs_filename = os.path.abspath(filename)
32910bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
32920bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # For Emacs's flymake.
32930bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # If cpp_style is invoked from Emacs's flymake, a temporary file is generated
32940bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # by flymake and that file name might end with '_flymake.cpp'. In that case,
32950bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # restore original file name here so that the corresponding header file can be
32960bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # found.
32970bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # e.g. If the file name is 'foo_flymake.cpp', we should search for 'foo.h'
32980bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # instead of 'foo_flymake.h'
3299dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    abs_filename = re.sub(r'_flymake\.cpp$', '.cpp', abs_filename)
33000bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
33010bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # include_state is modified during iteration, so we iterate over a copy of
33020bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # the keys.
33030bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    for header in include_state.keys():  #NOLINT
33040bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        (same_module, common_path) = files_belong_to_same_module(abs_filename, header)
33050bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        fullpath = common_path + header
3306f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch        if same_module and update_include_state(fullpath, include_state):
33070bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            header_found = True
33080bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
33090bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # If we can't find the header file for a .cpp, assume it's because we don't
33100bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # know where to look. In that case we'll give up as we're not sure they
33110bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # didn't include it in the .h file.
33120bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # FIXME: Do a better job of finding .h files so we are confident that
33130bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    #        not having the .h file means there isn't one.
33140bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if filename.endswith('.cpp') and not header_found:
33150bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        return
33160bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
33170bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # All the lines have been processed, report the errors found.
33180bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    for required_header_unstripped in required:
33190bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        template = required[required_header_unstripped][1]
33200bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        if template in _HEADERS_ACCEPTED_BUT_NOT_PROMOTED:
33210bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            headers = _HEADERS_ACCEPTED_BUT_NOT_PROMOTED[template]
33220bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            if [True for header in headers if header in include_state]:
33230bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                continue
33240bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        if required_header_unstripped.strip('<>"') not in include_state:
3325d0825bca7fe65beaee391d30da42e937db621564Steve Block            error(required[required_header_unstripped][0],
33260bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                  'build/include_what_you_use', 4,
33270bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                  'Add #include ' + required_header_unstripped + ' for ' + template)
33280bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
33290bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
33300bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdochdef process_line(filename, file_extension,
33310bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                 clean_lines, line, include_state, function_state,
3332643ca7872b450ea4efacab6188849e5aac2ba161Steve Block                 class_state, file_state, error):
33330bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """Processes a single line in the file.
33340bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
33350bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    Args:
33360bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      filename: Filename of the file that is being processed.
33370bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      file_extension: The extension (dot not included) of the file.
33380bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      clean_lines: An array of strings, each representing a line of the file,
33390bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                   with comments stripped.
33400bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      line: Number of line being processed.
33410bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      include_state: An _IncludeState instance in which the headers are inserted.
33420bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      function_state: A _FunctionState instance which counts function lines, etc.
33430bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      class_state: A _ClassState instance which maintains information about
33440bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                   the current stack of nested class declarations being parsed.
3345643ca7872b450ea4efacab6188849e5aac2ba161Steve Block      file_state: A _FileState instance which maintains information about
3346643ca7872b450ea4efacab6188849e5aac2ba161Steve Block                  the state of things in the file.
3347d0825bca7fe65beaee391d30da42e937db621564Steve Block      error: A callable to which errors are reported, which takes arguments:
3348d0825bca7fe65beaee391d30da42e937db621564Steve Block             line number, error level, and message
33490bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
33500bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """
33510bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    raw_lines = clean_lines.raw_lines
33526b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner    detect_functions(clean_lines, line, function_state, error)
3353d0825bca7fe65beaee391d30da42e937db621564Steve Block    check_for_function_lengths(clean_lines, line, function_state, error)
33540bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if search(r'\bNOLINT\b', raw_lines[line]):  # ignore nolint lines
33550bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        return
335681bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    check_function_definition(filename, file_extension, clean_lines, line, function_state, error)
33576b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner    check_pass_ptr_usage(clean_lines, line, function_state, error)
3358d0825bca7fe65beaee391d30da42e937db621564Steve Block    check_for_multiline_comments_and_strings(clean_lines, line, error)
33590617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen    check_style(clean_lines, line, file_extension, class_state, file_state, error)
33600bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    check_language(filename, clean_lines, line, file_extension, include_state,
3361f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch                   file_state, error)
3362d0825bca7fe65beaee391d30da42e937db621564Steve Block    check_for_non_standard_constructs(clean_lines, line, class_state, error)
3363d0825bca7fe65beaee391d30da42e937db621564Steve Block    check_posix_threading(clean_lines, line, error)
3364d0825bca7fe65beaee391d30da42e937db621564Steve Block    check_invalid_increment(clean_lines, line, error)
33650bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
33660bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
3367dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Blockdef _process_lines(filename, file_extension, lines, error, min_confidence):
33680bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """Performs lint checks and reports any errors to the given error function.
33690bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
33700bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    Args:
33710bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      filename: Filename of the file that is being processed.
33720bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      file_extension: The extension (dot not included) of the file.
33730bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      lines: An array of strings, each representing a line of the file, with the
33740bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch             last element being empty if the file is termined with a newline.
33750bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch      error: A callable to which errors are reported, which takes 4 arguments:
33760bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """
33770bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    lines = (['// marker so line numbers and indices both start at 1'] + lines +
33780bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch             ['// marker so line numbers end in a known way'])
33790bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
33800bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    include_state = _IncludeState()
3381dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    function_state = _FunctionState(min_confidence)
33820bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    class_state = _ClassState()
33830bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
3384d0825bca7fe65beaee391d30da42e937db621564Steve Block    check_for_copyright(lines, error)
33850bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
33860bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if file_extension == 'h':
33870bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        check_for_header_guard(filename, lines, error)
33880bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
3389d0825bca7fe65beaee391d30da42e937db621564Steve Block    remove_multi_line_comments(lines, error)
33900bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    clean_lines = CleansedLines(lines)
3391f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch    file_state = _FileState(clean_lines, file_extension)
33920bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    for line in xrange(clean_lines.num_lines()):
33930bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        process_line(filename, file_extension, clean_lines, line,
3394643ca7872b450ea4efacab6188849e5aac2ba161Steve Block                     include_state, function_state, class_state, file_state, error)
3395d0825bca7fe65beaee391d30da42e937db621564Steve Block    class_state.check_finished(error)
33960bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
33970bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    check_for_include_what_you_use(filename, clean_lines, include_state, error)
33980bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
33990bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # We check here rather than inside process_line so that we see raw
34000bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # lines rather than "cleaned" lines.
3401d0825bca7fe65beaee391d30da42e937db621564Steve Block    check_for_unicode_replacement_characters(lines, error)
34020bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
3403d0825bca7fe65beaee391d30da42e937db621564Steve Block    check_for_new_line_at_eof(lines, error)
34040bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
34050bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
340621939df44de1705786c545cd1bf519d47250322dBen Murdochclass CppChecker(object):
34070bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
3408d0825bca7fe65beaee391d30da42e937db621564Steve Block    """Processes C++ lines for checking style."""
34090bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
3410d0825bca7fe65beaee391d30da42e937db621564Steve Block    # This list is used to--
3411d0825bca7fe65beaee391d30da42e937db621564Steve Block    #
3412d0825bca7fe65beaee391d30da42e937db621564Steve Block    # (1) generate an explicit list of all possible categories,
3413d0825bca7fe65beaee391d30da42e937db621564Steve Block    # (2) unit test that all checked categories have valid names, and
3414d0825bca7fe65beaee391d30da42e937db621564Steve Block    # (3) unit test that all categories are getting unit tested.
3415d0825bca7fe65beaee391d30da42e937db621564Steve Block    #
3416d0825bca7fe65beaee391d30da42e937db621564Steve Block    categories = set([
3417d0825bca7fe65beaee391d30da42e937db621564Steve Block        'build/class',
3418d0825bca7fe65beaee391d30da42e937db621564Steve Block        'build/deprecated',
3419d0825bca7fe65beaee391d30da42e937db621564Steve Block        'build/endif_comment',
3420d0825bca7fe65beaee391d30da42e937db621564Steve Block        'build/forward_decl',
3421d0825bca7fe65beaee391d30da42e937db621564Steve Block        'build/header_guard',
3422d0825bca7fe65beaee391d30da42e937db621564Steve Block        'build/include',
3423d0825bca7fe65beaee391d30da42e937db621564Steve Block        'build/include_order',
3424d0825bca7fe65beaee391d30da42e937db621564Steve Block        'build/include_what_you_use',
3425d0825bca7fe65beaee391d30da42e937db621564Steve Block        'build/namespaces',
3426d0825bca7fe65beaee391d30da42e937db621564Steve Block        'build/printf_format',
3427d0825bca7fe65beaee391d30da42e937db621564Steve Block        'build/storage_class',
3428d0825bca7fe65beaee391d30da42e937db621564Steve Block        'build/using_std',
3429d0825bca7fe65beaee391d30da42e937db621564Steve Block        'legal/copyright',
3430d0825bca7fe65beaee391d30da42e937db621564Steve Block        'readability/braces',
3431d0825bca7fe65beaee391d30da42e937db621564Steve Block        'readability/casting',
3432d0825bca7fe65beaee391d30da42e937db621564Steve Block        'readability/check',
3433d0825bca7fe65beaee391d30da42e937db621564Steve Block        'readability/comparison_to_zero',
3434d0825bca7fe65beaee391d30da42e937db621564Steve Block        'readability/constructors',
3435d0825bca7fe65beaee391d30da42e937db621564Steve Block        'readability/control_flow',
3436d0825bca7fe65beaee391d30da42e937db621564Steve Block        'readability/fn_size',
3437d0825bca7fe65beaee391d30da42e937db621564Steve Block        'readability/function',
3438d0825bca7fe65beaee391d30da42e937db621564Steve Block        'readability/multiline_comment',
3439d0825bca7fe65beaee391d30da42e937db621564Steve Block        'readability/multiline_string',
3440cad810f21b803229eb11403f9209855525a25d57Steve Block        'readability/parameter_name',
3441d0825bca7fe65beaee391d30da42e937db621564Steve Block        'readability/naming',
3442d0825bca7fe65beaee391d30da42e937db621564Steve Block        'readability/null',
34436b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner        'readability/pass_ptr',
3444d0825bca7fe65beaee391d30da42e937db621564Steve Block        'readability/streams',
3445d0825bca7fe65beaee391d30da42e937db621564Steve Block        'readability/todo',
3446d0825bca7fe65beaee391d30da42e937db621564Steve Block        'readability/utf8',
344781bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch        'readability/webkit_api',
3448d0825bca7fe65beaee391d30da42e937db621564Steve Block        'runtime/arrays',
3449d0825bca7fe65beaee391d30da42e937db621564Steve Block        'runtime/casting',
3450d0825bca7fe65beaee391d30da42e937db621564Steve Block        'runtime/explicit',
3451d0825bca7fe65beaee391d30da42e937db621564Steve Block        'runtime/init',
3452d0825bca7fe65beaee391d30da42e937db621564Steve Block        'runtime/int',
3453d0825bca7fe65beaee391d30da42e937db621564Steve Block        'runtime/invalid_increment',
3454d0825bca7fe65beaee391d30da42e937db621564Steve Block        'runtime/max_min_macros',
3455d0825bca7fe65beaee391d30da42e937db621564Steve Block        'runtime/memset',
3456d0825bca7fe65beaee391d30da42e937db621564Steve Block        'runtime/printf',
3457d0825bca7fe65beaee391d30da42e937db621564Steve Block        'runtime/printf_format',
3458d0825bca7fe65beaee391d30da42e937db621564Steve Block        'runtime/references',
3459d0825bca7fe65beaee391d30da42e937db621564Steve Block        'runtime/rtti',
3460d0825bca7fe65beaee391d30da42e937db621564Steve Block        'runtime/sizeof',
3461d0825bca7fe65beaee391d30da42e937db621564Steve Block        'runtime/string',
3462d0825bca7fe65beaee391d30da42e937db621564Steve Block        'runtime/threadsafe_fn',
3463d0825bca7fe65beaee391d30da42e937db621564Steve Block        'runtime/virtual',
3464d0825bca7fe65beaee391d30da42e937db621564Steve Block        'whitespace/blank_line',
3465d0825bca7fe65beaee391d30da42e937db621564Steve Block        'whitespace/braces',
3466d0825bca7fe65beaee391d30da42e937db621564Steve Block        'whitespace/comma',
3467d0825bca7fe65beaee391d30da42e937db621564Steve Block        'whitespace/comments',
3468d0825bca7fe65beaee391d30da42e937db621564Steve Block        'whitespace/declaration',
3469d0825bca7fe65beaee391d30da42e937db621564Steve Block        'whitespace/end_of_line',
3470d0825bca7fe65beaee391d30da42e937db621564Steve Block        'whitespace/ending_newline',
3471d0825bca7fe65beaee391d30da42e937db621564Steve Block        'whitespace/indent',
3472d0825bca7fe65beaee391d30da42e937db621564Steve Block        'whitespace/labels',
3473d0825bca7fe65beaee391d30da42e937db621564Steve Block        'whitespace/line_length',
3474d0825bca7fe65beaee391d30da42e937db621564Steve Block        'whitespace/newline',
3475d0825bca7fe65beaee391d30da42e937db621564Steve Block        'whitespace/operators',
3476d0825bca7fe65beaee391d30da42e937db621564Steve Block        'whitespace/parens',
3477d0825bca7fe65beaee391d30da42e937db621564Steve Block        'whitespace/semicolon',
3478d0825bca7fe65beaee391d30da42e937db621564Steve Block        'whitespace/tab',
3479d0825bca7fe65beaee391d30da42e937db621564Steve Block        'whitespace/todo',
3480d0825bca7fe65beaee391d30da42e937db621564Steve Block        ])
3481d0825bca7fe65beaee391d30da42e937db621564Steve Block
3482dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    def __init__(self, file_path, file_extension, handle_style_error,
3483dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block                 min_confidence):
348421939df44de1705786c545cd1bf519d47250322dBen Murdoch        """Create a CppChecker instance.
34850bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
3486d0825bca7fe65beaee391d30da42e937db621564Steve Block        Args:
3487d0825bca7fe65beaee391d30da42e937db621564Steve Block          file_extension: A string that is the file extension, without
3488d0825bca7fe65beaee391d30da42e937db621564Steve Block                          the leading dot.
34890bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
3490d0825bca7fe65beaee391d30da42e937db621564Steve Block        """
3491d0825bca7fe65beaee391d30da42e937db621564Steve Block        self.file_extension = file_extension
3492d0825bca7fe65beaee391d30da42e937db621564Steve Block        self.file_path = file_path
3493d0825bca7fe65beaee391d30da42e937db621564Steve Block        self.handle_style_error = handle_style_error
3494dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        self.min_confidence = min_confidence
3495d0825bca7fe65beaee391d30da42e937db621564Steve Block
3496d0825bca7fe65beaee391d30da42e937db621564Steve Block    # Useful for unit testing.
3497d0825bca7fe65beaee391d30da42e937db621564Steve Block    def __eq__(self, other):
349821939df44de1705786c545cd1bf519d47250322dBen Murdoch        """Return whether this CppChecker instance is equal to another."""
3499d0825bca7fe65beaee391d30da42e937db621564Steve Block        if self.file_extension != other.file_extension:
3500d0825bca7fe65beaee391d30da42e937db621564Steve Block            return False
3501d0825bca7fe65beaee391d30da42e937db621564Steve Block        if self.file_path != other.file_path:
3502d0825bca7fe65beaee391d30da42e937db621564Steve Block            return False
3503d0825bca7fe65beaee391d30da42e937db621564Steve Block        if self.handle_style_error != other.handle_style_error:
3504d0825bca7fe65beaee391d30da42e937db621564Steve Block            return False
3505dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        if self.min_confidence != other.min_confidence:
3506d0825bca7fe65beaee391d30da42e937db621564Steve Block            return False
35070bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
3508d0825bca7fe65beaee391d30da42e937db621564Steve Block        return True
35090bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
3510d0825bca7fe65beaee391d30da42e937db621564Steve Block    # Useful for unit testing.
3511d0825bca7fe65beaee391d30da42e937db621564Steve Block    def __ne__(self, other):
3512d0825bca7fe65beaee391d30da42e937db621564Steve Block        # Python does not automatically deduce __ne__() from __eq__().
3513d0825bca7fe65beaee391d30da42e937db621564Steve Block        return not self.__eq__(other)
35140bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
351521939df44de1705786c545cd1bf519d47250322dBen Murdoch    def check(self, lines):
3516d0825bca7fe65beaee391d30da42e937db621564Steve Block        _process_lines(self.file_path, self.file_extension, lines,
3517dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block                       self.handle_style_error, self.min_confidence)
35180bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
35190bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
3520d0825bca7fe65beaee391d30da42e937db621564Steve Block# FIXME: Remove this function (requires refactoring unit tests).
3521f05b935882198ccf7d81675736e3aeb089c5113aBen Murdochdef process_file_data(filename, file_extension, lines, error, min_confidence, unit_test_config):
3522f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch    global _unit_test_config
3523f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch    _unit_test_config = unit_test_config
352421939df44de1705786c545cd1bf519d47250322dBen Murdoch    checker = CppChecker(filename, file_extension, error, min_confidence)
352521939df44de1705786c545cd1bf519d47250322dBen Murdoch    checker.check(lines)
3526f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch    _unit_test_config = {}
3527