1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
// Detection methods for CrossLanguageDependencies
// Included by cross_language_dependencies.rs — no `use` imports allowed
impl CrossLanguageDependencies {
/// Detect dependencies between nodes of two specific language groups
/// This function avoids borrowing self mutably while iterating
fn detect_between_language_groups(
&self,
node_ids1: &[String],
lang1: Language,
node_ids2: &[String],
lang2: Language,
) -> Vec<CrossLanguageDependency> {
let mut dependencies = Vec::new();
for id1 in node_ids1 {
let Some(source) = self.nodes.get(id1) else {
continue;
};
for reference in &source.references {
self.find_matching_targets(
source,
reference,
node_ids2,
lang1,
lang2,
&mut dependencies,
);
}
}
dependencies
}
/// Check each target node for a reference match and collect dependencies
fn find_matching_targets(
&self,
source: &UnifiedNode,
reference: &NodeReference,
node_ids2: &[String],
lang1: Language,
lang2: Language,
dependencies: &mut Vec<CrossLanguageDependency>,
) {
for id2 in node_ids2 {
let Some(target) = self.nodes.get(id2) else {
continue;
};
if self.is_reference_match(source, reference, target, lang1, lang2) {
dependencies.push(CrossLanguageDependency {
source_id: source.id.clone(),
target_id: target.id.clone(),
source_language: lang1,
target_language: lang2,
kind: reference.kind,
confidence: 1.0,
metadata: HashMap::new(),
});
}
}
}
/// Detect dependencies between nodes of two specific languages
#[allow(dead_code)]
fn detect_between_languages(
&mut self,
nodes1: &[&UnifiedNode],
lang1: Language,
nodes2: &[&UnifiedNode],
lang2: Language,
) {
// For each node in first language
for &source in nodes1 {
// For each reference in the node
for reference in &source.references {
// For each node in second language
for &target in nodes2 {
// Check if reference matches target
if self.is_reference_match(source, reference, target, lang1, lang2) {
self.add_dependency(source, target, reference.kind, 1.0);
}
}
}
}
}
/// Check if a reference from one node matches a target node
fn is_reference_match(
&self,
source: &UnifiedNode,
reference: &crate::ast::polyglot::unified_node::NodeReference,
target: &UnifiedNode,
source_lang: Language,
target_lang: Language,
) -> bool {
// Direct ID match
if !reference.target_id.is_empty() && reference.target_id == target.id {
return true;
}
// Name match
if reference.target_name == target.name || reference.target_name == target.fqn {
return true;
}
// Try to resolve using language-specific resolver
if let Some(resolver) = self.name_resolvers.get(&source_lang) {
if resolver.can_resolve(source_lang, target_lang, source, reference, target) {
return true;
}
}
false
}
/// Add a dependency between two nodes
#[allow(dead_code)]
fn add_dependency(
&mut self,
source: &UnifiedNode,
target: &UnifiedNode,
kind: ReferenceKind,
confidence: f64,
) {
let dependency = CrossLanguageDependency {
source_id: source.id.clone(),
target_id: target.id.clone(),
source_language: source.language,
target_language: target.language,
kind,
confidence,
metadata: HashMap::new(),
};
self.dependencies.push(dependency);
}
}