Skip to content

Commit 7e3d6ec

Browse files
authored
Merge pull request #1169 from codeflash-ai/codeflash/optimize-pr1166-2026-01-24T15.53.33
⚡️ Speed up function `detect_unused_helper_functions` by 15% in PR #1166 (`skyvern-grace`)
2 parents 65ff392 + b54dfca commit 7e3d6ec

1 file changed

Lines changed: 43 additions & 39 deletions

File tree

codeflash/context/unused_definition_remover.py

Lines changed: 43 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -634,43 +634,40 @@ def _analyze_imports_in_optimized_code(
634634
func_name = helper.only_function_name
635635
module_name = helper.file_path.stem
636636
# Cache function lookup for this (module, func)
637-
file_entry = helpers_by_file_and_func[module_name]
638-
if func_name in file_entry:
639-
file_entry[func_name].append(helper)
640-
else:
641-
file_entry[func_name] = [helper]
637+
helpers_by_file_and_func[module_name].setdefault(func_name, []).append(helper)
642638
helpers_by_file[module_name].append(helper)
643639

644-
# Optimize attribute lookups and method binding outside the loop
645-
helpers_by_file_and_func_get = helpers_by_file_and_func.get
646-
helpers_by_file_get = helpers_by_file.get
647-
648640
for node in ast.walk(optimized_ast):
649641
if isinstance(node, ast.ImportFrom):
650642
# Handle "from module import function" statements
651643
module_name = node.module
652644
if module_name:
653-
file_entry = helpers_by_file_and_func_get(module_name, None)
645+
file_entry = helpers_by_file_and_func.get(module_name)
654646
if file_entry:
655647
for alias in node.names:
656648
imported_name = alias.asname if alias.asname else alias.name
657649
original_name = alias.name
658-
helpers = file_entry.get(original_name, None)
650+
helpers = file_entry.get(original_name)
659651
if helpers:
652+
imported_set = imported_names_map[imported_name]
660653
for helper in helpers:
661-
imported_names_map[imported_name].add(helper.qualified_name)
662-
imported_names_map[imported_name].add(helper.fully_qualified_name)
654+
imported_set.add(helper.qualified_name)
655+
imported_set.add(helper.fully_qualified_name)
663656

664657
elif isinstance(node, ast.Import):
665658
# Handle "import module" statements
666659
for alias in node.names:
667660
imported_name = alias.asname if alias.asname else alias.name
668661
module_name = alias.name
669-
for helper in helpers_by_file_get(module_name, []):
670-
# For "import module" statements, functions would be called as module.function
671-
full_call = f"{imported_name}.{helper.only_function_name}"
672-
imported_names_map[full_call].add(helper.qualified_name)
673-
imported_names_map[full_call].add(helper.fully_qualified_name)
662+
helpers = helpers_by_file.get(module_name)
663+
if helpers:
664+
imported_set = imported_names_map[f"{imported_name}.{{func}}"]
665+
for helper in helpers:
666+
# For "import module" statements, functions would be called as module.function
667+
full_call = f"{imported_name}.{helper.only_function_name}"
668+
full_call_set = imported_names_map[full_call]
669+
full_call_set.add(helper.qualified_name)
670+
full_call_set.add(helper.fully_qualified_name)
674671

675672
return dict(imported_names_map)
676673

@@ -750,27 +747,31 @@ def detect_unused_helper_functions(
750747
called_name = node.func.id
751748
called_function_names.add(called_name)
752749
# Also add the qualified name if this is an imported function
753-
if called_name in imported_names_map:
754-
called_function_names.update(imported_names_map[called_name])
750+
mapped_names = imported_names_map.get(called_name)
751+
if mapped_names:
752+
called_function_names.update(mapped_names)
755753
elif isinstance(node.func, ast.Attribute):
756754
# Method call: obj.method() or self.method() or module.function()
757755
if isinstance(node.func.value, ast.Name):
758-
if node.func.value.id == "self":
756+
attr_name = node.func.attr
757+
value_id = node.func.value.id
758+
if value_id == "self":
759759
# self.method_name() -> add both method_name and ClassName.method_name
760-
called_function_names.add(node.func.attr)
760+
called_function_names.add(attr_name)
761+
# For class methods, also add the qualified name
761762
# For class methods, also add the qualified name
762763
if hasattr(function_to_optimize, "parents") and function_to_optimize.parents:
763764
class_name = function_to_optimize.parents[0].name
764-
called_function_names.add(f"{class_name}.{node.func.attr}")
765+
called_function_names.add(f"{class_name}.{attr_name}")
765766
else:
766-
# obj.method() or module.function()
767-
attr_name = node.func.attr
768767
called_function_names.add(attr_name)
769-
called_function_names.add(f"{node.func.value.id}.{attr_name}")
768+
full_call = f"{value_id}.{attr_name}"
769+
called_function_names.add(full_call)
770770
# Check if this is a module.function call that maps to a helper
771-
full_call = f"{node.func.value.id}.{attr_name}"
772-
if full_call in imported_names_map:
773-
called_function_names.update(imported_names_map[full_call])
771+
mapped_names = imported_names_map.get(full_call)
772+
if mapped_names:
773+
called_function_names.update(mapped_names)
774+
# Handle nested attribute access like obj.attr.method()
774775
# Handle nested attribute access like obj.attr.method()
775776
else:
776777
called_function_names.add(node.func.attr)
@@ -780,32 +781,35 @@ def detect_unused_helper_functions(
780781

781782
# Find helper functions that are no longer called
782783
unused_helpers = []
784+
entrypoint_file_path = function_to_optimize.file_path
783785
for helper_function in code_context.helper_functions:
784786
if helper_function.jedi_definition.type != "class":
785787
# Check if the helper function is called using multiple name variants
786788
helper_qualified_name = helper_function.qualified_name
787789
helper_simple_name = helper_function.only_function_name
788790
helper_fully_qualified_name = helper_function.fully_qualified_name
789791

790-
# Create a set of all possible names this helper might be called by
791-
possible_call_names = {helper_qualified_name, helper_simple_name, helper_fully_qualified_name}
792-
792+
# Check membership efficiently - exit early on first match
793+
if (
794+
helper_qualified_name in called_function_names
795+
or helper_simple_name in called_function_names
796+
or helper_fully_qualified_name in called_function_names
797+
):
798+
is_called = True
793799
# For cross-file helpers, also consider module-based calls
794-
if helper_function.file_path != function_to_optimize.file_path:
800+
elif helper_function.file_path != entrypoint_file_path:
795801
# Add potential module.function combinations
796802
module_name = helper_function.file_path.stem
797-
possible_call_names.add(f"{module_name}.{helper_simple_name}")
798-
799-
# Check if any of the possible names are in the called functions
800-
is_called = bool(possible_call_names.intersection(called_function_names))
803+
module_call = f"{module_name}.{helper_simple_name}"
804+
is_called = module_call in called_function_names
805+
else:
806+
is_called = False
801807

802808
if not is_called:
803809
unused_helpers.append(helper_function)
804810
logger.debug(f"Helper function {helper_qualified_name} is not called in optimized code")
805-
logger.debug(f" Checked names: {possible_call_names}")
806811
else:
807812
logger.debug(f"Helper function {helper_qualified_name} is still called in optimized code")
808-
logger.debug(f" Called via: {possible_call_names.intersection(called_function_names)}")
809813

810814
except Exception as e:
811815
logger.debug(f"Error detecting unused helper functions: {e}")

0 commit comments

Comments
 (0)