Skip to content

Commit 6ce7392

Browse files
committed
Honor symbol mappings in CLI MCP diffs
1 parent c1633ae commit 6ce7392

3 files changed

Lines changed: 33 additions & 9 deletions

File tree

‎objdiff-cli/src/cmd/mcp/diff.rs‎

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
//! These are UI-free and synchronous; the MCP server layer wraps them in
44
//! `spawn_blocking` and turns the results into tool responses.
55
6-
use std::{fmt::Write as _, path::Path};
6+
use std::{collections::BTreeMap, fmt::Write as _, path::Path};
77

88
use anyhow::{Context, Result};
99
use objdiff_core::{
@@ -16,14 +16,20 @@ use objdiff_core::{
1616
///
1717
/// `target` is the expected/baseline object (left); `base` is your current
1818
/// build (right).
19-
pub fn run_diff(target: &Path, base: &Path, config: &DiffObjConfig) -> Result<DiffResult> {
19+
pub fn run_diff(
20+
target: &Path,
21+
base: &Path,
22+
config: &DiffObjConfig,
23+
mappings: &BTreeMap<String, String>,
24+
) -> Result<DiffResult> {
2025
let target_obj = read::read(target, config, DiffSide::Target)
2126
.with_context(|| format!("Failed to read target object {}", target.display()))?;
2227
let base_obj = read::read(base, config, DiffSide::Base)
2328
.with_context(|| format!("Failed to read base object {}", base.display()))?;
24-
let result =
25-
diff_objs(Some(&target_obj), Some(&base_obj), None, config, &MappingConfig::default())
26-
.context("Failed to diff objects")?;
29+
let mapping_config =
30+
MappingConfig { mappings: mappings.clone(), selecting_left: None, selecting_right: None };
31+
let result = diff_objs(Some(&target_obj), Some(&base_obj), None, config, &mapping_config)
32+
.context("Failed to diff objects")?;
2733
DiffResult::new(
2834
result.left.as_ref().map(|d| (&target_obj, d)),
2935
result.right.as_ref().map(|d| (&base_obj, d)),
@@ -90,11 +96,21 @@ pub fn function_diff(diff: &DiffResult, symbol: &str) -> Result<String> {
9096
let right = diff.right.as_ref().context("No base object in diff result")?;
9197
let left = diff.left.as_ref();
9298

99+
// Look the symbol up by its base (current) name first; fall back to the
100+
// target-side name and follow its pairing back to the base symbol, so
101+
// mapped symbols (e.g. statics renamed between objects) resolve either way.
93102
let base_sym = right
94103
.symbols
95104
.iter()
96105
.find(|s| s.name == symbol)
97-
.with_context(|| format!("Symbol `{symbol}` not found in base (current) object"))?;
106+
.or_else(|| {
107+
left.and_then(|l| l.symbols.iter().find(|s| s.name == symbol))
108+
.and_then(|ls| ls.target_symbol)
109+
.and_then(|bi| right.symbols.get(bi as usize))
110+
})
111+
.with_context(|| {
112+
format!("Symbol `{symbol}` not found in base (current) or target object")
113+
})?;
98114

99115
let target_sym: Option<&DiffSymbol> = base_sym
100116
.target_symbol

‎objdiff-cli/src/cmd/mcp/server.rs‎

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,8 @@ impl ObjdiffServer {
165165
.map_err(err)?;
166166
let symbol = args.symbol;
167167
let out = tokio::task::spawn_blocking(move || -> anyhow::Result<String> {
168-
let result = diff::run_diff(&inputs.target, &inputs.base, &inputs.config)?;
168+
let result =
169+
diff::run_diff(&inputs.target, &inputs.base, &inputs.config, &inputs.mappings)?;
169170
diff::function_diff(&result, &symbol)
170171
})
171172
.await
@@ -192,7 +193,8 @@ impl ObjdiffServer {
192193
let only = args.only_mismatches;
193194
let limit = args.limit.unwrap_or(200);
194195
let out = tokio::task::spawn_blocking(move || -> anyhow::Result<String> {
195-
let result = diff::run_diff(&inputs.target, &inputs.base, &inputs.config)?;
196+
let result =
197+
diff::run_diff(&inputs.target, &inputs.base, &inputs.config, &inputs.mappings)?;
196198
Ok(diff::overview(&result, only, limit))
197199
})
198200
.await

‎objdiff-cli/src/cmd/mcp/state.rs‎

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ pub struct DiffInputs {
3232
pub target: PathBuf,
3333
pub base: PathBuf,
3434
pub config: DiffObjConfig,
35+
/// Manual symbol mappings (target name -> base name) from the unit config.
36+
pub mappings: BTreeMap<String, String>,
3537
}
3638

3739
impl AppState {
@@ -78,13 +80,17 @@ impl AppState {
7880
if let Some(project) = inner.project.as_ref() {
7981
project.apply_options(unit, &mut config)?;
8082
}
83+
let mappings = match (inner.project.as_ref(), unit) {
84+
(Some(project), Some(unit)) => project.symbol_mappings(unit)?,
85+
_ => BTreeMap::new(),
86+
};
8187
for (key, value) in overrides {
8288
let id = parse_property(key)?;
8389
config
8490
.set_property_value_str(id, value)
8591
.map_err(|_| anyhow!("Invalid value `{value}` for config property `{key}`"))?;
8692
}
87-
Ok(DiffInputs { target, base, config })
93+
Ok(DiffInputs { target, base, config, mappings })
8894
}
8995

9096
/// Add/remove/clear a unit's manual symbol mappings and persist them.

0 commit comments

Comments
 (0)