You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
122 lines
4.0 KiB
122 lines
4.0 KiB
#!/usr/bin/env python
|
|
#
|
|
#===- check-analyzer-fixit.py - Static Analyzer test helper ---*- python -*-===#
|
|
#
|
|
# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
# See https://llvm.org/LICENSE.txt for license information.
|
|
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
#
|
|
#===------------------------------------------------------------------------===#
|
|
#
|
|
# This file copy-pasted mostly from the Clang-Tidy's 'check_clang_tidy.py'.
|
|
#
|
|
#===------------------------------------------------------------------------===#
|
|
|
|
r"""
|
|
Clang Static Analyzer test helper
|
|
=================================
|
|
|
|
This script runs the Analyzer in fix-it mode and verify fixes, warnings, notes.
|
|
|
|
Usage:
|
|
check-analyzer-fixit.py <source-file> <temp-file> [analyzer arguments]
|
|
|
|
Example:
|
|
// RUN: %check-analyzer-fixit %s %t -analyzer-checker=core
|
|
"""
|
|
|
|
import argparse
|
|
import os
|
|
import re
|
|
import subprocess
|
|
import sys
|
|
|
|
|
|
def write_file(file_name, text):
|
|
with open(file_name, 'w') as f:
|
|
f.write(text)
|
|
|
|
|
|
def run_test_once(args, extra_args):
|
|
input_file_name = args.input_file_name
|
|
temp_file_name = args.temp_file_name
|
|
clang_analyzer_extra_args = extra_args
|
|
|
|
file_name_with_extension = input_file_name
|
|
_, extension = os.path.splitext(file_name_with_extension)
|
|
if extension not in ['.c', '.hpp', '.m', '.mm']:
|
|
extension = '.cpp'
|
|
temp_file_name = temp_file_name + extension
|
|
|
|
with open(input_file_name, 'r') as input_file:
|
|
input_text = input_file.read()
|
|
|
|
# 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-Z0-9\-]*:[^\r\n]*', '//', input_text)
|
|
write_file(temp_file_name, cleaned_test)
|
|
|
|
original_file_name = temp_file_name + ".orig"
|
|
write_file(original_file_name, cleaned_test)
|
|
|
|
try:
|
|
builtin_include_dir = subprocess.check_output(
|
|
['clang', '-print-file-name=include'], stderr=subprocess.STDOUT).decode()
|
|
except subprocess.CalledProcessError as e:
|
|
print('Cannot print Clang include directory: ' + e.output.decode())
|
|
|
|
builtin_include_dir = os.path.normpath(builtin_include_dir)
|
|
|
|
args = (['clang', '-cc1', '-internal-isystem', builtin_include_dir,
|
|
'-nostdsysteminc', '-analyze', '-analyzer-constraints=range',
|
|
'-analyzer-config', 'apply-fixits=true']
|
|
+ clang_analyzer_extra_args + ['-verify', temp_file_name])
|
|
|
|
print('Running ' + str(args) + '...')
|
|
|
|
try:
|
|
clang_analyzer_output = \
|
|
subprocess.check_output(args, stderr=subprocess.STDOUT).decode()
|
|
except subprocess.CalledProcessError as e:
|
|
print('Clang Static Analyzer test failed:\n' + e.output.decode())
|
|
raise
|
|
|
|
print('----------------- Clang Static Analyzer output -----------------\n' +
|
|
clang_analyzer_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
|
|
|
|
print('----------------------------- Fixes ----------------------------\n' +
|
|
diff_output.decode() +
|
|
'\n--------------------------------------------------------------')
|
|
|
|
try:
|
|
subprocess.check_output(
|
|
['FileCheck', '-input-file=' + temp_file_name, input_file_name,
|
|
'-check-prefixes=CHECK-FIXES', '-strict-whitespace'],
|
|
stderr=subprocess.STDOUT)
|
|
except subprocess.CalledProcessError as e:
|
|
print('FileCheck failed:\n' + e.output.decode())
|
|
raise
|
|
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser()
|
|
parser.add_argument('input_file_name')
|
|
parser.add_argument('temp_file_name')
|
|
|
|
args, extra_args = parser.parse_known_args()
|
|
run_test_once(args, extra_args)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
main()
|