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):
24 # The maximum number of non-include lines we can see before giving up.
25 _MAX_UNINTERESTING_LINES
= 50
27 # The maximum line length, this is to be efficient in the case of very long
28 # lines (which can't be #includes).
29 _MAX_LINE_LENGTH
= 128
31 # This regular expression will be used to extract filenames from include
33 _EXTRACT_INCLUDE_PATH
= re
.compile(
34 '[ \t]*#[ \t]*(?:include|import)[ \t]+"(.*)"')
36 def __init__(self
, verbose
):
37 self
._verbose
= verbose
39 def CheckLine(self
, rules
, line
, dependee_path
, fail_on_temp_allow
=False):
40 """Checks the given line with the given rule set.
42 Returns a tuple (is_include, dependency_violation) where
43 is_include is True only if the line is an #include or #import
44 statement, and dependency_violation is an instance of
45 results.DependencyViolation if the line violates a rule, or None
48 found_item
= self
._EXTRACT
_INCLUDE
_PATH
.match(line
)
50 return False, None # Not a match
52 include_path
= found_item
.group(1)
54 if '\\' in include_path
:
55 return True, results
.DependencyViolation(
57 MessageRule('Include paths may not include backslashes.'),
60 if '/' not in include_path
:
61 # Don't fail when no directory is specified. We may want to be more
62 # strict about this in the future.
64 print ' WARNING: directory specified with no path: ' + include_path
67 rule
= rules
.RuleApplyingTo(include_path
, dependee_path
)
68 if (rule
.allow
== Rule
.DISALLOW
or
69 (fail_on_temp_allow
and rule
.allow
== Rule
.TEMP_ALLOW
)):
70 return True, results
.DependencyViolation(include_path
, rule
, rules
)
73 def CheckFile(self
, rules
, filepath
):
75 print 'Checking: ' + filepath
77 dependee_status
= results
.DependeeStatus(filepath
)
78 ret_val
= '' # We'll collect the error messages in here
80 with codecs
.open(filepath
, encoding
='utf-8') as f
:
82 for line_num
, line
in enumerate(f
):
83 if line_num
- last_include
> self
._MAX
_UNINTERESTING
_LINES
:
88 # Check to see if we're at / inside a #if 0 block
89 if line
.startswith('#if 0'):
93 if line
.startswith('#if'):
95 elif line
.startswith('#endif'):
99 is_include
, violation
= self
.CheckLine(rules
, line
, filepath
)
101 last_include
= line_num
103 dependee_status
.AddViolation(violation
)
105 return dependee_status
108 def IsCppFile(file_path
):
109 """Returns True iff the given path ends in one of the extensions
110 handled by this checker.
112 return os
.path
.splitext(file_path
)[1] in CppChecker
.EXTENSIONS