浏览代码

[cpplint] add nolint region support

Both the internal and community maintained cpplint support regional
nolint annotation NOLINTBEGIN/NOLINTEND.

Bug: 409733462
Change-Id: If738e8f6b8b30e88adec74383fecd8198fe70fbd
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/tools/depot_tools/+/6446042
Auto-Submit: Tommy Chiang <ototot@google.com>
Reviewed-by: Yiwei Zhang <yiwzhang@google.com>
Commit-Queue: Tommy Chiang <ototot@google.com>
Tommy Chiang 4 月之前
父节点
当前提交
f088ff9f1b
共有 1 个文件被更改,包括 71 次插入22 次删除
  1. 71 22
      cpplint.py

+ 71 - 22
cpplint.py

@@ -70,6 +70,9 @@ Syntax: cpplint.py [--verbose=#] [--output=vs7] [--filter=-x,+y,...]
   'NOLINT(category)' comment to the line.  NOLINT or NOLINT(*)
   'NOLINT(category)' comment to the line.  NOLINT or NOLINT(*)
   suppresses errors of all categories on that line.
   suppresses errors of all categories on that line.
 
 
+  To suppress false-positive errors for a block of lines, enclose the
+  block with 'NOLINTBEGIN(category)' and 'NOLINTEND' comment lines.
+
   The files passed in will be linted; at least one file must be provided.
   The files passed in will be linted; at least one file must be provided.
   Default linted extensions are .cc, .cpp, .cu, .cuh and .h.  Change the
   Default linted extensions are .cc, .cpp, .cu, .cuh and .h.  Change the
   extensions with the --extensions flag.
   extensions with the --extensions flag.
@@ -785,7 +788,29 @@ _valid_extensions = set(['cc', 'h', 'cpp', 'cu', 'cuh'])
 _global_error_suppressions = {}
 _global_error_suppressions = {}
 
 
 
 
-def ParseNolintSuppressions(filename, raw_line, linenum, error):
+def AddSuppression(suppressed_line, category):
+    """Update global error_suppressions for a single line.
+
+  Args:
+    suppressed_line: int, line number where suppression is to be added.
+    category: str, category to suppress, or None to suppress all.
+  """
+    if category:
+        if category.startswith('(') and category.endswith(')'):
+            category = category[1:-1]
+        if category == '*':
+            category = None  # "(*)" -> Suppress all
+
+    if category is None or category in _ERROR_CATEGORIES:
+        _error_suppressions.setdefault(category, set()).add(suppressed_line)
+    else:
+        # Unknown category.  We used to track these in an _LEGACY_ERROR_CATEGORIES
+        # list, but these days we just silently ignore them since they may be
+        # intended for ClangTidy.
+        pass
+
+
+def ParseNolintSuppressions(filename, raw_lines, linenum, error):
     """Updates the global list of line error-suppressions.
     """Updates the global list of line error-suppressions.
 
 
     Parses any NOLINT comments on the current line, updating the global
     Parses any NOLINT comments on the current line, updating the global
@@ -794,28 +819,54 @@ def ParseNolintSuppressions(filename, raw_line, linenum, error):
 
 
     Args:
     Args:
         filename: str, the name of the input file.
         filename: str, the name of the input file.
-        raw_line: str, the line of input text, with comments.
+        raw_lines: List[str], list of input lines, with comments.
         linenum: int, the number of the current line.
         linenum: int, the number of the current line.
         error: function, an error handler.
         error: function, an error handler.
     """
     """
-    matched = Search(r'\bNOLINT(NEXTLINE)?\b(\([^)]+\))?', raw_line)
+    matched = Search(r'\bNOLINT(NEXTLINE|BEGIN)?\b(\([^)]+\))?',
+                     raw_lines[linenum])
     if matched:
     if matched:
-        if matched.group(1):
-            suppressed_line = linenum + 1
-        else:
-            suppressed_line = linenum
+        annotation_type = matched.group(1)
         category = matched.group(2)
         category = matched.group(2)
-        if category in (None, '(*)'):  # => "suppress all"
-            _error_suppressions.setdefault(None, set()).add(suppressed_line)
-        else:
-            if category.startswith('(') and category.endswith(')'):
-                category = category[1:-1]
-                if category in _ERROR_CATEGORIES:
-                    _error_suppressions.setdefault(category,
-                                                   set()).add(suppressed_line)
-                elif category not in _LEGACY_ERROR_CATEGORIES:
+        if annotation_type:
+            # Suppressed line(s) are not the current line.
+            if annotation_type == 'NEXTLINE':
+                # Silence next line only.
+                AddSuppression(linenum + 1, category)
+            else:
+                # Silence a block of lines.
+                #
+                # Note that multiple NOLINTBEGIN lines may be terminated by a
+                # single NOLINTEND line:
+                #
+                #   // NOLINTBEGIN(some-category)
+                #   // NOLINTBEGIN(different-category)
+                #   ...
+                #   // NOLINTEND  <- ends both silences
+                #
+                # Also note that because we only consume one single NOLINT
+                # annotation per line, in order to silence multiple categories
+                # of warnings, the above example would be the preferred way to
+                # do it.  This is actually an improvement over historical
+                # handling of single line NOLINT annotations, where the choices
+                # were to silence 0 or 1 or all categories on a single line.
+                lastline = None
+                for i in range(linenum + 1, len(raw_lines)):
+                    if Search(r'\bNOLINTEND\b', raw_lines[i]):
+                        lastline = i
+                        break
+                if not lastline:
+                    # Because multiple NOLINTBEGIN may be terminated by a single
+                    # NOLINTEND, the error message here deliberately avoids
+                    # something like "Unmatched NOLINTEND".
                     error(filename, linenum, 'readability/nolint', 5,
                     error(filename, linenum, 'readability/nolint', 5,
-                          'Unknown NOLINT error category: %s' % category)
+                          'Missing NOLINTEND')
+                else:
+                    for i in range(linenum + 1, lastline):
+                        AddSuppression(i, category)
+        else:
+            # Suppressing errors on current line.
+            AddSuppression(linenum, category)
 
 
 
 
 def ProcessGlobalSuppresions(lines):
 def ProcessGlobalSuppresions(lines):
@@ -2158,14 +2209,12 @@ def CheckForHeaderGuard(filename, clean_lines, error):
         if ifndef != cppvar + '_':
         if ifndef != cppvar + '_':
             error_level = 5
             error_level = 5
 
 
-        ParseNolintSuppressions(filename, raw_lines[ifndef_linenum],
-                                ifndef_linenum, error)
+        ParseNolintSuppressions(filename, raw_lines, ifndef_linenum, error)
         error(filename, ifndef_linenum, 'build/header_guard', error_level,
         error(filename, ifndef_linenum, 'build/header_guard', error_level,
               '#ifndef header guard has wrong style, please use: %s' % cppvar)
               '#ifndef header guard has wrong style, please use: %s' % cppvar)
 
 
     # Check for "//" comments on endif line.
     # Check for "//" comments on endif line.
-    ParseNolintSuppressions(filename, raw_lines[endif_linenum], endif_linenum,
-                            error)
+    ParseNolintSuppressions(filename, raw_lines, endif_linenum, error)
     match = Match(r'#endif\s*//\s*' + cppvar + r'(_)?\b', endif)
     match = Match(r'#endif\s*//\s*' + cppvar + r'(_)?\b', endif)
     if match:
     if match:
         if match.group(1) == '_':
         if match.group(1) == '_':
@@ -6137,7 +6186,7 @@ def ProcessLine(filename,
             clean_lines, line, error
             clean_lines, line, error
     """
     """
     raw_lines = clean_lines.raw_lines
     raw_lines = clean_lines.raw_lines
-    ParseNolintSuppressions(filename, raw_lines[line], line, error)
+    ParseNolintSuppressions(filename, raw_lines, line, error)
     nesting_state.Update(filename, clean_lines, line, error)
     nesting_state.Update(filename, clean_lines, line, error)
     CheckForNamespaceIndentation(filename, nesting_state, clean_lines, line,
     CheckForNamespaceIndentation(filename, nesting_state, clean_lines, line,
                                  error)
                                  error)