Skip to content

Commit ef86f26

Browse files
author
MarcoFalke
committed
Merge #13939: lint: Make format string linter understand basic template parameter syntax
4441ad6 Make format string linter understand basic template parameter syntax (practicalswift) Pull request description: Make format string linter understand basic template parameter syntax. Fixes issue described in bitcoin/bitcoin#13705 (comment). Thanks to @ken2812221 for reporting! Tree-SHA512: 8fb995bc6b29d8b9926ef5969e02cf71c494e829434fcdeb4ed5fabad5ab96e86e5b8eea705e8a416927757b4fa4e58abc0fd4f483daa58c94e2c6fdcb8ee822
2 parents 2115cba + 4441ad6 commit ef86f26

File tree

1 file changed

+37
-1
lines changed

1 file changed

+37
-1
lines changed

test/lint/lint-format-strings.py

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,32 @@ def parse_function_call_and_arguments(function_name, function_call):
123123
['foo(', '123', ')']
124124
>>> parse_function_call_and_arguments("foo", 'foo("foo")')
125125
['foo(', '"foo"', ')']
126+
>>> parse_function_call_and_arguments("strprintf", 'strprintf("%s (%d)", std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>,wchar_t>().to_bytes(buf), err);')
127+
['strprintf(', '"%s (%d)",', ' std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>,wchar_t>().to_bytes(buf),', ' err', ')']
128+
>>> parse_function_call_and_arguments("strprintf", 'strprintf("%s (%d)", foo<wchar_t>().to_bytes(buf), err);')
129+
['strprintf(', '"%s (%d)",', ' foo<wchar_t>().to_bytes(buf),', ' err', ')']
130+
>>> parse_function_call_and_arguments("strprintf", 'strprintf("%s (%d)", foo().to_bytes(buf), err);')
131+
['strprintf(', '"%s (%d)",', ' foo().to_bytes(buf),', ' err', ')']
132+
>>> parse_function_call_and_arguments("strprintf", 'strprintf("%s (%d)", foo << 1, err);')
133+
['strprintf(', '"%s (%d)",', ' foo << 1,', ' err', ')']
134+
>>> parse_function_call_and_arguments("strprintf", 'strprintf("%s (%d)", foo<bar>() >> 1, err);')
135+
['strprintf(', '"%s (%d)",', ' foo<bar>() >> 1,', ' err', ')']
136+
>>> parse_function_call_and_arguments("strprintf", 'strprintf("%s (%d)", foo < 1 ? bar : foobar, err);')
137+
['strprintf(', '"%s (%d)",', ' foo < 1 ? bar : foobar,', ' err', ')']
138+
>>> parse_function_call_and_arguments("strprintf", 'strprintf("%s (%d)", foo < 1, err);')
139+
['strprintf(', '"%s (%d)",', ' foo < 1,', ' err', ')']
140+
>>> parse_function_call_and_arguments("strprintf", 'strprintf("%s (%d)", foo > 1 ? bar : foobar, err);')
141+
['strprintf(', '"%s (%d)",', ' foo > 1 ? bar : foobar,', ' err', ')']
142+
>>> parse_function_call_and_arguments("strprintf", 'strprintf("%s (%d)", foo > 1, err);')
143+
['strprintf(', '"%s (%d)",', ' foo > 1,', ' err', ')']
144+
>>> parse_function_call_and_arguments("strprintf", 'strprintf("%s (%d)", foo <= 1, err);')
145+
['strprintf(', '"%s (%d)",', ' foo <= 1,', ' err', ')']
146+
>>> parse_function_call_and_arguments("strprintf", 'strprintf("%s (%d)", foo <= bar<1, 2>(1, 2), err);')
147+
['strprintf(', '"%s (%d)",', ' foo <= bar<1, 2>(1, 2),', ' err', ')']
148+
>>> parse_function_call_and_arguments("strprintf", 'strprintf("%s (%d)", foo>foo<1,2>(1,2)?bar:foobar,err)');
149+
['strprintf(', '"%s (%d)",', ' foo>foo<1,2>(1,2)?bar:foobar,', 'err', ')']
150+
>>> parse_function_call_and_arguments("strprintf", 'strprintf("%s (%d)", foo>foo<1,2>(1,2),err)');
151+
['strprintf(', '"%s (%d)",', ' foo>foo<1,2>(1,2),', 'err', ')']
126152
"""
127153
assert(type(function_name) is str and type(function_call) is str and function_name)
128154
remaining = normalize(escape(function_call))
@@ -131,9 +157,10 @@ def parse_function_call_and_arguments(function_name, function_call):
131157
parts = [expected_function_call]
132158
remaining = remaining[len(expected_function_call):]
133159
open_parentheses = 1
160+
open_template_arguments = 0
134161
in_string = False
135162
parts.append("")
136-
for char in remaining:
163+
for i, char in enumerate(remaining):
137164
parts.append(parts.pop() + char)
138165
if char == "\"":
139166
in_string = not in_string
@@ -151,6 +178,15 @@ def parse_function_call_and_arguments(function_name, function_call):
151178
parts.append(parts.pop()[:-1])
152179
parts.append(char)
153180
break
181+
prev_char = remaining[i - 1] if i - 1 >= 0 else None
182+
next_char = remaining[i + 1] if i + 1 <= len(remaining) - 1 else None
183+
if char == "<" and next_char not in [" ", "<", "="] and prev_char not in [" ", "<"]:
184+
open_template_arguments += 1
185+
continue
186+
if char == ">" and next_char not in [" ", ">", "="] and prev_char not in [" ", ">"] and open_template_arguments > 0:
187+
open_template_arguments -= 1
188+
if open_template_arguments > 0:
189+
continue
154190
if char == ",":
155191
parts.append("")
156192
return parts

0 commit comments

Comments
 (0)