Skip to content

Commit a3db94d

Browse files
authored
Merge pull request #22723 from github/tausbn/python-fail-early-on-syntax-errors
Python: Fail early on syntax errors
2 parents 072e00d + 13f585e commit a3db94d

2 files changed

Lines changed: 41 additions & 6 deletions

File tree

‎python/extractor/semmle/python/parser/tsg_parser.py‎

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,12 @@ def read_tsg_python_output(path, logger):
163163
current_node = encoded_node["id"]
164164
attrs = _decode_tsg_node_attributes(encoded_node["attrs"], path, logger)
165165
node_attr[current_node] = attrs
166+
if attrs.get("_kind") == "SyntaxErrorNode":
167+
lineno, offset, _, _ = get_location_info(attrs)
168+
exc = SyntaxError("Syntax Error")
169+
exc.lineno = lineno
170+
exc.offset = offset
171+
raise exc
166172
for encoded_edge in encoded_node["edges"]:
167173
current_end = encoded_edge["sink"]
168174
edge_fields = edge_attr.setdefault(current_node, {})
@@ -339,12 +345,6 @@ def parse(path, logger):
339345
node.lineno, node.col_offset, end_line, end_column = get_location_info(attrs)
340346
node._end = (end_line, end_column)
341347

342-
if isinstance(node, SyntaxErrorNode):
343-
exc = SyntaxError("Syntax Error")
344-
exc.lineno = node.lineno
345-
exc.offset = node.col_offset
346-
raise exc
347-
348348
# Set up context information, if any
349349
if "ctx" in expected_fields:
350350
node.ctx = get_context(id, node_attr, path, logger)

‎python/extractor/tests/test_tsg_parser.py‎

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,41 @@ def test_evaluate_string_on_reported_value(self):
7474
value = '"\u26a0\ufe0f problem %s: %s"'
7575
self.assertEqual(evaluate_string(value), "\u26a0\ufe0f problem %s: %s")
7676

77+
def test_syntax_error_node_raises(self):
78+
output = json.dumps(
79+
[
80+
{
81+
"id": 0,
82+
"edges": [],
83+
"attrs": {
84+
"_kind": {"type": "string", "string": "SyntaxErrorNode"},
85+
"_location": {
86+
"type": "list",
87+
"values": [
88+
{"type": "int", "int": 4},
89+
{"type": "int", "int": 5},
90+
{"type": "int", "int": 4},
91+
{"type": "int", "int": 6},
92+
],
93+
},
94+
"source": {"type": "string", "string": "!"},
95+
},
96+
}
97+
]
98+
).encode("utf-8")
99+
100+
process = unittest.mock.Mock()
101+
process.communicate.return_value = (output, None)
102+
process.returncode = 0
103+
with unittest.mock.patch(
104+
"semmle.python.parser.tsg_parser.subprocess.Popen", return_value=process
105+
):
106+
with self.assertRaises(SyntaxError) as raised:
107+
read_tsg_python_output("test.py", unittest.mock.Mock())
108+
109+
self.assertEqual(raised.exception.lineno, 5)
110+
self.assertEqual(raised.exception.offset, 5)
111+
77112

78113
class FormatMessageTest(unittest.TestCase):
79114
"""A pre-formatted log message may contain `%` directives coming from the analysed source, and

0 commit comments

Comments
 (0)