import and call nodes fix

This commit is contained in:
2025-11-14 17:26:06 +00:00
parent c66118a457
commit 4b7aff9062
+52 -37
View File
@@ -1628,11 +1628,15 @@ def parse_rust_file_cached(filepath_str: str, file_hash: str) -> tuple:
except Exception as e: except Exception as e:
logger.warning(f"Rust AST helper failed for {filepath}: {e}; falling back to regex") logger.warning(f"Rust AST helper failed for {filepath}: {e}; falling back to regex")
# Fallback: Regex-based Rust parsing
logger.info(f" Falling back to regex parsing for {filepath}") # --- Import extraction --------------------------------------------
regex_chunks = _parse_rust_with_regex(filepath, code, lines) import_re = re.compile(r'^\s*use\s+([^;]+);', re.MULTILINE)
chunks.extend(regex_chunks)
logger.info(f" Regex found {len(regex_chunks)} chunks") # Fallback: Regex-based Rust parsing
logger.info(f" Falling back to regex parsing for {filepath}")
regex_chunks = _parse_rust_with_regex(filepath, code, lines, import_re)
chunks.extend(regex_chunks)
logger.info(f" Regex found {len(regex_chunks)} chunks")
except Exception as e: except Exception as e:
logger.warning(f"parse_rust_file failed {filepath}: {e}") logger.warning(f"parse_rust_file failed {filepath}: {e}")
@@ -1641,13 +1645,13 @@ def parse_rust_file_cached(filepath_str: str, file_hash: str) -> tuple:
logger.info(f"📦 Final result: {len(final_result)} chunks with metadata") logger.info(f"📦 Final result: {len(final_result)} chunks with metadata")
return final_result return final_result
def _parse_rust_with_regex(filepath: Path, code: str, lines: list) -> list: def _parse_rust_with_regex(filepath: Path, code: str, lines: list, import_re) -> list:
"""Fallback regex-based Rust parser.""" """Fallback regex-based Rust parser."""
chunks = [] chunks = []
# Pattern for Rust functions (including async, unsafe, methods) # Pattern for Rust functions (including async, unsafe, methods)
func_pattern = re.compile( func_pattern = re.compile(
r'^(?:pub\s+)?(?:async\s+)?(?:unsafe\s+)?fn\s+(\w+)\s*[<(]', r'^(?:pub\\s+)?(?:async\\s+)?(?:unsafe\\s+)?fn\\s+(\\w+)\\s*[\u003c(]',
re.MULTILINE re.MULTILINE
) )
@@ -1683,15 +1687,20 @@ def _parse_rust_with_regex(filepath: Path, code: str, lines: list) -> list:
# Parse functions # Parse functions
for match in func_pattern.finditer(code): for match in func_pattern.finditer(code):
func_name = match.group(1)
start_pos = match.start() start_pos = match.start()
start_line = code[:start_pos].count('\n') start_line = code[:start_pos].count('\\n')
end_line = _find_rust_brace_block_end(lines, start_line) end_line = _find_rust_brace_block_end(lines, start_line)
func_code = "".join(lines[start_line:end_line + 1]) func_code = "".join(lines[start_line:end_line + 1])
# Enhanced function analysis # Extract function name
is_async = 'async' in match.group(0) func_name = match.group(1)
is_unsafe = 'unsafe' in match.group(0)
# Extract visibility (pub or private)
visibility = "pub" if "pub" in func_code else "private"
# Detect async/unsafe
is_async = "async" in func_code
is_unsafe = "unsafe" in func_code
is_pub = 'pub' in match.group(0) is_pub = 'pub' in match.group(0)
chunk_text = f"File: {filepath}\nType: function\nName: {func_name}\n" chunk_text = f"File: {filepath}\nType: function\nName: {func_name}\n"
@@ -2263,8 +2272,17 @@ def build_indexes():
graph.add_edge(file_node_id, node_id, "contains") graph.add_edge(file_node_id, node_id, "contains")
# ---------- IMPORTS ---------- # ---------- IMPORTS ----------
for imp in m.get("imports", []): # The imports metadata might be a list or a comma-separated string
# Find an existing module node with this name. # We need to handle both cases
imports_raw = m.get("imports", [])
if isinstance(imports_raw, str):
# Split the string back into a list
imports = [imp.strip() for imp in imports_raw.split(",") if imp.strip()]
else:
imports = imports_raw
for imp in imports:
# Try to find an existing node for this import
candidate_id = None candidate_id = None
for node_id, data in created_nodes.items(): for node_id, data in created_nodes.items():
if data.get("type") in {"module", "import"} and data.get("name") == imp: if data.get("type") in {"module", "import"} and data.get("name") == imp:
@@ -2272,14 +2290,10 @@ def build_indexes():
break break
if not candidate_id: if not candidate_id:
# If nothing exists, fall back to a generic import node. # No existing node found - create a placeholder
candidate_id = f"import::{imp}" candidate_id = f"import::{imp}"
# ---- Import node --------------------------------------------
# For imports we want a node that mirrors the target module if
# it exists; otherwise we still create a stub with language &
# file attributes for consistency.
if candidate_id not in graph.graph.nodes: if candidate_id not in graph.graph.nodes:
# First try to find a module node with that name # Double-check for a module node with this name
found = False found = False
for n_id, n_data in created_nodes.items(): for n_id, n_data in created_nodes.items():
if n_data.get("name") == imp and n_data.get("type") == "module": if n_data.get("name") == imp and n_data.get("type") == "module":
@@ -2287,8 +2301,7 @@ def build_indexes():
found = True found = True
break break
if not found: if not found:
# Generic import stub # Create a generic import node
candidate_id = f"import::{imp}"
graph.add_node( graph.add_node(
candidate_id, candidate_id,
type="Import", type="Import",
@@ -2296,13 +2309,20 @@ def build_indexes():
lang="unknown", lang="unknown",
file="", file="",
) )
graph.add_edge(file_node_id, candidate_id, "imports") graph.add_edge(file_node_id, candidate_id, "imports")
# Create the connection
graph.add_edge(file_node_id, candidate_id, "imports") graph.add_edge(file_node_id, candidate_id, "imports")
# ---------- FUNCTION CALLS ---------- # ---------- FUNCTION CALLS ----------
for call in m.get("calls", []): calls_raw = m.get("calls", [])
# Try to find a function/method node with this name. if isinstance(calls_raw, str):
# Split the string back into a list
calls = [c.strip() for c in calls_raw.split(",") if c.strip()]
else:
calls = calls_raw
for call in calls:
# Try to find the function/method being called
target_id = None target_id = None
for node_id, data in created_nodes.items(): for node_id, data in created_nodes.items():
if data.get("type") in {"function", "method", "constructor"} and data.get("name") == call: if data.get("type") in {"function", "method", "constructor"} and data.get("name") == call:
@@ -2310,14 +2330,10 @@ def build_indexes():
break break
if not target_id: if not target_id:
# Fallback to a generic call node. # No existing function found - create a placeholder
target_id = f"call::{call}" target_id = f"call::{call}"
# ---- Call node ---------------------------------------------
# If we already know the target node (by name), reuse it. Otherwise
# create a generic node that still carries language & file context
# so it can be displayed or filtered later.
if target_id not in graph.graph.nodes: if target_id not in graph.graph.nodes:
# Attempt a besteffort lookup for the actual function node # Double-check for a matching function
found = False found = False
for n_id, n_data in created_nodes.items(): for n_id, n_data in created_nodes.items():
if ( if (
@@ -2328,8 +2344,7 @@ def build_indexes():
found = True found = True
break break
if not found: if not found:
# Fallback to a generic FunctionCall node # Create a generic function call node
target_id = f"call::{call}"
graph.add_node( graph.add_node(
target_id, target_id,
type="FunctionCall", type="FunctionCall",
@@ -2337,8 +2352,8 @@ def build_indexes():
lang="unknown", lang="unknown",
file="", file="",
) )
graph.add_edge(node_id, target_id, "calls") graph.add_edge(node_id, target_id, "calls")
# Create the connection
graph.add_edge(node_id, target_id, "calls") graph.add_edge(node_id, target_id, "calls")
@@ -2517,7 +2532,7 @@ def _connect_impl_relationships(graph, node_id, node_data):
def build_bevy_relationships(graph, created_nodes): def build_bevy_relationships(graph, created_nodes):
"""Build Bevy-specific relationships""" """Build Bevy-specific relationships"""
connections = 0 # Extract return type = 0
# Find all plugin structs and impls # Find all plugin structs and impls
plugin_structs = {} plugin_structs = {}