1# Copyright 2024 The Chromium Authors 2# Use of this source code is governed by a BSD-style license that can be 3# found in the LICENSE file. 4"""Chromium presubmit script for base/allocator/partition_allocator. 5 6See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts 7for more details on the presubmit API built into depot_tools. 8""" 9 10PRESUBMIT_VERSION = '2.0.0' 11 12_PARTITION_ALLOC_BASE_PATH = 'base/allocator/partition_allocator/src/' 13 14 15# This is adapted from Chromium's PRESUBMIT.py. The differences are: 16# - Base path: It is relative to the partition_alloc's source directory instead 17# of chromium. 18# - Stricter: A single format is allowed: `PATH_ELEM_FILE_NAME_H_`. 19def CheckForIncludeGuards(input_api, output_api): 20 """Check that header files have proper include guards""" 21 22 def guard_for_file(file): 23 local_path = file.LocalPath() 24 if input_api.is_windows: 25 local_path = local_path.replace('\\', '/') 26 assert local_path.startswith(_PARTITION_ALLOC_BASE_PATH) 27 guard = input_api.os_path.normpath( 28 local_path[len(_PARTITION_ALLOC_BASE_PATH):]) 29 guard = guard + '_' 30 guard = guard.upper() 31 guard = input_api.re.sub(r'[+\\/.-]', '_', guard) 32 return guard 33 34 def is_partition_alloc_header_file(f): 35 # We only check header files. 36 return f.LocalPath().endswith('.h') 37 38 errors = [] 39 40 for f in input_api.AffectedSourceFiles(is_partition_alloc_header_file): 41 expected_guard = guard_for_file(f) 42 43 # Unlike the Chromium's top-level PRESUBMIT.py, we enforce a stricter 44 # rule which accepts only `PATH_ELEM_FILE_NAME_H_` per coding style. 45 guard_name_pattern = input_api.re.escape(expected_guard) 46 guard_pattern = input_api.re.compile(r'#ifndef\s+(' + 47 guard_name_pattern + ')') 48 49 guard_name = None 50 guard_line_number = None 51 seen_guard_end = False 52 for line_number, line in enumerate(f.NewContents()): 53 if guard_name is None: 54 match = guard_pattern.match(line) 55 if match: 56 guard_name = match.group(1) 57 guard_line_number = line_number 58 continue 59 60 # The line after #ifndef should have a #define of the same name. 61 if line_number == guard_line_number + 1: 62 expected_line = '#define %s' % guard_name 63 if line != expected_line: 64 errors.append( 65 output_api.PresubmitPromptWarning( 66 'Missing "%s" for include guard' % expected_line, 67 ['%s:%d' % (f.LocalPath(), line_number + 1)], 68 'Expected: %r\nGot: %r' % (expected_line, line))) 69 70 if not seen_guard_end and line == '#endif // %s' % guard_name: 71 seen_guard_end = True 72 continue 73 74 if seen_guard_end: 75 if line.strip() != '': 76 errors.append( 77 output_api.PresubmitPromptWarning( 78 'Include guard %s not covering the whole file' % 79 (guard_name), [f.LocalPath()])) 80 break # Nothing else to check and enough to warn once. 81 82 if guard_name is None: 83 errors.append( 84 output_api.PresubmitPromptWarning( 85 'Missing include guard in %s\n' 86 'Recommended name: %s\n' % 87 (f.LocalPath(), expected_guard))) 88 89 return errors 90