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. 4 5"""Top-level presubmit script for cc. 6 7See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts for 8details on the presubmit API built into gcl. 9""" 10 11import re 12import string 13 14CC_SOURCE_FILES=(r'^cc/.*\.(cc|h)$',) 15CC_PERF_TEST =(r'^.*_perftest.*\.(cc|h)$',) 16 17def CheckChangeLintsClean(input_api, output_api): 18 input_api.cpplint._cpplint_state.ResetErrorCounts() # reset global state 19 source_filter = lambda x: input_api.FilterSourceFile( 20 x, white_list=CC_SOURCE_FILES, black_list=None) 21 files = [f.AbsoluteLocalPath() for f in 22 input_api.AffectedSourceFiles(source_filter)] 23 level = 1 # strict, but just warn 24 25 for file_name in files: 26 input_api.cpplint.ProcessFile(file_name, level) 27 28 if not input_api.cpplint._cpplint_state.error_count: 29 return [] 30 31 return [output_api.PresubmitPromptWarning( 32 'Changelist failed cpplint.py check.')] 33 34def CheckAsserts(input_api, output_api, white_list=CC_SOURCE_FILES, black_list=None): 35 black_list = tuple(black_list or input_api.DEFAULT_BLACK_LIST) 36 source_file_filter = lambda x: input_api.FilterSourceFile(x, white_list, black_list) 37 38 assert_files = [] 39 notreached_files = [] 40 41 for f in input_api.AffectedSourceFiles(source_file_filter): 42 contents = input_api.ReadFile(f, 'rb') 43 # WebKit ASSERT() is not allowed. 44 if re.search(r"\bASSERT\(", contents): 45 assert_files.append(f.LocalPath()) 46 # WebKit ASSERT_NOT_REACHED() is not allowed. 47 if re.search(r"ASSERT_NOT_REACHED\(", contents): 48 notreached_files.append(f.LocalPath()) 49 50 if assert_files: 51 return [output_api.PresubmitError( 52 'These files use ASSERT instead of using DCHECK:', 53 items=assert_files)] 54 if notreached_files: 55 return [output_api.PresubmitError( 56 'These files use ASSERT_NOT_REACHED instead of using NOTREACHED:', 57 items=notreached_files)] 58 return [] 59 60def CheckStdAbs(input_api, output_api, 61 white_list=CC_SOURCE_FILES, black_list=None): 62 black_list = tuple(black_list or input_api.DEFAULT_BLACK_LIST) 63 source_file_filter = lambda x: input_api.FilterSourceFile(x, 64 white_list, 65 black_list) 66 67 using_std_abs_files = [] 68 found_fabs_files = [] 69 missing_std_prefix_files = [] 70 71 for f in input_api.AffectedSourceFiles(source_file_filter): 72 contents = input_api.ReadFile(f, 'rb') 73 if re.search(r"using std::f?abs;", contents): 74 using_std_abs_files.append(f.LocalPath()) 75 if re.search(r"\bfabsf?\(", contents): 76 found_fabs_files.append(f.LocalPath()); 77 # The following regular expression in words says: 78 # "if there is no 'std::' behind an 'abs(' or 'absf(', 79 # or if there is no 'std::' behind a 'fabs(' or 'fabsf(', 80 # then it's a match." 81 if re.search(r"((?<!std::)(\babsf?\()|(?<!std::)(\bfabsf?\())", contents): 82 missing_std_prefix_files.append(f.LocalPath()) 83 84 result = [] 85 if using_std_abs_files: 86 result.append(output_api.PresubmitError( 87 'These files have "using std::abs" which is not permitted.', 88 items=using_std_abs_files)) 89 if found_fabs_files: 90 result.append(output_api.PresubmitError( 91 'std::abs() should be used instead of std::fabs() for consistency.', 92 items=found_fabs_files)) 93 if missing_std_prefix_files: 94 result.append(output_api.PresubmitError( 95 'These files use abs(), absf(), fabs(), or fabsf() without qualifying ' 96 'the std namespace. Please use std::abs() in all places.', 97 items=missing_std_prefix_files)) 98 return result 99 100def CheckSpamLogging(input_api, 101 output_api, 102 white_list=CC_SOURCE_FILES, 103 black_list=None): 104 black_list = tuple(black_list or input_api.DEFAULT_BLACK_LIST) 105 source_file_filter = lambda x: input_api.FilterSourceFile(x, 106 white_list, 107 black_list) 108 109 log_info = [] 110 printf = [] 111 112 for f in input_api.AffectedSourceFiles(source_file_filter): 113 contents = input_api.ReadFile(f, 'rb') 114 if re.search(r"\bD?LOG\s*\(\s*INFO\s*\)", contents): 115 log_info.append(f.LocalPath()) 116 if re.search(r"\bf?printf\(", contents): 117 printf.append(f.LocalPath()) 118 119 if log_info: 120 return [output_api.PresubmitError( 121 'These files spam the console log with LOG(INFO):', 122 items=log_info)] 123 if printf: 124 return [output_api.PresubmitError( 125 'These files spam the console log with printf/fprintf:', 126 items=printf)] 127 return [] 128 129def CheckPassByValue(input_api, 130 output_api, 131 white_list=CC_SOURCE_FILES, 132 black_list=None): 133 black_list = tuple(black_list or input_api.DEFAULT_BLACK_LIST) 134 source_file_filter = lambda x: input_api.FilterSourceFile(x, 135 white_list, 136 black_list) 137 138 local_errors = [] 139 140 # Well-defined simple classes containing only <= 4 ints, or <= 2 floats. 141 pass_by_value_types = ['base::Time', 142 'base::TimeTicks', 143 'gfx::Point', 144 'gfx::PointF', 145 'gfx::Rect', 146 'gfx::Size', 147 'gfx::SizeF', 148 'gfx::Vector2d', 149 'gfx::Vector2dF', 150 ] 151 152 for f in input_api.AffectedSourceFiles(source_file_filter): 153 contents = input_api.ReadFile(f, 'rb') 154 match = re.search( 155 r'\bconst +' + '(?P<type>(%s))&' % 156 string.join(pass_by_value_types, '|'), 157 contents) 158 if match: 159 local_errors.append(output_api.PresubmitError( 160 '%s passes %s by const ref instead of by value.' % 161 (f.LocalPath(), match.group('type')))) 162 return local_errors 163 164def CheckTodos(input_api, output_api): 165 errors = [] 166 167 source_file_filter = lambda x: x 168 for f in input_api.AffectedSourceFiles(source_file_filter): 169 contents = input_api.ReadFile(f, 'rb') 170 if ('FIX'+'ME') in contents: 171 errors.append(f.LocalPath()) 172 173 if errors: 174 return [output_api.PresubmitError( 175 'All TODO comments should be of the form TODO(name).', 176 items=errors)] 177 return [] 178 179 180def CheckChangeOnUpload(input_api, output_api): 181 results = [] 182 results += CheckAsserts(input_api, output_api) 183 results += CheckStdAbs(input_api, output_api) 184 results += CheckSpamLogging(input_api, output_api, black_list=CC_PERF_TEST) 185 results += CheckPassByValue(input_api, output_api) 186 results += CheckChangeLintsClean(input_api, output_api) 187 results += CheckTodos(input_api, output_api) 188 return results 189 190def GetPreferredTrySlaves(project, change): 191 return [ 192 'linux_layout_rel', 193 ] 194