From ec6f0a27447ca9c77f693dc15a456d2465e1ccf8 Mon Sep 17 00:00:00 2001 From: "codeflash-ai[bot]" <148906541+codeflash-ai[bot]@users.noreply.github.com> Date: Fri, 27 Jun 2025 00:15:02 +0000 Subject: [PATCH] =?UTF-8?q?=E2=9A=A1=EF=B8=8F=20Speed=20up=20function=20`f?= =?UTF-8?q?unction=5Fhas=5Freturn=5Fstatement`=20by=2059%=20Here=20is=20an?= =?UTF-8?q?=20optimized=20version=20of=20your=20function.=20The=20performa?= =?UTF-8?q?nce=20bottleneck,=20according=20to=20your=20line=20profiling,?= =?UTF-8?q?=20is=20the=20frequent=20and=20expensive=20use=20of=20`ast.iter?= =?UTF-8?q?=5Fchild=5Fnodes(node)`=20and=20`stack.extend`,=20which=20resul?= =?UTF-8?q?ts=20in=20a=20lot=20of=20small=20object=20allocations=20and=20f?= =?UTF-8?q?unction=20calls.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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. --- codeflash/discovery/functions_to_optimize.py | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/codeflash/discovery/functions_to_optimize.py b/codeflash/discovery/functions_to_optimize.py index 792a9fcff..4c3e173db 100644 --- a/codeflash/discovery/functions_to_optimize.py +++ b/codeflash/discovery/functions_to_optimize.py @@ -604,11 +604,22 @@ def filter_files_optimized(file_path: Path, tests_root: Path, ignore_paths: list def function_has_return_statement(function_node: FunctionDef | AsyncFunctionDef) -> bool: # Custom DFS, return True as soon as a Return node is found stack = [function_node] + pop = stack.pop + push = stack.append + # Directly access _fields to avoid function call overhead of ast.iter_child_nodes while stack: - node = stack.pop() + node = pop() if isinstance(node, ast.Return): return True - stack.extend(ast.iter_child_nodes(node)) + # Fast field inspection to avoid ast.iter_child_nodes overhead + for field in getattr(node, "_fields", ()): + value = getattr(node, field, None) + if isinstance(value, list): + for item in value: + if isinstance(item, ast.AST): + push(item) + elif isinstance(value, ast.AST): + push(value) return False