From 8bd45ceb08b9416369114b0c72c20eebfb0f4122 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Fri, 20 Jun 2025 14:40:04 -0700 Subject: [PATCH 1/4] Fix layering of semantic model reuse service --- ...ceFactory.SemanticModelWorkspaceService.cs | 28 ------------------- .../Core/WorkspaceExtensions.projitems | 1 + ...ceFactory.SemanticModelWorkspaceService.cs | 0 3 files changed, 1 insertion(+), 28 deletions(-) delete mode 100644 src/CodeStyle/Core/CodeFixes/LanguageServices/SemanticModelWorkspaceService/SemanticModelWorkspaceServiceFactory.SemanticModelWorkspaceService.cs rename src/Workspaces/{Core/Portable => SharedUtilitiesAndExtensions/Workspace/Core/WorkspaceServices}/SemanticModelReuse/SemanticModelWorkspaceServiceFactory.SemanticModelWorkspaceService.cs (100%) diff --git a/src/CodeStyle/Core/CodeFixes/LanguageServices/SemanticModelWorkspaceService/SemanticModelWorkspaceServiceFactory.SemanticModelWorkspaceService.cs b/src/CodeStyle/Core/CodeFixes/LanguageServices/SemanticModelWorkspaceService/SemanticModelWorkspaceServiceFactory.SemanticModelWorkspaceService.cs deleted file mode 100644 index 0c525bec56899..0000000000000 --- a/src/CodeStyle/Core/CodeFixes/LanguageServices/SemanticModelWorkspaceService/SemanticModelWorkspaceServiceFactory.SemanticModelWorkspaceService.cs +++ /dev/null @@ -1,28 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System.Threading; -using System.Threading.Tasks; -using Microsoft.CodeAnalysis.Host.Mef; -using Microsoft.CodeAnalysis.Shared.Extensions; - -namespace Microsoft.CodeAnalysis.SemanticModelReuse; - -internal partial class SemanticModelReuseWorkspaceServiceFactory : IWorkspaceServiceFactory -{ - private sealed class SemanticModelReuseWorkspaceService : ISemanticModelReuseWorkspaceService - { - public SemanticModelReuseWorkspaceService(Workspace _) - { - } - - public ValueTask ReuseExistingSpeculativeModelAsync(Document document, SyntaxNode node, CancellationToken cancellationToken) - { - // TODO: port the GetSemanticModelForNodeAsync implementation from Workspaces layer, - // which currently relies on a bunch of internal APIs. - // For now, we fall back to the public API to fetch document's SemanticModel. - return document.GetRequiredSemanticModelAsync(cancellationToken); - } - } -} diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/WorkspaceExtensions.projitems b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/WorkspaceExtensions.projitems index ce805eed777bb..ee4e9515ebc4b 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/WorkspaceExtensions.projitems +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/WorkspaceExtensions.projitems @@ -157,6 +157,7 @@ + diff --git a/src/Workspaces/Core/Portable/SemanticModelReuse/SemanticModelWorkspaceServiceFactory.SemanticModelWorkspaceService.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/WorkspaceServices/SemanticModelReuse/SemanticModelWorkspaceServiceFactory.SemanticModelWorkspaceService.cs similarity index 100% rename from src/Workspaces/Core/Portable/SemanticModelReuse/SemanticModelWorkspaceServiceFactory.SemanticModelWorkspaceService.cs rename to src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/WorkspaceServices/SemanticModelReuse/SemanticModelWorkspaceServiceFactory.SemanticModelWorkspaceService.cs From 4b467df926e34ec06df3751c52dfb0a79f2385f5 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Fri, 20 Jun 2025 14:45:54 -0700 Subject: [PATCH 2/4] Fix layering of semantic model reuse service --- .../CSharp/CSharpWorkspaceExtensions.projitems | 1 + .../CSharpSemanticModelReuseLanguageService.cs | 0 .../AbstractSemanticModelReuseLanguageService.cs | 16 +++++++++++++--- .../ISemanticModelReuseLanguageService.cs | 0 .../ISemanticModelReuseWorkspaceService.cs | 0 .../SemanticModelReuseWorkspaceServiceFactory.cs | 0 ...rviceFactory.SemanticModelWorkspaceService.cs | 10 +++++++++- .../Workspace/Core/WorkspaceExtensions.projitems | 8 +++++--- ...sualBasicSemanticModelReuseLanguageService.vb | 0 .../VisualBasicWorkspaceExtensions.projitems | 1 + 10 files changed, 29 insertions(+), 7 deletions(-) rename src/Workspaces/{CSharp/Portable => SharedUtilitiesAndExtensions/Workspace/CSharp}/SemanticModelReuse/CSharpSemanticModelReuseLanguageService.cs (100%) rename src/Workspaces/{Core/Portable => SharedUtilitiesAndExtensions/Workspace/Core}/SemanticModelReuse/AbstractSemanticModelReuseLanguageService.cs (96%) rename src/Workspaces/{Core/Portable => SharedUtilitiesAndExtensions/Workspace/Core}/SemanticModelReuse/ISemanticModelReuseLanguageService.cs (100%) rename src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/{WorkspaceServices => }/SemanticModelReuse/ISemanticModelReuseWorkspaceService.cs (100%) rename src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/{WorkspaceServices => }/SemanticModelReuse/SemanticModelReuseWorkspaceServiceFactory.cs (100%) rename src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/{WorkspaceServices => }/SemanticModelReuse/SemanticModelWorkspaceServiceFactory.SemanticModelWorkspaceService.cs (98%) rename src/Workspaces/{VisualBasic/Portable => SharedUtilitiesAndExtensions/Workspace/VisualBasic}/SemanticModelReuse/VisualBasicSemanticModelReuseLanguageService.vb (100%) diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/CSharpWorkspaceExtensions.projitems b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/CSharpWorkspaceExtensions.projitems index 2db3182cbc458..60ac10a5da8bc 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/CSharpWorkspaceExtensions.projitems +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/CSharpWorkspaceExtensions.projitems @@ -86,6 +86,7 @@ + diff --git a/src/Workspaces/CSharp/Portable/SemanticModelReuse/CSharpSemanticModelReuseLanguageService.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/SemanticModelReuse/CSharpSemanticModelReuseLanguageService.cs similarity index 100% rename from src/Workspaces/CSharp/Portable/SemanticModelReuse/CSharpSemanticModelReuseLanguageService.cs rename to src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/SemanticModelReuse/CSharpSemanticModelReuseLanguageService.cs diff --git a/src/Workspaces/Core/Portable/SemanticModelReuse/AbstractSemanticModelReuseLanguageService.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/SemanticModelReuse/AbstractSemanticModelReuseLanguageService.cs similarity index 96% rename from src/Workspaces/Core/Portable/SemanticModelReuse/AbstractSemanticModelReuseLanguageService.cs rename to src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/SemanticModelReuse/AbstractSemanticModelReuseLanguageService.cs index fa8f5a5360b00..634a0b63126f0 100644 --- a/src/Workspaces/Core/Portable/SemanticModelReuse/AbstractSemanticModelReuseLanguageService.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/SemanticModelReuse/AbstractSemanticModelReuseLanguageService.cs @@ -6,10 +6,13 @@ using System.Diagnostics; using System.Threading; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.Internal.Log; using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.PooledObjects; +#if WORKSPACE +using Microsoft.CodeAnalysis.Internal.Log; +#endif + namespace Microsoft.CodeAnalysis.SemanticModelReuse; internal abstract class AbstractSemanticModelReuseLanguageService< @@ -20,7 +23,9 @@ internal abstract class AbstractSemanticModelReuseLanguageService< where TBasePropertyDeclarationSyntax : TMemberDeclarationSyntax where TAccessorDeclarationSyntax : SyntaxNode { +#if WORKSPACE private readonly CountLogAggregator _logAggregator = new(); +#endif protected abstract ISyntaxFacts SyntaxFacts { get; } @@ -32,11 +37,13 @@ internal abstract class AbstractSemanticModelReuseLanguageService< public void Dispose() { +#if WORKSPACE Logger.Log(FunctionId.SemanticModelReuseLanguageService_TryGetSpeculativeSemanticModelAsync_Equivalent, KeyValueLogMessage.Create(static (m, _logAggregator) => { foreach (var kv in _logAggregator) m[kv.Key.ToString()] = kv.Value.GetCount(); }, _logAggregator)); +#endif } public async Task TryGetSpeculativeSemanticModelAsync(SemanticModel previousSemanticModel, SyntaxNode currentBodyNode, CancellationToken cancellationToken) @@ -48,7 +55,10 @@ public void Dispose() // then something very bad happened as we did that document.Project.GetDependentSemanticVersionAsync was // still the same. Log information so we can be alerted if this isn't being as successful as we expect. var isEquivalentTo = previousSyntaxTree.IsEquivalentTo(currentSyntaxTree, topLevel: true); + +#if WORKSPACE _logAggregator.IncreaseCount(isEquivalentTo); +#endif if (!isEquivalentTo) return null; @@ -71,13 +81,13 @@ public void Dispose() // Given that the common use case for us is continuously editing/typing inside a method body, we believe we can be conservative // in creating speculative model with those kind of trivia change, by requiring the method body block not to shift position, // w/o sacrificing performance in those common scenarios. - if (previousBodyNode.SpanStart != currentBodyNode.SpanStart) + if (previousBodyNode?.SpanStart != currentBodyNode.SpanStart) return null; return TryGetSpeculativeSemanticModelWorker(previousSemanticModel, previousBodyNode, currentBodyNode); } - protected SyntaxNode GetPreviousBodyNode(SyntaxNode previousRoot, SyntaxNode currentRoot, SyntaxNode currentBodyNode) + protected SyntaxNode? GetPreviousBodyNode(SyntaxNode previousRoot, SyntaxNode currentRoot, SyntaxNode currentBodyNode) { if (currentBodyNode is TAccessorDeclarationSyntax currentAccessor) { diff --git a/src/Workspaces/Core/Portable/SemanticModelReuse/ISemanticModelReuseLanguageService.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/SemanticModelReuse/ISemanticModelReuseLanguageService.cs similarity index 100% rename from src/Workspaces/Core/Portable/SemanticModelReuse/ISemanticModelReuseLanguageService.cs rename to src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/SemanticModelReuse/ISemanticModelReuseLanguageService.cs diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/WorkspaceServices/SemanticModelReuse/ISemanticModelReuseWorkspaceService.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/SemanticModelReuse/ISemanticModelReuseWorkspaceService.cs similarity index 100% rename from src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/WorkspaceServices/SemanticModelReuse/ISemanticModelReuseWorkspaceService.cs rename to src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/SemanticModelReuse/ISemanticModelReuseWorkspaceService.cs diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/WorkspaceServices/SemanticModelReuse/SemanticModelReuseWorkspaceServiceFactory.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/SemanticModelReuse/SemanticModelReuseWorkspaceServiceFactory.cs similarity index 100% rename from src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/WorkspaceServices/SemanticModelReuse/SemanticModelReuseWorkspaceServiceFactory.cs rename to src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/SemanticModelReuse/SemanticModelReuseWorkspaceServiceFactory.cs diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/WorkspaceServices/SemanticModelReuse/SemanticModelWorkspaceServiceFactory.SemanticModelWorkspaceService.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/SemanticModelReuse/SemanticModelWorkspaceServiceFactory.SemanticModelWorkspaceService.cs similarity index 98% rename from src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/WorkspaceServices/SemanticModelReuse/SemanticModelWorkspaceServiceFactory.SemanticModelWorkspaceService.cs rename to src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/SemanticModelReuse/SemanticModelWorkspaceServiceFactory.SemanticModelWorkspaceService.cs index 8be7d9d051cdb..f4a84e8057b27 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/WorkspaceServices/SemanticModelReuse/SemanticModelWorkspaceServiceFactory.SemanticModelWorkspaceService.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/SemanticModelReuse/SemanticModelWorkspaceServiceFactory.SemanticModelWorkspaceService.cs @@ -61,7 +61,11 @@ private sealed class SemanticModelReuseWorkspaceService : ISemanticModelReuseWor public SemanticModelReuseWorkspaceService(Workspace workspace) { _workspace = workspace; +#if WORKSPACE _workspace.RegisterWorkspaceChangedHandler((e) => +#else + _workspace.WorkspaceChanged += (sender, e) => +#endif { // if our map points at documents not in the current solution, then we want to clear things out. // this way we don't hold onto semantic models past, say, the c#/vb solutions closing. @@ -78,7 +82,11 @@ public SemanticModelReuseWorkspaceService(Workspace workspace) return; } } - }); + } +#if WORKSPACE + ) +#endif + ; } public async ValueTask ReuseExistingSpeculativeModelAsync(Document document, SyntaxNode node, CancellationToken cancellationToken) diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/WorkspaceExtensions.projitems b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/WorkspaceExtensions.projitems index ee4e9515ebc4b..bcd7a64cba81f 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/WorkspaceExtensions.projitems +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/WorkspaceExtensions.projitems @@ -152,12 +152,14 @@ - - + + + + - + diff --git a/src/Workspaces/VisualBasic/Portable/SemanticModelReuse/VisualBasicSemanticModelReuseLanguageService.vb b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/VisualBasic/SemanticModelReuse/VisualBasicSemanticModelReuseLanguageService.vb similarity index 100% rename from src/Workspaces/VisualBasic/Portable/SemanticModelReuse/VisualBasicSemanticModelReuseLanguageService.vb rename to src/Workspaces/SharedUtilitiesAndExtensions/Workspace/VisualBasic/SemanticModelReuse/VisualBasicSemanticModelReuseLanguageService.vb diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/VisualBasic/VisualBasicWorkspaceExtensions.projitems b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/VisualBasic/VisualBasicWorkspaceExtensions.projitems index 60d98682fafa9..cd5ccc277fb2c 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/VisualBasic/VisualBasicWorkspaceExtensions.projitems +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/VisualBasic/VisualBasicWorkspaceExtensions.projitems @@ -85,6 +85,7 @@ + From 1b8dbf41fb6e37e771d0b4af3d1b0a00feb5271b Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Fri, 20 Jun 2025 14:49:53 -0700 Subject: [PATCH 3/4] Fix layering of semantic model reuse service --- .../VisualBasic/Extensions/SyntaxNodeExtensions.vb | 11 +++++++++++ .../VisualBasicSemanticModelReuseLanguageService.vb | 2 +- .../CodeGeneration/VisualBasicSyntaxGenerator.vb | 12 ------------ 3 files changed, 12 insertions(+), 13 deletions(-) diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/VisualBasic/Extensions/SyntaxNodeExtensions.vb b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/VisualBasic/Extensions/SyntaxNodeExtensions.vb index 0574feab90895..8b2595ea230be 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/VisualBasic/Extensions/SyntaxNodeExtensions.vb +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/VisualBasic/Extensions/SyntaxNodeExtensions.vb @@ -1295,5 +1295,16 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Extensions Return node End If End Function + + Friend Function GetAccessorList(declaration As SyntaxNode) As SyntaxList(Of AccessorBlockSyntax) + Select Case declaration.Kind + Case SyntaxKind.PropertyBlock + Return DirectCast(declaration, PropertyBlockSyntax).Accessors + Case SyntaxKind.EventBlock + Return DirectCast(declaration, EventBlockSyntax).Accessors + Case Else + Return Nothing + End Select + End Function End Module End Namespace diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/VisualBasic/SemanticModelReuse/VisualBasicSemanticModelReuseLanguageService.vb b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/VisualBasic/SemanticModelReuse/VisualBasicSemanticModelReuseLanguageService.vb index f2b17231d5975..9ed1e508c2af6 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/VisualBasic/SemanticModelReuse/VisualBasicSemanticModelReuseLanguageService.vb +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/VisualBasic/SemanticModelReuse/VisualBasicSemanticModelReuseLanguageService.vb @@ -35,7 +35,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.SemanticModelReuse Protected Overrides Function GetAccessors(member As DeclarationStatementSyntax) As SyntaxList(Of AccessorBlockSyntax) Contract.ThrowIfFalse(TypeOf member Is PropertyBlockSyntax OrElse TypeOf member Is EventBlockSyntax) - Return VisualBasicSyntaxGenerator.GetAccessorList(member) + Return GetAccessorList(member) End Function Public Overrides Function TryGetContainingMethodBodyForSpeculation(node As SyntaxNode) As SyntaxNode diff --git a/src/Workspaces/VisualBasic/Portable/CodeGeneration/VisualBasicSyntaxGenerator.vb b/src/Workspaces/VisualBasic/Portable/CodeGeneration/VisualBasicSyntaxGenerator.vb index 44fa9c9800250..e778643388cce 100644 --- a/src/Workspaces/VisualBasic/Portable/CodeGeneration/VisualBasicSyntaxGenerator.vb +++ b/src/Workspaces/VisualBasic/Portable/CodeGeneration/VisualBasicSyntaxGenerator.vb @@ -3030,7 +3030,6 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeGeneration End Function Public Overrides Function InsertAccessors(declaration As SyntaxNode, index As Integer, accessors As IEnumerable(Of SyntaxNode)) As SyntaxNode - Dim currentList = GetAccessorList(declaration) Dim newList = AsAccessorList(accessors, declaration.Kind) @@ -3041,17 +3040,6 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeGeneration End If End Function - Friend Shared Function GetAccessorList(declaration As SyntaxNode) As SyntaxList(Of AccessorBlockSyntax) - Select Case declaration.Kind - Case SyntaxKind.PropertyBlock - Return DirectCast(declaration, PropertyBlockSyntax).Accessors - Case SyntaxKind.EventBlock - Return DirectCast(declaration, EventBlockSyntax).Accessors - Case Else - Return Nothing - End Select - End Function - Private Shared Function WithAccessorList(declaration As SyntaxNode, accessorList As SyntaxList(Of AccessorBlockSyntax)) As SyntaxNode Select Case declaration.Kind Case SyntaxKind.PropertyBlock From 4993cab2ad03c3db65dd25ba923001625f07821d Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Fri, 20 Jun 2025 14:52:40 -0700 Subject: [PATCH 4/4] Allow access --- ...rkspaceServiceFactory.SemanticModelWorkspaceService.cs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/SemanticModelReuse/SemanticModelWorkspaceServiceFactory.SemanticModelWorkspaceService.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/SemanticModelReuse/SemanticModelWorkspaceServiceFactory.SemanticModelWorkspaceService.cs index f4a84e8057b27..89b4f90426827 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/SemanticModelReuse/SemanticModelWorkspaceServiceFactory.SemanticModelWorkspaceService.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/SemanticModelReuse/SemanticModelWorkspaceServiceFactory.SemanticModelWorkspaceService.cs @@ -61,6 +61,8 @@ private sealed class SemanticModelReuseWorkspaceService : ISemanticModelReuseWor public SemanticModelReuseWorkspaceService(Workspace workspace) { _workspace = workspace; + +#pragma warning disable RS0030 // Do not use banned APIs #if WORKSPACE _workspace.RegisterWorkspaceChangedHandler((e) => #else @@ -84,9 +86,11 @@ public SemanticModelReuseWorkspaceService(Workspace workspace) } } #if WORKSPACE - ) -#endif + ); +#else ; +#endif +#pragma warning restore RS0030 // Do not use banned APIs } public async ValueTask ReuseExistingSpeculativeModelAsync(Document document, SyntaxNode node, CancellationToken cancellationToken)