Title: [254831] trunk/Tools
Revision
254831
Author
[email protected]
Date
2020-01-20 10:07:34 -0800 (Mon, 20 Jan 2020)

Log Message

check-webkit-style: Improve header guard checks
<https://webkit.org/b/206480>

Reviewed by Darin Adler.

* Scripts/webkitpy/style/checkers/cpp.py:
(check_for_header_guard):
- Add `file_path` (filename) argument to check for config.h and
  *Prefix.h headers.
- Use hints in header file to determine if this is a header file
  only used by Objective-C or not.
- Change #ifndef/#define check to use both lines instead of
  assuming a format for the macro.
- Emit new 'build/header_guard_missing' error.
(_process_lines):
- Pass `filename` argument to check_for_header_guard().
(CppChecker):
- Enable new 'build/header_guard_missing' check.

* Scripts/webkitpy/style/checkers/cpp_unittest.py:
(CppStyleTestBase.perform_header_guard_check):
(CppStyleTestBase.assert_header_guard):
- Move default `filename` argument from
  perform_header_guard_check() to assert_header_guard() so tests
  may pass in different values for header paths.
(CppStyleTest):
- Add tests for config.h, *Prefix.h headers.
- Update test for `build/header_guard' (legacy header guard)
  error.
- Update test for missing header guard so that it now expects a
  'build/header_guard_missing' error message.
- Add tests for Objective-C headers with and without __OBJC__
  checks.

Modified Paths

Diff

Modified: trunk/Tools/ChangeLog (254830 => 254831)


--- trunk/Tools/ChangeLog	2020-01-20 16:56:49 UTC (rev 254830)
+++ trunk/Tools/ChangeLog	2020-01-20 18:07:34 UTC (rev 254831)
@@ -1,3 +1,39 @@
+2020-01-20  David Kilzer  <[email protected]>
+
+        check-webkit-style: Improve header guard checks
+        <https://webkit.org/b/206480>
+
+        Reviewed by Darin Adler.
+
+        * Scripts/webkitpy/style/checkers/cpp.py:
+        (check_for_header_guard):
+        - Add `file_path` (filename) argument to check for config.h and
+          *Prefix.h headers.
+        - Use hints in header file to determine if this is a header file
+          only used by Objective-C or not.
+        - Change #ifndef/#define check to use both lines instead of
+          assuming a format for the macro.
+        - Emit new 'build/header_guard_missing' error.
+        (_process_lines):
+        - Pass `filename` argument to check_for_header_guard().
+        (CppChecker):
+        - Enable new 'build/header_guard_missing' check.
+
+        * Scripts/webkitpy/style/checkers/cpp_unittest.py:
+        (CppStyleTestBase.perform_header_guard_check):
+        (CppStyleTestBase.assert_header_guard):
+        - Move default `filename` argument from
+          perform_header_guard_check() to assert_header_guard() so tests
+          may pass in different values for header paths.
+        (CppStyleTest):
+        - Add tests for config.h, *Prefix.h headers.
+        - Update test for `build/header_guard' (legacy header guard)
+          error.
+        - Update test for missing header guard so that it now expects a
+          'build/header_guard_missing' error message.
+        - Add tests for Objective-C headers with and without __OBJC__
+          checks.
+
 2020-01-20  Zan Dobersek  <[email protected]>
 
         [WPE] Add WebKitRectangle, use it for WebKitWebView's SHOW_MENU signal

Modified: trunk/Tools/Scripts/webkitpy/style/checkers/cpp.py (254830 => 254831)


--- trunk/Tools/Scripts/webkitpy/style/checkers/cpp.py	2020-01-20 16:56:49 UTC (rev 254830)
+++ trunk/Tools/Scripts/webkitpy/style/checkers/cpp.py	2020-01-20 18:07:34 UTC (rev 254831)
@@ -2,7 +2,7 @@
 #
 # Copyright (C) 2009, 2010, 2012 Google Inc. All rights reserved.
 # Copyright (C) 2009 Torch Mobile Inc.
-# Copyright (C) 2009-2019 Apple Inc. All rights reserved.
+# Copyright (C) 2009-2020 Apple Inc. All rights reserved.
 # Copyright (C) 2010 Chris Jerdonek ([email protected])
 #
 # Redistribution and use in source and binary forms, with or without
@@ -37,6 +37,7 @@
 """Support for check-webkit-style."""
 
 import codecs
+import functools
 import math  # for log
 import os
 import os.path
@@ -930,32 +931,61 @@
               'You should have a line: "Copyright [year] <Copyright Owner>"')
 
 
-def check_for_header_guard(lines, error):
+def check_for_header_guard(file_path, lines, error):
     """Checks that the file contains a header guard.
 
     Logs an error if there was an #ifndef guard in a header
-    that should be a #pragma once guard.
+    that should be a #pragma once guard, or if there is a missing
+    #pragma once guard.
 
     Args:
+      file_path: Path to the header file that is being processed.
       lines: An array of strings, each representing a line of the file.
       error: The function to call with any errors found.
     """
 
+    filename = os.path.split(file_path)[-1]
+    if filename == 'config.h' or filename.endswith('Prefix.h'):
+        return
+
+    first_blank_line_number = 0
+    has_import_statement = False
+    has_objc_check = False
+    has_objc_keywords = False
     for line_number, line in enumerate(lines):
+        if line == '' and first_blank_line_number == 0:
+            first_blank_line_number = line_number
         if line.startswith('#pragma once'):
             return
+        if line.startswith('#import '):
+            has_import_statement = True
+        if '__OBJC__' in line:
+            has_objc_check = True
+        if functools.reduce(lambda x, y: x or y, map(lambda x: x in line, ['@class', '@interface', '@protocol'])):
+            has_objc_keywords = True
 
+    if (has_import_statement or has_objc_keywords) and not has_objc_check:
+        return  # Objective-C-only headers don't need guards.
+
     # If there is no #pragma once, but there is an #ifndef, warn only if it was modified.
     ifndef_line_number = 0
+    previous_line = None
     for line_number, line in enumerate(lines):
-        line_split = line.split()
-        if len(line_split) >= 2:
-            if line_split[0] == '#ifndef' and line_split[1].endswith('_h'):
-                error(line_number, 'build/header_guard', 5,
-                    'Use #pragma once instead of #ifndef for header guard.')
-                return
+        if previous_line is not None:
+            previous_line_split = previous_line.split()
+            line_split = line.split()
+            if len(previous_line_split) >= 2 and len(line_split) >= 2:
+                if previous_line_split[0] == '#ifndef' and line_split[0] == '#define' \
+                        and previous_line_split[1] == line_split[1]:
+                    error(line_number, 'build/header_guard', 5,
+                          'Use #pragma once instead of #ifndef for header guard.')
+                    return
+        previous_line = line
 
+    error(first_blank_line_number + 1, 'build/header_guard_missing', 5,
+          'Missing #pragma once for header guard.')
 
+
 def check_for_unicode_replacement_characters(lines, error):
     """Logs an error for each line containing Unicode replacement characters.
 
@@ -4079,7 +4109,7 @@
     check_for_copyright(lines, error)
 
     if file_extension == 'h':
-        check_for_header_guard(lines, error)
+        check_for_header_guard(filename, lines, error)
         if filename == 'Source/WTF/wtf/Platform.h':
             check_platformh_comments(lines, error)
 
@@ -4120,6 +4150,7 @@
         'build/endif_comment',
         'build/forward_decl',
         'build/header_guard',
+        'build/header_guard_missing',
         'build/include',
         'build/include_order',
         'build/include_what_you_use',

Modified: trunk/Tools/Scripts/webkitpy/style/checkers/cpp_unittest.py (254830 => 254831)


--- trunk/Tools/Scripts/webkitpy/style/checkers/cpp_unittest.py	2020-01-20 16:56:49 UTC (rev 254830)
+++ trunk/Tools/Scripts/webkitpy/style/checkers/cpp_unittest.py	2020-01-20 18:07:34 UTC (rev 254831)
@@ -2,7 +2,7 @@
 #
 # Copyright (C) 2011 Google Inc. All rights reserved.
 # Copyright (C) 2009 Torch Mobile Inc.
-# Copyright (C) 2009-2019 Apple Inc. All rights reserved.
+# Copyright (C) 2009-2020 Apple Inc. All rights reserved.
 # Copyright (C) 2010 Chris Jerdonek ([email protected])
 #
 # Redistribution and use in source and binary forms, with or without
@@ -309,7 +309,7 @@
         return self.perform_lint(code, filename, basic_error_rules, unit_test_config)
 
     # Only include header guard errors.
-    def perform_header_guard_check(self, code, filename='foo.h'):
+    def perform_header_guard_check(self, code, filename):
         basic_error_rules = ('-', '+build/header_guard')
         return self.perform_lint(code, filename, basic_error_rules)
 
@@ -343,9 +343,9 @@
         self.assertEqual(expected_message,
                           self.perform_include_what_you_use(code))
 
-    def assert_header_guard(self, code, expected_message):
+    def assert_header_guard(self, code, expected_message, filename='foo.h'):
         self.assertEqual(expected_message,
-                          self.perform_header_guard_check(code))
+                         self.perform_header_guard_check(code, filename))
 
     def assert_blank_lines_check(self, lines, start_errors, end_errors):
         error_collector = ErrorCollector(self.assertTrue)
@@ -2676,17 +2676,83 @@
     def test_build_header_guard(self):
         rules = ('-', '+build/header_guard')
 
-        # Old header guard.
-        self.assert_header_guard('#ifndef Foo_h',
+        # No warning for config.h and *Prefix.h headers.
+        self.assert_header_guard('', '', 'config.h')
+        self.assert_header_guard('', '', 'FooPrefix.h')
+
+        # No warning for valid header guard.
+        self.assert_header_guard('#pragma once', '')
+
+        # Warning for old header guard.
+        self.assert_header_guard(
+            '#ifndef Foo_h\n'
+            '#define Foo_h\n'
+            '#endif /* Foo_h */\n',
             'Use #pragma once instead of #ifndef for header guard.'
             '  [build/header_guard] [5]')
 
-        # No header guard. Okay, since this could be an ObjC header.
-        self.assert_header_guard('', '')
+        # Warning for missing header guard.
+        self.assert_header_guard(
+            '',
+            'Missing #pragma once for header guard.'
+            '  [build/header_guard_missing] [5]')
 
-        # Valid header guard.
-        self.assert_header_guard('#pragma once', '')
+        # No warning for Obj-C header with #import statement.
+        self.assert_header_guard(
+            '#import <Foundation/Foundation.h>',
+            '')
 
+        # No warning for Obj-C header with @class keyword.
+        self.assert_header_guard(
+            '@class NSString;',
+            '')
+
+        # No warning for Obj-C header with @interface keyword.
+        self.assert_header_guard(
+            '@interface NSString (MyCategory)\n'
+            '@end\n',
+            '')
+
+        # No warning for Obj-C header with @protocol keyword.
+        self.assert_header_guard(
+            '@protocol MyProtocol : NSObject\n'
+            '@end\n',
+            '')
+
+        # Warning for Obj-C header with #import statement and __OBJC__ check.
+        self.assert_header_guard(
+            '#ifdef __OBJC__\n'
+            '#import <Foundation/Foundation.h>\n'
+            '#endif /* __OBJC__ */\n',
+            'Missing #pragma once for header guard.'
+            '  [build/header_guard_missing] [5]')
+
+        # Warning for Obj-C header with @class keyword and __OBJC__ check.
+        self.assert_header_guard(
+            '#ifdef __OBJC__\n'
+            '@class NSString;\n'
+            '#endif /* __OBJC__ */\n',
+            'Missing #pragma once for header guard.'
+            '  [build/header_guard_missing] [5]')
+
+        # Warning for Obj-C header with @interface keyword and __OBJC__ check.
+        self.assert_header_guard(
+            '#ifdef __OBJC__\n'
+            '@interface NSString (MyCategory)\n'
+            '@end\n'
+            '#endif /* __OBJC__ */\n',
+            'Missing #pragma once for header guard.'
+            '  [build/header_guard_missing] [5]')
+
+        # Warning for Obj-C header with @protocol keyword and __OBJC__ check.
+        self.assert_header_guard(
+            '#ifdef __OBJC__\n'
+            '@protocol MyProtocol : NSObject\n'
+            '@end\n'
+            '#endif /* __OBJC__ */\n',
+            'Missing #pragma once for header guard.'
+            '  [build/header_guard_missing] [5]')
+
     def test_build_printf_format(self):
         self.assert_lint(
             r'printf("\%%d", value);',
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to