1 # Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file.
5 """Checks C++ and Objective-C files for illegal includes."""
12 from rules
import Rule
, MessageRule
15 class CppChecker(object):
25 # The maximum number of non-include lines we can see before giving up.
26 _MAX_UNINTERESTING_LINES
= 50
28 # The maximum line length, this is to be efficient in the case of very long
29 # lines (which can't be #includes).
30 _MAX_LINE_LENGTH
= 128
32 # This regular expression will be used to extract filenames from include
34 _EXTRACT_INCLUDE_PATH
= re
.compile(
35 '[ \t]*#[ \t]*(?:include|import)[ \t]+"(.*)"')
37 def __init__(self
, verbose
):
38 self
._verbose
= verbose
40 def CheckLine(self
, rules
, line
, dependee_path
, fail_on_temp_allow
=False):
41 """Checks the given line with the given rule set.
43 Returns a tuple (is_include, dependency_violation) where
44 is_include is True only if the line is an #include or #import
45 statement, and dependency_violation is an instance of
46 results.DependencyViolation if the line violates a rule, or None
49 found_item
= self
._EXTRACT
_INCLUDE
_PATH
.match(line
)
51 return False, None # Not a match
53 include_path
= found_item
.group(1)
55 if '\\' in include_path
:
56 return True, results
.DependencyViolation(
58 MessageRule('Include paths may not include backslashes.'),
61 if '/' not in include_path
:
62 # Don't fail when no directory is specified. We may want to be more
63 # strict about this in the future.
65 print ' WARNING: directory specified with no path: ' + include_path
68 rule
= rules
.RuleApplyingTo(include_path
, dependee_path
)
69 if (rule
.allow
== Rule
.DISALLOW
or
70 (fail_on_temp_allow
and rule
.allow
== Rule
.TEMP_ALLOW
)):
71 return True, results
.DependencyViolation(include_path
, rule
, rules
)
74 def CheckFile(self
, rules
, filepath
):
76 print 'Checking: ' + filepath
78 dependee_status
= results
.DependeeStatus(filepath
)
79 ret_val
= '' # We'll collect the error messages in here
81 with codecs
.open(filepath
, encoding
='utf-8') as f
:
83 for line_num
, line
in enumerate(f
):
84 if line_num
- last_include
> self
._MAX
_UNINTERESTING
_LINES
:
89 # Check to see if we're at / inside a #if 0 block
90 if line
.startswith('#if 0'):
94 if line
.startswith('#if'):
96 elif line
.startswith('#endif'):
100 is_include
, violation
= self
.CheckLine(rules
, line
, filepath
)
102 last_include
= line_num
104 dependee_status
.AddViolation(violation
)
106 return dependee_status
109 def IsCppFile(file_path
):
110 """Returns True iff the given path ends in one of the extensions
111 handled by this checker.
113 return os
.path
.splitext(file_path
)[1] in CppChecker
.EXTENSIONS