| Index: PRESUBMIT.py
|
| diff --git a/PRESUBMIT.py b/PRESUBMIT.py
|
| index 686ae511773be4835973f9e2dac4ab7d9776bd2b..a87d017275ec7c8cf0e74943e58c4af2bcb26eed 100644
|
| --- a/PRESUBMIT.py
|
| +++ b/PRESUBMIT.py
|
| @@ -58,6 +58,11 @@ _TEST_ONLY_WARNING = (
|
| 'not perfect. The commit queue will not block on this warning.')
|
|
|
|
|
| +_INCLUDE_IMPORT_WARNING = (
|
| + 'You are including ObjC headers or importing C++ headers. Remember to use '
|
| + 'the right #include/#import directive.')
|
| +
|
| +
|
| _INCLUDE_ORDER_WARNING = (
|
| 'Your #include order seems to be broken. Remember to use the right '
|
| 'collation (LC_COLLATE=C) and check\nhttps://google.github.io/styleguide/'
|
| @@ -790,6 +795,133 @@ def _CheckNoAuraWindowPropertyHInHeaders(input_api, output_api):
|
| return results
|
|
|
|
|
| +def _CheckHeaderIsObjectiveC(input_api, included_file, included_file_content):
|
| + """Checks if f is a C++ or an Objective-C header.
|
| +
|
| + An Objective-C header is a header with a line starting with
|
| + - #import
|
| + - @class
|
| + - @interface
|
| + - @implementation
|
| + - @protocol
|
| + - @end
|
| +
|
| + or with the two lines
|
| + #if !defined(__OBJC__)
|
| + #error ...
|
| +
|
| + Returns a pair of booleans.
|
| + - First is true if the determination of Objective-C could be done without
|
| + error
|
| + - Second is true if the file has been determined as Objective-C header.
|
| + """
|
| + file_path_ios_mac_pattern = input_api.re.compile(
|
| + r'(?:.*[_./])?(?:ios|mac)[_./].*')
|
| + if not file_path_ios_mac_pattern.match(included_file):
|
| + return (False, False)
|
| + guard_noobjc_pattern = input_api.re.compile(
|
| + r'\s*#if !defined\(__OBJC__\).*')
|
| + guard_objc_pattern = input_api.re.compile(
|
| + r'\s*#if defined\(__OBJC__\).*')
|
| + error_pattern = input_api.re.compile(
|
| + r'\s*#error .*')
|
| + block_pattern = input_api.re.compile(
|
| + r'\s*typedef.*\(\^.*')
|
| + objc_pattern = input_api.re.compile(
|
| + r'\s*(@class|@interface|@end|@implementation|@protocol|#import).*')
|
| + lines = included_file_content.NewContents()
|
| + previous_was_noobjc_define = False
|
| + for included_line in lines:
|
| + if guard_noobjc_pattern.match(included_line):
|
| + previous_was_noobjc_define = True
|
| + continue
|
| + if previous_was_noobjc_define:
|
| + # Found No Objc Guard. The next line must be check to see if it is
|
| + # throwing an error.
|
| + if error_pattern.match(included_line):
|
| + # There is an error thrown if the file is compiled without ObjC.
|
| + # Header is Objective-C.
|
| + return (True, True)
|
| + else:
|
| + # There are ifdefs about Objective-C, file can likely be imported or
|
| + # included.
|
| + return (False, False)
|
| + previous_was_noobjc_define = False
|
| + if guard_objc_pattern.match(included_line):
|
| + # Found ObjcGuard. This file can be included or imported.
|
| + return (False, False)
|
| + if objc_pattern.match(included_line) or block_pattern.match(included_line):
|
| + # Found an Objective-C keyword. File is an Objective-C header.
|
| + return (True, True)
|
| + # No Objective-C clue, file must be C++.
|
| + return (True, False)
|
| +
|
| +
|
| +def _CheckIncludeImportInFile(input_api, f):
|
| + """Checks the include/import coherence in file f."""
|
| + custom_include_pattern = input_api.re.compile(r'\s*#include "(?P<FILE>.*)"')
|
| + custom_import_pattern = input_api.re.compile(r'\s*#import "(?P<FILE>.*)"')
|
| + contents = f.NewContents()
|
| + warnings = []
|
| + for (line_num, line) in enumerate(contents):
|
| + is_imported = False
|
| + included_file = ""
|
| + match_cpp = custom_include_pattern.match(line)
|
| + if match_cpp:
|
| + match_dict = match_cpp.groupdict()
|
| + included_file = match_dict['FILE']
|
| + match_objc = custom_import_pattern.match(line)
|
| + if match_objc:
|
| + match_dict = match_objc.groupdict()
|
| + included_file = match_dict['FILE']
|
| + is_imported = True
|
| + if included_file == "":
|
| + continue
|
| + included_absolute_path = input_api.os_path.join(
|
| + input_api.change.RepositoryRoot(), included_file)
|
| + if not input_api.os_path.isfile(included_absolute_path):
|
| + # Included file may need a custom -I flag.
|
| + # Ignore it.
|
| + continue
|
| + included_file_content = input_api.ReadFile(included_absolute_path)
|
| + (detection_ok, has_objc) = \
|
| + _CheckHeaderIsObjectiveC(input_api,
|
| + included_file,
|
| + included_file_content)
|
| + if not detection_ok:
|
| + # There is an Objective-C guard, the file is internded to be included or
|
| + # imported.
|
| + continue
|
| + if is_imported and f.LocalPath().endswith('.cc'):
|
| + warnings.append('%s:%d %s' % (f.LocalPath(), line_num, line))
|
| + warnings.append('Header is imported in a C++ file.')
|
| + if has_objc and not is_imported:
|
| + warnings.append('%s:%d %s' % (f.LocalPath(), line_num, line))
|
| + warnings.append('Header is included but has Objective-C instructions.')
|
| + if not has_objc and is_imported:
|
| + warnings.append('%s:%d %s' % (f.LocalPath(), line_num, line))
|
| + warnings.append('Header is imported but has no Objective-C instructions.')
|
| + return warnings
|
| +
|
| +
|
| +def _CheckIncludeImport(input_api, output_api):
|
| + """Checks that C++ headers are included, Objective-C headers imported.
|
| + """
|
| + def FileFilterIncludeImport(affected_file):
|
| + black_list = (_EXCLUDED_PATHS + input_api.DEFAULT_BLACK_LIST)
|
| + return input_api.FilterSourceFile(affected_file, black_list=black_list)
|
| +
|
| + warnings = []
|
| + for f in input_api.AffectedFiles(file_filter=FileFilterIncludeImport):
|
| + warnings.extend(_CheckIncludeImportInFile(input_api, f))
|
| +
|
| + results = []
|
| + if warnings:
|
| + results.append(output_api.PresubmitPromptOrNotify(_INCLUDE_IMPORT_WARNING,
|
| + warnings))
|
| + return results
|
| +
|
| +
|
| def _CheckIncludeOrderForScope(scope, input_api, file_path, changed_linenums):
|
| """Checks that the lines in scope occur in the right order.
|
|
|
| @@ -2088,6 +2220,7 @@ def _CommonChecks(input_api, output_api):
|
| results.extend(_CheckFilePermissions(input_api, output_api))
|
| results.extend(_CheckTeamTags(input_api, output_api))
|
| results.extend(_CheckNoAuraWindowPropertyHInHeaders(input_api, output_api))
|
| + results.extend(_CheckIncludeImport(input_api, output_api))
|
| results.extend(_CheckIncludeOrder(input_api, output_api))
|
| results.extend(_CheckForVersionControlConflicts(input_api, output_api))
|
| results.extend(_CheckPatchFiles(input_api, output_api))
|
|
|