Skip to content

⚡️ Speed up function _extract_context_subscriptions by 29% in PR #1571 (codeflash/optimize-pr1561-2026-02-20T03.56.09)#1575

Closed
codeflash-ai[bot] wants to merge 1 commit intocodeflash/optimize-pr1561-2026-02-20T03.56.09from
codeflash/optimize-pr1571-2026-02-20T04.13.10
Closed

⚡️ Speed up function _extract_context_subscriptions by 29% in PR #1571 (codeflash/optimize-pr1561-2026-02-20T03.56.09)#1575
codeflash-ai[bot] wants to merge 1 commit intocodeflash/optimize-pr1561-2026-02-20T03.56.09from
codeflash/optimize-pr1571-2026-02-20T04.13.10

Conversation

@codeflash-ai
Copy link
Contributor

@codeflash-ai codeflash-ai bot commented Feb 20, 2026

⚡️ This pull request contains optimizations for PR #1571

If you approve this dependent PR, these changes will be merged into the original PR branch codeflash/optimize-pr1561-2026-02-20T03.56.09.

This PR will be automatically closed if the original PR is merged.


📄 29% (0.29x) speedup for _extract_context_subscriptions in codeflash/languages/javascript/frameworks/react/context.py

⏱️ Runtime : 1.32 milliseconds 1.02 milliseconds (best of 241 runs)

📝 Explanation and details

The optimization replaces finditer() with findall() for regex matching, achieving a 29% speedup in runtime (from 1.32ms to 1.02ms).

What Changed:
Instead of iterating over match objects and calling .group(1) on each ([match.group(1) for match in _CONTEXT_RE.finditer(component_source)]), the code now uses _CONTEXT_RE.findall(component_source) to directly extract captured groups.

Why It's Faster:

  1. Eliminates intermediate objects: finditer() returns an iterator of match objects, each requiring instantiation and a method call to group(1). findall() with a capturing group directly returns the captured strings as a list.

  2. Reduces overhead: The list comprehension in the original code introduces iteration overhead and function call overhead for each match. findall() is implemented in C within Python's regex engine, making it significantly more efficient.

  3. Memory efficiency: No intermediate match objects need to be created, reducing allocations and garbage collection pressure.

Performance Impact:
The test results show consistent speedups across all cases:

  • Simple cases (single context): 89-98% faster (4.28μs → 2.26μs)
  • Multiple contexts: 52-67% faster
  • Large-scale tests (1000 contexts): 37-39% faster (454μs → 330μs)
  • Edge cases (empty strings): 206% faster (1.65μs → 541ns)

Workload Benefits:
Based on the function references, _extract_context_subscriptions is called during React component analysis for detecting context dependencies. While not in a tight loop, this function processes potentially large source files (test shows 1500+ line files). The optimization particularly benefits:

  • Codebases with many context subscriptions (the 100-context test shows 39% speedup)
  • Large source files (1000+ line files show 12-37% improvement)
  • Batch analysis of multiple components

The optimization is universally beneficial across all input patterns with no regressions, making it a pure performance win.

Correctness verification report:

Test Status
⚙️ Existing Unit Tests 🔘 None Found
🌀 Generated Regression Tests 39 Passed
⏪ Replay Tests 🔘 None Found
🔎 Concolic Coverage Tests 🔘 None Found
📊 Tests Coverage 100.0%
🌀 Click to see Generated Regression Tests
import pytest
from codeflash.languages.javascript.frameworks.react.context import \
    _extract_context_subscriptions

def test_single_context_subscription():
    """Test extraction of a single useContext call."""
    # Arrange
    source = "const theme = useContext(ThemeContext);"
    # Act
    codeflash_output = _extract_context_subscriptions(source); result = codeflash_output # 4.28μs -> 2.26μs (89.0% faster)

def test_multiple_context_subscriptions():
    """Test extraction of multiple useContext calls."""
    # Arrange
    source = """
    const theme = useContext(ThemeContext);
    const user = useContext(UserContext);
    const config = useContext(ConfigContext);
    """
    # Act
    codeflash_output = _extract_context_subscriptions(source); result = codeflash_output # 5.49μs -> 3.37μs (63.1% faster)

def test_context_with_spaces_before_parenthesis():
    """Test useContext with space between function name and parenthesis."""
    # Arrange
    source = "const theme = useContext (ThemeContext);"
    # Act
    codeflash_output = _extract_context_subscriptions(source); result = codeflash_output # 3.71μs -> 1.87μs (97.8% faster)

def test_context_with_multiple_spaces():
    """Test useContext with multiple spaces before parenthesis."""
    # Arrange
    source = "const theme = useContext    (ThemeContext);"
    # Act
    codeflash_output = _extract_context_subscriptions(source); result = codeflash_output # 3.61μs -> 1.94μs (85.6% faster)

def test_context_with_newline_before_parenthesis():
    """Test useContext with newline before parenthesis."""
    # Arrange
    source = """const theme = useContext
    (ThemeContext);"""
    # Act
    codeflash_output = _extract_context_subscriptions(source); result = codeflash_output # 3.66μs -> 1.96μs (86.2% faster)

def test_context_with_tab_before_parenthesis():
    """Test useContext with tab character before parenthesis."""
    # Arrange
    source = "const theme = useContext\t(ThemeContext);"
    # Act
    codeflash_output = _extract_context_subscriptions(source); result = codeflash_output # 3.66μs -> 1.98μs (84.3% faster)

def test_context_with_spaces_inside_parenthesis():
    """Test useContext with spaces inside parenthesis."""
    # Arrange
    source = "const theme = useContext(  ThemeContext  );"
    # Act
    codeflash_output = _extract_context_subscriptions(source); result = codeflash_output # 3.51μs -> 1.92μs (82.3% faster)

def test_alphanumeric_context_name():
    """Test context name with letters and numbers."""
    # Arrange
    source = "const value = useContext(Context123);"
    # Act
    codeflash_output = _extract_context_subscriptions(source); result = codeflash_output # 3.56μs -> 1.94μs (83.0% faster)

def test_underscore_in_context_name():
    """Test context name with underscores."""
    # Arrange
    source = "const value = useContext(Theme_Context);"
    # Act
    codeflash_output = _extract_context_subscriptions(source); result = codeflash_output # 3.56μs -> 1.95μs (82.0% faster)

def test_context_in_different_positions():
    """Test useContext appearing in different code positions."""
    # Arrange
    source = """
    export function Component() {
        const a = useContext(ContextA);
        const b = useContext(ContextB);
        return <div>{a}{b}</div>;
    }
    """
    # Act
    codeflash_output = _extract_context_subscriptions(source); result = codeflash_output # 5.70μs -> 3.69μs (54.6% faster)

def test_context_in_hook_chain():
    """Test useContext among other hooks."""
    # Arrange
    source = """
    const state = useState(null);
    const theme = useContext(ThemeContext);
    const effect = useEffect(() => {}, []);
    """
    # Act
    codeflash_output = _extract_context_subscriptions(source); result = codeflash_output # 4.80μs -> 3.16μs (52.1% faster)

def test_context_in_return_statement():
    """Test useContext called within a return statement."""
    # Arrange
    source = "return <div>{useContext(MyContext).value}</div>;"
    # Act
    codeflash_output = _extract_context_subscriptions(source); result = codeflash_output # 3.78μs -> 2.08μs (81.2% faster)

def test_empty_string():
    """Test with empty source code string."""
    # Arrange
    source = ""
    # Act
    codeflash_output = _extract_context_subscriptions(source); result = codeflash_output # 1.65μs -> 541ns (206% faster)

def test_no_usecontext_calls():
    """Test source code with no useContext calls."""
    # Arrange
    source = """
    const value = useState(null);
    const ref = useRef(null);
    const callback = useCallback(() => {}, []);
    """
    # Act
    codeflash_output = _extract_context_subscriptions(source); result = codeflash_output # 3.80μs -> 2.56μs (48.0% faster)

def test_usecontext_in_comment():
    """Test that useContext in comments is still extracted (regex doesn't exclude comments)."""
    # Arrange
    source = "// const x = useContext(CommentContext);"
    # Act
    codeflash_output = _extract_context_subscriptions(source); result = codeflash_output # 3.55μs -> 1.94μs (82.6% faster)

def test_usecontext_in_string_literal():
    """Test useContext in string literal is still matched by regex."""
    # Arrange
    source = 'const str = "const x = useContext(StringContext);";'
    # Act
    codeflash_output = _extract_context_subscriptions(source); result = codeflash_output # 3.69μs -> 2.11μs (74.4% faster)

def test_usecontext_case_sensitive():
    """Test that useContext matching is case-sensitive."""
    # Arrange
    source = """
    const a = useContext(Context1);
    const b = UseContext(Context2);
    const c = usecontext(Context3);
    """
    # Act
    codeflash_output = _extract_context_subscriptions(source); result = codeflash_output # 4.63μs -> 3.04μs (52.5% faster)

def test_context_name_with_only_numbers():
    """Test context name that is purely numeric."""
    # Arrange
    source = "const x = useContext(123);"
    # Act
    codeflash_output = _extract_context_subscriptions(source); result = codeflash_output # 3.59μs -> 1.86μs (92.4% faster)

def test_single_letter_context_name():
    """Test context name that is a single letter."""
    # Arrange
    source = "const x = useContext(A);"
    # Act
    codeflash_output = _extract_context_subscriptions(source); result = codeflash_output # 3.49μs -> 1.89μs (84.1% faster)

def test_very_long_context_name():
    """Test extraction of very long context name."""
    # Arrange
    long_name = "A" * 1000
    source = f"const x = useContext({long_name});"
    # Act
    codeflash_output = _extract_context_subscriptions(source); result = codeflash_output # 5.90μs -> 4.45μs (32.7% faster)

def test_consecutive_usecontext_calls():
    """Test multiple useContext calls on the same line."""
    # Arrange
    source = "const a = useContext(A), b = useContext(B), c = useContext(C);"
    # Act
    codeflash_output = _extract_context_subscriptions(source); result = codeflash_output # 4.49μs -> 2.48μs (80.6% faster)

def test_nested_component_with_context():
    """Test nested component definitions with useContext."""
    # Arrange
    source = """
    function Outer() {
        const outerCtx = useContext(OuterContext);
        function Inner() {
            const innerCtx = useContext(InnerContext);
        }
        return null;
    }
    """
    # Act
    codeflash_output = _extract_context_subscriptions(source); result = codeflash_output # 6.00μs -> 4.01μs (49.7% faster)

def test_duplicate_context_subscriptions():
    """Test same context subscribed multiple times."""
    # Arrange
    source = """
    const a = useContext(DuplicateContext);
    const b = useContext(DuplicateContext);
    const c = useContext(DuplicateContext);
    """
    # Act
    codeflash_output = _extract_context_subscriptions(source); result = codeflash_output # 5.03μs -> 3.00μs (67.4% faster)

def test_context_with_special_jsx_syntax():
    """Test useContext in JSX prop expressions."""
    # Arrange
    source = "<Component theme={useContext(ThemeContext).theme} />"
    # Act
    codeflash_output = _extract_context_subscriptions(source); result = codeflash_output # 3.56μs -> 2.00μs (77.5% faster)

def test_usecontext_not_word_boundary():
    """Test that useContext must be a word boundary (not part of longer identifier)."""
    # Arrange
    source = "const x = myuseContext(A);"
    # Act
    codeflash_output = _extract_context_subscriptions(source); result = codeflash_output # 2.56μs -> 1.32μs (93.1% faster)

def test_usecontext_followed_by_other_characters():
    """Test useContext must be followed by whitespace or parenthesis."""
    # Arrange
    source = "const x = useContext_other(Context);"
    # Act
    codeflash_output = _extract_context_subscriptions(source); result = codeflash_output # 2.79μs -> 1.62μs (71.6% faster)

def test_context_name_cannot_contain_special_chars():
    """Test that context name must be word characters only (letters, digits, underscore)."""
    # Arrange
    source = "const x = useContext(Context-Name);"
    # Act
    codeflash_output = _extract_context_subscriptions(source); result = codeflash_output # 3.61μs -> 1.93μs (86.6% faster)

def test_context_with_dot_notation():
    """Test that useContext doesn't capture dot notation (dots not in \\w)."""
    # Arrange
    source = "const x = useContext(Theme.DarkContext);"
    # Act
    codeflash_output = _extract_context_subscriptions(source); result = codeflash_output # 3.72μs -> 2.04μs (81.8% faster)

def test_multiline_source_with_mixed_content():
    """Test complex multiline source with mixed React hooks."""
    # Arrange
    source = """
    import React, { useContext, useState, useEffect } from 'react';
    
    function MyComponent() {
        const [count, setCount] = useState(0);
        const theme = useContext(ThemeContext);
        const user = useContext(UserContext);
        
        useEffect(() => {
            console.log(count);
        }, [count]);
        
        const config = useContext(ConfigContext);
        
        return <div>{theme}</div>;
    }
    """
    # Act
    codeflash_output = _extract_context_subscriptions(source); result = codeflash_output # 9.04μs -> 7.19μs (25.6% faster)

def test_many_context_subscriptions():
    """Test extraction with many context subscriptions (100 contexts)."""
    # Arrange
    lines = [f"const ctx{i} = useContext(Context{i});" for i in range(100)]
    source = "\n".join(lines)
    # Act
    codeflash_output = _extract_context_subscriptions(source); result = codeflash_output # 49.2μs -> 35.3μs (39.3% faster)
    # Assert
    expected = [f"Context{i}" for i in range(100)]

def test_large_source_code_file():
    """Test extraction from a large source code file (1000+ lines)."""
    # Arrange
    # Create a large source with many hooks mixed in
    lines = []
    for i in range(500):
        lines.append(f"const state{i} = useState(null);")
        lines.append(f"const ctx{i} = useContext(LargeContext{i});")
        lines.append(f"const ref{i} = useRef(null);")
    source = "\n".join(lines)
    # Act
    codeflash_output = _extract_context_subscriptions(source); result = codeflash_output # 560μs -> 497μs (12.7% faster)
    # Assert
    expected = [f"LargeContext{i}" for i in range(500)]

def test_deeply_nested_structure():
    """Test with deeply nested component structure."""
    # Arrange
    source = "function A() { function B() { function C() { const x = useContext(DeepContext); } } }"
    # Act
    codeflash_output = _extract_context_subscriptions(source); result = codeflash_output # 4.39μs -> 2.54μs (72.4% faster)

def test_many_contexts_on_single_line():
    """Test many useContext calls on a single line."""
    # Arrange
    contexts = ", ".join([f"useContext(Ctx{i})" for i in range(200)])
    source = f"const [a, b, c] = [{contexts}];"
    # Act
    codeflash_output = _extract_context_subscriptions(source); result = codeflash_output # 66.7μs -> 40.7μs (63.7% faster)
    # Assert
    expected = [f"Ctx{i}" for i in range(200)]

def test_very_large_context_name_with_numbers():
    """Test with very large context name containing alphanumeric."""
    # Arrange
    name = "Context" + "A1B2C3D4E5" * 100  # 1010 character name
    source = f"const x = useContext({name});"
    # Act
    codeflash_output = _extract_context_subscriptions(source); result = codeflash_output # 6.16μs -> 4.48μs (37.6% faster)

def test_regex_iteration_performance():
    """Test regex finditer performance on large source."""
    # Arrange
    # Create source with 1000 useContext calls
    source = ";\n".join([f"const ctx{i} = useContext(Ctx{i})" for i in range(1000)])
    # Act
    codeflash_output = _extract_context_subscriptions(source); result = codeflash_output # 454μs -> 330μs (37.6% faster)

def test_whitespace_variations_at_scale():
    """Test various whitespace patterns at scale."""
    # Arrange
    lines = []
    for i in range(100):
        if i % 4 == 0:
            lines.append(f"const x = useContext(Ctx{i});")
        elif i % 4 == 1:
            lines.append(f"const x = useContext (Ctx{i});")
        elif i % 4 == 2:
            lines.append(f"const x = useContext   (Ctx{i});")
        else:
            lines.append(f"const x = useContext\n(Ctx{i});")
    source = "\n".join(lines)
    # Act
    codeflash_output = _extract_context_subscriptions(source); result = codeflash_output # 44.7μs -> 31.0μs (44.1% faster)
    # Assert
    expected = [f"Ctx{i}" for i in range(100)]

def test_return_type_is_list():
    """Test that return type is always a list."""
    # Arrange
    source = "const x = useContext(TestContext);"
    # Act
    codeflash_output = _extract_context_subscriptions(source); result = codeflash_output # 3.60μs -> 1.93μs (85.9% faster)

def test_return_order_preserved():
    """Test that extraction order matches source order."""
    # Arrange
    source = """
    const a = useContext(Alpha);
    const b = useContext(Beta);
    const c = useContext(Gamma);
    const d = useContext(Delta);
    const e = useContext(Epsilon);
    """
    # Act
    codeflash_output = _extract_context_subscriptions(source); result = codeflash_output # 5.97μs -> 3.70μs (61.5% faster)

def test_empty_list_equality():
    """Test that empty results are properly empty lists."""
    # Arrange
    source = "no hooks here"
    # Act
    codeflash_output = _extract_context_subscriptions(source); result = codeflash_output # 2.27μs -> 1.14μs (98.3% faster)
# codeflash_output is used to check that the output of the original code is the same as that of the optimized code.

To edit these changes git checkout codeflash/optimize-pr1571-2026-02-20T04.13.10 and push.

Codeflash Static Badge

The optimization replaces `finditer()` with `findall()` for regex matching, achieving a **29% speedup** in runtime (from 1.32ms to 1.02ms).

**What Changed:**
Instead of iterating over match objects and calling `.group(1)` on each (`[match.group(1) for match in _CONTEXT_RE.finditer(component_source)]`), the code now uses `_CONTEXT_RE.findall(component_source)` to directly extract captured groups.

**Why It's Faster:**
1. **Eliminates intermediate objects**: `finditer()` returns an iterator of match objects, each requiring instantiation and a method call to `group(1)`. `findall()` with a capturing group directly returns the captured strings as a list.

2. **Reduces overhead**: The list comprehension in the original code introduces iteration overhead and function call overhead for each match. `findall()` is implemented in C within Python's regex engine, making it significantly more efficient.

3. **Memory efficiency**: No intermediate match objects need to be created, reducing allocations and garbage collection pressure.

**Performance Impact:**
The test results show consistent speedups across all cases:
- Simple cases (single context): **89-98% faster** (4.28μs → 2.26μs)
- Multiple contexts: **52-67% faster** 
- Large-scale tests (1000 contexts): **37-39% faster** (454μs → 330μs)
- Edge cases (empty strings): **206% faster** (1.65μs → 541ns)

**Workload Benefits:**
Based on the function references, `_extract_context_subscriptions` is called during React component analysis for detecting context dependencies. While not in a tight loop, this function processes potentially large source files (test shows 1500+ line files). The optimization particularly benefits:
- Codebases with many context subscriptions (the 100-context test shows 39% speedup)
- Large source files (1000+ line files show 12-37% improvement)
- Batch analysis of multiple components

The optimization is universally beneficial across all input patterns with no regressions, making it a pure performance win.
@codeflash-ai codeflash-ai bot added ⚡️ codeflash Optimization PR opened by Codeflash AI 🎯 Quality: High Optimization Quality according to Codeflash labels Feb 20, 2026
@claude claude bot deleted the branch codeflash/optimize-pr1561-2026-02-20T03.56.09 February 20, 2026 04:18
@claude claude bot closed this Feb 20, 2026
@codeflash-ai codeflash-ai bot deleted the codeflash/optimize-pr1571-2026-02-20T04.13.10 branch February 20, 2026 04:18
@claude
Copy link
Contributor

claude bot commented Feb 20, 2026

PR Review Summary

Prek Checks

✅ All checks passed — ruff check and ruff format both clean. No fixes needed.

Mypy

✅ No type errors found in codeflash/languages/javascript/frameworks/react/context.py.

Code Review

✅ No critical issues found.

The change replaces finditer() + list comprehension with findall() in _extract_context_subscriptions. This is a correct optimization — re.findall() with a single capturing group returns the captured group strings directly, producing identical results to [match.group(1) for match in finditer(...)] while avoiding intermediate match object allocation.

Test Coverage

File Stmts Miss Coverage
codeflash/languages/javascript/frameworks/react/context.py 119 1 99%
  • File status: New file (does not exist on main), introduced in base branch
  • Changed line covered: ✅ The modified line (177) is exercised by tests
  • Coverage threshold: ✅ Well above the 75% requirement for new files

Note: 8 pre-existing test failures in tests/test_tracer.py (unrelated to this PR — tracer attribute/API mismatches).


Last updated: 2026-02-20

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

Labels

⚡️ codeflash Optimization PR opened by Codeflash AI 🎯 Quality: High Optimization Quality according to Codeflash

Projects

None yet

Development

Successfully merging this pull request may close these issues.

0 participants

Comments