13 ClangTidy Diff Checker
14 ======================
16 This script reads input from a unified diff, runs clang-tidy on all changed
17 files and outputs clang-tidy warnings in changed lines only. This is useful to
18 detect clang-tidy regressions in the lines touched by a specific patch.
19 Example usage for git/svn users:
21 git diff -U0 HEAD^ | clang-tidy-diff.py -p1
22 svn diff --diff-cmd=diff -x-U0 | \
23 clang-tidy-diff.py -fix -checks=-*,modernize-use-override
35 parser = argparse.ArgumentParser(description=
36 'Run clang-tidy against changed files, and '
37 'output diagnostics only for modified '
39 parser.add_argument(
'-clang-tidy-binary', metavar=
'PATH',
41 help=
'path to clang-tidy binary')
42 parser.add_argument(
'-p', metavar=
'NUM', default=0,
43 help=
'strip the smallest prefix containing P slashes')
44 parser.add_argument(
'-regex', metavar=
'PATTERN', default=
None,
45 help=
'custom pattern selecting file paths to check '
46 '(case sensitive, overrides -iregex)')
47 parser.add_argument(
'-iregex', metavar=
'PATTERN', default=
48 r'.*\.(cpp|cc|c\+\+|cxx|c|cl|h|hpp|m|mm|inc)',
49 help=
'custom pattern selecting file paths to check '
50 '(case insensitive, overridden by -regex)')
52 parser.add_argument(
'-fix', action=
'store_true', default=
False,
53 help=
'apply suggested fixes')
54 parser.add_argument(
'-checks',
55 help=
'checks filter, when not specified, use clang-tidy '
61 clang_tidy_args.extend(argv[argv.index(
'--'):])
62 argv = argv[:argv.index(
'--')]
64 args = parser.parse_args(argv)
69 for line
in sys.stdin:
70 match = re.search(
'^\+\+\+\ \"?(.*?/){%s}([^ \t\n\"]*)' % args.p, line)
72 filename = match.group(2)
76 if args.regex
is not None:
77 if not re.match(
'^%s$' % args.regex, filename):
80 if not re.match(
'^%s$' % args.iregex, filename, re.IGNORECASE):
83 match = re.search(
'^@@.*\+(\d+)(,(\d+))?', line)
85 start_line = int(match.group(1))
88 line_count = int(match.group(3))
91 end_line = start_line + line_count - 1;
92 lines_by_file.setdefault(filename, []).append([start_line, end_line])
94 if len(lines_by_file) == 0:
95 print(
"No relevant changes found.")
98 line_filter_json = json.dumps(
99 [{
"name" : name,
"lines" : lines_by_file[name]}
for name
in lines_by_file],
100 separators = (
',',
':'))
103 if sys.platform ==
'win32':
104 line_filter_json=re.sub(
r'"',
r'"""', line_filter_json)
109 command = [args.clang_tidy_binary]
110 command.append(
'-line-filter=' + quote + line_filter_json + quote)
112 command.append(
'-fix')
113 if args.checks !=
'':
114 command.append(
'-checks=' + quote + args.checks + quote)
115 command.extend(lines_by_file.keys())
116 command.extend(clang_tidy_args)
118 sys.exit(subprocess.call(
' '.join(command), shell=
True))
120 if __name__ ==
'__main__':