[presubmit] Add check for unbalanced #define / #undef
With jumbo builds, we get spurious errors if several .cc files define the same preprocessor macro without undefining it. This is also disallowed by the style guide. This patch adds a presubmit check to check that each #define is eventually followed by a corresponding #undef. Special care has to be taken for conditionally defined macros. Here, the logic to check that there are not multiple defines and that they are undefined in all cases is not perfect; it's optimistic in order to avoid false positives. R=mstarzinger@chromium.org, machenbach@chromium.org Bug: v8:6811 Change-Id: I55cde499399d97a5eb02fbc5ecfa34e6a8099d06 Reviewed-on: https://chromium-review.googlesource.com/657104 Commit-Queue: Clemens Hammacher <clemensh@chromium.org> Reviewed-by: Michael Achenbach <machenbach@chromium.org> Reviewed-by: Michael Starzinger <mstarzinger@chromium.org> Cr-Commit-Position: refs/heads/master@{#47944}
This commit is contained in:
parent
f9efb571ab
commit
b8cc63ee6d
61
PRESUBMIT.py
61
PRESUBMIT.py
@ -279,6 +279,7 @@ def _CommonChecks(input_api, output_api):
|
||||
_CheckNoInlineHeaderIncludesInNormalHeaders(input_api, output_api))
|
||||
results.extend(_CheckMissingFiles(input_api, output_api))
|
||||
results.extend(_CheckJSONFiles(input_api, output_api))
|
||||
results.extend(_CheckMacroUndefs(input_api, output_api))
|
||||
return results
|
||||
|
||||
|
||||
@ -337,6 +338,66 @@ def _CheckJSONFiles(input_api, output_api):
|
||||
return [output_api.PresubmitError(r) for r in results]
|
||||
|
||||
|
||||
def _CheckMacroUndefs(input_api, output_api):
|
||||
"""
|
||||
Checks that each #define in a .cc file is eventually followed by an #undef.
|
||||
|
||||
TODO(clemensh): This check should eventually be enabled for all cc files via
|
||||
tools/presubmit.py (https://crbug.com/v8/6811).
|
||||
"""
|
||||
def FilterFile(affected_file):
|
||||
# Skip header files, as they often define type lists which are used in
|
||||
# other files.
|
||||
white_list = (r'.+\.cc',r'.+\.cpp',r'.+\.c')
|
||||
return input_api.FilterSourceFile(affected_file, white_list=white_list)
|
||||
|
||||
def TouchesMacros(f):
|
||||
for line in f.GenerateScmDiff().splitlines():
|
||||
if not line.startswith('+') and not line.startswith('-'):
|
||||
continue
|
||||
if define_pattern.match(line[1:]) or undef_pattern.match(line[1:]):
|
||||
return True
|
||||
return False
|
||||
|
||||
define_pattern = input_api.re.compile(r'#define (\w+)')
|
||||
undef_pattern = input_api.re.compile(r'#undef (\w+)')
|
||||
errors = []
|
||||
for f in input_api.AffectedFiles(
|
||||
file_filter=FilterFile, include_deletes=False):
|
||||
if not TouchesMacros(f):
|
||||
continue
|
||||
|
||||
defined_macros = dict()
|
||||
with open(f.LocalPath()) as fh:
|
||||
line_nr = 0
|
||||
for line in fh:
|
||||
line_nr += 1
|
||||
|
||||
define_match = define_pattern.match(line)
|
||||
if define_match:
|
||||
name = define_match.group(1)
|
||||
defined_macros[name] = line_nr
|
||||
|
||||
undef_match = undef_pattern.match(line)
|
||||
if undef_match:
|
||||
name = undef_match.group(1)
|
||||
if not name in defined_macros:
|
||||
errors.append('{}:{}: Macro named \'{}\' was not defined before.'
|
||||
.format(f.LocalPath(), line_nr, name))
|
||||
else:
|
||||
del defined_macros[name]
|
||||
for name, line_nr in sorted(defined_macros.items(), key=lambda e: e[1]):
|
||||
errors.append('{}:{}: Macro missing #undef: {}'
|
||||
.format(f.LocalPath(), line_nr, name))
|
||||
|
||||
if errors:
|
||||
return [output_api.PresubmitPromptOrNotify(
|
||||
'Detected mismatches in #define / #undef in the file(s) where you '
|
||||
'modified preprocessor macros.',
|
||||
errors)]
|
||||
return []
|
||||
|
||||
|
||||
def CheckChangeOnUpload(input_api, output_api):
|
||||
results = []
|
||||
results.extend(_CommonChecks(input_api, output_api))
|
||||
|
Loading…
Reference in New Issue
Block a user