Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(16)

Side by Side Diff: tools/checkdeps/cpp_checker.py

Issue 10832062: Add ability to format errors as a list of temp-allow rules to paste (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Address review comments. Created 8 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « tools/checkdeps/checkdeps_test.py ('k') | tools/checkdeps/java_checker.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 # Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file. 3 # found in the LICENSE file.
4 4
5 """Checks C++ and Objective-C files for illegal includes.""" 5 """Checks C++ and Objective-C files for illegal includes."""
6 6
7 import codecs 7 import codecs
8 import os 8 import os
9 import re 9 import re
10 10
11 import results
11 from rules import Rule 12 from rules import Rule
12 13
13 14
14 class CppChecker(object): 15 class CppChecker(object):
15 16
16 EXTENSIONS = [ 17 EXTENSIONS = [
17 '.h', 18 '.h',
18 '.cc', 19 '.cc',
19 '.m', 20 '.m',
20 '.mm', 21 '.mm',
21 ] 22 ]
22 23
23 # The maximum number of non-include lines we can see before giving up. 24 # The maximum number of non-include lines we can see before giving up.
24 _MAX_UNINTERESTING_LINES = 50 25 _MAX_UNINTERESTING_LINES = 50
25 26
26 # The maximum line length, this is to be efficient in the case of very long 27 # The maximum line length, this is to be efficient in the case of very long
27 # lines (which can't be #includes). 28 # lines (which can't be #includes).
28 _MAX_LINE_LENGTH = 128 29 _MAX_LINE_LENGTH = 128
29 30
30 # This regular expression will be used to extract filenames from include 31 # This regular expression will be used to extract filenames from include
31 # statements. 32 # statements.
32 _EXTRACT_INCLUDE_PATH = re.compile( 33 _EXTRACT_INCLUDE_PATH = re.compile(
33 '[ \t]*#[ \t]*(?:include|import)[ \t]+"(.*)"') 34 '[ \t]*#[ \t]*(?:include|import)[ \t]+"(.*)"')
34 35
35 def __init__(self, verbose): 36 def __init__(self, verbose):
36 self._verbose = verbose 37 self._verbose = verbose
37 38
38 def CheckLine(self, rules, line, fail_on_temp_allow=False): 39 def CheckLine(self, rules, line, fail_on_temp_allow=False):
39 """Checks the given line with the given rule set. 40 """Checks the given line with the given rule set.
40 Returns a triplet (is_include, illegal_description, rule_type).
41 41
42 If the line is an #include directive the first value will be True. 42 Returns a tuple (is_include, dependency_violation) where
43 If it is also an illegal include, the second value will be a 43 is_include is True only if the line is an #include or #import
44 string describing the error. Otherwise, it will be None. If 44 statement, and dependency_violation is an instance of
45 fail_on_temp_allow is False, only Rule.DISALLOW rules will cause a 45 results.DependencyViolation if the line violates a rule, or None
46 problem to be reported. If it is true, both Rule.DISALLOW and 46 if it does not.
47 Rule.TEMP_ALLOW will cause an error.
48
49 The last item in the triplet returns the type of rule that
50 applied, one of Rule.ALLOW (which implies the second item is
51 None), Rule.DISALLOW (which implies that the second item is not
52 None) and Rule.TEMP_ALLOW (in which case the second item will be
53 None only if fail_on_temp_allow is False).
54 """ 47 """
55 found_item = self._EXTRACT_INCLUDE_PATH.match(line) 48 found_item = self._EXTRACT_INCLUDE_PATH.match(line)
56 if not found_item: 49 if not found_item:
57 return False, None, Rule.ALLOW # Not a match 50 return False, None # Not a match
58 51
59 include_path = found_item.group(1) 52 include_path = found_item.group(1)
60 53
61 if '\\' in include_path: 54 if '\\' in include_path:
62 return True, 'Include paths may not include backslashes', Rule.DISALLOW 55 return True, rules.SpecificRule(
56 'Include paths may not include backslashes.')
63 57
64 if '/' not in include_path: 58 if '/' not in include_path:
65 # Don't fail when no directory is specified. We may want to be more 59 # Don't fail when no directory is specified. We may want to be more
66 # strict about this in the future. 60 # strict about this in the future.
67 if self._verbose: 61 if self._verbose:
68 print ' WARNING: directory specified with no path: ' + include_path 62 print ' WARNING: directory specified with no path: ' + include_path
69 return True, None, Rule.ALLOW 63 return True, None
70 64
71 (allowed, why_failed) = rules.DirAllowed(include_path) 65 rule = rules.RuleApplyingTo(include_path)
72 if (allowed == Rule.DISALLOW or 66 if (rule.allow == Rule.DISALLOW or
73 (fail_on_temp_allow and allowed == Rule.TEMP_ALLOW)): 67 (fail_on_temp_allow and rule.allow == Rule.TEMP_ALLOW)):
74 if self._verbose: 68 return True, results.DependencyViolation(include_path, rule, rules)
75 retval = '\nFor %s' % rules 69 return True, None
76 else:
77 retval = ''
78 return True, retval + ('Illegal include: "%s"\n Because of %s' %
79 (include_path, why_failed)), allowed
80
81 return True, None, allowed
82 70
83 def CheckFile(self, rules, filepath): 71 def CheckFile(self, rules, filepath):
84 if self._verbose: 72 if self._verbose:
85 print 'Checking: ' + filepath 73 print 'Checking: ' + filepath
86 74
75 dependee_status = results.DependeeStatus(filepath)
87 ret_val = '' # We'll collect the error messages in here 76 ret_val = '' # We'll collect the error messages in here
88 last_include = 0 77 last_include = 0
89 with codecs.open(filepath, encoding='utf-8') as f: 78 with codecs.open(filepath, encoding='utf-8') as f:
90 in_if0 = 0 79 in_if0 = 0
91 for line_num, line in enumerate(f): 80 for line_num, line in enumerate(f):
92 if line_num - last_include > self._MAX_UNINTERESTING_LINES: 81 if line_num - last_include > self._MAX_UNINTERESTING_LINES:
93 break 82 break
94 83
95 line = line.strip() 84 line = line.strip()
96 85
97 # Check to see if we're at / inside a #if 0 block 86 # Check to see if we're at / inside a #if 0 block
98 if line.startswith('#if 0'): 87 if line.startswith('#if 0'):
99 in_if0 += 1 88 in_if0 += 1
100 continue 89 continue
101 if in_if0 > 0: 90 if in_if0 > 0:
102 if line.startswith('#if'): 91 if line.startswith('#if'):
103 in_if0 += 1 92 in_if0 += 1
104 elif line.startswith('#endif'): 93 elif line.startswith('#endif'):
105 in_if0 -= 1 94 in_if0 -= 1
106 continue 95 continue
107 96
108 is_include, line_status, rule_type = self.CheckLine(rules, line) 97 is_include, violation = self.CheckLine(rules, line)
109 if is_include: 98 if is_include:
110 last_include = line_num 99 last_include = line_num
111 if line_status is not None: 100 if violation:
112 if len(line_status) > 0: # Add newline to separate messages. 101 dependee_status.AddViolation(violation)
113 line_status += '\n'
114 ret_val += line_status
115 102
116 return ret_val 103 return dependee_status
117 104
118 @staticmethod 105 @staticmethod
119 def IsCppFile(file_path): 106 def IsCppFile(file_path):
120 """Returns True iff the given path ends in one of the extensions 107 """Returns True iff the given path ends in one of the extensions
121 handled by this checker. 108 handled by this checker.
122 """ 109 """
123 return os.path.splitext(file_path)[1] in CppChecker.EXTENSIONS 110 return os.path.splitext(file_path)[1] in CppChecker.EXTENSIONS
OLDNEW
« no previous file with comments | « tools/checkdeps/checkdeps_test.py ('k') | tools/checkdeps/java_checker.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698