diff --git a/.editorconfig b/.editorconfig index ef6bdb6471..a46e3e379f 100644 --- a/.editorconfig +++ b/.editorconfig @@ -7,9 +7,6 @@ dotnet_sort_system_directives_first = true # VSTHRD002: Avoid problematic synchronous waits dotnet_diagnostic.VSTHRD002.severity = none -# VSTHRD200: Use "Async" suffix for async methods -dotnet_diagnostic.VSTHRD200.severity = none - [test/**/*.cs] # MSML_GeneralName: This name should be PascalCased @@ -25,3 +22,7 @@ dotnet_diagnostic.MSML_NoInstanceInitializers.severity = none # BaseTestClass does not apply for analyzer testing. # MSML_ExtendBaseTestClass: Test classes should be derived from BaseTestClass dotnet_diagnostic.MSML_ExtendBaseTestClass.severity = none + +# The MSML_RelaxTestNaming suppressor for VSTHRD200 is not active for CodeAnalyzer.Tests, so we disable it altogether. +# VSTHRD200: Use "Async" suffix for async methods +dotnet_diagnostic.VSTHRD200.severity = none diff --git a/src/Microsoft.Extensions.ML/ModelLoaders/UriModelLoader.cs b/src/Microsoft.Extensions.ML/ModelLoaders/UriModelLoader.cs index 487a8750be..fe84bdb0a7 100644 --- a/src/Microsoft.Extensions.ML/ModelLoaders/UriModelLoader.cs +++ b/src/Microsoft.Extensions.ML/ModelLoaders/UriModelLoader.cs @@ -46,7 +46,7 @@ internal void Start(Uri uri, TimeSpan period) { _timerPeriod = period; _uri = uri; - if (LoadModel().ConfigureAwait(false).GetAwaiter().GetResult()) + if (LoadModelAsync().ConfigureAwait(false).GetAwaiter().GetResult()) { StartReloadTimer(); } @@ -78,10 +78,10 @@ internal async Task RunAsync() cancellation.CancelAfter(TimeoutMilliseconds); Logger.UriReloadBegin(_logger, _uri); - var eTagMatches = await MatchEtag(_uri, _eTag); + var eTagMatches = await MatchEtagAsync(_uri, _eTag); if (!eTagMatches) { - await LoadModel(); + await LoadModelAsync(); var previousToken = Interlocked.Exchange(ref _reloadToken, new ModelReloadToken()); previousToken.OnReload(); } @@ -102,7 +102,7 @@ internal async Task RunAsync() } } - internal virtual async Task MatchEtag(Uri uri, string eTag) + internal virtual async Task MatchEtagAsync(Uri uri, string eTag) { using (var client = new HttpClient()) { @@ -133,7 +133,7 @@ internal void StopReloadTimer() } } - internal virtual async Task LoadModel() + internal virtual async Task LoadModelAsync() { //TODO: We probably need some sort of retry policy for this. try diff --git a/src/Microsoft.ML.Core/Utilities/ResourceManagerUtils.cs b/src/Microsoft.ML.Core/Utilities/ResourceManagerUtils.cs index f731b12e91..2c1f853431 100644 --- a/src/Microsoft.ML.Core/Utilities/ResourceManagerUtils.cs +++ b/src/Microsoft.ML.Core/Utilities/ResourceManagerUtils.cs @@ -98,7 +98,7 @@ public static string GetUrl(string suffix) /// An integer indicating the number of milliseconds to wait before timing out while downloading a resource. /// The download results, containing the file path where the resources was (or should have been) downloaded to, and an error message /// (or null if there was no error). - public async Task EnsureResource(IHostEnvironment env, IChannel ch, string relativeUrl, string fileName, string dir, int timeout) + public async Task EnsureResourceAsync(IHostEnvironment env, IChannel ch, string relativeUrl, string fileName, string dir, int timeout) { var filePath = GetFilePath(ch, fileName, dir, out var error); if (File.Exists(filePath) || !string.IsNullOrEmpty(error)) @@ -120,7 +120,7 @@ private async Task DownloadFromUrlWithRetryAsync(IHostEnvironment env, I for (int i = 0; i < retryTimes; ++i) { - var thisDownloadResult = await DownloadFromUrl(env, ch, url, fileName, timeout, filePath); + var thisDownloadResult = await DownloadFromUrlAsync(env, ch, url, fileName, timeout, filePath); if (string.IsNullOrEmpty(thisDownloadResult)) return thisDownloadResult; @@ -134,7 +134,7 @@ private async Task DownloadFromUrlWithRetryAsync(IHostEnvironment env, I } /// Returns the error message if an error occurred, null if download was successful. - private async Task DownloadFromUrl(IHostEnvironment env, IChannel ch, string url, string fileName, int timeout, string filePath) + private async Task DownloadFromUrlAsync(IHostEnvironment env, IChannel ch, string url, string fileName, int timeout, string filePath) { using (var webClient = new WebClient()) using (var downloadCancel = new CancellationTokenSource()) diff --git a/src/Microsoft.ML.Core/Utilities/ThreadUtils.cs b/src/Microsoft.ML.Core/Utilities/ThreadUtils.cs index 45a2ccfe9a..d4f2cec383 100644 --- a/src/Microsoft.ML.Core/Utilities/ThreadUtils.cs +++ b/src/Microsoft.ML.Core/Utilities/ThreadUtils.cs @@ -12,11 +12,11 @@ namespace Microsoft.ML.Internal.Utilities { internal static partial class Utils { - public static Task RunOnBackgroundThread(Action start) => - ImmediateBackgroundThreadPool.Queue(start); + public static Task RunOnBackgroundThreadAsync(Action start) => + ImmediateBackgroundThreadPool.QueueAsync(start); - public static Task RunOnBackgroundThread(Action start, object obj) => - ImmediateBackgroundThreadPool.Queue(start, obj); + public static Task RunOnBackgroundThreadAsync(Action start, object obj) => + ImmediateBackgroundThreadPool.QueueAsync(start, obj); public static Thread RunOnForegroundThread(ParameterizedThreadStart start) => new Thread(start) { IsBackground = false }; @@ -42,7 +42,7 @@ private static class ImmediateBackgroundThreadPool /// always end in the state; if the delegate throws /// an exception, it'll be allowed to propagate on the thread, crashing the process. /// - public static Task Queue(Action threadStart) => Queue((Delegate)threadStart, null); + public static Task QueueAsync(Action threadStart) => QueueAsync((Delegate)threadStart, null); /// /// Queues an delegate and associated state to be executed immediately on another thread, @@ -50,9 +50,9 @@ private static class ImmediateBackgroundThreadPool /// always end in the state; if the delegate throws /// an exception, it'll be allowed to propagate on the thread, crashing the process. /// - public static Task Queue(Action threadStart, object state) => Queue((Delegate)threadStart, state); + public static Task QueueAsync(Action threadStart, object state) => QueueAsync((Delegate)threadStart, state); - private static Task Queue(Delegate threadStart, object state) + private static Task QueueAsync(Delegate threadStart, object state) { // Create the TaskCompletionSource used to represent this work. // Call sites only care about completion, not about the distinction between diff --git a/src/Microsoft.ML.Data/Data/DataViewUtils.cs b/src/Microsoft.ML.Data/Data/DataViewUtils.cs index 8e464ebd2e..4f5fadf96a 100644 --- a/src/Microsoft.ML.Data/Data/DataViewUtils.cs +++ b/src/Microsoft.ML.Data/Data/DataViewUtils.cs @@ -367,7 +367,7 @@ private static DataViewRowCursor ConsolidateCore(IChannelProvider provider, Data ch.Assert(localCursor.Position < 0); // Note that these all take ownership of their respective cursors, // so they all handle their disposal internal to the thread. - workers[t] = Utils.RunOnBackgroundThread(() => + workers[t] = Utils.RunOnBackgroundThreadAsync(() => { // This will be the last batch sent in the finally. If iteration proceeds without // error, it will remain null, and be sent as a sentinel. If iteration results in @@ -557,7 +557,7 @@ private DataViewRowCursor[] SplitCore(IChannelProvider ch, DataViewRowCursor inp // Set up and start the thread that consumes the input, and utilizes the InPipe // instances to compose the Batch objects. The thread takes ownership of the // cursor, and so handles its disposal. - Task thread = Utils.RunOnBackgroundThread( + Task thread = Utils.RunOnBackgroundThreadAsync( () => { Batch lastBatch = null; diff --git a/src/Microsoft.ML.Data/DataLoadSave/Binary/BinaryLoader.cs b/src/Microsoft.ML.Data/DataLoadSave/Binary/BinaryLoader.cs index 02cb4bb131..9899210009 100644 --- a/src/Microsoft.ML.Data/DataLoadSave/Binary/BinaryLoader.cs +++ b/src/Microsoft.ML.Data/DataLoadSave/Binary/BinaryLoader.cs @@ -1333,9 +1333,9 @@ public Cursor(BinaryLoader parent, IEnumerable columnsNee _pipeGetters[c] = _pipes[c].GetGetter(); } // The data structures are initialized. Now set up the workers. - _readerThread = Utils.RunOnBackgroundThread(ReaderWorker); + _readerThread = Utils.RunOnBackgroundThreadAsync(ReaderWorker); - _pipeTask = SetupDecompressTask(); + _pipeTask = DecompressAsync(); } protected override void Dispose(bool disposing) @@ -1405,14 +1405,14 @@ protected override void Dispose(bool disposing) base.Dispose(disposing); } - private Task SetupDecompressTask() + private Task DecompressAsync() { Task[] pipeWorkers = new Task[_parent._threads]; long decompressSequence = -1; long decompressSequenceLim = (long)_numBlocks * _actives.Length; for (int w = 0; w < pipeWorkers.Length; ++w) { - pipeWorkers[w] = Utils.RunOnBackgroundThread(() => + pipeWorkers[w] = Utils.RunOnBackgroundThreadAsync(() => { try { diff --git a/src/Microsoft.ML.Data/DataLoadSave/Binary/BinarySaver.cs b/src/Microsoft.ML.Data/DataLoadSave/Binary/BinarySaver.cs index 2d0a87eb21..80c1b59a06 100644 --- a/src/Microsoft.ML.Data/DataLoadSave/Binary/BinarySaver.cs +++ b/src/Microsoft.ML.Data/DataLoadSave/Binary/BinarySaver.cs @@ -664,7 +664,7 @@ public void SaveData(Stream stream, IDataView data, params int[] colIndices) Task[] compressionThreads = new Task[Environment.ProcessorCount]; for (int i = 0; i < compressionThreads.Length; ++i) { - compressionThreads[i] = Utils.RunOnBackgroundThread( + compressionThreads[i] = Utils.RunOnBackgroundThreadAsync( () => CompressionWorker(toCompress, toWrite, activeColumns.Length, waiter, exMarshaller)); } compressionTask = Task.WhenAll(compressionThreads); @@ -672,7 +672,7 @@ public void SaveData(Stream stream, IDataView data, params int[] colIndices) // While there is an advantage to putting the IO into a separate thread, there is not an // advantage to having more than one worker. - Task writeThread = Utils.RunOnBackgroundThread( + Task writeThread = Utils.RunOnBackgroundThreadAsync( () => WriteWorker(stream, toWrite, activeColumns, data.Schema, rowsPerBlock, _host, exMarshaller)); sw.Start(); diff --git a/src/Microsoft.ML.Data/DataLoadSave/Text/TextLoaderCursor.cs b/src/Microsoft.ML.Data/DataLoadSave/Text/TextLoaderCursor.cs index 4394b26121..fed1b97c7d 100644 --- a/src/Microsoft.ML.Data/DataLoadSave/Text/TextLoaderCursor.cs +++ b/src/Microsoft.ML.Data/DataLoadSave/Text/TextLoaderCursor.cs @@ -427,7 +427,7 @@ public LineReader(IMultiStreamSource files, int batchSize, int bufSize, bool has _cref = cref; _queue = new BlockingQueue(bufSize); - _thdRead = Utils.RunOnBackgroundThread(ThreadProc); + _thdRead = Utils.RunOnBackgroundThreadAsync(ThreadProc); } public void Release() @@ -691,7 +691,7 @@ public ParallelState(Cursor curs, out RowSet rows, int cthd) for (int tid = 0; tid < _threads.Length; tid++) { - _threads[tid] = Utils.RunOnBackgroundThread(ThreadProc, tid); + _threads[tid] = Utils.RunOnBackgroundThreadAsync(ThreadProc, tid); } } diff --git a/src/Microsoft.ML.Data/DataView/CacheDataView.cs b/src/Microsoft.ML.Data/DataView/CacheDataView.cs index e24ed9c59d..a820fc139f 100644 --- a/src/Microsoft.ML.Data/DataView/CacheDataView.cs +++ b/src/Microsoft.ML.Data/DataView/CacheDataView.cs @@ -364,7 +364,7 @@ private void KickoffFiller(int[] columns) // They will not be caught by the big catch in the main thread, as filler is not running // in the main thread. Some sort of scheme by which these exceptions could be // cleanly handled would be more appropriate. See task 3740. - var fillerThread = Utils.RunOnBackgroundThread(() => Filler(cursor, caches, waiter)); + var fillerThread = Utils.RunOnBackgroundThreadAsync(() => Filler(cursor, caches, waiter)); _cacheFillerThreads.Add(fillerThread); } diff --git a/src/Microsoft.ML.Data/Transforms/RowShufflingTransformer.cs b/src/Microsoft.ML.Data/Transforms/RowShufflingTransformer.cs index 72984958ce..edba9396b5 100644 --- a/src/Microsoft.ML.Data/Transforms/RowShufflingTransformer.cs +++ b/src/Microsoft.ML.Data/Transforms/RowShufflingTransformer.cs @@ -546,7 +546,7 @@ public Cursor(IChannelProvider provider, int poolRows, DataViewRowCursor input, for (int i = 1; i < _bufferDepth; ++i) PostAssert(_toProduce, _blockSize); - _producerTask = LoopProducerWorker(); + _producerTask = ProduceAsync(); } protected override void Dispose(bool disposing) @@ -586,7 +586,7 @@ public override ValueGetter GetIdGetter() return _idGetter; } - private async Task LoopProducerWorker() + private async Task ProduceAsync() { try { diff --git a/src/Microsoft.ML.Sweeper/AsyncSweeper.cs b/src/Microsoft.ML.Sweeper/AsyncSweeper.cs index 703bdf4443..a300999ebc 100644 --- a/src/Microsoft.ML.Sweeper/AsyncSweeper.cs +++ b/src/Microsoft.ML.Sweeper/AsyncSweeper.cs @@ -47,7 +47,7 @@ public interface IAsyncSweeper /// Propose a . /// /// A future and its id. Null if unavailable or cancelled. - Task Propose(); + Task ProposeAsync(); /// /// Notify the sweeper of a finished run. @@ -108,7 +108,7 @@ public void Update(int id, IRunResult result) } } - public Task Propose() + public Task ProposeAsync() { if (_canceled) return Task.FromResult(null); @@ -272,7 +272,7 @@ private void UpdateBarrierStatus(int id) } } - public async Task Propose() + public async Task ProposeAsync() { if (_cts.IsCancellationRequested) return null; diff --git a/src/Microsoft.ML.TensorFlow/TensorflowUtils.cs b/src/Microsoft.ML.TensorFlow/TensorflowUtils.cs index 49cb34040e..f1cbdffd87 100644 --- a/src/Microsoft.ML.TensorFlow/TensorflowUtils.cs +++ b/src/Microsoft.ML.TensorFlow/TensorflowUtils.cs @@ -180,7 +180,7 @@ internal static void DownloadIfNeeded(IHostEnvironment env, string url, string d { using (var ch = env.Start("Ensuring meta files are present.")) { - var ensureModel = ResourceManagerUtils.Instance.EnsureResource(env, ch, url, fileName, dir, timeout); + var ensureModel = ResourceManagerUtils.Instance.EnsureResourceAsync(env, ch, url, fileName, dir, timeout); ensureModel.Wait(); var errorResult = ResourceManagerUtils.GetErrorMessage(out var errorMessage, ensureModel.Result); if (errorResult != null) diff --git a/src/Microsoft.ML.Transforms/Text/WordEmbeddingsExtractor.cs b/src/Microsoft.ML.Transforms/Text/WordEmbeddingsExtractor.cs index 99cf0580cb..6afa0e2390 100644 --- a/src/Microsoft.ML.Transforms/Text/WordEmbeddingsExtractor.cs +++ b/src/Microsoft.ML.Transforms/Text/WordEmbeddingsExtractor.cs @@ -628,7 +628,7 @@ private string EnsureModelFile(IHostEnvironment env, out int linesToSkip, WordEm { string dir = kind == WordEmbeddingEstimator.PretrainedModelKind.SentimentSpecificWordEmbedding ? Path.Combine("Text", "Sswe") : "WordVectors"; var url = $"{dir}/{modelFileName}"; - var ensureModel = ResourceManagerUtils.Instance.EnsureResource(Host, ch, url, modelFileName, dir, Timeout); + var ensureModel = ResourceManagerUtils.Instance.EnsureResourceAsync(Host, ch, url, modelFileName, dir, Timeout); ensureModel.Wait(); var errorResult = ResourceManagerUtils.GetErrorMessage(out var errorMessage, ensureModel.Result); if (errorResult != null) diff --git a/test/Microsoft.Extensions.ML.Tests/UriLoaderTests.cs b/test/Microsoft.Extensions.ML.Tests/UriLoaderTests.cs index e71c94872b..358baeb736 100644 --- a/test/Microsoft.Extensions.ML.Tests/UriLoaderTests.cs +++ b/test/Microsoft.Extensions.ML.Tests/UriLoaderTests.cs @@ -92,12 +92,12 @@ public override ITransformer GetModel() return null; } - internal override Task LoadModel() + internal override Task LoadModelAsync() { return Task.FromResult(true); } - internal override Task MatchEtag(Uri uri, string eTag) + internal override Task MatchEtagAsync(Uri uri, string eTag) { return Task.FromResult(ETagMatches(uri, eTag)); } diff --git a/test/Microsoft.ML.Sweeper.Tests/TestSweeper.cs b/test/Microsoft.ML.Sweeper.Tests/TestSweeper.cs index d0c116a80b..b9c8894584 100644 --- a/test/Microsoft.ML.Sweeper.Tests/TestSweeper.cs +++ b/test/Microsoft.ML.Sweeper.Tests/TestSweeper.cs @@ -145,7 +145,7 @@ public void TestSimpleSweeperAsync() var paramSets = new List(); for (int i = 0; i < sweeps; i++) { - var task = sweeper.Propose(); + var task = sweeper.ProposeAsync(); Assert.True(task.IsCompleted); paramSets.Add(task.Result.ParameterSet); var result = new RunResult(task.Result.ParameterSet, random.NextDouble(), true); @@ -166,7 +166,7 @@ public void TestSimpleSweeperAsync() paramSets.Clear(); for (int i = 0; i < sweeps; i++) { - var task = gridSweeper.Propose(); + var task = gridSweeper.ProposeAsync(); Assert.True(task.IsCompleted); paramSets.Add(task.Result.ParameterSet); } @@ -202,7 +202,7 @@ public async Task TestDeterministicSweeperAsyncCancellation() int numCompleted = 0; for (int i = 0; i < sweeps; i++) { - var task = sweeper.Propose(); + var task = sweeper.ProposeAsync(); if (i < args.BatchSize - args.Relaxation) { Assert.True(task.IsCompleted); @@ -252,7 +252,7 @@ public async Task TestDeterministicSweeperAsync() var paramSets = new List(); for (int i = 0; i < sweeps; i++) { - var task = sweeper.Propose(); + var task = sweeper.ProposeAsync(); Assert.True(task.IsCompleted); paramSets.Add(task.CompletedResult().ParameterSet); var result = new RunResult(task.CompletedResult().ParameterSet, random.NextDouble(), true); @@ -270,7 +270,7 @@ public async Task TestDeterministicSweeperAsync() var results = new List>(); for (int i = 0; i < args.BatchSize; i++) { - var task = sweeper.Propose(); + var task = sweeper.ProposeAsync(); Assert.True(task.IsCompleted); tasks[i] = task; if (task.CompletedResult() == null) @@ -281,7 +281,7 @@ public async Task TestDeterministicSweeperAsync() // in the previous batch has been posted to the sweeper. for (int i = args.BatchSize; i < 2 * args.BatchSize; i++) { - var task = sweeper.Propose(); + var task = sweeper.ProposeAsync(); Assert.False(task.IsCompleted); tasks[i] = task; } @@ -328,7 +328,7 @@ public void TestDeterministicSweeperAsyncParallel() sleeps[i] = random.Next(10, 100); var r = Task.Run(() => Parallel.For(0, sweeps, options, (int i) => { - var task = sweeper.Propose(); + var task = sweeper.ProposeAsync(); task.Wait(); Assert.Equal(TaskStatus.RanToCompletion, task.Status); var paramWithId = task.Result; @@ -386,7 +386,7 @@ public async Task TestNelderMeadSweeperAsync() for (int i = 0; i < sweeps; i++) { - var paramWithId = await sweeper.Propose(); + var paramWithId = await sweeper.ProposeAsync(); if (paramWithId == null) return; var result = new RunResult(paramWithId.ParameterSet, metrics[i], true); diff --git a/tools-local/Microsoft.ML.InternalCodeAnalyzer/ContractsCheckNameofFixProvider.cs b/tools-local/Microsoft.ML.InternalCodeAnalyzer/ContractsCheckNameofFixProvider.cs index 378082e5a3..0d09e4bbf2 100644 --- a/tools-local/Microsoft.ML.InternalCodeAnalyzer/ContractsCheckNameofFixProvider.cs +++ b/tools-local/Microsoft.ML.InternalCodeAnalyzer/ContractsCheckNameofFixProvider.cs @@ -62,7 +62,7 @@ public override async Task RegisterCodeFixesAsync(CodeFixContext context) argList.Arguments[1] == nameArg && argList.Arguments[0].Expression.ToString() == nameArgValue) { context.RegisterCodeFix(CodeAction.Create(Title, - c => StringReplace(context.Document, nameArgValue, nameArg, c), Id), diagnostic); + c => StringReplaceAsync(context.Document, nameArgValue, nameArg, c), Id), diagnostic); return; } // Check all symbols used in the Check/Except argument. Let's see if there's a match. @@ -99,7 +99,7 @@ public override async Task RegisterCodeFixesAsync(CodeFixContext context) if (bestSymbol != null) { context.RegisterCodeFix(CodeAction.Create(Title, - c => ExpressionReplace(context.Document, bestSymbol, nameArg, c), Id), diagnostic); + c => ExpressionReplaceAsync(context.Document, bestSymbol, nameArg, c), Id), diagnostic); return; } @@ -118,7 +118,7 @@ public override async Task RegisterCodeFixesAsync(CodeFixContext context) if (param.Identifier.ToString() == nameArgValue) { context.RegisterCodeFix(CodeAction.Create(Title, - c => StringReplace(context.Document, nameArgValue, nameArg, c), Id), diagnostic); + c => StringReplaceAsync(context.Document, nameArgValue, nameArg, c), Id), diagnostic); return; } // A hack, but whatever works. @@ -146,7 +146,7 @@ public override async Task RegisterCodeFixesAsync(CodeFixContext context) if (s.Name == nameArgValue) { context.RegisterCodeFix(CodeAction.Create(Title, - c => StringReplace(context.Document, argName + "." + s.Name, nameArg, c), Id), diagnostic); + c => StringReplaceAsync(context.Document, argName + "." + s.Name, nameArg, c), Id), diagnostic); return; } var shortPair = attr.NamedArguments.FirstOrDefault(p => p.Key == "ShortName"); @@ -156,7 +156,7 @@ public override async Task RegisterCodeFixesAsync(CodeFixContext context) if (shortName.Split(',').Contains(nameArgValue)) { context.RegisterCodeFix(CodeAction.Create(Title, - c => StringReplace(context.Document, argName + "." + s.Name, nameArg, c), Id), diagnostic); + c => StringReplaceAsync(context.Document, argName + "." + s.Name, nameArg, c), Id), diagnostic); return; } } @@ -164,7 +164,7 @@ public override async Task RegisterCodeFixesAsync(CodeFixContext context) } } - private async Task StringReplace(Document document, string name, ArgumentSyntax nameArg, CancellationToken cancellationToken) + private async Task StringReplaceAsync(Document document, string name, ArgumentSyntax nameArg, CancellationToken cancellationToken) { var nameofExp = SyntaxFactory.ParseExpression($"nameof({name})").WithTriviaFrom(nameArg); var tree = await document.GetSyntaxTreeAsync(cancellationToken); @@ -173,7 +173,7 @@ private async Task StringReplace(Document document, string name, Argum return document.WithSyntaxRoot(newRoot); } - private async Task ExpressionReplace(Document document, SyntaxNode exp, ArgumentSyntax nameArg, CancellationToken cancellationToken) + private async Task ExpressionReplaceAsync(Document document, SyntaxNode exp, ArgumentSyntax nameArg, CancellationToken cancellationToken) { var nameofExp = (InvocationExpressionSyntax)SyntaxFactory.ParseExpression($"nameof(a)").WithTriviaFrom(nameArg); var newNameofExp = nameofExp.ReplaceNode(nameofExp.ArgumentList.Arguments[0].Expression, exp.WithoutTrivia());