Skip to content

Commit 5d872e8

Browse files
authored
Merge pull request #1650 from codeflash-ai/fix/unused-helper-attribute-refs
fix: detect attribute-referenced methods as used in unused helper detection
2 parents e5ee5cd + 5c829cd commit 5d872e8

2 files changed

Lines changed: 763 additions & 3 deletions

File tree

codeflash/languages/python/context/unused_definition_remover.py

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -774,7 +774,7 @@ def detect_unused_helper_functions(
774774
# First, analyze imports to build a mapping of imported names to their original qualified names
775775
imported_names_map = _analyze_imports_in_optimized_code(optimized_ast, code_context)
776776

777-
# Extract all function calls in the entrypoint function
777+
# Extract all function calls and attribute references in the entrypoint function
778778
called_function_names = {function_to_optimize.function_name}
779779
for node in ast.walk(entrypoint_function_ast):
780780
if isinstance(node, ast.Call):
@@ -795,7 +795,6 @@ def detect_unused_helper_functions(
795795
# self.method_name() -> add both method_name and ClassName.method_name
796796
called_function_names.add(attr_name)
797797
# For class methods, also add the qualified name
798-
# For class methods, also add the qualified name
799798
if hasattr(function_to_optimize, "parents") and function_to_optimize.parents:
800799
class_name = function_to_optimize.parents[0].name
801800
called_function_names.add(f"{class_name}.{attr_name}")
@@ -808,9 +807,25 @@ def detect_unused_helper_functions(
808807
if mapped_names:
809808
called_function_names.update(mapped_names)
810809
# Handle nested attribute access like obj.attr.method()
811-
# Handle nested attribute access like obj.attr.method()
812810
else:
813811
called_function_names.add(node.func.attr)
812+
elif isinstance(node, ast.Attribute) and isinstance(node.value, ast.Name):
813+
# Attribute reference without call: e.g. self._parse1 = self._parse_literal
814+
# This covers methods used as callbacks, stored in variables, passed as arguments, etc.
815+
attr_name = node.attr
816+
value_id = node.value.id
817+
if value_id == "self":
818+
called_function_names.add(attr_name)
819+
if hasattr(function_to_optimize, "parents") and function_to_optimize.parents:
820+
class_name = function_to_optimize.parents[0].name
821+
called_function_names.add(f"{class_name}.{attr_name}")
822+
else:
823+
called_function_names.add(attr_name)
824+
full_ref = f"{value_id}.{attr_name}"
825+
called_function_names.add(full_ref)
826+
mapped_names = imported_names_map.get(full_ref)
827+
if mapped_names:
828+
called_function_names.update(mapped_names)
814829

815830
logger.debug(f"Functions called in optimized entrypoint: {called_function_names}")
816831
logger.debug(f"Imported names mapping: {imported_names_map}")

0 commit comments

Comments
 (0)