Skip to content

Comments

⚡️ Speed up function detect_optimization_opportunities by 36% in PR #1561 (add/support_react)#1562

Open
codeflash-ai[bot] wants to merge 4 commits intoadd/support_reactfrom
codeflash/optimize-pr1561-2026-02-20T03.10.31
Open

⚡️ Speed up function detect_optimization_opportunities by 36% in PR #1561 (add/support_react)#1562
codeflash-ai[bot] wants to merge 4 commits intoadd/support_reactfrom
codeflash/optimize-pr1561-2026-02-20T03.10.31

Conversation

@codeflash-ai
Copy link
Contributor

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

⚡️ This pull request contains optimizations for PR #1561

If you approve this dependent PR, these changes will be merged into the original PR branch add/support_react.

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


📄 36% (0.36x) speedup for detect_optimization_opportunities in codeflash/languages/javascript/frameworks/react/analyzer.py

⏱️ Runtime : 8.09 milliseconds 5.95 milliseconds (best of 250 runs)

📝 Explanation and details

The optimized code achieves a 35% runtime improvement (8.09ms → 5.95ms) through strategic regex avoidance and elimination of expensive string operations:

Key Optimizations

  1. Eliminated Component Source Join: Removed component_source = "\n".join(component_lines) which was creating a large concatenated string. This alone saves significant memory allocation and copying overhead, especially for large components (tests show 43-62% speedup on 1000+ line components).

  2. Fast-Path Substring Checks Before Regex: Added cheap substring presence checks before running expensive regex patterns:

    • if "={" not in line: continue before JSX prop regexes (reduces ~2,664 regex calls in typical cases)
    • if "." not in stripped: continue before expensive operations regex (reduces ~2,523 regex calls)
    • if ("const" not in stripped and "let" not in stripped...) before function definition regex (reduces ~1,414 regex calls)
  3. Line-by-Line useCallback Detection: Changed from USECALLBACK_RE.search(component_source) on the entire joined string to iterating lines with substring check first (if "useCallback" in l), then regex only when needed. This avoids regex on large text and short-circuits on first match.

Performance Impact by Workload

The optimization particularly benefits:

  • Large components (1000+ lines): 26-43% faster, as seen in test_large_scale_detection_performance and test_detection_accuracy_with_1000_items
  • Dense JSX with many props (100+ inline props): 54-62% faster, as shown in test_many_inline_props_in_large_component and test_complex_nested_jsx_structure
  • Components with many function definitions: 27% faster in test_many_function_definitions

The approach maintains identical detection logic and results while dramatically reducing computational cost through algorithmic improvements: O(n) substring checks filter out non-matching lines before expensive O(n*m) regex operations.

Correctness verification report:

Test Status
⚙️ Existing Unit Tests 🔘 None Found
🌀 Generated Regression Tests 44 Passed
⏪ Replay Tests 🔘 None Found
🔎 Concolic Coverage Tests 🔘 None Found
📊 Tests Coverage 100.0%
🌀 Click to see Generated Regression Tests
import pytest  # used for our unit tests
from codeflash.languages.javascript.frameworks.react.analyzer import \
    detect_optimization_opportunities
from codeflash.languages.javascript.frameworks.react.discovery import \
    ReactComponentInfo

def test_detects_inline_object_and_array_props_and_reports_lines():
    # Component source contains both an inline object and inline array in JSX props.
    source = (
        "<div>\n"
        "  <Child a={ { x: 1 } } />\n"  # line 2: inline object prop
        "  <Child b={ [1, 2, 3] } />\n"  # line 3: inline array prop
        "</div>\n"
    )
    # Component spans the entire source (1-indexed line numbers)
    info = ReactComponentInfo(function_name="MyComp", component_type=None, start_line=1, end_line=4)
    codeflash_output = detect_optimization_opportunities(source, info); ops = codeflash_output # 15.3μs -> 13.4μs (14.1% faster)

    # There should be at least two entries for inline object and inline array,
    # plus one for missing React.memo (since is_memoized defaults to False).
    # Find by substring in description to avoid depending on enum types.
    inline_object_ops = [o for o in ops if "Inline object literal" in o.description]
    inline_array_ops = [o for o in ops if "Inline array literal" in o.description]
    memo_ops = [o for o in ops if "React.memo" in o.description]

def test_detects_missing_usecallback_for_functions_defined_in_render_and_omits_when_usecallback_present():
    # Two components: one without useCallback and one that uses useCallback.
    src_no_callback = (
        "return (\n"
        "  <div>\n"
        "    {/* inline function defined in render */}\n"
        "    const handleClick = () => {};\n"  # should be flagged
        "  </div>\n"
        ");\n"
    )
    info1 = ReactComponentInfo(function_name="NoCallback", component_type=None, start_line=1, end_line=7)
    codeflash_output = detect_optimization_opportunities(src_no_callback, info1); ops1 = codeflash_output # 17.1μs -> 15.1μs (13.4% faster)
    # Find missing useCallback by description substring
    missing_uc_ops = [o for o in ops1 if "Function defined inside render body" in o.description]

    # Now component that already uses useCallback anywhere - should not flag missing useCallback
    src_with_callback = (
        "const memoized = useCallback(() => {}, []);\n"
        "return (\n"
        "  <div>\n"
        "    const handleClick = () => {};\n"  # would be flagged if no useCallback present
        "  </div>\n"
        ");\n"
    )
    info2 = ReactComponentInfo(function_name="HasCallback", component_type=None, start_line=1, end_line=7)
    codeflash_output = detect_optimization_opportunities(src_with_callback, info2); ops2 = codeflash_output # 11.3μs -> 10.7μs (4.85% faster)
    missing_uc_ops2 = [o for o in ops2 if "Function defined inside render body" in o.description]

def test_detects_expensive_operations_and_ignores_when_usememo_present_inline():
    # Expensive operation (filter) should be flagged
    source = (
        "const list = items.filter(x => x.active);\n"  # flagged
        "const kept = useMemo(() => items.filter(x => x.active), [items]);\n"  # not flagged because useMemo present
    )
    info = ReactComponentInfo(function_name="ExpComp", component_type=None, start_line=1, end_line=3)
    codeflash_output = detect_optimization_opportunities(source, info); ops = codeflash_output # 16.8μs -> 15.0μs (11.9% faster)

    expensive_ops = [o for o in ops if "Expensive array operation" in o.description]

    # Also ensure missing React.memo is present
    memo_ops = [o for o in ops if "React.memo" in o.description]

def test_missing_react_memo_not_reported_if_component_is_memoized():
    # Even if the component has inline problems, if is_memoized True then MISSING_REACT_MEMO shouldn't be added.
    source = "<div>\n  <Child a={ { x: 1 } } />\n</div>\n"
    info = ReactComponentInfo(function_name="MemoizedComp", component_type=None, start_line=1, end_line=3, is_memoized=True)
    codeflash_output = detect_optimization_opportunities(source, info); ops = codeflash_output # 11.1μs -> 9.28μs (19.4% faster)

    # Search for memo-related description
    memo_ops = [o for o in ops if "React.memo" in o.description]

    # Inline object should still be reported
    inline_obj_ops = [o for o in ops if "Inline object literal" in o.description]

def test_empty_source_still_reports_missing_memo_at_start_line_and_no_other_issues():
    # Empty source; start_line set to 1 and end_line > 0.
    source = ""
    info = ReactComponentInfo(function_name="EmptyComp", component_type=None, start_line=1, end_line=10)
    codeflash_output = detect_optimization_opportunities(source, info); ops = codeflash_output # 5.18μs -> 4.71μs (10.0% faster)

def test_component_with_start_line_out_of_bounds_behaves_gracefully_and_reports_memo_at_start():
    # Source has only a few lines, but the component's start_line is beyond the file length.
    source = "line1\nline2\nline3\n"
    # Set start_line beyond the number of lines in the source
    info = ReactComponentInfo(function_name="OOBComp", component_type=None, start_line=10, end_line=20)
    codeflash_output = detect_optimization_opportunities(source, info); ops = codeflash_output # 5.39μs -> 4.89μs (10.2% faster)

    # Should still report missing React.memo using the provided start_line
    memo_ops = [o for o in ops if "React.memo" in o.description]
    # No inline/function/expensive issues should be reported because component slice is empty
    other_ops = [o for o in ops if "React.memo" not in o.description]

def test_large_scale_detection_performance_and_correct_count():
    # Build a large component with 1000 lines.
    # Odd lines contain a function definition; even lines contain an expensive op.
    lines = []
    for i in range(1, 1001):
        if i % 2 == 1:
            # function definition line that should trigger missing useCallback
            lines.append(f"const fn{i} = () => {{ return {i}; }};")
        else:
            # expensive operation line that should trigger missing useMemo
            lines.append(f"arr{i}.filter(x => x.value);")
    source = "\n".join(lines) + "\n"

    info = ReactComponentInfo(function_name="BigComp", component_type=None, start_line=1, end_line=1001)
    codeflash_output = detect_optimization_opportunities(source, info); ops = codeflash_output # 2.32ms -> 1.62ms (43.2% faster)

    # Verify a few sampled lines were correctly flagged with expected descriptions and correct line numbers
    # Sample a function definition line
    fn_line = 1  # first line is a function definition
    fn_ops = [o for o in ops if o.line == fn_line]

    # Sample an expensive op line
    exp_line = 2
    exp_ops = [o for o in ops if o.line == exp_line]

    # Ensure missing React.memo is present and located at start_line 1
    memo_ops = [o for o in ops if "React.memo" in o.description]
# codeflash_output is used to check that the output of the original code is the same as that of the optimized code.
import re
from dataclasses import dataclass
from enum import Enum

# imports
import pytest
from codeflash.languages.javascript.frameworks.react.analyzer import \
    detect_optimization_opportunities
from codeflash.languages.javascript.frameworks.react.discovery import \
    ReactComponentInfo

# Define the enums and classes needed for testing
class ComponentType(Enum):
    """Enum for React component types."""
    FUNCTIONAL = "functional"
    CLASS = "class"

class OpportunityType(Enum):
    """Enum for optimization opportunity types."""
    INLINE_OBJECT_PROP = "inline_object_prop"
    INLINE_ARRAY_PROP = "inline_array_prop"
    MISSING_USECALLBACK = "missing_usecallback"
    MISSING_USEMEMO = "missing_usememo"
    MISSING_REACT_MEMO = "missing_react_memo"

class OpportunitySeverity(Enum):
    """Enum for optimization opportunity severity."""
    LOW = "low"
    MEDIUM = "medium"
    HIGH = "high"

def test_empty_source_non_memoized_component():
    """Test detection with empty source code and non-memoized component."""
    # When analyzing an empty component that is not memoized,
    # only the missing React.memo opportunity should be detected
    source = ""
    component_info = ReactComponentInfo(
        function_name="MyComponent",
        component_type=ComponentType.FUNCTIONAL,
        start_line=1,
        end_line=1,
        is_memoized=False,
    )
    codeflash_output = detect_optimization_opportunities(source, component_info); opportunities = codeflash_output # 5.47μs -> 4.91μs (11.4% faster)

def test_memoized_component_no_issues():
    """Test that a properly memoized component with no other issues returns empty list."""
    # A memoized component with clean code should have no optimization opportunities
    source = "const MyComponent = memo(({ prop }) => <div>{prop}</div>);"
    component_info = ReactComponentInfo(
        function_name="MyComponent",
        component_type=ComponentType.FUNCTIONAL,
        start_line=1,
        end_line=1,
        is_memoized=True,
    )
    codeflash_output = detect_optimization_opportunities(source, component_info); opportunities = codeflash_output # 8.87μs -> 7.46μs (18.8% faster)

def test_inline_object_prop_detection():
    """Test detection of inline object literals in JSX props."""
    # Inline objects like ={{ key: value }} create new references on every render
    source = "<Component style={{ color: 'red' }} />"
    component_info = ReactComponentInfo(
        function_name="MyComponent",
        component_type=ComponentType.FUNCTIONAL,
        start_line=1,
        end_line=1,
        is_memoized=True,
    )
    codeflash_output = detect_optimization_opportunities(source, component_info); opportunities = codeflash_output # 9.42μs -> 7.80μs (20.7% faster)

def test_inline_array_prop_detection():
    """Test detection of inline array literals in JSX props."""
    # Inline arrays like ={[ item1, item2 ]} create new references on every render
    source = "<Component items={['a', 'b']} />"
    component_info = ReactComponentInfo(
        function_name="MyComponent",
        component_type=ComponentType.FUNCTIONAL,
        start_line=1,
        end_line=1,
        is_memoized=True,
    )
    codeflash_output = detect_optimization_opportunities(source, component_info); opportunities = codeflash_output # 8.43μs -> 7.53μs (11.8% faster)

def test_expensive_operation_detection_map():
    """Test detection of expensive .map() operation without useMemo."""
    # Expensive operations like .map() on every render should be wrapped in useMemo
    source = "const items = data.map(item => item.value);"
    component_info = ReactComponentInfo(
        function_name="MyComponent",
        component_type=ComponentType.FUNCTIONAL,
        start_line=1,
        end_line=1,
        is_memoized=True,
    )
    codeflash_output = detect_optimization_opportunities(source, component_info); opportunities = codeflash_output # 10.3μs -> 9.42μs (9.25% faster)

def test_expensive_operation_detection_filter():
    """Test detection of expensive .filter() operation without useMemo."""
    source = "const filtered = items.filter(item => item.active);"
    component_info = ReactComponentInfo(
        function_name="MyComponent",
        component_type=ComponentType.FUNCTIONAL,
        start_line=1,
        end_line=1,
        is_memoized=True,
    )
    codeflash_output = detect_optimization_opportunities(source, component_info); opportunities = codeflash_output # 10.7μs -> 9.78μs (9.63% faster)

def test_function_definition_without_usecallback():
    """Test detection of function definitions that could use useCallback."""
    # Functions defined inside components create new references on every render
    source = "const handleClick = () => { console.log('clicked'); };"
    component_info = ReactComponentInfo(
        function_name="MyComponent",
        component_type=ComponentType.FUNCTIONAL,
        start_line=1,
        end_line=1,
        is_memoized=True,
    )
    codeflash_output = detect_optimization_opportunities(source, component_info); opportunities = codeflash_output # 9.63μs -> 8.55μs (12.7% faster)

def test_all_opportunities_detected():
    """Test detection of multiple optimization opportunities in one component."""
    # A component with multiple issues should report all of them
    source = """
    const Component = () => {
        const handleClick = () => {};
        const items = data.map(x => x);
        return <div style={{ color: 'red' }} />;
    }
    """
    component_info = ReactComponentInfo(
        function_name="Component",
        component_type=ComponentType.FUNCTIONAL,
        start_line=1,
        end_line=6,
        is_memoized=False,
    )
    codeflash_output = detect_optimization_opportunities(source, component_info); opportunities = codeflash_output # 24.3μs -> 20.8μs (17.0% faster)
    types = [opp.type for opp in opportunities]

def test_line_number_calculation_with_offset():
    """Test that line numbers are correctly calculated when component starts at non-zero line."""
    # When a component starts at line 5, opportunities should reference lines >= 5
    source = "line1\nline2\nline3\nline4\nconst items = data.map(x => x);\nline6"
    component_info = ReactComponentInfo(
        function_name="MyComponent",
        component_type=ComponentType.FUNCTIONAL,
        start_line=5,
        end_line=6,
        is_memoized=True,
    )
    codeflash_output = detect_optimization_opportunities(source, component_info); opportunities = codeflash_output # 11.5μs -> 10.4μs (10.2% faster)

def test_multiline_source_with_multiple_issues_per_line():
    """Test detection with multiple issues on the same line."""
    # A single line can contain multiple optimization issues
    source = "<Component style={{ color: 'red' }} items={[1, 2, 3]} />"
    component_info = ReactComponentInfo(
        function_name="MyComponent",
        component_type=ComponentType.FUNCTIONAL,
        start_line=1,
        end_line=1,
        is_memoized=True,
    )
    codeflash_output = detect_optimization_opportunities(source, component_info); opportunities = codeflash_output # 10.6μs -> 8.74μs (21.0% faster)
    types = [opp.type for opp in opportunities]

def test_usecallback_prevents_function_detection():
    """Test that if useCallback is used, individual function definitions are not flagged."""
    # If component uses useCallback, function definitions inside should not be flagged
    source = """
    const Component = () => {
        useCallback(() => { console.log('test'); }, []);
        const handleClick = () => { console.log('clicked'); };
        return null;
    }
    """
    component_info = ReactComponentInfo(
        function_name="Component",
        component_type=ComponentType.FUNCTIONAL,
        start_line=1,
        end_line=6,
        is_memoized=False,
    )
    codeflash_output = detect_optimization_opportunities(source, component_info); opportunities = codeflash_output # 16.9μs -> 14.4μs (16.8% faster)
    
    # Assert that no useCallback opportunities are found because component uses useCallback
    callback_opps = [opp for opp in opportunities if opp.type == OpportunityType.MISSING_USECALLBACK]

def test_usememo_wrapping_prevents_detection():
    """Test that operations wrapped in useMemo are not flagged."""
    # Operations already wrapped in useMemo should not be flagged
    source = "const items = useMemo(() => data.map(x => x), [data]);"
    component_info = ReactComponentInfo(
        function_name="MyComponent",
        component_type=ComponentType.FUNCTIONAL,
        start_line=1,
        end_line=1,
        is_memoized=True,
    )
    codeflash_output = detect_optimization_opportunities(source, component_info); opportunities = codeflash_output # 9.11μs -> 8.12μs (12.1% faster)

def test_all_expensive_operations():
    """Test detection of all types of expensive array operations."""
    # Test detection of various expensive operations
    operations = ["filter", "map", "sort", "reduce", "flatMap", "find", "findIndex", "every", "some"]
    
    for op in operations:
        source = f"const result = data.{op}(x => x);"
        component_info = ReactComponentInfo(
            function_name="MyComponent",
            component_type=ComponentType.FUNCTIONAL,
            start_line=1,
            end_line=1,
            is_memoized=True,
        )
        codeflash_output = detect_optimization_opportunities(source, component_info); opportunities = codeflash_output # 49.4μs -> 44.7μs (10.7% faster)

def test_component_info_with_hooks():
    """Test that component info with hooks is processed correctly."""
    # Component info can indicate which hooks are used
    source = "const MyComponent = () => <div>test</div>;"
    component_info = ReactComponentInfo(
        function_name="MyComponent",
        component_type=ComponentType.FUNCTIONAL,
        uses_hooks=("useState", "useEffect"),
        start_line=1,
        end_line=1,
        is_memoized=False,
    )
    codeflash_output = detect_optimization_opportunities(source, component_info); opportunities = codeflash_output # 10.3μs -> 8.96μs (14.5% faster)

def test_component_with_props_type():
    """Test detection with component info including props_type."""
    # Component props type is tracked but should not affect opportunity detection
    source = "const items = data.map(x => x);"
    component_info = ReactComponentInfo(
        function_name="MyComponent",
        component_type=ComponentType.FUNCTIONAL,
        props_type="{ value: string }",
        start_line=1,
        end_line=1,
        is_memoized=True,
    )
    codeflash_output = detect_optimization_opportunities(source, component_info); opportunities = codeflash_output # 9.94μs -> 8.99μs (10.6% faster)

def test_empty_lines_skipped():
    """Test that empty lines don't produce false positives."""
    # Empty lines and lines with just whitespace should not trigger false positives
    source = "\n\n\n\n"
    component_info = ReactComponentInfo(
        function_name="MyComponent",
        component_type=ComponentType.FUNCTIONAL,
        start_line=1,
        end_line=4,
        is_memoized=False,
    )
    codeflash_output = detect_optimization_opportunities(source, component_info); opportunities = codeflash_output # 7.97μs -> 6.66μs (19.7% faster)

def test_start_line_and_end_line_boundaries():
    """Test that only lines within start_line and end_line are analyzed."""
    # Source contains multiple components, but only one should be analyzed
    source = """line 1 - should not be analyzed
function other() { const x = data.map(i => i); }
const MyComponent = () => {
    const items = data.filter(x => x);
    return null;
}
const AnotherComponent = () => { const x = data.sort(); }"""
    
    # Analyze only MyComponent (lines 3-5)
    component_info = ReactComponentInfo(
        function_name="MyComponent",
        component_type=ComponentType.FUNCTIONAL,
        start_line=3,
        end_line=5,
        is_memoized=False,
    )
    codeflash_output = detect_optimization_opportunities(source, component_info); opportunities = codeflash_output # 17.5μs -> 15.5μs (12.8% faster)
    
    # Assert that only the filter operation (line 4) and missing React.memo are detected
    # The map on line 2 and sort on line 7 should not be detected
    usememo_opps = [opp for opp in opportunities if opp.type == OpportunityType.MISSING_USEMEMO]

def test_class_component_type():
    """Test detection works with class components."""
    # Class components should be analyzed the same way as functional components
    source = "render() { const items = data.map(x => x); return null; }"
    component_info = ReactComponentInfo(
        function_name="MyClassComponent",
        component_type=ComponentType.CLASS,
        start_line=1,
        end_line=1,
        is_memoized=False,
    )
    codeflash_output = detect_optimization_opportunities(source, component_info); opportunities = codeflash_output # 12.1μs -> 11.0μs (9.36% faster)

def test_special_characters_in_source():
    """Test handling of source code with special characters."""
    # Source code may contain special regex characters
    source = "const x = data.map(item => item.value + '...');"
    component_info = ReactComponentInfo(
        function_name="MyComponent",
        component_type=ComponentType.FUNCTIONAL,
        start_line=1,
        end_line=1,
        is_memoized=True,
    )
    codeflash_output = detect_optimization_opportunities(source, component_info); opportunities = codeflash_output # 10.4μs -> 9.42μs (10.3% faster)

def test_consecutive_line_numbers():
    """Test correct line numbering with consecutive lines."""
    # Each line should get the correct sequential line number
    source = "line1\nline2\nconst x = data.map(i => i);\nline4\nline5"
    component_info = ReactComponentInfo(
        function_name="MyComponent",
        component_type=ComponentType.FUNCTIONAL,
        start_line=1,
        end_line=5,
        is_memoized=False,
    )
    codeflash_output = detect_optimization_opportunities(source, component_info); opportunities = codeflash_output # 14.2μs -> 12.8μs (10.9% faster)
    
    # Assert that the map operation on line 3 is correctly identified
    usememo_opps = [opp for opp in opportunities if opp.type == OpportunityType.MISSING_USEMEMO]

def test_no_false_positives_on_similar_patterns():
    """Test that similar patterns that aren't actual issues don't trigger false positives."""
    # Code that looks similar but isn't an issue should not be flagged
    source = "const comment = 'data.map(x => x)'; // This is a comment"
    component_info = ReactComponentInfo(
        function_name="MyComponent",
        component_type=ComponentType.FUNCTIONAL,
        start_line=1,
        end_line=1,
        is_memoized=True,
    )
    codeflash_output = detect_optimization_opportunities(source, component_info); opportunities = codeflash_output # 10.6μs -> 9.55μs (11.2% faster)

def test_large_component_with_many_operations():
    """Test detection in a large component with many operations."""
    # Generate a component with 100 lines and multiple issues
    lines = ["const MyComponent = () => {"]
    for i in range(100):
        if i % 10 == 0:
            lines.append(f"  const items{i} = data.map(x => x); // line {i+2}")
        else:
            lines.append(f"  const var{i} = {i};")
    lines.append("  return null;")
    lines.append("};")
    
    source = "\n".join(lines)
    component_info = ReactComponentInfo(
        function_name="MyComponent",
        component_type=ComponentType.FUNCTIONAL,
        start_line=1,
        end_line=len(lines),
        is_memoized=False,
    )
    codeflash_output = detect_optimization_opportunities(source, component_info); opportunities = codeflash_output # 161μs -> 128μs (26.3% faster)
    
    # Assert that multiple expensive operations are detected (10 map calls)
    usememo_opps = [opp for opp in opportunities if opp.type == OpportunityType.MISSING_USEMEMO]

def test_many_inline_props_in_large_component():
    """Test detection of many inline props in a large JSX tree."""
    # Generate a component with many inline object and array props
    lines = ["const MyComponent = () => {"]
    lines.append("  return (")
    for i in range(100):
        lines.append(f'    <Component{i} style={{{{ color: "red{i}" }}}} items={{[{i}]}} />')
    lines.append("  );")
    lines.append("};")
    
    source = "\n".join(lines)
    component_info = ReactComponentInfo(
        function_name="MyComponent",
        component_type=ComponentType.FUNCTIONAL,
        start_line=1,
        end_line=len(lines),
        is_memoized=False,
    )
    codeflash_output = detect_optimization_opportunities(source, component_info); opportunities = codeflash_output # 421μs -> 272μs (54.5% faster)
    
    # Assert that inline props are detected for each component (100 of each)
    inline_obj_opps = [opp for opp in opportunities if opp.type == OpportunityType.INLINE_OBJECT_PROP]
    inline_arr_opps = [opp for opp in opportunities if opp.type == OpportunityType.INLINE_ARRAY_PROP]

def test_many_function_definitions():
    """Test detection of many function definitions in a component."""
    # Generate a component with many function definitions
    lines = ["const MyComponent = () => {"]
    for i in range(100):
        lines.append(f"  const handler{i} = () => console.log({i});")
    lines.append("  return null;")
    lines.append("};")
    
    source = "\n".join(lines)
    component_info = ReactComponentInfo(
        function_name="MyComponent",
        component_type=ComponentType.FUNCTIONAL,
        start_line=1,
        end_line=len(lines),
        is_memoized=False,
    )
    codeflash_output = detect_optimization_opportunities(source, component_info); opportunities = codeflash_output # 246μs -> 193μs (27.4% faster)
    
    # Assert that function definitions are detected (100 handlers)
    usecallback_opps = [opp for opp in opportunities if opp.type == OpportunityType.MISSING_USECALLBACK]

def test_performance_with_very_large_source():
    """Test that function completes in reasonable time with very large source."""
    # Generate a very large source file (1000 lines)
    lines = []
    for i in range(1000):
        if i % 50 == 0:
            lines.append(f"  const item{i} = data.filter(x => x);")
        else:
            lines.append(f"  const var{i} = {i};")
    
    source = "\n".join(lines)
    component_info = ReactComponentInfo(
        function_name="MyComponent",
        component_type=ComponentType.FUNCTIONAL,
        start_line=1,
        end_line=len(lines),
        is_memoized=True,
    )
    
    # This should complete without timeout
    codeflash_output = detect_optimization_opportunities(source, component_info); opportunities = codeflash_output # 1.39ms -> 1.07ms (30.1% faster)

def test_complex_nested_jsx_structure():
    """Test detection in complex nested JSX with many potential issues."""
    # Create deeply nested JSX with multiple issues
    jsx_lines = ["<div>"]
    for i in range(50):
        jsx_lines.append(f'  <Component{i} config={{{{ id: {i}, color: "red" }}}} data={{[1, 2, 3]}} />')
    jsx_lines.append("</div>")
    
    source = "\n".join(jsx_lines)
    component_info = ReactComponentInfo(
        function_name="MyComponent",
        component_type=ComponentType.FUNCTIONAL,
        start_line=1,
        end_line=len(jsx_lines),
        is_memoized=False,
    )
    codeflash_output = detect_optimization_opportunities(source, component_info); opportunities = codeflash_output # 230μs -> 142μs (62.0% faster)
    
    # Assert detection of inline objects and arrays
    inline_obj_opps = [opp for opp in opportunities if opp.type == OpportunityType.INLINE_OBJECT_PROP]
    inline_arr_opps = [opp for opp in opportunities if opp.type == OpportunityType.INLINE_ARRAY_PROP]

def test_mixed_issues_in_large_component():
    """Test detection of all types of issues in a large mixed component."""
    # Create a component with all types of issues mixed together
    lines = ["const MyComponent = () => {"]
    for i in range(100):
        if i % 4 == 0:
            lines.append(f"  const h{i} = () => {{}};")
        elif i % 4 == 1:
            lines.append(f"  const items{i} = data.map(x => x);")
        elif i % 4 == 2:
            lines.append(f'  <Comp{i} style={{{{ color: "red" }}}} />')
        else:
            lines.append(f'  <Comp{i} items={{[1, 2]}} />')
    lines.append("  return null;")
    lines.append("};")
    
    source = "\n".join(lines)
    component_info = ReactComponentInfo(
        function_name="MyComponent",
        component_type=ComponentType.FUNCTIONAL,
        start_line=1,
        end_line=len(lines),
        is_memoized=False,
    )
    codeflash_output = detect_optimization_opportunities(source, component_info); opportunities = codeflash_output # 265μs -> 200μs (32.1% faster)
    
    # Assert that all types of opportunities are detected
    types_found = set(opp.type for opp in opportunities)

def test_detection_accuracy_with_1000_items():
    """Test detection accuracy when processing a component with 1000 lines."""
    # Create exactly 1000 lines with predictable content
    lines = ["const LargeComponent = () => {"]
    expected_usememo_count = 0
    expected_inline_obj_count = 0
    expected_inline_arr_count = 0
    
    for i in range(1000):
        if i % 3 == 0:
            lines.append(f"  const x{i} = data.sort(a => a);")
            expected_usememo_count += 1
        elif i % 3 == 1:
            lines.append(f'  <Component style={{{{ x: {i} }}}} />')
            expected_inline_obj_count += 1
        else:
            lines.append(f'  <Component items={{[1, 2, {i}]}} />')
            expected_inline_arr_count += 1
    
    lines.append("  return null;")
    lines.append("};")
    
    source = "\n".join(lines)
    component_info = ReactComponentInfo(
        function_name="LargeComponent",
        component_type=ComponentType.FUNCTIONAL,
        start_line=1,
        end_line=len(lines),
        is_memoized=False,
    )
    codeflash_output = detect_optimization_opportunities(source, component_info); opportunities = codeflash_output # 2.70ms -> 2.01ms (34.0% faster)
    
    # Verify counts match expectations
    usememo_opps = [opp for opp in opportunities if opp.type == OpportunityType.MISSING_USEMEMO]
    inline_obj_opps = [opp for opp in opportunities if opp.type == OpportunityType.INLINE_OBJECT_PROP]
    inline_arr_opps = [opp for opp in opportunities if opp.type == OpportunityType.INLINE_ARRAY_PROP]
# 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-pr1561-2026-02-20T03.10.31 and push.

Codeflash Static Badge

The optimized code achieves a **35% runtime improvement** (8.09ms → 5.95ms) through strategic regex avoidance and elimination of expensive string operations:

## Key Optimizations

1. **Eliminated Component Source Join**: Removed `component_source = "\n".join(component_lines)` which was creating a large concatenated string. This alone saves significant memory allocation and copying overhead, especially for large components (tests show 43-62% speedup on 1000+ line components).

2. **Fast-Path Substring Checks Before Regex**: Added cheap substring presence checks before running expensive regex patterns:
   - `if "={" not in line: continue` before JSX prop regexes (reduces ~2,664 regex calls in typical cases)
   - `if "." not in stripped: continue` before expensive operations regex (reduces ~2,523 regex calls)
   - `if ("const" not in stripped and "let" not in stripped...)` before function definition regex (reduces ~1,414 regex calls)

3. **Line-by-Line useCallback Detection**: Changed from `USECALLBACK_RE.search(component_source)` on the entire joined string to iterating lines with substring check first (`if "useCallback" in l`), then regex only when needed. This avoids regex on large text and short-circuits on first match.

## Performance Impact by Workload

The optimization particularly benefits:
- **Large components** (1000+ lines): 26-43% faster, as seen in `test_large_scale_detection_performance` and `test_detection_accuracy_with_1000_items`
- **Dense JSX with many props** (100+ inline props): 54-62% faster, as shown in `test_many_inline_props_in_large_component` and `test_complex_nested_jsx_structure`
- **Components with many function definitions**: 27% faster in `test_many_function_definitions`

The approach maintains identical detection logic and results while dramatically reducing computational cost through algorithmic improvements: O(n) substring checks filter out non-matching lines before expensive O(n*m) regex operations.
@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
Copy link
Contributor

claude bot commented Feb 20, 2026

PR Review Summary

Prek Checks

All checks passing. Fixed 10 linting issues in commit 8008c8e8:

  • TC003: Moved Path imports into TYPE_CHECKING blocks (4 files)
  • E741: Renamed ambiguous variable lline in analyzer.py
  • SIM110: Replaced for loops with any() in discovery.py and profiler.py
  • RET504: Removed unnecessary assignment before return in profiler.py
  • FURB171: Changed single-item tuple membership tests to equality in treesitter_utils.py

Mypy: 26 pre-existing errors in base.py, parse.py, support.py — none introduced by this PR.

Code Review

The optimization to detect_optimization_opportunities is correct and well-structured. Changes:

  • Replaces "\n".join(component_lines) with line-by-line scanning to avoid large string allocation
  • Adds substring pre-checks ("={" in line, "." in stripped, etc.) before regex to reduce unnecessary regex calls
  • Refactors useCallback detection from full-string regex to line-by-line scan with early exit

Minor observations (non-blocking):

  • component_source parameter is now dead code in _detect_missing_usecallback and _detect_missing_usememo (always receives "")
  • Duplicate comment # Check for inline objects in JSX props on lines 70-72 of analyzer.py

No critical bugs, security issues, or breaking changes found.

Test Coverage

File Type Stmts Miss Coverage
frameworks/__init__.py New 0 0 100%
frameworks/react/__init__.py New 0 0 100%
frameworks/detector.py New 0%
frameworks/react/analyzer.py New 0%
frameworks/react/context.py New 0%
frameworks/react/discovery.py New 127 53 58%
frameworks/react/profiler.py New 0%
frameworks/react/testgen.py New 0%
treesitter_utils.py New 0%
languages/base.py Modified 133 2 98%
languages/javascript/parse.py Modified 272 138 49%
languages/javascript/support.py Modified 1047 315 70%
models/function_types.py Modified 47 0 100%

Note: Most new React framework files (detector.py, analyzer.py, context.py, profiler.py, testgen.py) have 0% test coverage — no test files exist for the React framework code. These files were introduced in the parent PR #1561 and lack dedicated tests. discovery.py has partial coverage (58%) likely from indirect imports during other tests.

Overall: 2411 passed, 8 failed (all in test_tracer.py, pre-existing), 57 skipped. No test regressions from this PR.


Last updated: 2026-02-20

@claude claude bot mentioned this pull request Feb 20, 2026
The optimized code achieves a **149% speedup** (539μs → 216μs) by replacing recursive tree traversal with an iterative stack-based approach.

## Key Optimization

**Eliminated recursive function calls**: The original implementation used `any(_contains_jsx(child) for child in node.children)`, which created a new stack frame for each recursive call. The line profiler shows this consumed **84.1% of total runtime** (2.23ms out of 2.65ms). The optimized version uses an explicit stack data structure with a while loop, avoiding Python's function call overhead entirely.

## Why This Is Faster

1. **No recursive overhead**: Each recursive call in Python involves creating a new stack frame, copying arguments, and managing return values. The iterative approach eliminates all of this.

2. **Early termination efficiency**: Both versions can return `True` early when JSX is found, but the iterative version does this more efficiently without unwinding the call stack.

3. **Better memory locality**: The explicit stack keeps all traversal state in a single list object, improving CPU cache utilization compared to scattered stack frames.

## Performance Characteristics

The optimization shines particularly well on:
- **Deep nesting**: 100-level deep tree shows **691% speedup** (94.9μs → 12.0μs)
- **Wide trees with JSX at end**: 100 siblings with JSX as last child shows **1985% speedup** (34.3μs → 1.64μs)  
- **Balanced trees**: 512-node tree shows **195% speedup** (308μs → 104μs)

Trade-off: Direct JSX matches (root node is JSX) are ~20-26% slower due to stack initialization overhead, but these simple cases are already extremely fast (<1μs) and the optimization dramatically benefits complex real-world AST traversals.

## Impact

For React code analysis tools that traverse Abstract Syntax Trees to detect JSX elements, this optimization significantly reduces profiling overhead, especially when analyzing large component files with deeply nested or wide component trees.
@codeflash-ai
Copy link
Contributor Author

codeflash-ai bot commented Feb 20, 2026

⚡️ Codeflash found optimizations for this PR

📄 149% (1.49x) speedup for _contains_jsx in codeflash/languages/javascript/frameworks/react/profiler.py

⏱️ Runtime : 539 microseconds 216 microseconds (best of 101 runs)

A dependent PR with the suggested changes has been created. Please review:

If you approve, it will be merged into this PR (branch codeflash/optimize-pr1561-2026-02-20T03.10.31).

Static Badge

…2026-02-20T03.28.04

⚡️ Speed up function `_contains_jsx` by 149% in PR #1562 (`codeflash/optimize-pr1561-2026-02-20T03.10.31`)
@codeflash-ai
Copy link
Contributor Author

codeflash-ai bot commented Feb 20, 2026

This PR is now faster! 🚀 @claude[bot] accepted my optimizations from:

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