diff options
author | Peter Goldsborough <peter@goldsborough.me> | 2018-05-09 10:08:53 -0700 |
---|---|---|
committer | Soumith Chintala <soumith@gmail.com> | 2018-05-09 13:08:53 -0400 |
commit | 23be4ac3a230349b273f473dc70bda96c4130731 (patch) | |
tree | 70a09ce061c0c8bb15a7915e7d4995097b54ff75 | |
parent | 769397eb7714c9da1ff3a472f67f063e2da7c483 (diff) | |
download | pytorch-23be4ac3a230349b273f473dc70bda96c4130731.tar.gz pytorch-23be4ac3a230349b273f473dc70bda96c4130731.tar.bz2 pytorch-23be4ac3a230349b273f473dc70bda96c4130731.zip |
Add clang tidy tooling (#7412)
-rw-r--r-- | .clang-tidy | 40 | ||||
-rw-r--r-- | tools/clang_tidy.py | 196 | ||||
-rw-r--r-- | tools/cpp_build/libtorch/CMakeLists.txt | 1 |
3 files changed, 237 insertions, 0 deletions
diff --git a/.clang-tidy b/.clang-tidy new file mode 100644 index 0000000000..19dad14435 --- /dev/null +++ b/.clang-tidy @@ -0,0 +1,40 @@ +--- +# NOTE: there must be no spaces before the '-', so put the comma first. +Checks: ' + * + ,modernize-* + ,clang-analyzer-* + ,-clang-diagnostic-* + ,-hicpp-no-array-decay + ,-fuchsia-* + ,-google-readability-namespace-comments + ,-llvm-namespace-comment + ,-google-readability-todo + ,-cppcoreguidelines-pro-bounds-array-to-pointer-decay + ,-cert-err60-cpp + ,-llvm-header-guard + ,-cppcoreguidelines-special-member-functions + ,-misc-unused-parameters + ,-hicpp-braces-around-statements + ,-hicpp-special-member-functions + ,-readability-braces-around-statements + ,-modernize-use-default-member-init + ,-google-runtime-references + ,-cppcoreguidelines-pro-type-vararg + ,-google-readability-braces-around-statements + ,-google-build-using-namespace + ,-hicpp-vararg + ,-hicpp-explicit-conversions + ,-performance-unnecessary-value-param + ,-google-runtime-references + ,-cppcoreguidelines-pro-type-static-cast-downcast + ,-cppcoreguidelines-pro-bounds-constant-array-index + ,-cert-err58-cpp + ,-modernize-make-unique + ,-cppcoreguidelines-owning-memory + ' +WarningsAsErrors: '' +HeaderFilterRegex: 'torch/csrc/' +AnalyzeTemporaryDtors: false +CheckOptions: +... diff --git a/tools/clang_tidy.py b/tools/clang_tidy.py new file mode 100644 index 0000000000..f8c0563633 --- /dev/null +++ b/tools/clang_tidy.py @@ -0,0 +1,196 @@ +#!/usr/bin/env python + +import argparse +import json +import os.path +import re +import subprocess +import sys + +DEFAULT_FILE_PATTERN = r".*\.[ch](pp)?" + +# @@ -start,count +start,count @@ +CHUNK_PATTERN = r"^@@\s+-\d+,\d+\s+\+(\d+)(?:,(\d+))?\s+@@" + + +def run_shell_command(arguments, process_name=None): + """Executes a shell command.""" + assert len(arguments) > 0 + try: + output = subprocess.check_output(arguments, stderr=subprocess.STDOUT) + except OSError: + _, e, _ = sys.exc_info() + process_name = process_name or arguments[0] + raise RuntimeError("Error executing {}: {}".format(process_name, e)) + else: + return output.decode() + + +def transform_globs_into_regexes(globs): + """Turns glob patterns into regular expressions.""" + return [glob.replace("*", ".*").replace("?", ".") for glob in globs] + + +def get_file_patterns(globs, regexes): + """Returns a list of compiled regex objects from globs and regex pattern strings.""" + regexes += transform_globs_into_regexes(globs) + if not regexes: + regexes = [DEFAULT_FILE_PATTERN] + return [re.compile(regex + "$") for regex in regexes] + + +def git_diff(args, verbose): + """Executes a git diff command in the shell and returns its output.""" + # --no-pager gets us the plain output, without pagination. + # --no-color removes color codes. + command = ["git", "--no-pager", "diff", "--no-color"] + args + if verbose: + print(" ".join(command)) + return run_shell_command(command, process_name="git diff") + + +def filter_files(files, file_patterns): + """Returns all files that match any of the patterns.""" + filtered = [] + for file in files: + for pattern in file_patterns: + if pattern.match(file): + filtered.append(file) + return filtered + + +def get_changed_files(revision, paths, verbose): + """Runs git diff to get the paths of all changed files.""" + # --diff-filter AMU gets us files that are (A)dded, (M)odified or (U)nmerged (in the working copy). + # --name-only makes git diff return only the file paths, without any of the source changes. + args = ["--diff-filter", "AMU", "--ignore-all-space", "--name-only", revision] + output = git_diff(args + paths, verbose) + return output.split("\n") + + +def get_all_files(paths): + """Yields all files in any of the given paths""" + for path in paths: + for root, _, files in os.walk(path): + for file in files: + yield os.path.join(root, file) + + +def get_changed_lines(revision, filename, verbose): + """Runs git diff to get the line ranges of all file changes.""" + output = git_diff(["--unified=0", revision, filename], verbose) + changed_lines = [] + for chunk in re.finditer(CHUNK_PATTERN, output, re.MULTILINE): + start = int(chunk.group(1)) + count = int(chunk.group(2) or 1) + changed_lines.append([start, start + count]) + + return {"name": filename, "lines": changed_lines} + + +def run_clang_tidy(options, line_filters, files): + """Executes the actual clang-tidy command in the shell.""" + command = [options.clang_tidy_exe, "-p", options.compile_commands_dir] + if not options.config_file and os.path.exists(".clang-tidy"): + options.config_file = ".clang-tidy" + if options.config_file: + import yaml + + with open(options.config_file) as config: + # Here we convert the YAML config file to a JSON blob. + command += ["-config", json.dumps(yaml.load(config))] + if options.checks: + command += ["-checks", options.checks] + if line_filters: + command += ["-line-filter", json.dumps(line_filters)] + command += ["-{}".format(arg) for arg in options.extra_args] + command += files + + if options.verbose: + print(" ".join(command)) + if options.show_command_only: + command = [re.sub(r"^([{[].*[]}])$", r"'\1'", arg) for arg in command] + return " ".join(command) + + return run_shell_command(command) + + +def parse_options(): + parser = argparse.ArgumentParser(description="Run Clang-Tidy (on your Git changes)") + parser.add_argument( + "-c", + "--clang-tidy-exe", + default="clang-tidy", + help="{ath to clang-tidy executable", + ) + parser.add_argument( + "-e", + "--extra-args", + nargs="+", + default=[], + help="Extra arguments to forward to clang-tidy", + ) + parser.add_argument( + "-g", + "--glob", + nargs="+", + default=[], + help="File patterns as UNIX globs (no **)", + ) + parser.add_argument( + "-x", "--regex", nargs="+", default=[], help="File patterns as regexes" + ) + parser.add_argument( + "-d", + "--compile-commands-dir", + default=".", + help="Path to the folder containing compile_commands.json", + ) + parser.add_argument("-r", "--revision", help="Git revision to get changes from") + parser.add_argument( + "-p", "--paths", nargs="+", default=["."], help="Lint only the given paths" + ) + parser.add_argument( + "-s", + "--show-command-only", + action="store_true", + help="Only show the command to be executed, without running it", + ) + parser.add_argument("-v", "--verbose", action="store_true", help="Verbose output") + parser.add_argument( + "--config-file", + help="Path to a clang-tidy config file. Defaults to '.clang-tidy'.", + ) + parser.add_argument( + "--checks", help="Appends checks to those from the config file (if any)" + ) + return parser.parse_args() + + +def main(): + options = parse_options() + if options.revision: + files = get_changed_files(options.revision, options.paths, options.verbose) + else: + files = get_all_files(options.paths) + file_patterns = get_file_patterns(options.glob, options.regex) + files = filter_files(files, file_patterns) + + # clang-tidy error's when it does not get input files. + if not files: + print("No files detected.") + sys.exit() + + line_filters = [] + if options.revision: + for filename in files: + changed_lines = get_changed_lines( + options.revision, filename, options.verbose + ) + line_filters.append(changed_lines) + + print(run_clang_tidy(options, line_filters, files)) + + +if __name__ == "__main__": + main() diff --git a/tools/cpp_build/libtorch/CMakeLists.txt b/tools/cpp_build/libtorch/CMakeLists.txt index 6f30a879ce..e546529aab 100644 --- a/tools/cpp_build/libtorch/CMakeLists.txt +++ b/tools/cpp_build/libtorch/CMakeLists.txt @@ -4,6 +4,7 @@ cmake_policy(VERSION 3.0) set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_POSITION_INDEPENDENT_CODE ON) +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) if (VERBOSE) message(STATUS "ATEN_PATH is ${ATEN_PATH}") |