mirror of
https://github.com/pytorch/pytorch.git
synced 2025-10-20 21:14:14 +08:00
Summary: More clang tidy cleanups in `torch/csrc`. This time: 1. `hicpp-use-equals-default` recommends `= default` instead of `{}` for constructors/destructors. This is better practice because it expresses the intent better (https://stackoverflow.com/questions/6502828/what-does-default-mean-after-a-class-function-declaration) 2. `readability-inconsistent-declaration-parameter-name` enforces that parameter names in the declaration match parameter names in the definition. This is just generally useful and can prevent confusion and bugs. Also updated my script a little bit. apaszke ezyang Pull Request resolved: https://github.com/pytorch/pytorch/pull/9737 Differential Revision: D9069069 Pulled By: goldsborough fbshipit-source-id: f7b3f3a4eb4c9fadc30425a153566d3b613a41ae
241 lines
7.6 KiB
Python
241 lines
7.6 KiB
Python
#!/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 normalize_directory_path(path):
|
|
"""Normalizes a directory path."""
|
|
return path.rstrip('/')
|
|
|
|
|
|
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, verbose):
|
|
"""Returns all files that match any of the patterns."""
|
|
filtered = []
|
|
for file in files:
|
|
has_match = False
|
|
for pattern in file_patterns:
|
|
if pattern.search(file):
|
|
filtered.append(file)
|
|
has_match = True
|
|
if not has_match and verbose:
|
|
message = "{} does not match any ".format(file)
|
|
message += "file pattern in {{{}}}".format(', '.join(map(str, file_patterns)))
|
|
print(message)
|
|
return filtered
|
|
|
|
|
|
def remove_recursive_files(files, paths, verbose):
|
|
"""
|
|
Removes all files that are not immediately under one of the given paths.
|
|
"""
|
|
for file in files:
|
|
if os.path.dirname(file) in paths:
|
|
yield file
|
|
else:
|
|
if verbose:
|
|
|
|
message = "{} ({}) does not match any ".format(file, os.path.dirname(file))
|
|
message += "non-recursive path in {{{}}}".format(", ".join(paths))
|
|
print(message)
|
|
|
|
|
|
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="Path to clang-tidy executable",
|
|
)
|
|
parser.add_argument(
|
|
"-e",
|
|
"--extra-args",
|
|
nargs="+",
|
|
default=[],
|
|
help="Extra arguments to forward to clang-tidy, without the hypen (e.g. -e 'header-filter=\"path\"')",
|
|
)
|
|
parser.add_argument(
|
|
"-g",
|
|
"--glob",
|
|
nargs="+",
|
|
default=[],
|
|
help="File patterns as UNIX globs (support * and ?, not recursive **)",
|
|
)
|
|
parser.add_argument(
|
|
"-x",
|
|
"--regex",
|
|
nargs="+",
|
|
default=[],
|
|
help="File patterns as regular expressions",
|
|
)
|
|
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 (recursively)",
|
|
)
|
|
parser.add_argument(
|
|
"-n",
|
|
"--no-recursive",
|
|
action="store_true",
|
|
help="If paths are supplied with -p/--paths, do not recurse into 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()
|
|
paths = map(normalize_directory_path, options.paths)
|
|
if options.revision:
|
|
files = get_changed_files(options.revision, paths, options.verbose)
|
|
else:
|
|
files = get_all_files(paths)
|
|
if options.no_recursive:
|
|
files = remove_recursive_files(files, paths, options.verbose)
|
|
file_patterns = get_file_patterns(options.glob, options.regex)
|
|
files = filter_files(files, file_patterns, options.verbose)
|
|
|
|
# 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()
|