Home | History | Annotate | Download | only in cc
      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 
      7 See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts for
      8 details on the presubmit API built into gcl.
      9 """
     10 
     11 import re
     12 import string
     13 
     14 CC_SOURCE_FILES=(r'^cc/.*\.(cc|h)$',)
     15 CC_PERF_TEST =(r'^.*_perftest.*\.(cc|h)$',)
     16 
     17 def 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 
     34 def 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 
     60 def 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 
    100 def 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 
    129 def 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 
    164 def 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 
    180 def 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 
    190 def GetPreferredTrySlaves(project, change):
    191   return [
    192     'linux_layout_rel',
    193     ]
    194