@@ -989,7 +989,7 @@ private static async Task<Solution> RenameCancellationTokenForInterfaceAndImplem
989989 IMethodSymbol interfaceMethod ,
990990 CancellationToken cancellationToken )
991991 {
992- // 1. Find CT parameter ordinal on the interface
992+ // 1. Find CT parameter index on the interface
993993 var ctIndex = - 1 ;
994994 for ( var i = 0 ; i < interfaceMethod . Parameters . Length ; i ++ )
995995 {
@@ -1006,9 +1006,14 @@ private static async Task<Solution> RenameCancellationTokenForInterfaceAndImplem
10061006 return solution ;
10071007 }
10081008
1009- // 2. Collect interface + implementing methods
1010- var allMethods = ImmutableArray . CreateBuilder < IMethodSymbol > ( ) ;
1011- allMethods . Add ( interfaceMethod ) ;
1009+ // 2. Collect documentation IDs for the interface method and all implementations
1010+ var methodIds = new List < string > ( ) ;
1011+
1012+ var interfaceId = interfaceMethod . GetDocumentationCommentId ( ) ;
1013+ if ( ! string . IsNullOrEmpty ( interfaceId ) )
1014+ {
1015+ methodIds . Add ( interfaceId ! ) ;
1016+ }
10121017
10131018 var impls = await SymbolFinder . FindImplementationsAsync (
10141019 interfaceMethod ,
@@ -1019,92 +1024,73 @@ private static async Task<Solution> RenameCancellationTokenForInterfaceAndImplem
10191024
10201025 foreach ( var impl in impls . OfType < IMethodSymbol > ( ) )
10211026 {
1022- if ( impl . DeclaringSyntaxReferences . Length > 0 )
1027+ if ( impl . DeclaringSyntaxReferences . Length == 0 )
10231028 {
1024- allMethods . Add ( impl ) ;
1029+ continue ; // skip metadata-only
10251030 }
1026- }
10271031
1028- // 3. Group by document
1029- var methodsByDocument = new Dictionary < DocumentId , ImmutableArray < MethodDeclarationSyntax > . Builder > ( ) ;
1032+ var id = impl . GetDocumentationCommentId ( ) ;
1033+ if ( ! string . IsNullOrEmpty ( id ) )
1034+ {
1035+ methodIds . Add ( id ! ) ;
1036+ }
1037+ }
10301038
1031- foreach ( var method in allMethods )
1039+ // 3. Resolve each method symbol in the current solution and rename its CT param
1040+ foreach ( var methodId in methodIds )
10321041 {
1033- foreach ( var syntaxRef in method . DeclaringSyntaxReferences )
1042+ IMethodSymbol ? methodSymbol = null ;
1043+
1044+ foreach ( var project in solution . Projects )
10341045 {
1035- var syntax = await syntaxRef . GetSyntaxAsync ( cancellationToken )
1036- . ConfigureAwait ( false ) ;
1037- if ( syntax is not MethodDeclarationSyntax methodDecl )
1046+ var compilation = await project . GetCompilationAsync ( cancellationToken )
1047+ . ConfigureAwait ( false ) ;
1048+ if ( compilation is null )
10381049 {
10391050 continue ;
10401051 }
10411052
1042- var doc = solution . GetDocument ( methodDecl . SyntaxTree ) ;
1043- if ( doc is null )
1044- {
1045- continue ;
1046- }
1053+ var symbol = DocumentationCommentId . GetFirstSymbolForDeclarationId ( methodId , compilation )
1054+ as IMethodSymbol ;
10471055
1048- var docId = doc . Id ;
1049- if ( ! methodsByDocument . TryGetValue ( docId , out var list ) )
1056+ if ( symbol is null )
10501057 {
1051- list = ImmutableArray . CreateBuilder < MethodDeclarationSyntax > ( ) ;
1052- methodsByDocument [ docId ] = list ;
1058+ continue ;
10531059 }
10541060
1055- list . Add ( methodDecl ) ;
1061+ methodSymbol = symbol ;
1062+ break ;
10561063 }
1057- }
1058-
1059- // 4. Rewrite name in each method declaration at the same ordinal
1060- foreach ( var kvp in methodsByDocument )
1061- {
1062- var docId = kvp . Key ;
1063- var methodDecls = kvp . Value . ToImmutable ( ) ;
10641064
1065- var document = solution . GetDocument ( docId ) ;
1066- if ( document is null )
1065+ if ( methodSymbol is null )
10671066 {
10681067 continue ;
10691068 }
10701069
1071- var root = await document . GetSyntaxRootAsync ( cancellationToken )
1072- . ConfigureAwait ( false ) ;
1073- if ( root is null )
1070+ if ( ctIndex >= methodSymbol . Parameters . Length )
10741071 {
1072+ // Signature drifted – be conservative.
10751073 continue ;
10761074 }
10771075
1078- var newRoot = root . ReplaceNodes (
1079- methodDecls ,
1080- ( original , _ ) =>
1081- {
1082- var parameters = original . ParameterList . Parameters ;
1083- if ( ctIndex < 0 || ctIndex >= parameters . Count )
1084- {
1085- // Signature drifted; be conservative.
1086- return original ;
1087- }
1088-
1089- var ctParamSyntax = parameters [ ctIndex ] ;
1090-
1091- // If it's already 'ct', no change needed.
1092- if ( ctParamSyntax . Identifier . Text == "ct" )
1093- {
1094- return original ;
1095- }
1096-
1097- var newCtParamSyntax = ctParamSyntax . WithIdentifier (
1098- SyntaxFactory . Identifier ( "ct" )
1099- . WithTriviaFrom ( ctParamSyntax . Identifier ) ) ;
1100-
1101- var newParameters = parameters . Replace ( ctParamSyntax , newCtParamSyntax ) ;
1076+ var p = methodSymbol . Parameters [ ctIndex ] ;
1077+ if ( ! IsCancellationToken ( p . Type ) )
1078+ {
1079+ continue ;
1080+ }
11021081
1103- return original . WithParameterList (
1104- original . ParameterList . WithParameters ( newParameters ) ) ;
1105- } ) ;
1082+ if ( string . Equals ( p . Name , "ct" , StringComparison . Ordinal ) )
1083+ {
1084+ continue ;
1085+ }
11061086
1107- solution = solution . WithDocumentSyntaxRoot ( docId , newRoot ) ;
1087+ solution = await Renamer . RenameSymbolAsync (
1088+ solution ,
1089+ p ,
1090+ new SymbolRenameOptions ( ) ,
1091+ "ct" ,
1092+ cancellationToken )
1093+ . ConfigureAwait ( false ) ;
11081094 }
11091095
11101096 return solution ;
0 commit comments