@@ -756,16 +756,30 @@ function buildObjectRestParamPostPass(
756756 symbols . typeMap instanceof Map ? symbols . typeMap : [ ] ,
757757 ) ;
758758
759- // Seed typeMap[restName] = { type: argName } for each matching pair.
760- // Mirrors the seeding in buildCallEdgesJS Phase 8.3f.
759+ // Seed typeMap[callee::restName] = { type: argName } for each matching pair.
760+ // Mirrors the seeding in buildCallEdgesJS Phase 8.3f. Keys are scoped by
761+ // callee so two functions with the same rest-param name (e.g. `...rest`) in
762+ // the same file don't collide (#1358).
763+ // When only one callee uses a given rest name, also seed the unscoped key
764+ // as a null-callerName fallback so edges aren't silently dropped if
765+ // findCaller can't identify the enclosing function (#1358).
766+ const restNameCallees = new Map < string , Set < string > > ( ) ;
767+ for ( const orpb of symbols . objectRestParamBindings ! ) {
768+ if ( ! restNameCallees . has ( orpb . restName ) ) restNameCallees . set ( orpb . restName , new Set ( ) ) ;
769+ restNameCallees . get ( orpb . restName ) ! . add ( orpb . callee ) ;
770+ }
761771 const restNames = new Set < string > ( ) ;
762772 for ( const orpb of symbols . objectRestParamBindings ! ) {
763773 for ( const pb of symbols . paramBindings ! ) {
764774 if ( pb . callee === orpb . callee && pb . argIndex === orpb . argIndex ) {
765- if ( ! typeMap . has ( orpb . restName ) ) {
766- typeMap . set ( orpb . restName , { type : pb . argName , confidence : 0.65 } ) ;
767- restNames . add ( orpb . restName ) ;
775+ const scopedKey = `${ orpb . callee } ::${ orpb . restName } ` ;
776+ if ( ! typeMap . has ( scopedKey ) ) {
777+ typeMap . set ( scopedKey , { type : pb . argName , confidence : 0.65 } ) ;
778+ if ( restNameCallees . get ( orpb . restName ) ! . size === 1 && ! typeMap . has ( orpb . restName ) ) {
779+ typeMap . set ( orpb . restName , { type : pb . argName , confidence : 0.65 } ) ;
780+ }
768781 }
782+ restNames . add ( orpb . restName ) ;
769783 }
770784 }
771785 }
@@ -777,14 +791,16 @@ function buildObjectRestParamPostPass(
777791
778792 const caller = findCaller ( lookup , call , symbols . definitions , relPath , fileNodeRow ) ;
779793
780- // Resolve with the enriched typeMap (typeMap[restName] = { type: argName } is seeded above).
794+ // Resolve with the enriched typeMap. callerName is passed so
795+ // resolveByMethodOrGlobal can look up the scoped key callee::restName (#1358).
781796 // seenByPair deduplicates edges the native engine already emitted.
782797 const { targets, importedFrom } = resolveCallTargets (
783798 lookup ,
784799 call ,
785800 relPath ,
786801 importedNames ,
787802 typeMap as Map < string , unknown > ,
803+ caller . callerName ,
788804 ) ;
789805 for ( const t of targets ) {
790806 const edgeKey = `${ caller . id } |${ t . id } ` ;
@@ -1019,16 +1035,26 @@ function buildCallEdgesJS(
10191035 symbols . typeMap instanceof Map ? symbols . typeMap : [ ] ,
10201036 ) ;
10211037
1022- // Phase 8.3f: seed typeMap[restName] = { type: argName } for each object-destructuring
1023- // rest parameter binding cross-referenced with call-site argument bindings.
1024- // e.g. function f({ a, ...rest }) called as f(obj) → typeMap['rest'] = { type: 'obj' }
1025- // so that `rest.method()` resolves via typeMap['obj.method'].
1038+ // Phase 8.3f: seed typeMap[callee::restName] = { type: argName } for each
1039+ // object-destructuring rest parameter binding × call-site argument binding.
1040+ // Keys are scoped so two functions with the same rest-param name in the same
1041+ // file don't collide (#1358). When only one callee uses a given rest name,
1042+ // also seed the unscoped key as a null-callerName fallback.
10261043 if ( symbols . objectRestParamBindings ?. length && symbols . paramBindings ?. length ) {
1044+ const restNameCallees = new Map < string , Set < string > > ( ) ;
1045+ for ( const orpb of symbols . objectRestParamBindings ) {
1046+ if ( ! restNameCallees . has ( orpb . restName ) ) restNameCallees . set ( orpb . restName , new Set ( ) ) ;
1047+ restNameCallees . get ( orpb . restName ) ! . add ( orpb . callee ) ;
1048+ }
10271049 for ( const orpb of symbols . objectRestParamBindings ) {
10281050 for ( const pb of symbols . paramBindings ) {
10291051 if ( pb . callee === orpb . callee && pb . argIndex === orpb . argIndex ) {
1030- if ( ! typeMap . has ( orpb . restName ) ) {
1031- typeMap . set ( orpb . restName , { type : pb . argName , confidence : 0.65 } ) ;
1052+ const scopedKey = `${ orpb . callee } ::${ orpb . restName } ` ;
1053+ if ( ! typeMap . has ( scopedKey ) ) {
1054+ typeMap . set ( scopedKey , { type : pb . argName , confidence : 0.65 } ) ;
1055+ if ( restNameCallees . get ( orpb . restName ) ! . size === 1 && ! typeMap . has ( orpb . restName ) ) {
1056+ typeMap . set ( orpb . restName , { type : pb . argName , confidence : 0.65 } ) ;
1057+ }
10321058 }
10331059 }
10341060 }
0 commit comments