This revision was landed with ongoing or failed builds.
This revision was automatically updated to reflect the committed changes.
Closed by commit rG89e663c4f83a: [clang-tidy] Improve add_new_check.py to 
recognize more checks (authored by LegalizeAdulthood).

Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D126134/new/

https://reviews.llvm.org/D126134

Files:
  clang-tools-extra/clang-tidy/add_new_check.py
  clang-tools-extra/docs/clang-tidy/checks/list.rst

Index: clang-tools-extra/docs/clang-tidy/checks/list.rst
===================================================================
--- clang-tools-extra/docs/clang-tidy/checks/list.rst
+++ clang-tools-extra/docs/clang-tidy/checks/list.rst
@@ -37,19 +37,19 @@
    `altera-struct-pack-align <altera-struct-pack-align.html>`_, "Yes"
    `altera-unroll-loops <altera-unroll-loops.html>`_,
    `android-cloexec-accept <android-cloexec-accept.html>`_, "Yes"
-   `android-cloexec-accept4 <android-cloexec-accept4.html>`_,
+   `android-cloexec-accept4 <android-cloexec-accept4.html>`_, "Yes"
    `android-cloexec-creat <android-cloexec-creat.html>`_, "Yes"
    `android-cloexec-dup <android-cloexec-dup.html>`_, "Yes"
-   `android-cloexec-epoll-create <android-cloexec-epoll-create.html>`_,
-   `android-cloexec-epoll-create1 <android-cloexec-epoll-create1.html>`_,
-   `android-cloexec-fopen <android-cloexec-fopen.html>`_,
-   `android-cloexec-inotify-init <android-cloexec-inotify-init.html>`_,
-   `android-cloexec-inotify-init1 <android-cloexec-inotify-init1.html>`_,
-   `android-cloexec-memfd-create <android-cloexec-memfd-create.html>`_,
-   `android-cloexec-open <android-cloexec-open.html>`_,
+   `android-cloexec-epoll-create <android-cloexec-epoll-create.html>`_, "Yes"
+   `android-cloexec-epoll-create1 <android-cloexec-epoll-create1.html>`_, "Yes"
+   `android-cloexec-fopen <android-cloexec-fopen.html>`_, "Yes"
+   `android-cloexec-inotify-init <android-cloexec-inotify-init.html>`_, "Yes"
+   `android-cloexec-inotify-init1 <android-cloexec-inotify-init1.html>`_, "Yes"
+   `android-cloexec-memfd-create <android-cloexec-memfd-create.html>`_, "Yes"
+   `android-cloexec-open <android-cloexec-open.html>`_, "Yes"
    `android-cloexec-pipe <android-cloexec-pipe.html>`_, "Yes"
-   `android-cloexec-pipe2 <android-cloexec-pipe2.html>`_,
-   `android-cloexec-socket <android-cloexec-socket.html>`_,
+   `android-cloexec-pipe2 <android-cloexec-pipe2.html>`_, "Yes"
+   `android-cloexec-socket <android-cloexec-socket.html>`_, "Yes"
    `android-comparison-in-temp-failure-retry <android-comparison-in-temp-failure-retry.html>`_,
    `boost-use-to-string <boost-use-to-string.html>`_, "Yes"
    `bugprone-argument-comment <bugprone-argument-comment.html>`_, "Yes"
@@ -105,7 +105,7 @@
    `bugprone-terminating-continue <bugprone-terminating-continue.html>`_, "Yes"
    `bugprone-throw-keyword-missing <bugprone-throw-keyword-missing.html>`_,
    `bugprone-too-small-loop-variable <bugprone-too-small-loop-variable.html>`_,
-   `bugprone-unchecked-optional-access <bugprone-unchecked-optional-access.html>`_, "Yes"
+   `bugprone-unchecked-optional-access <bugprone-unchecked-optional-access.html>`_,
    `bugprone-undefined-memory-manipulation <bugprone-undefined-memory-manipulation.html>`_,
    `bugprone-undelegated-constructor <bugprone-undelegated-constructor.html>`_,
    `bugprone-unhandled-exception-at-new <bugprone-unhandled-exception-at-new.html>`_,
Index: clang-tools-extra/clang-tidy/add_new_check.py
===================================================================
--- clang-tools-extra/clang-tidy/add_new_check.py
+++ clang-tools-extra/clang-tidy/add_new_check.py
@@ -158,12 +158,17 @@
        'namespace': namespace})
 
 
-# Modifies the module to include the new check.
-def adapt_module(module_path, module, check_name, check_name_camel):
+# Returns the source filename that implements the module.
+def get_module_filename(module_path, module):
   modulecpp = list(filter(
       lambda p: p.lower() == module.lower() + 'tidymodule.cpp',
       os.listdir(module_path)))[0]
-  filename = os.path.join(module_path, modulecpp)
+  return os.path.join(module_path, modulecpp)
+
+
+# Modifies the module to include the new check.
+def adapt_module(module_path, module, check_name, check_name_camel):
+  filename = get_module_filename(module_path, module)
   with io.open(filename, 'r', encoding='utf8') as f:
     lines = f.readlines()
 
@@ -320,24 +325,100 @@
                      os.listdir(docs_dir)))
   doc_files.sort()
 
+  # We couldn't find the source file from the check name, so try to find the
+  # class name that corresponds to the check in the module file.
+  def filename_from_module(module_name, check_name):
+    module_path = os.path.join(clang_tidy_path, module_name)
+    if not os.path.isdir(module_path):
+      return ''
+    module_file = get_module_filename(module_path, module_name)
+    if not os.path.isfile(module_file):
+      return ''
+    with io.open(module_file, 'r') as f:
+      code = f.read()
+      full_check_name = module_name + '-' + check_name
+      name_pos = code.find('"' + full_check_name + '"')
+      if name_pos == -1:
+        return ''
+      stmt_end_pos = code.find(';', name_pos)
+      if stmt_end_pos == -1:
+        return ''
+      stmt_start_pos = code.rfind(';', 0, name_pos)
+      if stmt_start_pos == -1:
+        stmt_start_pos = code.rfind('{', 0, name_pos)
+      if stmt_start_pos == -1:
+        return ''
+      stmt = code[stmt_start_pos+1:stmt_end_pos]
+      matches = re.search('registerCheck<([^>:]*)>\(\s*"([^"]*)"\s*\)', stmt)
+      if matches and matches[2] == full_check_name:
+        class_name = matches[1]
+        if '::' in class_name:
+          parts = class_name.split('::')
+          class_name = parts[-1]
+          class_path = os.path.join(clang_tidy_path, module_name, '..', *parts[0:-1])
+        else:
+          class_path = os.path.join(clang_tidy_path, module_name)
+        return get_actual_filename(class_path, class_name + '.cpp')
+
+    return ''
+
+  # Examine code looking for a c'tor definition to get the base class name.
+  def get_base_class(code, check_file):
+    check_class_name = os.path.splitext(os.path.basename(check_file))[0]
+    ctor_pattern = check_class_name + '\([^:]*\)\s*:\s*([A-Z][A-Za-z0-9]*Check)\('
+    matches = re.search('\s+' + check_class_name + '::' + ctor_pattern, code)
+
+    # The constructor might be inline in the header.
+    if not matches:
+      header_file = os.path.splitext(check_file)[0] + '.h'
+      if not os.path.isfile(header_file):
+        return ''
+      with io.open(header_file, encoding='utf8') as f:
+        code = f.read()
+      matches = re.search(' ' + ctor_pattern, code)
+
+    if matches and matches[1] != 'ClangTidyCheck':
+      return matches[1]
+    return ''
+
+  # Some simple heuristics to figure out if a check has an autofix or not.
+  def has_fixits(code):
+    for needle in ['FixItHint', 'ReplacementText', 'fixit',
+                   'TransformerClangTidyCheck']:
+      if needle in code:
+        return True
+    return False
+
+  # Try to figure out of the check supports fixits.
   def has_auto_fix(check_name):
     dirname, _, check_name = check_name.partition('-')
 
-    checker_code = get_actual_filename(os.path.join(clang_tidy_path, dirname),
+    check_file = get_actual_filename(os.path.join(clang_tidy_path, dirname),
                                        get_camel_check_name(check_name) + '.cpp')
-    if not os.path.isfile(checker_code):
+    if not os.path.isfile(check_file):
       # Some older checks don't end with 'Check.cpp'
-      checker_code = get_actual_filename(os.path.join(clang_tidy_path, dirname),
+      check_file = get_actual_filename(os.path.join(clang_tidy_path, dirname),
                                          get_camel_name(check_name) + '.cpp')
-      if not os.path.isfile(checker_code):
-        return ''
+      if not os.path.isfile(check_file):
+        # Some checks aren't in a file based on the check name.
+        check_file = filename_from_module(dirname, check_name)
+        if not check_file or not os.path.isfile(check_file):
+          return ''
 
-    with io.open(checker_code, encoding='utf8') as f:
+    with io.open(check_file, encoding='utf8') as f:
       code = f.read()
-      for needle in ['FixItHint', 'ReplacementText', 'fixit', 'TransformerClangTidyCheck']:
-        if needle in code:
-          # Some simple heuristics to figure out if a checker has an autofix or not.
-          return ' "Yes"'
+      if has_fixits(code):
+        return ' "Yes"'
+
+    base_class = get_base_class(code, check_file)
+    if base_class:
+      base_file = os.path.join(clang_tidy_path, dirname, base_class + '.cpp')
+      if os.path.isfile(base_file):
+        with io.open(base_file, encoding='utf8') as f:
+          code = f.read()
+          if has_fixits(code):
+            return ' "Yes"'
+
     return ''
 
   def process_doc(doc_file):
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to