1111from typing import TYPE_CHECKING
1212
1313from codeflash .code_utils .code_utils import encoded_tokens_len
14- from codeflash .languages .base import CodeContext , HelperFunction , Language
14+ from codeflash .languages .base import CodeContext , HelperFunction
1515from codeflash .languages .java .discovery import discover_functions_from_source
1616from codeflash .languages .java .import_resolver import JavaImportResolver , find_helper_files
1717from codeflash .languages .java .parser import get_java_analyzer
18+ from codeflash .languages .language_enum import Language
1819
1920if TYPE_CHECKING :
2021 from pathlib import Path
2122
2223 from tree_sitter import Node
2324
2425 from codeflash .discovery .functions_to_optimize import FunctionToOptimize
25- from codeflash .languages .java .parser import JavaAnalyzer , JavaMethodNode
26+ from codeflash .languages .java .import_resolver import ResolvedImport
27+ from codeflash .languages .java .parser import JavaAnalyzer , JavaImportInfo , JavaMethodNode
2628
2729logger = logging .getLogger (__name__ )
2830
@@ -360,7 +362,7 @@ def _extract_type_declaration(type_node: Node, source_bytes: bytes, type_kind: s
360362
361363
362364# Keep old function name for backwards compatibility
363- def _extract_class_declaration (node , source_bytes ) :
365+ def _extract_class_declaration (node : Node , source_bytes : bytes ) -> str :
364366 return _extract_type_declaration (node , source_bytes , "class" )
365367
366368
@@ -629,6 +631,8 @@ def _extract_function_source_by_lines(source: str, function: FunctionToOptimize)
629631
630632 start_line = function .doc_start_line or function .starting_line
631633 end_line = function .ending_line
634+ if start_line is None or end_line is None :
635+ return ""
632636
633637 # Convert from 1-indexed to 0-indexed
634638 start_idx = start_line - 1
@@ -672,6 +676,8 @@ def find_helper_functions(
672676 func_id = f"{ file_path } :{ func .qualified_name } "
673677 if func_id not in visited_functions :
674678 visited_functions .add (func_id )
679+ if func .starting_line is None or func .ending_line is None :
680+ continue
675681
676682 # Extract the function source using tree-sitter for resilient lookup
677683 func_source = extract_function_source (source , func , analyzer = analyzer )
@@ -795,7 +801,7 @@ def extract_read_only_context(source: str, function: FunctionToOptimize, analyze
795801 return "\n " .join (context_parts )
796802
797803
798- def _import_to_statement (import_info ) -> str :
804+ def _import_to_statement (import_info : JavaImportInfo ) -> str :
799805 """Convert a JavaImportInfo to an import statement string.
800806
801807 Args:
@@ -863,6 +869,10 @@ def extract_class_context(file_path: Path, class_name: str, analyzer: JavaAnalyz
863869
864870# Maximum token budget for imported type skeletons to avoid bloating testgen context
865871IMPORTED_SKELETON_TOKEN_BUDGET = 4000
872+ # Maximum types to expand from a single wildcard import before filtering to referenced types only.
873+ # Packages with more types than this (e.g. org.jooq with 870+) would waste minutes of disk I/O
874+ # and almost always exceed the token budget.
875+ MAX_WILDCARD_TYPES_UNFILTERED = 50
866876
867877
868878def _extract_type_names_from_code (code : str , analyzer : JavaAnalyzer ) -> set [str ]:
@@ -894,7 +904,11 @@ def _extract_type_names_from_code(code: str, analyzer: JavaAnalyzer) -> set[str]
894904
895905
896906def get_java_imported_type_skeletons (
897- imports : list , project_root : Path , module_root : Path | None , analyzer : JavaAnalyzer , target_code : str = ""
907+ imports : list [JavaImportInfo ],
908+ project_root : Path ,
909+ module_root : Path | None ,
910+ analyzer : JavaAnalyzer ,
911+ target_code : str = "" ,
898912) -> str :
899913 """Extract type skeletons for project-internal imported types.
900914
@@ -929,14 +943,32 @@ def get_java_imported_type_skeletons(
929943 priority_types = _extract_type_names_from_code (target_code , analyzer )
930944
931945 # Pre-resolve all imports, expanding wildcards into individual types
932- resolved_imports : list = []
946+ resolved_imports : list [ ResolvedImport ] = []
933947 for imp in imports :
934948 if imp .is_wildcard :
935- # Expand wildcard imports (e.g., com.aerospike.client.policy.*) into individual types
936- expanded = resolver .expand_wildcard_import (imp .import_path )
949+ # First try unfiltered expansion with a cap. If the package is small enough, take all types.
950+ # If it's huge (e.g. org.jooq.* with 870+ types), filter to only types referenced in the target code.
951+ expanded = resolver .expand_wildcard_import (imp .import_path , max_types = MAX_WILDCARD_TYPES_UNFILTERED + 1 )
952+ if len (expanded ) > MAX_WILDCARD_TYPES_UNFILTERED :
953+ if priority_types :
954+ expanded = resolver .expand_wildcard_import (imp .import_path , filter_names = priority_types )
955+ logger .debug (
956+ "Wildcard %s.* exceeds %d types, filtered to %d referenced types" ,
957+ imp .import_path ,
958+ MAX_WILDCARD_TYPES_UNFILTERED ,
959+ len (expanded ),
960+ )
961+ else :
962+ expanded = expanded [:MAX_WILDCARD_TYPES_UNFILTERED ]
963+ logger .debug (
964+ "Wildcard %s.* exceeds %d types, capped (no target types to filter by)" ,
965+ imp .import_path ,
966+ MAX_WILDCARD_TYPES_UNFILTERED ,
967+ )
968+ elif expanded :
969+ logger .debug ("Expanded wildcard import %s.* into %d types" , imp .import_path , len (expanded ))
937970 if expanded :
938971 resolved_imports .extend (expanded )
939- logger .debug ("Expanded wildcard import %s.* into %d types" , imp .import_path , len (expanded ))
940972 continue
941973
942974 resolved = resolver .resolve_import (imp )
@@ -956,7 +988,7 @@ def get_java_imported_type_skeletons(
956988
957989 for resolved in resolved_imports :
958990 class_name = resolved .class_name
959- if not class_name :
991+ if not class_name or resolved . file_path is None :
960992 continue
961993
962994 dedup_key = (str (resolved .file_path ), class_name )
@@ -1078,8 +1110,6 @@ def _extract_public_method_signatures(source: str, class_name: str, analyzer: Ja
10781110 continue
10791111
10801112 node = method .node
1081- if not node :
1082- continue
10831113
10841114 # Check if the method is public
10851115 is_public = False
0 commit comments