Skip to content

Commit 8096f76

Browse files
committed
fix analyze order
1 parent dcca02f commit 8096f76

File tree

1 file changed

+78
-36
lines changed

1 file changed

+78
-36
lines changed

crates/emmylua_code_analysis/src/db_index/dependency/file_dependency_relation.rs

Lines changed: 78 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -12,61 +12,59 @@ impl<'a> FileDependencyRelation<'a> {
1212
}
1313

1414
pub fn get_best_analysis_order(&self, file_ids: Vec<FileId>) -> Vec<FileId> {
15-
if self.dependencies.is_empty() {
15+
let n = file_ids.len();
16+
if n == 0 || self.dependencies.is_empty() {
1617
return file_ids;
1718
}
1819

19-
let file_set: HashSet<_> = file_ids.iter().copied().collect();
20+
let file_to_idx: HashMap<FileId, usize> = file_ids
21+
.iter()
22+
.enumerate()
23+
.map(|(i, &f)| (f, i))
24+
.collect();
2025

21-
let mut in_degree: HashMap<FileId, usize> = HashMap::new();
22-
let mut adjacency: HashMap<FileId, Vec<FileId>> = HashMap::new();
26+
let mut in_degree = vec![0usize; n];
27+
let mut adjacency: Vec<Vec<usize>> = vec![Vec::new(); n];
2328

24-
for file_id in &file_ids {
25-
if let Some(deps) = self.dependencies.get(file_id) {
26-
adjacency.entry(*file_id).or_default();
29+
for (idx, &file_id) in file_ids.iter().enumerate() {
30+
if let Some(deps) = self.dependencies.get(&file_id) {
2731
for &dep in deps {
28-
if file_set.contains(&dep) {
29-
adjacency.entry(dep).or_default().push(*file_id);
30-
*in_degree.entry(*file_id).or_default() += 1;
32+
if let Some(&dep_idx) = file_to_idx.get(&dep) {
33+
adjacency[dep_idx].push(idx);
34+
in_degree[idx] += 1;
3135
}
3236
}
33-
} else {
34-
adjacency.entry(*file_id).or_default();
35-
in_degree.entry(*file_id).or_default();
3637
}
3738
}
39+
let mut result = Vec::with_capacity(n);
40+
let mut queue = VecDeque::with_capacity(n);
3841

39-
let mut queue = VecDeque::new();
40-
let mut sorted_keys: Vec<_> = adjacency.keys().copied().collect();
41-
sorted_keys.sort();
42-
for &file in &sorted_keys {
43-
if *in_degree.get(&file).unwrap_or(&0) == 0 {
44-
queue.push_back(file);
45-
}
42+
let mut zero_in_degree: Vec<usize> = (0..n).filter(|&i| in_degree[i] == 0).collect();
43+
zero_in_degree.sort_by_key(|&i| file_ids[i]);
44+
45+
for idx in zero_in_degree {
46+
queue.push_back(idx);
4647
}
4748

48-
let mut order = Vec::new();
49-
while let Some(node) = queue.pop_front() {
50-
order.push(node);
51-
if let Some(neighbors) = adjacency.get(&node) {
52-
for &n in neighbors {
53-
if let Some(x) = in_degree.get_mut(&n) {
54-
*x = x.saturating_sub(1);
55-
if *x == 0 {
56-
queue.push_back(n);
57-
}
58-
}
49+
while let Some(idx) = queue.pop_front() {
50+
result.push(file_ids[idx]);
51+
for &neighbor in &adjacency[idx] {
52+
in_degree[neighbor] -= 1;
53+
if in_degree[neighbor] == 0 {
54+
queue.push_back(neighbor);
5955
}
6056
}
6157
}
6258

63-
let processed: HashSet<_> = order.iter().copied().collect();
64-
for file in file_ids {
65-
if !processed.contains(&file) {
66-
order.push(file);
59+
if result.len() < n {
60+
for (idx, &deg) in in_degree.iter().enumerate() {
61+
if deg > 0 {
62+
result.push(file_ids[idx]);
63+
}
6764
}
6865
}
69-
order
66+
67+
result
7068
}
7169

7270
/// Get all direct and indirect dependencies for the file list
@@ -102,36 +100,80 @@ mod tests {
102100
#[test]
103101
fn test_best_analysis_order() {
104102
let mut map = HashMap::new();
103+
// 文件1依赖文件2
105104
map.insert(FileId::new(1), {
106105
let mut s = HashSet::new();
107106
s.insert(FileId::new(2));
108107
s
109108
});
109+
// 文件2没有依赖
110110
map.insert(FileId::new(2), HashSet::new());
111111
let rel = FileDependencyRelation::new(&map);
112112
let result = rel.get_best_analysis_order(vec![FileId::new(1), FileId::new(2)]);
113+
// 文件2没有依赖,应该在前;文件1依赖文件2,在后
113114
assert_eq!(result, vec![FileId::new(2), FileId::new(1)]);
114115
}
115116

116117
#[test]
117118
fn test_best_analysis_order2() {
118119
let mut map = HashMap::new();
120+
// 文件1依赖文件2和文件3
119121
map.insert(1.into(), {
120122
let mut s = HashSet::new();
121123
s.insert(2.into());
122124
s.insert(3.into());
123125
s
124126
});
127+
// 文件2依赖文件3
125128
map.insert(2.into(), {
126129
let mut s = HashSet::new();
127130
s.insert(3.into());
128131
s
129132
});
133+
// 文件3没有依赖
134+
map.insert(3.into(), HashSet::new());
130135
let rel = FileDependencyRelation::new(&map);
131136
let result = rel.get_best_analysis_order(vec![1.into(), 2.into(), 3.into()]);
137+
// 文件3没有依赖,应该在最前面;然后是2,最后是1
132138
assert_eq!(result, vec![3.into(), 2.into(), 1.into()]);
133139
}
134140

141+
#[test]
142+
fn test_no_deps_files_first() {
143+
let mut map = HashMap::new();
144+
// 文件1依赖文件2
145+
map.insert(FileId::new(1), {
146+
let mut s = HashSet::new();
147+
s.insert(FileId::new(2));
148+
s
149+
});
150+
// 文件2依赖文件1(循环依赖)
151+
map.insert(FileId::new(2), {
152+
let mut s = HashSet::new();
153+
s.insert(FileId::new(1));
154+
s
155+
});
156+
// 文件3没有依赖
157+
map.insert(FileId::new(3), HashSet::new());
158+
// 文件4没有依赖
159+
map.insert(FileId::new(4), HashSet::new());
160+
161+
let rel = FileDependencyRelation::new(&map);
162+
let result = rel.get_best_analysis_order(vec![
163+
FileId::new(1),
164+
FileId::new(2),
165+
FileId::new(3),
166+
FileId::new(4),
167+
]);
168+
169+
// 文件3和4没有依赖,应该在前面
170+
assert_eq!(result[0], FileId::new(3));
171+
assert_eq!(result[1], FileId::new(4));
172+
// 文件1和2有循环依赖,在后面
173+
assert!(result.contains(&FileId::new(1)));
174+
assert!(result.contains(&FileId::new(2)));
175+
}
176+
135177
#[test]
136178
fn test_collect_file_dependents() {
137179
let mut deps = HashMap::new();

0 commit comments

Comments
 (0)