Skip to content

Conversation

KRRT7
Copy link
Contributor

@KRRT7 KRRT7 commented Aug 22, 2025

PR Type

Enhancement, Bug fix, Tests


Description

  • Add support for async function detection

  • Remove has_any_async_functions usage

  • Fix coverage utils empty database return

  • Update tests for async discovery and code validation


Diagram Walkthrough

flowchart LR
  A["Code parsing"] -- "detect `AsyncFunctionDef`" --> B["Function discovery"]
  B -- "flag `is_async`" --> C["FunctionToOptimize"]
  C -- "optimize without blocking on async" --> D["FunctionOptimizer"]
  D -- "generate coverage" --> E["CoverageUtils"]
Loading

File Walkthrough

Relevant files
Enhancement
4 files
code_utils.py
Remove unused async detection function                                     
+0/-8     
static_analysis.py
Add AsyncFunctionDef support to lookup functions                 
+9/-3     
functions_to_optimize.py
Enable async function discovery and flagging                         
+30/-2   
function_optimizer.py
Remove async restriction and support async AST                     
+1/-7     
Bug fix
1 files
coverage_utils.py
Fix empty DB check order and return `CoverageData`             
+3/-3     
Tests
3 files
test_async_function_discovery.py
Add comprehensive async discovery tests                                   
+286/-0 
test_code_context_extractor.py
Resolve symlink paths in code context tests                           
+9/-4     
test_code_utils.py
Replace async detection tests with code validation             
+34/-18 

Copy link

PR Reviewer Guide 🔍

Here are some key observations to aid the review process:

⏱️ Estimated effort to review: 4 🔵🔵🔵🔵⚪
🧪 PR contains tests
🔒 No security concerns identified
⚡ Recommended focus areas for review

Coverage Empty DB

Ensure the fallback to create_empty uses the correct CoverageData.create_empty method and that CoverageData is properly imported. Confirm the exists/stat check avoids errors when the database file is missing.

if not database_path.exists() or not database_path.stat().st_size:
    logger.debug(f"Coverage database {database_path} is empty or does not exist")
    sentry_sdk.capture_message(f"Coverage database {database_path} is empty or does not exist")
    return CoverageData.create_empty(source_code_path, function_name, code_context)
Async metadata consistency

The AsyncFunctionDef visitor appends functions without setting starting_line and ending_line, and uses a different parent list than the sync FunctionDef visitor. Ensure metadata consistency for async functions.

def visit_AsyncFunctionDef(self, node: AsyncFunctionDef) -> None:
    # Check if the async function has a return statement and add it to the list
    if function_has_return_statement(node) and not function_is_a_property(node):
        self.functions.append(
            FunctionToOptimize(
                function_name=node.name, file_path=self.file_path, parents=self.ast_path[:], is_async=True
            )
        )
AST return type

get_first_top_level_function_or_method_ast now returns both FunctionDef and AsyncFunctionDef. Verify downstream callers and type hints handle the async case correctly.

) -> ast.FunctionDef | ast.AsyncFunctionDef | None:
    if not parents:
        result = get_first_top_level_object_def_ast(function_name, ast.FunctionDef, node)
        if result is not None:
            return result
        return get_first_top_level_object_def_ast(function_name, ast.AsyncFunctionDef, node)

Copy link

PR Code Suggestions ✨

No code suggestions found for the PR.

codeflash-ai bot added a commit that referenced this pull request Sep 2, 2025
…17% in PR #678 (`standalone-fto-async`)

The optimized code achieves a **16% speedup** through several targeted micro-optimizations that reduce overhead in the tight loops that traverse AST nodes:

**Key Optimizations:**

1. **Local Variable Bindings**: Assigns `ast.iter_child_nodes` and the type tuple to local variables, eliminating repeated attribute lookups during iteration. The profiler shows this reduces the per-hit cost of the main loop from 1560.1ns to 1530.6ns.

2. **Restructured Type Checking**: Splits the combined `isinstance(child, object_type) and child.name == object_name` check into separate conditions. This allows early exit after the type check fails and uses `getattr(child, "name", None)` for safer attribute access, reducing the attribute lookup overhead shown in the profiler (from 403.8ns to 308ns per hit).

3. **Optimized Control Flow**: Changes the nested if-statements to `elif` structure, reducing redundant type checks. The `isinstance(child, fn_type_tuple)` check now only runs when needed, improving branch prediction.

4. **Direct Parent Access**: Caches `parents[0]` as `parent0` to avoid repeated list indexing, though this has minimal impact on the overall performance.

**Performance Impact by Test Type:**
- **Large-scale tests** (500+ functions/classes): Benefit most from reduced per-node overhead in deep traversals
- **Basic cases**: See consistent but smaller improvements due to fewer nodes processed
- **Edge cases**: Minimal impact since they often involve early returns or empty searches

The optimizations are most effective for codebases with complex AST structures where the functions traverse many nodes, making the micro-optimizations compound significantly.
Copy link
Contributor

codeflash-ai bot commented Sep 2, 2025

⚡️ Codeflash found optimizations for this PR

📄 17% (0.17x) speedup for get_first_top_level_function_or_method_ast in codeflash/code_utils/static_analysis.py

⏱️ Runtime : 390 microseconds 334 microseconds (best of 59 runs)

I created a new dependent PR with the suggested changes. Please review:

If you approve, it will be merged into this PR (branch standalone-fto-async).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant