Improve code-correctness script (#8659)

- Sort failures alphabetically
- Add way to suppress error when necessary
- Add way to run test on a subset of files for testing
- Fix case where number of files is less than number of workers
This commit is contained in:
Powei Feng
2025-04-28 10:00:40 -07:00
committed by GitHub
parent 68a99ef54c
commit 7c6b470650
2 changed files with 50 additions and 15 deletions

View File

@@ -12,6 +12,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
import argparse
import os
import glob
import yaml
@@ -36,12 +37,14 @@ def get_func_name(msg):
return msg
def run_tidy(files):
if len(files) == 0:
return []
files_str = ' '.join(files)
hid = hashlib.md5(files_str.encode('utf-8')).hexdigest()
_, _ = execute(f'clang-tidy --export-fixes=/tmp/{hid}.yaml --quiet --checks=-*,bugprone-exception-escape {files_str}')
results = []
with open(f'/tmp/{hid}.yaml', 'r') as file:
data = yaml.safe_load(file)
with open(f'/tmp/{hid}.yaml', 'r') as f:
data = yaml.safe_load(f)
for d in data['Diagnostics']:
if d['DiagnosticName'] != 'bugprone-exception-escape':
continue
@@ -52,12 +55,20 @@ def run_tidy(files):
results.append((msg['FilePath'].replace(f'{os.getcwd()}/', ''), line_num, get_func_name(msg['Message'])))
return results
def exception_escape_test():
files = glob.glob('filament/**/*.mm', recursive=True) + \
glob.glob('filament/**/*.cpp', recursive=True) + \
glob.glob('filament/**/*.h', recursive=True)
DEFAULT_SRC_GLOBS=[
'filament/**/*.mm',
'filament/**/*.cpp',
'filament/**/*.h',
]
num_workers = 5 # Number of threads to spawn
def exception_escape_test(src_globs=DEFAULT_SRC_GLOBS):
files = []
if not isinstance(src_globs, list):
src_globs = [src_globs]
for i in src_globs:
files += glob.glob(i, recursive=True)
num_workers = min(len(files), 5) # Number of threads to spawn
part_len = len(files) // num_workers
workloads = []
for i in range(num_workers):
@@ -78,21 +89,46 @@ def exception_escape_test():
test_name = 'code-correctness::exception-escape'
failure_str_lines = []
if len(all_results) > 0:
all_results.sort(key=lambda x: x[0])
failure_str_lines.append(f'Number of failures: {len(all_results)}')
for fname, line_num, msg in all_results:
failure_str_lines.append(f'{fname}({line_num}): {msg}()')
return (len(all_results) == 0, failure_str_lines)
TESTS = [
(exception_escape_test,
'exception-escape',
'\'an exception may be thrown in a function which should not throw exceptions\'')
(
exception_escape_test,
# Test name
'exception-escape',
# Test description
'An exception may be thrown in a function which should not throw exceptions. '
'Consider adding \'NOLINT(bugprone-exception-escape)\' for valid suppression this check.',
# Maps a command line argument to a function argument
[('exception_escape_globs', 'src_globs')],
)
]
if __name__ == "__main__":
parser = argparse.ArgumentParser()
for f, name, desc, args in TESTS:
for cmd_arg_name, _ in args:
parser.add_argument(f'--{cmd_arg_name}', required=False)
args = parser.parse_args()
has_failures = False
for test_func, test_name, test_desc in TESTS:
result, res_strs = test_func()
for test_func, test_name, test_desc, arguments in TESTS:
func_args = {}
for cmdline_arg, func_arg in arguments:
arg_val = getattr(args, cmdline_arg, None)
if arg_val is not None:
func_args[func_arg] = arg_val.split(',') if ',' in arg_val else arg_val
result, res_strs = test_func(**func_args)
ss = ' ' * 4
if result:
print(f'[{test_name}] PASSED')
@@ -104,6 +140,5 @@ if __name__ == "__main__":
print(f'{ss}{s}')
if has_failures:
# TODO: Enable this when we've fixed all the exception-escape errors
#exit(1)
#exit(1)
pass