Skip to content

⚡️ Speed up method JavaAnalyzer.find_methods by 11% in PR #1199 (omni-java)#1298

Closed
codeflash-ai[bot] wants to merge 1 commit intoomni-javafrom
codeflash/optimize-pr1199-2026-02-03T10.01.07
Closed

⚡️ Speed up method JavaAnalyzer.find_methods by 11% in PR #1199 (omni-java)#1298
codeflash-ai[bot] wants to merge 1 commit intoomni-javafrom
codeflash/optimize-pr1199-2026-02-03T10.01.07

Conversation

@codeflash-ai
Copy link
Contributor

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

⚡️ This pull request contains optimizations for PR #1199

If you approve this dependent PR, these changes will be merged into the original PR branch omni-java.

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


📄 11% (0.11x) speedup for JavaAnalyzer.find_methods in codeflash/languages/java/parser.py

⏱️ Runtime : 24.5 milliseconds 22.0 milliseconds (best of 123 runs)

📝 Explanation and details

The optimized code achieves an 11% runtime improvement (24.5ms → 22.0ms) by eliminating recursive function call overhead through two key optimizations:

Primary Optimization: Iterative Tree Traversal

The core improvement replaces recursive calls to _walk_tree_for_methods with an explicit stack-based iteration. In Python, each recursive call incurs significant overhead from:

  • Stack frame creation and teardown
  • Parameter passing (6 parameters per call)
  • Return address management

The profiler data confirms this: the original code spent 24.5% of time in recursive call setup (lines 39338 hits at 816.7ns per hit), while the optimized version eliminates this entirely by using a stack data structure.

The iterative approach processes nodes in the same depth-first, left-to-right order (by reversing children before pushing to stack) but replaces ~19,726 recursive function calls with simple stack operations. This is particularly effective for Java code analysis where the AST can have deep nesting (nested classes, methods, etc.).

Secondary Optimization: Type Declaration Tuple Caching

Moving type_declarations = ("class_declaration", "interface_declaration", "enum_declaration") from a local variable allocated on every call (19,726 times) to a single instance attribute self._type_declarations eliminates 19,726 tuple allocations. The profiler shows this saved 3.3% of execution time in the original version.

Performance Characteristics

The optimization excels on test cases with:

  • Many methods (100+ methods): 11.6-14.6% speedup as recursive overhead compounds
  • Deep nesting (nested classes): 8.85% speedup by avoiding deep call stacks
  • Large files with filtering: 11-12% speedup as the stack approach handles conditional logic efficiently
  • Mixed interfaces/classes: 13.2% speedup due to reduced overhead when tracking type context

The optimization maintains identical correctness across all test cases, preserving method discovery, filtering behavior, line numbers, class tracking, and return types.

Correctness verification report:

Test Status
⚙️ Existing Unit Tests 🔘 None Found
🌀 Generated Regression Tests 156 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.java.parser import JavaAnalyzer, JavaMethodNode
from tree_sitter import Node

class TestJavaAnalyzerFindMethods:
    """Comprehensive test suite for JavaAnalyzer.find_methods function."""

    # ============================================================================
    # BASIC TEST CASES
    # ============================================================================

    def test_empty_source_code(self):
        """Test with empty source code string."""
        analyzer = JavaAnalyzer()
        codeflash_output = analyzer.find_methods(""); result = codeflash_output # 8.94μs -> 9.58μs (6.70% slower)

    def test_single_simple_method(self):
        """Test finding a single public method with no modifiers issues."""
        analyzer = JavaAnalyzer()
        source = """
        public class TestClass {
            public void simpleMethod() {
                System.out.println("Hello");
            }
        }
        """
        codeflash_output = analyzer.find_methods(source); result = codeflash_output # 70.2μs -> 67.4μs (4.07% faster)

    def test_multiple_methods_in_class(self):
        """Test finding multiple methods in a single class."""
        analyzer = JavaAnalyzer()
        source = """
        public class Calculator {
            public int add(int a, int b) {
                return a + b;
            }
            
            public int subtract(int a, int b) {
                return a - b;
            }
            
            public int multiply(int a, int b) {
                return a * b;
            }
        }
        """
        codeflash_output = analyzer.find_methods(source); result = codeflash_output # 128μs -> 120μs (7.19% faster)
        method_names = [m.name for m in result]

    def test_private_method_included_by_default(self):
        """Test that private methods are included by default."""
        analyzer = JavaAnalyzer()
        source = """
        public class MyClass {
            private void privateMethod() {
            }
        }
        """
        codeflash_output = analyzer.find_methods(source); result = codeflash_output # 45.1μs -> 44.2μs (2.01% faster)

    def test_static_method_included_by_default(self):
        """Test that static methods are included by default."""
        analyzer = JavaAnalyzer()
        source = """
        public class MyClass {
            public static void staticMethod() {
            }
        }
        """
        codeflash_output = analyzer.find_methods(source); result = codeflash_output # 45.3μs -> 44.9μs (0.891% faster)

    def test_exclude_private_methods(self):
        """Test excluding private methods when include_private=False."""
        analyzer = JavaAnalyzer()
        source = """
        public class MyClass {
            public void publicMethod() {
            }
            private void privateMethod() {
            }
        }
        """
        codeflash_output = analyzer.find_methods(source, include_private=False); result = codeflash_output # 61.1μs -> 60.5μs (0.961% faster)

    def test_exclude_static_methods(self):
        """Test excluding static methods when include_static=False."""
        analyzer = JavaAnalyzer()
        source = """
        public class MyClass {
            public void instanceMethod() {
            }
            public static void staticMethod() {
            }
        }
        """
        codeflash_output = analyzer.find_methods(source, include_static=False); result = codeflash_output # 63.0μs -> 61.4μs (2.49% faster)

    def test_protected_method(self):
        """Test finding protected methods."""
        analyzer = JavaAnalyzer()
        source = """
        public class MyClass {
            protected void protectedMethod() {
            }
        }
        """
        codeflash_output = analyzer.find_methods(source); result = codeflash_output # 43.5μs -> 42.9μs (1.50% faster)

    def test_abstract_method(self):
        """Test finding abstract methods."""
        analyzer = JavaAnalyzer()
        source = """
        public abstract class MyAbstractClass {
            public abstract void abstractMethod();
        }
        """
        codeflash_output = analyzer.find_methods(source); result = codeflash_output # 45.3μs -> 44.6μs (1.62% faster)

    def test_synchronized_method(self):
        """Test finding synchronized methods."""
        analyzer = JavaAnalyzer()
        source = """
        public class MyClass {
            public synchronized void synchronizedMethod() {
            }
        }
        """
        codeflash_output = analyzer.find_methods(source); result = codeflash_output # 45.4μs -> 44.4μs (2.33% faster)

    def test_method_with_return_type(self):
        """Test method return type extraction."""
        analyzer = JavaAnalyzer()
        source = """
        public class MyClass {
            public String getString() {
                return "test";
            }
            
            public List<String> getList() {
                return new ArrayList<>();
            }
        }
        """
        codeflash_output = analyzer.find_methods(source); result = codeflash_output # 84.0μs -> 80.4μs (4.49% faster)

    def test_method_line_numbers(self):
        """Test that method line numbers are correctly extracted."""
        analyzer = JavaAnalyzer()
        source = """public class MyClass {
    public void method1() {
        System.out.println("line 2");
    }
    
    public void method2() {
        System.out.println("line 6");
    }
}"""
        codeflash_output = analyzer.find_methods(source); result = codeflash_output # 97.6μs -> 91.9μs (6.28% faster)

    def test_method_in_interface(self):
        """Test finding methods declared in an interface."""
        analyzer = JavaAnalyzer()
        source = """
        public interface MyInterface {
            void methodOne();
            String methodTwo();
        }
        """
        codeflash_output = analyzer.find_methods(source); result = codeflash_output # 53.3μs -> 51.8μs (2.94% faster)
        method_names = [m.name for m in result]

    def test_method_in_enum(self):
        """Test finding methods declared in an enum."""
        analyzer = JavaAnalyzer()
        source = """
        public enum Color {
            RED, GREEN, BLUE;
            
            public String getHexCode() {
                return "#FF0000";
            }
        }
        """
        codeflash_output = analyzer.find_methods(source); result = codeflash_output # 61.1μs -> 59.2μs (3.29% faster)
        hex_method = [m for m in result if m.name == "getHexCode"]

    def test_nested_classes_methods(self):
        """Test finding methods in nested classes."""
        analyzer = JavaAnalyzer()
        source = """
        public class OuterClass {
            public void outerMethod() {
            }
            
            public static class InnerClass {
                public void innerMethod() {
                }
            }
        }
        """
        codeflash_output = analyzer.find_methods(source); result = codeflash_output # 70.1μs -> 67.7μs (3.55% faster)
        method_names = [m.name for m in result]

    def test_class_name_tracking(self):
        """Test that class names are correctly tracked for methods."""
        analyzer = JavaAnalyzer()
        source = """
        public class ClassA {
            public void methodA() {
            }
        }
        
        public class ClassB {
            public void methodB() {
            }
        }
        """
        codeflash_output = analyzer.find_methods(source); result = codeflash_output # 66.3μs -> 64.2μs (3.39% faster)
        for method in result:
            if method.name == "methodA":
                pass
            elif method.name == "methodB":
                pass

    def test_method_with_parameters(self):
        """Test finding methods with various parameter types."""
        analyzer = JavaAnalyzer()
        source = """
        public class MyClass {
            public void methodWithParams(String name, int age, List<String> items) {
            }
        }
        """
        codeflash_output = analyzer.find_methods(source); result = codeflash_output # 61.4μs -> 58.6μs (4.77% faster)

    def test_method_with_throws_clause(self):
        """Test finding methods with throws clause."""
        analyzer = JavaAnalyzer()
        source = """
        public class MyClass {
            public void methodWithThrows() throws IOException, SQLException {
            }
        }
        """
        codeflash_output = analyzer.find_methods(source); result = codeflash_output # 49.9μs -> 48.2μs (3.47% faster)

    def test_method_with_generic_return_type(self):
        """Test method with generic return type."""
        analyzer = JavaAnalyzer()
        source = """
        public class GenericClass {
            public <T> T getValue() {
                return null;
            }
        }
        """
        codeflash_output = analyzer.find_methods(source); result = codeflash_output # 52.7μs -> 49.7μs (6.04% faster)

    # ============================================================================
    # EDGE CASE TEST CASES
    # ============================================================================

    def test_source_with_only_class_definition(self):
        """Test source code with only a class definition and no methods."""
        analyzer = JavaAnalyzer()
        source = """
        public class EmptyClass {
        }
        """
        codeflash_output = analyzer.find_methods(source); result = codeflash_output # 22.5μs -> 23.0μs (2.27% slower)

    def test_source_with_no_class_definition(self):
        """Test source code with methods outside class (edge case)."""
        analyzer = JavaAnalyzer()
        source = "public void orphanMethod() { }"
        codeflash_output = analyzer.find_methods(source); result = codeflash_output # 32.9μs -> 33.0μs (0.155% slower)

    def test_whitespace_only_source(self):
        """Test source code with only whitespace."""
        analyzer = JavaAnalyzer()
        source = "   \n\n\t\t  \n"
        codeflash_output = analyzer.find_methods(source); result = codeflash_output # 8.72μs -> 9.27μs (5.95% slower)

    def test_method_names_with_numbers(self):
        """Test method names containing numbers."""
        analyzer = JavaAnalyzer()
        source = """
        public class MyClass {
            public void method1() {
            }
            public void method2Test() {
            }
            public void test3Method() {
            }
        }
        """
        codeflash_output = analyzer.find_methods(source); result = codeflash_output # 77.3μs -> 74.4μs (3.94% faster)
        names = [m.name for m in result]

    def test_method_with_underscore_in_name(self):
        """Test method names containing underscores."""
        analyzer = JavaAnalyzer()
        source = """
        public class MyClass {
            public void test_method_name() {
            }
        }
        """
        codeflash_output = analyzer.find_methods(source); result = codeflash_output # 43.4μs -> 42.9μs (1.21% faster)

    def test_all_access_modifiers_combined(self):
        """Test method with multiple access modifiers."""
        analyzer = JavaAnalyzer()
        source = """
        public class MyClass {
            public static synchronized void allModifiers() {
            }
        }
        """
        codeflash_output = analyzer.find_methods(source); result = codeflash_output # 48.2μs -> 46.5μs (3.86% faster)

    def test_exclude_both_private_and_static(self):
        """Test excluding both private and static methods."""
        analyzer = JavaAnalyzer()
        source = """
        public class MyClass {
            public void publicInstance() {
            }
            public static void publicStatic() {
            }
            private void privateInstance() {
            }
            private static void privateStatic() {
            }
        }
        """
        codeflash_output = analyzer.find_methods(
            source, include_private=False, include_static=False
        ); result = codeflash_output # 97.1μs -> 91.6μs (6.10% faster)

    def test_method_with_multiline_signature(self):
        """Test method with signature spanning multiple lines."""
        analyzer = JavaAnalyzer()
        source = """
        public class MyClass {
            public void methodWithMultilineSignature(
                String param1,
                int param2,
                List<String> param3
            ) {
            }
        }
        """
        codeflash_output = analyzer.find_methods(source); result = codeflash_output # 65.8μs -> 63.1μs (4.24% faster)

    def test_method_with_annotations(self):
        """Test method with annotations."""
        analyzer = JavaAnalyzer()
        source = """
        public class MyClass {
            @Override
            @Deprecated
            public void annotatedMethod() {
            }
        }
        """
        codeflash_output = analyzer.find_methods(source); result = codeflash_output # 51.2μs -> 50.1μs (2.12% faster)

    def test_method_with_default_access_modifier(self):
        """Test method with default (package-private) access modifier."""
        analyzer = JavaAnalyzer()
        source = """
        public class MyClass {
            void packagePrivateMethod() {
            }
        }
        """
        codeflash_output = analyzer.find_methods(source); result = codeflash_output # 41.1μs -> 41.3μs (0.414% slower)

    def test_source_with_comments(self):
        """Test source code with comments."""
        analyzer = JavaAnalyzer()
        source = """
        public class MyClass {
            // This is a comment
            public void method1() {
                // Another comment
            }
            
            /* Block comment */
            public void method2() {
            }
        }
        """
        codeflash_output = analyzer.find_methods(source); result = codeflash_output # 67.1μs -> 64.3μs (4.33% faster)

    def test_source_with_string_literals_containing_method_keyword(self):
        """Test source code with method keyword in string literals."""
        analyzer = JavaAnalyzer()
        source = """
        public class MyClass {
            public void actualMethod() {
                String text = "this is a method definition";
                System.out.println(text);
            }
        }
        """
        codeflash_output = analyzer.find_methods(source); result = codeflash_output # 74.7μs -> 71.2μs (4.94% faster)

    def test_very_long_method_name(self):
        """Test method with very long name."""
        analyzer = JavaAnalyzer()
        long_name = "a" * 200
        source = f"""
        public class MyClass {{
            public void {long_name}() {{
            }}
        }}
        """
        codeflash_output = analyzer.find_methods(source); result = codeflash_output # 48.8μs -> 47.9μs (1.82% faster)

    def test_method_returning_primitive_array(self):
        """Test method returning primitive array type."""
        analyzer = JavaAnalyzer()
        source = """
        public class MyClass {
            public int[] getArray() {
                return new int[10];
            }
        }
        """
        codeflash_output = analyzer.find_methods(source); result = codeflash_output # 59.2μs -> 56.7μs (4.32% faster)

    def test_method_returning_generic_array(self):
        """Test method returning generic array type."""
        analyzer = JavaAnalyzer()
        source = """
        public class MyClass {
            public List<String>[] getGenericArray() {
                return new List[10];
            }
        }
        """
        codeflash_output = analyzer.find_methods(source); result = codeflash_output # 61.7μs -> 58.9μs (4.87% faster)

    def test_multiple_nested_classes(self):
        """Test deeply nested classes with methods."""
        analyzer = JavaAnalyzer()
        source = """
        public class Level1 {
            public void level1Method() {
            }
            
            public static class Level2 {
                public void level2Method() {
                }
                
                public static class Level3 {
                    public void level3Method() {
                    }
                }
            }
        }
        """
        codeflash_output = analyzer.find_methods(source); result = codeflash_output # 95.7μs -> 90.4μs (5.81% faster)
        names = [m.name for m in result]

    def test_interface_with_default_methods(self):
        """Test interface with default method implementations."""
        analyzer = JavaAnalyzer()
        source = """
        public interface MyInterface {
            void abstractMethod();
            
            default void defaultMethod() {
                System.out.println("default");
            }
        }
        """
        codeflash_output = analyzer.find_methods(source); result = codeflash_output # 79.9μs -> 77.2μs (3.41% faster)

    def test_method_with_varargs(self):
        """Test method with variable arguments."""
        analyzer = JavaAnalyzer()
        source = """
        public class MyClass {
            public void methodWithVarargs(String... args) {
            }
        }
        """
        codeflash_output = analyzer.find_methods(source); result = codeflash_output # 49.4μs -> 47.6μs (3.79% faster)

    def test_constructors_not_in_results(self):
        """Test that constructors are not included in find_methods results."""
        analyzer = JavaAnalyzer()
        source = """
        public class MyClass {
            public MyClass() {
                // Constructor
            }
            
            public void regularMethod() {
            }
        }
        """
        codeflash_output = analyzer.find_methods(source); result = codeflash_output # 55.7μs -> 54.0μs (3.06% faster)
        # Constructors should be in method_declaration nodes or separate
        # This tests the actual behavior
        method_names = [m.name for m in result]

    def test_method_returning_wildcard_generic(self):
        """Test method returning wildcard generic type."""
        analyzer = JavaAnalyzer()
        source = """
        public class MyClass {
            public List<?> getWildcard() {
                return null;
            }
        }
        """
        codeflash_output = analyzer.find_methods(source); result = codeflash_output # 52.6μs -> 51.0μs (3.12% faster)

    def test_final_method(self):
        """Test method with final modifier."""
        analyzer = JavaAnalyzer()
        source = """
        public class MyClass {
            public final void finalMethod() {
            }
        }
        """
        codeflash_output = analyzer.find_methods(source); result = codeflash_output # 44.7μs -> 43.7μs (2.39% faster)

    def test_native_method(self):
        """Test method with native modifier."""
        analyzer = JavaAnalyzer()
        source = """
        public class MyClass {
            public native void nativeMethod();
        }
        """
        codeflash_output = analyzer.find_methods(source); result = codeflash_output # 43.5μs -> 42.5μs (2.38% faster)

    def test_strict_floating_point_method(self):
        """Test method with strictfp modifier."""
        analyzer = JavaAnalyzer()
        source = """
        public class MyClass {
            public strictfp void floatMethod() {
            }
        }
        """
        codeflash_output = analyzer.find_methods(source); result = codeflash_output # 44.9μs -> 43.4μs (3.37% faster)

    # ============================================================================
    # LARGE SCALE TEST CASES
    # ============================================================================

    def test_many_methods_in_single_class(self):
        """Test performance with many methods in a single class."""
        analyzer = JavaAnalyzer()
        # Generate 100 methods
        methods = "\n            ".join(
            f"public void method{i}() {{}}"
            for i in range(100)
        )
        source = f"""
        public class LargeClass {{
            {methods}
        }}
        """
        codeflash_output = analyzer.find_methods(source); result = codeflash_output # 1.36ms -> 1.22ms (11.6% faster)
        # Verify method names are correctly extracted
        names = [m.name for m in result]

    def test_many_classes_with_methods(self):
        """Test performance with many classes, each with methods."""
        analyzer = JavaAnalyzer()
        classes = "\n        ".join(
            f"""public class Class{i} {{
            public void method{i}() {{}}
        }}"""
            for i in range(50)
        )
        source = f"""
        {classes}
        """
        codeflash_output = analyzer.find_methods(source); result = codeflash_output # 1.04ms -> 907μs (14.6% faster)
        # Verify class tracking
        for i in range(50):
            found = [m for m in result if m.class_name == f"Class{i}"]

    def test_methods_with_complex_return_types(self):
        """Test performance with methods having complex return types."""
        analyzer = JavaAnalyzer()
        methods = "\n            ".join(
            f"public Map<String, List<Set<Integer>>> method{i}() {{}}"
            for i in range(50)
        )
        source = f"""
        public class ComplexClass {{
            {methods}
        }}
        """
        codeflash_output = analyzer.find_methods(source); result = codeflash_output # 1.29ms -> 1.13ms (14.5% faster)

    def test_large_source_file_with_mixed_modifiers(self):
        """Test performance with large source file containing various method modifiers."""
        analyzer = JavaAnalyzer()
        # Create 100 methods with different combinations of modifiers
        modifiers = [
            "public",
            "private",
            "protected",
            "public static",
            "public synchronized",
            "private static",
            "protected abstract",
        ]
        methods_list = []
        for i in range(100):
            modifier = modifiers[i % len(modifiers)]
            methods_list.append(f"{modifier} void method{i}() {{}}")
        methods = "\n            ".join(methods_list)
        source = f"""
        public class LargeModifiedClass {{
            {methods}
        }}
        """
        codeflash_output = analyzer.find_methods(source); result = codeflash_output # 1.45ms -> 1.29ms (12.5% faster)

    def test_all_filters_on_large_dataset(self):
        """Test filtering behavior on large dataset."""
        analyzer = JavaAnalyzer()
        # Create 100 methods: 50 public, 50 private; 25 static each group
        methods_list = []
        for i in range(50):
            methods_list.append(f"public void publicMethod{i}() {{}}")
            methods_list.append(f"private void privateMethod{i}() {{}}")
            if i < 25:
                methods_list[i * 2] = f"public static void publicStaticMethod{i}() {{}}"
                methods_list[i * 2 + 1] = f"private static void privateStaticMethod{i}() {{}}"
        methods = "\n            ".join(methods_list[:100])
        source = f"""
        public class LargeFilteredClass {{
            {methods}
        }}
        """
        # Test with all filters
        codeflash_output = analyzer.find_methods(source); all_methods = codeflash_output # 1.46ms -> 1.31ms (11.7% faster)

        codeflash_output = analyzer.find_methods(source, include_private=False); no_private = codeflash_output # 1.46ms -> 1.31ms (11.1% faster)

        codeflash_output = analyzer.find_methods(source, include_static=False); no_static = codeflash_output # 1.46ms -> 1.31ms (11.3% faster)

        codeflash_output = analyzer.find_methods(
            source, include_private=False, include_static=False
        ); no_private_no_static = codeflash_output # 1.49ms -> 1.33ms (12.2% faster)

    def test_deeply_nested_structure_scalability(self):
        """Test performance with deeply nested class structures."""
        analyzer = JavaAnalyzer()
        # Create nested classes structure
        nested = ""
        for i in range(10):
            nested += f"""
        public class Nested{i} {{
            public void method{i}() {{}}
            """
        nested += "}" * 10
        source = f"""
        public class Root {{
            public void rootMethod() {{}}
            {nested}
        }}
        """
        codeflash_output = analyzer.find_methods(source); result = codeflash_output # 254μs -> 233μs (8.85% faster)

    def test_return_type_extraction_on_many_methods(self):
        """Test return type extraction consistency across many methods."""
        analyzer = JavaAnalyzer()
        return_types = [
            "void",
            "String",
            "int",
            "List<String>",
            "Map<String, Integer>",
            "Optional<T>",
            "Stream<List<String>>",
        ]
        methods_list = []
        for i, ret_type in enumerate(return_types * 10):  # 70 methods
            methods_list.append(f"public {ret_type} method{i}() {{}}")
        methods = "\n            ".join(methods_list)
        source = f"""
        public class ManyReturnTypesClass {{
            {methods}
        }}
        """
        codeflash_output = analyzer.find_methods(source); result = codeflash_output # 1.17ms -> 1.05ms (12.1% faster)
        # Verify return types are preserved
        for method in result:
            pass

    def test_line_number_consistency_on_large_file(self):
        """Test that line numbers are correctly tracked in large files."""
        analyzer = JavaAnalyzer()
        methods_list = [f"public void method{i}() {{}}" for i in range(100)]
        methods = "\n            ".join(methods_list)
        source = f"""
        public class LargeLineNumberClass {{
            {methods}
        }}
        """
        codeflash_output = analyzer.find_methods(source); result = codeflash_output # 1.35ms -> 1.21ms (11.9% faster)
        # Verify all have valid line numbers
        for method in result:
            pass

    def test_class_name_tracking_many_classes(self):
        """Test class name tracking across many classes."""
        analyzer = JavaAnalyzer()
        classes = "\n        ".join(
            f"""public class ClassName{i} {{
            public void methodA{i}() {{}}
            public void methodB{i}() {{}}
        }}"""
            for i in range(50)
        )
        source = f"""
        {classes}
        """
        codeflash_output = analyzer.find_methods(source); result = codeflash_output # 1.69ms -> 1.50ms (13.0% faster)
        # Verify correct class association
        class_to_methods = {}
        for method in result:
            if method.class_name not in class_to_methods:
                class_to_methods[method.class_name] = []
            class_to_methods[method.class_name].append(method.name)
        for i in range(50):
            pass

    def test_mixed_interfaces_and_classes_scalability(self):
        """Test finding methods in large file with both interfaces and classes."""
        analyzer = JavaAnalyzer()
        components = ""
        for i in range(25):
            components += f"""
        public interface Interface{i} {{
            void method{i}();
        }}
        
        public class Implementation{i} {{
            public void method{i}() {{}}
        }}
        """
        source = components
        codeflash_output = analyzer.find_methods(source); result = codeflash_output # 1.00ms -> 884μs (13.2% faster)

    def test_filter_performance_on_large_dataset(self):
        """Test filter performance remains consistent on large dataset."""
        analyzer = JavaAnalyzer()
        # Create 200 methods with various modifiers
        methods_list = []
        for i in range(200):
            if i % 2 == 0:
                methods_list.append(f"public void publicMethod{i}() {{}}")
            else:
                methods_list.append(f"private void privateMethod{i}() {{}}")
        methods = "\n            ".join(methods_list)
        source = f"""
        public class FilterPerformanceClass {{
            {methods}
        }}
        """
        # All methods
        codeflash_output = analyzer.find_methods(source); all_result = codeflash_output # 2.74ms -> 2.45ms (11.8% faster)

        # Filtered for public only
        codeflash_output = analyzer.find_methods(source, include_private=False); public_only = codeflash_output # 2.85ms -> 2.56ms (11.3% faster)
        for method in public_only:
            pass
# 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-pr1199-2026-02-03T10.01.07 and push.

Codeflash Static Badge

The optimized code achieves an **11% runtime improvement** (24.5ms → 22.0ms) by eliminating recursive function call overhead through two key optimizations:

## Primary Optimization: Iterative Tree Traversal

The core improvement replaces recursive calls to `_walk_tree_for_methods` with an explicit stack-based iteration. In Python, each recursive call incurs significant overhead from:
- Stack frame creation and teardown
- Parameter passing (6 parameters per call)
- Return address management

The profiler data confirms this: the original code spent 24.5% of time in recursive call setup (lines 39338 hits at 816.7ns per hit), while the optimized version eliminates this entirely by using a stack data structure.

The iterative approach processes nodes in the same depth-first, left-to-right order (by reversing children before pushing to stack) but replaces ~19,726 recursive function calls with simple stack operations. This is particularly effective for Java code analysis where the AST can have deep nesting (nested classes, methods, etc.).

## Secondary Optimization: Type Declaration Tuple Caching

Moving `type_declarations = ("class_declaration", "interface_declaration", "enum_declaration")` from a local variable allocated on every call (19,726 times) to a single instance attribute `self._type_declarations` eliminates 19,726 tuple allocations. The profiler shows this saved 3.3% of execution time in the original version.

## Performance Characteristics

The optimization excels on test cases with:
- **Many methods** (100+ methods): 11.6-14.6% speedup as recursive overhead compounds
- **Deep nesting** (nested classes): 8.85% speedup by avoiding deep call stacks  
- **Large files with filtering**: 11-12% speedup as the stack approach handles conditional logic efficiently
- **Mixed interfaces/classes**: 13.2% speedup due to reduced overhead when tracking type context

The optimization maintains identical correctness across all test cases, preserving method discovery, filtering behavior, line numbers, class tracking, and return types.
@codeflash-ai codeflash-ai bot added ⚡️ codeflash Optimization PR opened by Codeflash AI 🎯 Quality: High Optimization Quality according to Codeflash labels Feb 3, 2026
@codeflash-ai codeflash-ai bot mentioned this pull request Feb 3, 2026
@KRRT7
Copy link
Collaborator

KRRT7 commented Feb 19, 2026

Closing stale bot PR.

@KRRT7 KRRT7 closed this Feb 19, 2026
@KRRT7 KRRT7 deleted the codeflash/optimize-pr1199-2026-02-03T10.01.07 branch February 19, 2026 13:02
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.

1 participant