Changeset View
Changeset View
Standalone View
Standalone View
test/lint/lint-format-strings.py
Show First 20 Lines • Show All 58 Lines • ▼ Show 20 Lines | def parse_function_calls(function_name, source_code): | ||||
>>> len(parse_function_calls("foo", "#define FOO foo();")) | >>> len(parse_function_calls("foo", "#define FOO foo();")) | ||||
0 | 0 | ||||
""" | """ | ||||
assert isinstance(function_name, str) and isinstance( | assert isinstance(function_name, str) and isinstance( | ||||
source_code, str) and function_name | source_code, str) and function_name | ||||
lines = [re.sub("// .*", " ", line).strip() | lines = [re.sub("// .*", " ", line).strip() | ||||
for line in source_code.split("\n") | for line in source_code.split("\n") | ||||
if not line.strip().startswith("#")] | if not line.strip().startswith("#")] | ||||
return re.findall(r"[^a-zA-Z_](?=({}\(.*).*)".format(function_name), " " + " ".join(lines)) | return re.findall( | ||||
r"[^a-zA-Z_](?=({}\(.*).*)".format(function_name), " " + " ".join(lines)) | |||||
def normalize(s): | def normalize(s): | ||||
"""Return a normalized version of string s with newlines, tabs and C style comments ("/* ... */") | """Return a normalized version of string s with newlines, tabs and C style comments ("/* ... */") | ||||
replaced with spaces. Multiple spaces are replaced with a single space. | replaced with spaces. Multiple spaces are replaced with a single space. | ||||
>>> normalize(" /* nothing */ foo\tfoo /* bar */ foo ") | >>> normalize(" /* nothing */ foo\tfoo /* bar */ foo ") | ||||
'foo foo foo' | 'foo foo foo' | ||||
▲ Show 20 Lines • Show All 149 Lines • ▼ Show 20 Lines | def count_format_specifiers(format_string): | ||||
3 | 3 | ||||
>>> count_format_specifiers("foo %d bar %i foo %% foo %*d foo") | >>> count_format_specifiers("foo %d bar %i foo %% foo %*d foo") | ||||
4 | 4 | ||||
""" | """ | ||||
assert isinstance(format_string, str) | assert isinstance(format_string, str) | ||||
n = 0 | n = 0 | ||||
in_specifier = False | in_specifier = False | ||||
for i, char in enumerate(format_string): | for i, char in enumerate(format_string): | ||||
if format_string[i - 1:i + 1] == "%%" or format_string[i:i + 2] == "%%": | if format_string[i - 1:i + | ||||
1] == "%%" or format_string[i:i + 2] == "%%": | |||||
pass | pass | ||||
elif char == "%": | elif char == "%": | ||||
in_specifier = True | in_specifier = True | ||||
n += 1 | n += 1 | ||||
elif char in "aAcdeEfFgGinopsuxX": | elif char in "aAcdeEfFgGinopsuxX": | ||||
in_specifier = False | in_specifier = False | ||||
elif in_specifier and char == "*": | elif in_specifier and char == "*": | ||||
n += 1 | n += 1 | ||||
Show All 20 Lines | parser = argparse.ArgumentParser(description="This program checks that the number of arguments passed " | ||||
"to a variadic format string function matches the number of format " | "to a variadic format string function matches the number of format " | ||||
"specifiers in the format string.") | "specifiers in the format string.") | ||||
parser.add_argument("file", type=argparse.FileType( | parser.add_argument("file", type=argparse.FileType( | ||||
"r", encoding="utf-8"), nargs="*", help="C++ source code file (e.g. foo.cpp)") | "r", encoding="utf-8"), nargs="*", help="C++ source code file (e.g. foo.cpp)") | ||||
args = parser.parse_args(args_in) | args = parser.parse_args(args_in) | ||||
for f in args.file: | for f in args.file: | ||||
file_content = f.read() | file_content = f.read() | ||||
for (function_name, skip_arguments) in FUNCTION_NAMES_AND_NUMBER_OF_LEADING_ARGUMENTS: | for (function_name, | ||||
for function_call_str in parse_function_calls(function_name, file_content): | skip_arguments) in FUNCTION_NAMES_AND_NUMBER_OF_LEADING_ARGUMENTS: | ||||
for function_call_str in parse_function_calls( | |||||
function_name, file_content): | |||||
parts = parse_function_call_and_arguments( | parts = parse_function_call_and_arguments( | ||||
function_name, function_call_str) | function_name, function_call_str) | ||||
relevant_function_call_str = unescape("".join(parts))[:512] | relevant_function_call_str = unescape("".join(parts))[:512] | ||||
if (f.name, relevant_function_call_str) in FALSE_POSITIVES: | if (f.name, relevant_function_call_str) in FALSE_POSITIVES: | ||||
continue | continue | ||||
if len(parts) < 3 + skip_arguments: | if len(parts) < 3 + skip_arguments: | ||||
print("{}: Could not parse function call string \"{}(...)\": {}".format( | print("{}: Could not parse function call string \"{}(...)\": {}".format( | ||||
f.name, function_name, relevant_function_call_str)) | f.name, function_name, relevant_function_call_str)) | ||||
Show All 13 Lines |