Skip to content

Commit 1e31c97

Browse files
authored
perf: filter reverse-dep files from native build analysis scope (#782)
* perf: filter reverse-dep files from native build analysis scope (#761) The Rust build orchestrator included reverse-dep files in changedFiles, causing the JS analysis phase to run AST/complexity/CFG/dataflow on files whose content didn't change. Track reverse-dep relative paths and exclude them from analysis_scope, matching the JS pipeline's _reverseDepOnly filtering in run-analyses.ts. * docs: update BuildPipelineResult comments for analysis scope semantics (#782) Update the doc comment on `changed_files` to reflect that it now holds the analysis scope (reverse-dep files excluded) rather than the full parsed-file list. Add explanatory comment on role classification explaining why it intentionally uses the full file list including reverse-dep files.
1 parent 203d670 commit 1e31c97

1 file changed

Lines changed: 26 additions & 5 deletions

File tree

crates/codegraph-core/src/build_pipeline.rs

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,10 @@ pub struct BuildPipelineResult {
5757
pub edge_count: i64,
5858
pub file_count: usize,
5959
pub early_exit: bool,
60-
/// Files that were parsed/changed in this build cycle.
61-
/// `None` for full builds (all files), `Some` for incremental builds.
60+
/// Analysis scope: files whose content genuinely changed (reverse-dep-only
61+
/// files excluded). `None` for full builds (all files), `Some` for
62+
/// incremental builds. Consumers (e.g. the JS analysis phase) use this to
63+
/// scope expensive AST/complexity/CFG/dataflow work.
6264
#[serde(skip_serializing_if = "Option::is_none")]
6365
pub changed_files: Option<Vec<String>>,
6466
pub changed_count: usize,
@@ -205,8 +207,12 @@ pub fn run_pipeline(
205207
});
206208
}
207209

208-
// Track reverse-dep files that need re-parsing for edge reconstruction
210+
// Track reverse-dep files that need re-parsing for edge reconstruction.
211+
// Also track their relative paths so we can exclude them from analysis_scope —
212+
// reverse-dep files are re-parsed for edge rebuilding but their content didn't
213+
// change, so running AST/complexity/CFG/dataflow on them is wasted work (#761).
209214
let mut reverse_dep_abs_paths: Vec<String> = Vec::new();
215+
let mut reverse_dep_rel_paths: HashSet<String> = HashSet::new();
210216

211217
// Handle full build: clear all graph data
212218
if change_result.is_full_build {
@@ -243,6 +249,7 @@ pub fn run_pipeline(
243249
let abs = Path::new(root_dir).join(rdep);
244250
if abs.exists() {
245251
reverse_dep_abs_paths.push(abs.to_str().unwrap_or("").to_string());
252+
reverse_dep_rel_paths.insert(rdep.clone());
246253
}
247254
}
248255
}
@@ -347,11 +354,20 @@ pub fn run_pipeline(
347354
let t0 = Instant::now();
348355
let line_count_map = structure::build_line_count_map(&file_symbols, root_dir);
349356
let changed_files: Vec<String> = file_symbols.keys().cloned().collect();
350-
// Keep a copy for the result — changed_files is moved into roles classification below.
357+
// Build analysis_scope excluding reverse-dep files — they were re-parsed for
358+
// edge reconstruction but their content didn't change, so AST/complexity/CFG/
359+
// dataflow analysis would be redundant (#761). This matches the JS pipeline's
360+
// _reverseDepOnly filtering in run-analyses.ts.
351361
let analysis_scope: Option<Vec<String>> = if change_result.is_full_build {
352362
None
353363
} else {
354-
Some(changed_files.clone())
364+
Some(
365+
changed_files
366+
.iter()
367+
.filter(|f| !reverse_dep_rel_paths.contains(f.as_str()))
368+
.cloned()
369+
.collect(),
370+
)
355371
};
356372

357373
let existing_file_count = structure::get_existing_file_count(conn);
@@ -385,6 +401,11 @@ pub fn run_pipeline(
385401
timing.structure_ms = t0.elapsed().as_secs_f64() * 1000.0;
386402

387403
let t0 = Instant::now();
404+
// Role classification intentionally uses the full `changed_files` list
405+
// (including reverse-dep files), not `analysis_scope`. Reverse-dep files
406+
// had their edges rebuilt, which can change fan-in/fan-out and therefore
407+
// role assignments — so they must be re-classified even though their
408+
// content didn't change and they are excluded from AST analysis.
388409
let changed_file_list: Option<Vec<String>> = if change_result.is_full_build {
389410
None
390411
} else {

0 commit comments

Comments
 (0)