Index: test/clang-tidy/check_clang_tidy.py =================================================================== --- test/clang-tidy/check_clang_tidy.py +++ test/clang-tidy/check_clang_tidy.py @@ -25,6 +25,7 @@ """ import argparse +import os import re import subprocess import sys @@ -35,9 +36,90 @@ f.write(text) f.truncate() + +# Remove the contents of the CHECK lines to avoid CHECKs matching on +# themselves. We need to keep the comments to preserve line numbers while +# avoiding empty lines which could potentially trigger formatting-related +# checks. +def clean_text(input_text): + return re.sub('// *CHECK-[A-Z-]*:[^\r\n]*', '//', input_text) + + +def write_cleaned_header(input_file_path, temp_file_name, header_file_name): + src_path = os.path.join(os.path.dirname(input_file_path), header_file_name) + fixed_path = os.path.join(os.path.dirname(temp_file_name), header_file_name) + with open(src_path, 'r') as input_file: + cleaned_text = clean_text(input_file.read()) + cleaned_path = fixed_path + '.orig' + write_file(cleaned_path, cleaned_text) + write_file(fixed_path, cleaned_text) + return cleaned_path, fixed_path, src_path + + +def separate_output(clang_tidy_output, header_file_name, input_file_name): + input_file_name = os.path.basename(input_file_name) + input_file_output = '' + header_file_output = '' + input_messages = True + for line in clang_tidy_output.splitlines(True): + if input_messages: + if header_file_name in line: + input_messages = False + header_file_output += line + else: + input_file_output += line + else: + if input_file_name in line: + input_messages = True + input_file_output += line + else: + header_file_output += line + return header_file_output, input_file_output + + +def try_run(args): + try: + process_output = \ + subprocess.check_output(args, stderr=subprocess.STDOUT).decode() + except subprocess.CalledProcessError as e: + print('%s failed:\n%s' % (' '.join(args), e.output.decode())) + raise + return process_output + + +def check_output_for_messages(messages_file, input_file_name): + try_run( + ['FileCheck', '-input-file=' + messages_file, input_file_name, + '-check-prefix=CHECK-MESSAGES', + '-implicit-check-not={{warning|error}}:']) + + +def check_output_for_fixes(temp_file_name, input_file_name): + try_run( + ['FileCheck', '-input-file=' + temp_file_name, input_file_name, + '-check-prefix=CHECK-FIXES', '-strict-whitespace']) + + +def has_checks(input_text): + has_check_fixes = input_text.find('CHECK-FIXES') >= 0 + has_check_messages = input_text.find('CHECK-MESSAGES') >= 0 + return has_check_fixes, has_check_messages + + +def diff_source_files(original_file_name, temp_file_name): + try: + diff_output = subprocess.check_output( + ['diff', '-u', original_file_name, temp_file_name], + stderr=subprocess.STDOUT) + except subprocess.CalledProcessError as e: + diff_output = e.output + return diff_output + + def main(): parser = argparse.ArgumentParser() parser.add_argument('-resource-dir') + parser.add_argument('--header-filter') parser.add_argument('input_file_name') parser.add_argument('check_name') parser.add_argument('temp_file_name') @@ -45,6 +127,7 @@ args, extra_args = parser.parse_known_args() resource_dir = args.resource_dir + header_filter = args.header_filter input_file_name = args.input_file_name check_name = args.check_name temp_file_name = args.temp_file_name @@ -66,70 +149,64 @@ with open(input_file_name, 'r') as input_file: input_text = input_file.read() - has_check_fixes = input_text.find('CHECK-FIXES') >= 0 - has_check_messages = input_text.find('CHECK-MESSAGES') >= 0 + has_check_fixes, has_check_messages = has_checks(input_text) if not has_check_fixes and not has_check_messages: sys.exit('Neither CHECK-FIXES nor CHECK-MESSAGES found in the input') - # Remove the contents of the CHECK lines to avoid CHECKs matching on - # themselves. We need to keep the comments to preserve line numbers while - # avoiding empty lines which could potentially trigger formatting-related - # checks. - cleaned_test = re.sub('// *CHECK-[A-Z-]*:[^\r\n]*', '//', input_text) - + cleaned_test = clean_text(input_text) write_file(temp_file_name, cleaned_test) - original_file_name = temp_file_name + ".orig" write_file(original_file_name, cleaned_test) - args = ['clang-tidy', temp_file_name, '-fix', '--checks=-*,' + check_name] + \ - clang_tidy_extra_args + cleaned_header_path = '' + fixed_header_path = '' + source_header_path = '' + if header_filter is not None: + cleaned_header_path, fixed_header_path, source_header_path = \ + write_cleaned_header(input_file_name, temp_file_name, header_filter) + args = ['clang-tidy', '-header-filter=%s' % header_filter, + temp_file_name, '-fix', '--checks=-*,' + check_name] + \ + clang_tidy_extra_args + [ '-I', '.' ] + else: + args = ['clang-tidy', temp_file_name, '-fix', '--checks=-*,' + check_name] + \ + clang_tidy_extra_args + print('Running ' + repr(args) + '...') - try: - clang_tidy_output = \ - subprocess.check_output(args, stderr=subprocess.STDOUT).decode() - except subprocess.CalledProcessError as e: - print('clang-tidy failed:\n' + e.output.decode()) - raise + clang_tidy_output = try_run(args) print('------------------------ clang-tidy output -----------------------\n' + clang_tidy_output + '\n------------------------------------------------------------------') - try: - diff_output = subprocess.check_output( - ['diff', '-u', original_file_name, temp_file_name], - stderr=subprocess.STDOUT) - except subprocess.CalledProcessError as e: - diff_output = e.output + diff_output = diff_source_files(original_file_name, temp_file_name) + if header_filter is not None: + diff_output += diff_source_files(cleaned_header_path, fixed_header_path) print('------------------------------ Fixes -----------------------------\n' + diff_output.decode() + '\n------------------------------------------------------------------') if has_check_fixes: - try: - subprocess.check_output( - ['FileCheck', '-input-file=' + temp_file_name, input_file_name, - '-check-prefix=CHECK-FIXES', '-strict-whitespace'], - stderr=subprocess.STDOUT) - except subprocess.CalledProcessError as e: - print('FileCheck failed:\n' + e.output.decode()) - raise + if header_filter is not None: + check_output_for_fixes(fixed_header_path, source_header_path) + check_output_for_fixes(temp_file_name, input_file_name) if has_check_messages: messages_file = temp_file_name + '.msg' - write_file(messages_file, clang_tidy_output) - try: - subprocess.check_output( - ['FileCheck', '-input-file=' + messages_file, input_file_name, - '-check-prefix=CHECK-MESSAGES', - '-implicit-check-not={{warning|error}}:'], - stderr=subprocess.STDOUT) - except subprocess.CalledProcessError as e: - print('FileCheck failed:\n' + e.output.decode()) - raise + if header_filter is not None: + header_messages_file = messages_file + '.h' + header_output, input_file_output = \ + separate_output(clang_tidy_output, header_filter, input_file_name) + write_file(header_messages_file, header_output) + write_file(messages_file, input_file_output) + + check_output_for_messages(messages_file, input_file_name) + check_output_for_messages(header_messages_file, source_header_path) + else: + write_file(messages_file, clang_tidy_output) + check_output_for_messages(messages_file, input_file_name) + if __name__ == '__main__': main() Index: test/clang-tidy/modernize-redundant-void-arg.h =================================================================== --- /dev/null +++ test/clang-tidy/modernize-redundant-void-arg.h @@ -0,0 +1,8 @@ +#ifndef LLVM_CLANG_TOOLS_EXTRA_TEST_CLANG_TIDY_MODERNIZE_REDUNDANT_VOID_ARG_H +#define LLVM_CLANG_TOOLS_EXTRA_TEST_CLANG_TIDY_MODERNIZE_REDUNDANT_VOID_ARG_H + +extern int foo(void); +// CHECK-MESSAGES: :[[@LINE-1]]:16: warning: redundant void argument list in function declaration [modernize-redundant-void-arg] +// CHECK-FIXES: {{^}}extern int foo();{{$}} + +#endif // LLVM_CLANG_TOOLS_EXTRA_TEST_CLANG_TIDY_MODERNIZE_REDUNDANT_VOID_ARG_H Index: test/clang-tidy/modernize-redundant-void-arg.cpp =================================================================== --- test/clang-tidy/modernize-redundant-void-arg.cpp +++ test/clang-tidy/modernize-redundant-void-arg.cpp @@ -1,4 +1,6 @@ -// RUN: %check_clang_tidy %s modernize-redundant-void-arg %t +// RUN: %check_clang_tidy --header-filter=modernize-redundant-void-arg.h %s modernize-redundant-void-arg %t + +#include "modernize-redundant-void-arg.h" #define NULL 0