Skip to content

Commit ec6f0a2

Browse files
⚡️ Speed up function function_has_return_statement by 59%
Here is an optimized version of your function. The performance bottleneck, according to your line profiling, is the frequent and expensive use of `ast.iter_child_nodes(node)` and `stack.extend`, which results in a lot of small object allocations and function calls. A standard approach for faster AST traversals is to avoid repeatedly building stack lists and avoid function call overhead in performance-critical loops. Additionally, instead of manually maintaining your own DFS stack, you can use a custom generator that flattens out iteration, but for **maximum speed**, we can use the following techniques. - Use `__slots__` if building custom object wrappers (not needed here). - **Replace `stack.extend` with direct in-place iteration** (avoid function call). - Use a tuple for `append` instead of repeat calls if possible. - Live with the stack, but **reduce attr lookups** by caching methods. - Avoid `isinstance` in the hot path where possible (but that's hard here; checking for `ast.Return` is what we want). But the biggest win is to avoid use of `ast.iter_child_nodes` within the loop. Since `ast.AST` objects all have a `_fields` attribute, you can directly and quickly access children yourself, avoiding the internal generator overhead. #### Optimized code ### Key improvements - **Avoid expensive ast.iter_child_nodes** in the loop. - **Reduce attribute lookups** by caching local variables (`pop`, `push`). - **Directly scan node fields** to find children. This version will usually run up to 2x faster on deep/crowded ASTs. The logic and return value are unchanged. All comments are preserved except for changes referring to iter_child_nodes, now referencing direct field inspection.
1 parent 639e42e commit ec6f0a2

File tree

1 file changed

+13
-2
lines changed

1 file changed

+13
-2
lines changed

codeflash/discovery/functions_to_optimize.py

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -604,11 +604,22 @@ def filter_files_optimized(file_path: Path, tests_root: Path, ignore_paths: list
604604
def function_has_return_statement(function_node: FunctionDef | AsyncFunctionDef) -> bool:
605605
# Custom DFS, return True as soon as a Return node is found
606606
stack = [function_node]
607+
pop = stack.pop
608+
push = stack.append
609+
# Directly access _fields to avoid function call overhead of ast.iter_child_nodes
607610
while stack:
608-
node = stack.pop()
611+
node = pop()
609612
if isinstance(node, ast.Return):
610613
return True
611-
stack.extend(ast.iter_child_nodes(node))
614+
# Fast field inspection to avoid ast.iter_child_nodes overhead
615+
for field in getattr(node, "_fields", ()):
616+
value = getattr(node, field, None)
617+
if isinstance(value, list):
618+
for item in value:
619+
if isinstance(item, ast.AST):
620+
push(item)
621+
elif isinstance(value, ast.AST):
622+
push(value)
612623
return False
613624

614625

0 commit comments

Comments
 (0)