1010using Microsoft . CodeAnalysis . CSharp . Syntax ;
1111using Microsoft . CodeAnalysis . Formatting ;
1212using Microsoft . CodeAnalysis . Operations ;
13+ using Microsoft . CodeAnalysis . Simplification ;
1314using Microsoft . CodeAnalysis . Text ;
1415
1516namespace IntelliTect . Analyzer . CodeFixes
@@ -86,11 +87,18 @@ public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context)
8687 return null ;
8788 }
8889
90+ // Task.Delay overloads that include a TimeProvider cannot be safely rewritten to
91+ // Task.CompletedTask/Task.FromCanceled without changing observable behavior.
92+ if ( invocation . Arguments . Any ( a => a . Parameter ? . Name == "timeProvider" ) )
93+ {
94+ return null ;
95+ }
96+
8997 IArgumentOperation ? cancellationTokenArgument = invocation . Arguments
9098 . FirstOrDefault ( a => a . Parameter ? . Name == "cancellationToken" ) ;
9199 if ( cancellationTokenArgument is null )
92100 {
93- return SyntaxFactory . ParseExpression ( "global::System.Threading.Tasks.Task.CompletedTask" ) ;
101+ return CreateTaskCompletedTaskExpression ( ) ;
94102 }
95103
96104 if ( cancellationTokenArgument . Value . Syntax is not ExpressionSyntax cancellationTokenExpression )
@@ -104,13 +112,40 @@ public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context)
104112 }
105113
106114 string tokenExpressionText = NormalizeCancellationTokenExpression ( cancellationTokenExpression ) ;
115+ ExpressionSyntax normalizedTokenExpression = SyntaxFactory . ParseExpression ( tokenExpressionText )
116+ . WithAdditionalAnnotations ( Simplifier . Annotation ) ;
107117
108118 // Runtime behavior reference:
109119 // https://github.com/dotnet/runtime/blob/1acc89c305165239a5a824567a3176b6b3342790/src/libraries/System.Private.CoreLib/src/System/Threading/Tasks/Task.cs#L5907-L5911
110120 // Task.Delay(0, token) maps to:
111121 // token.IsCancellationRequested ? Task.FromCanceled(token) : Task.CompletedTask
112- return SyntaxFactory . ParseExpression (
113- $ "({ tokenExpressionText } .IsCancellationRequested ? global::System.Threading.Tasks.Task.FromCanceled({ tokenExpressionText } ) : global::System.Threading.Tasks.Task.CompletedTask)") ;
122+ return SyntaxFactory . ConditionalExpression (
123+ SyntaxFactory . MemberAccessExpression (
124+ SyntaxKind . SimpleMemberAccessExpression ,
125+ normalizedTokenExpression ,
126+ SyntaxFactory . IdentifierName ( "IsCancellationRequested" ) ) ,
127+ CreateTaskFromCanceledExpression ( normalizedTokenExpression ) ,
128+ CreateTaskCompletedTaskExpression ( ) ) ;
129+ }
130+
131+ private static ExpressionSyntax CreateTaskCompletedTaskExpression ( )
132+ {
133+ return SyntaxFactory . MemberAccessExpression (
134+ SyntaxKind . SimpleMemberAccessExpression ,
135+ SyntaxFactory . ParseName ( "global::System.Threading.Tasks.Task" ) . WithAdditionalAnnotations ( Simplifier . Annotation ) ,
136+ SyntaxFactory . IdentifierName ( "CompletedTask" ) ) ;
137+ }
138+
139+ private static InvocationExpressionSyntax CreateTaskFromCanceledExpression ( ExpressionSyntax cancellationTokenExpression )
140+ {
141+ return SyntaxFactory . InvocationExpression (
142+ SyntaxFactory . MemberAccessExpression (
143+ SyntaxKind . SimpleMemberAccessExpression ,
144+ SyntaxFactory . ParseName ( "global::System.Threading.Tasks.Task" ) . WithAdditionalAnnotations ( Simplifier . Annotation ) ,
145+ SyntaxFactory . IdentifierName ( "FromCanceled" ) ) ,
146+ SyntaxFactory . ArgumentList (
147+ SyntaxFactory . SingletonSeparatedList (
148+ SyntaxFactory . Argument ( cancellationTokenExpression ) ) ) ) ;
114149 }
115150
116151 private static string NormalizeCancellationTokenExpression ( ExpressionSyntax cancellationTokenExpression )
@@ -154,7 +189,7 @@ private static async Task<Document> ReplaceInvocationAsync(
154189
155190 ExpressionSyntax replacementExpression = replacement
156191 . WithTriviaFrom ( invocation )
157- . WithAdditionalAnnotations ( Formatter . Annotation ) ;
192+ . WithAdditionalAnnotations ( Formatter . Annotation , Simplifier . Annotation ) ;
158193
159194 SyntaxNode newRoot = oldRoot . ReplaceNode ( invocation , replacementExpression ) ;
160195 return document . WithSyntaxRoot ( newRoot ) ;
0 commit comments