update graph

This commit is contained in:
2025-11-15 23:48:16 +00:00
parent dffe175059
commit 76bab8abc2
2 changed files with 172 additions and 133 deletions
+79 -2
View File
@@ -41,9 +41,37 @@ class LocalGraph:
self.add_edge(src, target, "imports")
def _add_call_edges(self, src: str, calls: list[str], file_path: str):
"""Enhanced call edges that work cross-file by searching the entire graph."""
for cal in calls:
target = f"rust::function::{file_path}::{cal}"
self.add_edge(src, target, "calls")
if not cal or not isinstance(cal, str):
continue
# Try to find the called function in the graph
target_found = False
# Search for functions with this name across ALL files
for node_id, data in self.graph.nodes(data=True):
if (data.get('type') in ['function', 'method', 'async_function', 'constructor'] and
data.get('name') == cal):
# Found a matching function - create call edge
self.add_edge(src, node_id, "calls")
target_found = True
# Don't break - a function might be called from multiple places
# If not found, create a symbolic node for the call target
if not target_found:
# Create a canonical function node (file-less) for cross-file references
symbolic_id = f"rust::function::{cal}" # Assuming Rust for now
if symbolic_id not in self.graph.nodes:
self.add_node(
symbolic_id,
type="function",
name=cal,
file="", # No specific file
lang="rust",
is_symbolic=True
)
self.add_edge(src, symbolic_id, "calls")
@@ -284,3 +312,52 @@ class LocalGraph:
entities.append(f"{entity_type}:{entity_name}")
return entities
def find_nodes_by_attributes(self, **filters):
"""Find nodes by attributes (not just exact matches)."""
for node_id, data in self.graph.nodes(data=True):
if all(data.get(k) == v for k, v in filters.items()):
yield node_id, data
def get_node_by_name_and_file(self, name: str, file_path: str, node_type: str = None, lang: str = None):
"""Find a node by name and file path with optional type/language filtering."""
candidates = []
for node_id, data in self.graph.nodes(data=True):
if (data.get('name') == name and
data.get('file') == file_path and
(node_type is None or data.get('type') == node_type) and
(lang is None or data.get('lang') == lang)):
candidates.append((node_id, data))
return candidates
def get_cross_file_relationships(self, node_id: str, current_file: str):
"""Get relationships that cross file boundaries."""
if node_id not in self.graph.nodes:
return [], []
cross_file_out = []
cross_file_in = []
# Outgoing cross-file relationships
for neighbor_id in self.graph.successors(node_id):
if neighbor_id in self.graph.nodes:
neighbor_file = self.graph.nodes[neighbor_id].get('file', '')
if neighbor_file and neighbor_file != current_file:
edge_data = self.graph.edges[node_id, neighbor_id]
rel_type = edge_data.get('type', 'related')
neighbor_name = self.graph.nodes[neighbor_id].get('name', '')
neighbor_type = self.graph.nodes[neighbor_id].get('type', '')
cross_file_out.append(f"{rel_type}:{neighbor_type}:{neighbor_name}@{neighbor_file}")
# Incoming cross-file relationships
for predecessor_id in self.graph.predecessors(node_id):
if predecessor_id in self.graph.nodes:
pred_file = self.graph.nodes[predecessor_id].get('file', '')
if pred_file and pred_file != current_file:
edge_data = self.graph.edges[predecessor_id, node_id]
rel_type = edge_data.get('type', 'related')
pred_name = self.graph.nodes[predecessor_id].get('name', '')
pred_type = self.graph.nodes[predecessor_id].get('type', '')
cross_file_in.append(f"{rel_type}:{pred_type}:{pred_name}@{pred_file}")
return cross_file_out, cross_file_in