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
88use anyhow:: { Context , Result } ;
99use 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
0 commit comments