From e30b18a00c8599436e765eba5fb6d73568d2273b Mon Sep 17 00:00:00 2001 From: Jason Malinowski Date: Wed, 30 Mar 2022 17:29:30 -0700 Subject: [PATCH 01/66] Fix the KeybindingResetDetector We switched VisualStudioInfoBar to no longer be a MEF service in 347cd02a80446b47eb93d1effc6d675810457bc2, but this was still importing it. It's now a helper type, so create it instead. --- .../Def/KeybindingReset/KeybindingResetDetector.cs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/VisualStudio/Core/Def/KeybindingReset/KeybindingResetDetector.cs b/src/VisualStudio/Core/Def/KeybindingReset/KeybindingResetDetector.cs index b39e08e8ea4fc..ac9cd810e355f 100644 --- a/src/VisualStudio/Core/Def/KeybindingReset/KeybindingResetDetector.cs +++ b/src/VisualStudio/Core/Def/KeybindingReset/KeybindingResetDetector.cs @@ -15,6 +15,7 @@ using Microsoft.CodeAnalysis.Extensions; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Options; +using Microsoft.CodeAnalysis.Shared.TestHooks; using Microsoft.VisualStudio.LanguageServices.Implementation; using Microsoft.VisualStudio.LanguageServices.Implementation.Utilities; using Microsoft.VisualStudio.LanguageServices.Utilities; @@ -64,7 +65,7 @@ internal sealed class KeybindingResetDetector : ForegroundThreadAffinitizedObjec private readonly IGlobalOptionService _globalOptions; private readonly System.IServiceProvider _serviceProvider; - private readonly VisualStudioInfoBar _infoBarService; + private readonly VisualStudioInfoBar _infoBar; // All mutable fields are UI-thread affinitized @@ -91,13 +92,13 @@ internal sealed class KeybindingResetDetector : ForegroundThreadAffinitizedObjec public KeybindingResetDetector( IThreadingContext threadingContext, IGlobalOptionService globalOptions, - VisualStudioInfoBar infoBarService, - SVsServiceProvider serviceProvider) + SVsServiceProvider serviceProvider, + IAsynchronousOperationListenerProvider listenerProvider) : base(threadingContext) { _globalOptions = globalOptions; - _infoBarService = infoBarService; _serviceProvider = serviceProvider; + _infoBar = new VisualStudioInfoBar(threadingContext, serviceProvider, listenerProvider); } public Task InitializeAsync() @@ -236,7 +237,7 @@ private void ShowGoldBar() var message = ServicesVSResources.We_notice_you_suspended_0_Reset_keymappings_to_continue_to_navigate_and_refactor; KeybindingsResetLogger.Log("InfoBarShown"); - _infoBarService.ShowInfoBar( + _infoBar.ShowInfoBar( string.Format(message, ReSharperExtensionName), new InfoBarUI(title: ServicesVSResources.Reset_Visual_Studio_default_keymapping, kind: InfoBarUI.UIKind.Button, From ea4e25fe45e71a177991a66b45708205ba6e6716 Mon Sep 17 00:00:00 2001 From: Jonathon Marolf Date: Mon, 4 Apr 2022 12:04:24 -0700 Subject: [PATCH 02/66] handle null compilations in entry point finder --- .../CSharpProjectShim.ICSharpProjectSite.cs | 13 +++++++++---- .../Impl/ProjectSystemShim/EntryPointFinder.cs | 4 ++-- .../Impl/ProjectSystemShim/EntryPointFinder.vb | 6 +++++- 3 files changed, 16 insertions(+), 7 deletions(-) diff --git a/src/VisualStudio/CSharp/Impl/ProjectSystemShim/CSharpProjectShim.ICSharpProjectSite.cs b/src/VisualStudio/CSharp/Impl/ProjectSystemShim/CSharpProjectShim.ICSharpProjectSite.cs index 911e393ac226a..998fecdf94b93 100644 --- a/src/VisualStudio/CSharp/Impl/ProjectSystemShim/CSharpProjectShim.ICSharpProjectSite.cs +++ b/src/VisualStudio/CSharp/Impl/ProjectSystemShim/CSharpProjectShim.ICSharpProjectSite.cs @@ -2,7 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable +#nullable enable using System; using System.Linq; @@ -23,7 +23,7 @@ internal partial class CSharpProjectShim : ICSharpProjectSite /// native heap for each call and keep the pointers here. On subsequent calls /// or on disposal, we free the old strings before allocating the new ones. /// - private IntPtr[] _startupClasses = null; + private IntPtr[]? _startupClasses = null; public void GetCompiler(out ICSCompiler compiler, out ICSInputSet inputSet) { @@ -124,9 +124,14 @@ public int GetValidStartupClasses(IntPtr[] classNames, ref int count) // If classNames is NULL, then we need to populate the number of valid startup // classes only var project = Workspace.CurrentSolution.GetProject(VisualStudioProject.Id); - var compilation = project.GetCompilationAsync(CancellationToken.None).WaitAndGetResult(CancellationToken.None); + var compilation = project?.GetCompilationAsync(CancellationToken.None).WaitAndGetResult(CancellationToken.None); + if (compilation == null) + { + count = 0; + return VSConstants.S_OK; + } - var entryPoints = EntryPointFinder.FindEntryPoints(compilation.Assembly.GlobalNamespace); + var entryPoints = EntryPointFinder.FindEntryPoints(compilation.SourceModule.GlobalNamespace); if (classNames == null) { diff --git a/src/VisualStudio/CSharp/Impl/ProjectSystemShim/EntryPointFinder.cs b/src/VisualStudio/CSharp/Impl/ProjectSystemShim/EntryPointFinder.cs index 04128a4ad7786..2139e4c825136 100644 --- a/src/VisualStudio/CSharp/Impl/ProjectSystemShim/EntryPointFinder.cs +++ b/src/VisualStudio/CSharp/Impl/ProjectSystemShim/EntryPointFinder.cs @@ -2,7 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable +#nullable enable using System.Collections.Generic; using Microsoft.CodeAnalysis; @@ -19,7 +19,7 @@ public static IEnumerable FindEntryPoints(INamespaceSymbol sym { var visitor = new EntryPointFinder(); // Only search source symbols - visitor.Visit(symbol.ContainingCompilation.SourceModule.GlobalNamespace); + visitor.Visit(symbol.ContainingCompilation?.SourceModule.GlobalNamespace ?? symbol); return visitor.EntryPoints; } } diff --git a/src/VisualStudio/VisualBasic/Impl/ProjectSystemShim/EntryPointFinder.vb b/src/VisualStudio/VisualBasic/Impl/ProjectSystemShim/EntryPointFinder.vb index 9738441fcd543..bb2545aca2341 100644 --- a/src/VisualStudio/VisualBasic/Impl/ProjectSystemShim/EntryPointFinder.vb +++ b/src/VisualStudio/VisualBasic/Impl/ProjectSystemShim/EntryPointFinder.vb @@ -26,7 +26,11 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.ProjectSystemShim Public Shared Function FindEntryPoints(symbol As INamespaceSymbol, findFormsOnly As Boolean) As IEnumerable(Of INamedTypeSymbol) Dim visitor = New EntryPointFinder(findFormsOnly) ' Only search source symbols - visitor.Visit(symbol.ContainingCompilation.SourceModule.GlobalNamespace) + If symbol.ContainingCompilation IsNot Nothing Then + symbol = symbol.ContainingCompilation.SourceModule.GlobalNamespace + End If + + visitor.Visit(symbol) Return visitor.EntryPoints End Function From 33adbdb9ad965c13190fd07f68d1514ffa22fad0 Mon Sep 17 00:00:00 2001 From: Jonathon Marolf Date: Mon, 4 Apr 2022 14:22:22 -0700 Subject: [PATCH 03/66] remove unnecessary nullable directives --- .../ProjectSystemShim/CSharpProjectShim.ICSharpProjectSite.cs | 4 +--- .../CSharp/Impl/ProjectSystemShim/EntryPointFinder.cs | 4 +--- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/src/VisualStudio/CSharp/Impl/ProjectSystemShim/CSharpProjectShim.ICSharpProjectSite.cs b/src/VisualStudio/CSharp/Impl/ProjectSystemShim/CSharpProjectShim.ICSharpProjectSite.cs index 998fecdf94b93..c57021d525a25 100644 --- a/src/VisualStudio/CSharp/Impl/ProjectSystemShim/CSharpProjectShim.ICSharpProjectSite.cs +++ b/src/VisualStudio/CSharp/Impl/ProjectSystemShim/CSharpProjectShim.ICSharpProjectSite.cs @@ -1,9 +1,7 @@ -// Licensed to the .NET Foundation under one or more agreements. +// 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. -#nullable enable - using System; using System.Linq; using System.Runtime.InteropServices; diff --git a/src/VisualStudio/CSharp/Impl/ProjectSystemShim/EntryPointFinder.cs b/src/VisualStudio/CSharp/Impl/ProjectSystemShim/EntryPointFinder.cs index 2139e4c825136..3bbb522f568d3 100644 --- a/src/VisualStudio/CSharp/Impl/ProjectSystemShim/EntryPointFinder.cs +++ b/src/VisualStudio/CSharp/Impl/ProjectSystemShim/EntryPointFinder.cs @@ -1,9 +1,7 @@ -// Licensed to the .NET Foundation under one or more agreements. +// 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. -#nullable enable - using System.Collections.Generic; using Microsoft.CodeAnalysis; using Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem; From b2479fe6d955b1bcda1cb03c5ee06d1d14baabbe Mon Sep 17 00:00:00 2001 From: Jonathon Marolf Date: Mon, 4 Apr 2022 14:23:02 -0700 Subject: [PATCH 04/66] improve null checking logic --- .../CSharpProjectShim.ICSharpProjectSite.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/VisualStudio/CSharp/Impl/ProjectSystemShim/CSharpProjectShim.ICSharpProjectSite.cs b/src/VisualStudio/CSharp/Impl/ProjectSystemShim/CSharpProjectShim.ICSharpProjectSite.cs index c57021d525a25..298a2d53bf75e 100644 --- a/src/VisualStudio/CSharp/Impl/ProjectSystemShim/CSharpProjectShim.ICSharpProjectSite.cs +++ b/src/VisualStudio/CSharp/Impl/ProjectSystemShim/CSharpProjectShim.ICSharpProjectSite.cs @@ -1,4 +1,4 @@ -// Licensed to the .NET Foundation under one or more agreements. +// 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. @@ -7,6 +7,7 @@ using System.Runtime.InteropServices; using System.Threading; using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.VisualStudio.LanguageServices.CSharp.ProjectSystemShim.Interop; using Roslyn.Utilities; @@ -122,13 +123,13 @@ public int GetValidStartupClasses(IntPtr[] classNames, ref int count) // If classNames is NULL, then we need to populate the number of valid startup // classes only var project = Workspace.CurrentSolution.GetProject(VisualStudioProject.Id); - var compilation = project?.GetCompilationAsync(CancellationToken.None).WaitAndGetResult(CancellationToken.None); - if (compilation == null) + if (project == null) { count = 0; return VSConstants.S_OK; } + var compilation = project.GetRequiredCompilationAsync(CancellationToken.None).WaitAndGetResult(CancellationToken.None); var entryPoints = EntryPointFinder.FindEntryPoints(compilation.SourceModule.GlobalNamespace); if (classNames == null) From 3e03b68db40d9eb2ac1261518670dc0578134be9 Mon Sep 17 00:00:00 2001 From: Jonathon Marolf Date: Mon, 4 Apr 2022 14:25:01 -0700 Subject: [PATCH 05/66] document fallback logic for source modules --- .../CSharp/Impl/ProjectSystemShim/EntryPointFinder.cs | 10 ++++++++-- .../Impl/ProjectSystemShim/EntryPointFinder.vb | 3 ++- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/VisualStudio/CSharp/Impl/ProjectSystemShim/EntryPointFinder.cs b/src/VisualStudio/CSharp/Impl/ProjectSystemShim/EntryPointFinder.cs index 3bbb522f568d3..4a950a81b38a4 100644 --- a/src/VisualStudio/CSharp/Impl/ProjectSystemShim/EntryPointFinder.cs +++ b/src/VisualStudio/CSharp/Impl/ProjectSystemShim/EntryPointFinder.cs @@ -1,4 +1,4 @@ -// Licensed to the .NET Foundation under one or more agreements. +// 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. @@ -17,7 +17,13 @@ public static IEnumerable FindEntryPoints(INamespaceSymbol sym { var visitor = new EntryPointFinder(); // Only search source symbols - visitor.Visit(symbol.ContainingCompilation?.SourceModule.GlobalNamespace ?? symbol); + // Some callers will give a symbol that is not part of a compilation + if (symbol.ContainingCompilation is not null) + { + symbol = symbol.ContainingCompilation.SourceModule.GlobalNamespace; + } + + visitor.Visit(symbol); return visitor.EntryPoints; } } diff --git a/src/VisualStudio/VisualBasic/Impl/ProjectSystemShim/EntryPointFinder.vb b/src/VisualStudio/VisualBasic/Impl/ProjectSystemShim/EntryPointFinder.vb index bb2545aca2341..5103491c8ea0b 100644 --- a/src/VisualStudio/VisualBasic/Impl/ProjectSystemShim/EntryPointFinder.vb +++ b/src/VisualStudio/VisualBasic/Impl/ProjectSystemShim/EntryPointFinder.vb @@ -25,7 +25,8 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.ProjectSystemShim Public Shared Function FindEntryPoints(symbol As INamespaceSymbol, findFormsOnly As Boolean) As IEnumerable(Of INamedTypeSymbol) Dim visitor = New EntryPointFinder(findFormsOnly) - ' Only search source symbols + ' Attempt to only search source symbols + ' Some callers will give a symbol that is not part of a compilation If symbol.ContainingCompilation IsNot Nothing Then symbol = symbol.ContainingCompilation.SourceModule.GlobalNamespace End If From 4cb70240d74126b9af09a8e66576486907064aca Mon Sep 17 00:00:00 2001 From: Jason Malinowski Date: Tue, 5 Apr 2022 12:39:12 -0700 Subject: [PATCH 06/66] Report non-fatal errors if the background load throws exceptions --- src/VisualStudio/Core/Def/RoslynPackage.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/VisualStudio/Core/Def/RoslynPackage.cs b/src/VisualStudio/Core/Def/RoslynPackage.cs index ccead2d180960..2f7a10822fb04 100644 --- a/src/VisualStudio/Core/Def/RoslynPackage.cs +++ b/src/VisualStudio/Core/Def/RoslynPackage.cs @@ -224,7 +224,7 @@ protected override async Task LoadComponentsAsync(CancellationToken cancellation await LoadAnalyzerNodeComponentsAsync(cancellationToken).ConfigureAwait(false); - LoadComponentsBackgroundAsync(cancellationToken).Forget(); + LoadComponentsBackgroundAsync(cancellationToken).ReportNonFatalErrorUnlessCancelledAsync(cancellationToken).Forget(); } // Overrides for VSSDK003 fix From cbb517a3c94544691e31d8579e52a6e7aa3725b3 Mon Sep 17 00:00:00 2001 From: Jonathon Marolf Date: Thu, 7 Apr 2022 18:02:14 -0700 Subject: [PATCH 07/66] simplify null checking --- .../CSharpProjectShim.ICSharpProjectSite.cs | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/src/VisualStudio/CSharp/Impl/ProjectSystemShim/CSharpProjectShim.ICSharpProjectSite.cs b/src/VisualStudio/CSharp/Impl/ProjectSystemShim/CSharpProjectShim.ICSharpProjectSite.cs index 298a2d53bf75e..96884798af235 100644 --- a/src/VisualStudio/CSharp/Impl/ProjectSystemShim/CSharpProjectShim.ICSharpProjectSite.cs +++ b/src/VisualStudio/CSharp/Impl/ProjectSystemShim/CSharpProjectShim.ICSharpProjectSite.cs @@ -120,18 +120,12 @@ public void OnModuleRemoved(string filename) public int GetValidStartupClasses(IntPtr[] classNames, ref int count) { - // If classNames is NULL, then we need to populate the number of valid startup - // classes only - var project = Workspace.CurrentSolution.GetProject(VisualStudioProject.Id); - if (project == null) - { - count = 0; - return VSConstants.S_OK; - } - + var project = Workspace.CurrentSolution.GetProject(VisualStudioProject.Id)!; var compilation = project.GetRequiredCompilationAsync(CancellationToken.None).WaitAndGetResult(CancellationToken.None); var entryPoints = EntryPointFinder.FindEntryPoints(compilation.SourceModule.GlobalNamespace); + // If classNames is NULL, then we need to populate the number of valid startup + // classes only if (classNames == null) { count = entryPoints.Count(); From 9ab051237935140c78ea8f1707f46ce4307a0d5f Mon Sep 17 00:00:00 2001 From: Jonathon Marolf Date: Thu, 7 Apr 2022 18:03:14 -0700 Subject: [PATCH 08/66] always pass in source module namespace symbol on VB --- .../CSharp/Impl/ProjectSystemShim/EntryPointFinder.cs | 7 ------- .../Impl/ProjectSystemShim/VisualBasicProject.vb | 3 ++- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/src/VisualStudio/CSharp/Impl/ProjectSystemShim/EntryPointFinder.cs b/src/VisualStudio/CSharp/Impl/ProjectSystemShim/EntryPointFinder.cs index 4a950a81b38a4..1cd3897ba2abf 100644 --- a/src/VisualStudio/CSharp/Impl/ProjectSystemShim/EntryPointFinder.cs +++ b/src/VisualStudio/CSharp/Impl/ProjectSystemShim/EntryPointFinder.cs @@ -16,13 +16,6 @@ protected override bool MatchesMainMethodName(string name) public static IEnumerable FindEntryPoints(INamespaceSymbol symbol) { var visitor = new EntryPointFinder(); - // Only search source symbols - // Some callers will give a symbol that is not part of a compilation - if (symbol.ContainingCompilation is not null) - { - symbol = symbol.ContainingCompilation.SourceModule.GlobalNamespace; - } - visitor.Visit(symbol); return visitor.EntryPoints; } diff --git a/src/VisualStudio/VisualBasic/Impl/ProjectSystemShim/VisualBasicProject.vb b/src/VisualStudio/VisualBasic/Impl/ProjectSystemShim/VisualBasicProject.vb index 76e32e491524a..e756e722b4139 100644 --- a/src/VisualStudio/VisualBasic/Impl/ProjectSystemShim/VisualBasicProject.vb +++ b/src/VisualStudio/VisualBasic/Impl/ProjectSystemShim/VisualBasicProject.vb @@ -210,8 +210,9 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.ProjectSystemShim ByVal pcActualItems As IntPtr, findFormsOnly As Boolean) + Dim entryPoints = EntryPointFinder.FindEntryPoints(compilation.SourceModule.GlobalNamespace, findFormsOnly:=findFormsOnly) + ' If called with cItems = 0 and pcActualItems != NULL, GetEntryPointsList returns in pcActualItems the number of items available. - Dim entryPoints = EntryPointFinder.FindEntryPoints(compilation.Assembly.GlobalNamespace, findFormsOnly:=findFormsOnly) If cItems = 0 AndAlso pcActualItems <> Nothing Then Marshal.WriteInt32(pcActualItems, entryPoints.Count()) Exit Sub From d3c6f964f5c566b77a2a3d4a6c2dc279d56ef13f Mon Sep 17 00:00:00 2001 From: Jonathon Marolf Date: Fri, 8 Apr 2022 11:41:37 -0700 Subject: [PATCH 09/66] use GetRequiredProject --- .../ProjectSystemShim/CSharpProjectShim.ICSharpProjectSite.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/VisualStudio/CSharp/Impl/ProjectSystemShim/CSharpProjectShim.ICSharpProjectSite.cs b/src/VisualStudio/CSharp/Impl/ProjectSystemShim/CSharpProjectShim.ICSharpProjectSite.cs index 96884798af235..10daf994f1fd6 100644 --- a/src/VisualStudio/CSharp/Impl/ProjectSystemShim/CSharpProjectShim.ICSharpProjectSite.cs +++ b/src/VisualStudio/CSharp/Impl/ProjectSystemShim/CSharpProjectShim.ICSharpProjectSite.cs @@ -120,7 +120,7 @@ public void OnModuleRemoved(string filename) public int GetValidStartupClasses(IntPtr[] classNames, ref int count) { - var project = Workspace.CurrentSolution.GetProject(VisualStudioProject.Id)!; + var project = Workspace.CurrentSolution.GetRequiredProject(VisualStudioProject.Id); var compilation = project.GetRequiredCompilationAsync(CancellationToken.None).WaitAndGetResult(CancellationToken.None); var entryPoints = EntryPointFinder.FindEntryPoints(compilation.SourceModule.GlobalNamespace); From baf15f9b7339980cc99249188777dde4e4ea2697 Mon Sep 17 00:00:00 2001 From: DoctorKrolic Date: Mon, 11 Apr 2022 18:02:51 +0300 Subject: [PATCH 10/66] Allow generating variable with contextual keyword name in return statements --- .../GenerateVariable/GenerateVariableTests.cs | 71 ++++++++++++++++++- .../CSharpGenerateVariableService.cs | 8 +-- 2 files changed, 73 insertions(+), 6 deletions(-) diff --git a/src/EditorFeatures/CSharpTest/GenerateVariable/GenerateVariableTests.cs b/src/EditorFeatures/CSharpTest/GenerateVariable/GenerateVariableTests.cs index 2d16cc1bea506..fbb7dcc7f6ede 100644 --- a/src/EditorFeatures/CSharpTest/GenerateVariable/GenerateVariableTests.cs +++ b/src/EditorFeatures/CSharpTest/GenerateVariable/GenerateVariableTests.cs @@ -37,11 +37,11 @@ public GenerateVariableTests(ITestOutputHelper logger) internal override (DiagnosticAnalyzer?, CodeFixProvider) CreateDiagnosticProviderAndFixer(Workspace workspace) => (null, new CSharpGenerateVariableCodeFixProvider()); - private readonly CodeStyleOption2 onWithInfo = new CodeStyleOption2(true, NotificationOption2.Suggestion); + private readonly CodeStyleOption2 onWithInfo = new(true, NotificationOption2.Suggestion); // specify all options explicitly to override defaults. private OptionsCollection ImplicitTypingEverywhere() - => new OptionsCollection(GetLanguage()) + => new(GetLanguage()) { { CSharpCodeStyleOptions.VarElsewhere, onWithInfo }, { CSharpCodeStyleOptions.VarWhenTypeIsApparent, onWithInfo }, @@ -9618,5 +9618,72 @@ void M(bool expected) } }", index: Parameter); } + + [WorkItem(27646, "https://github.com/dotnet/roslyn/issues/27646")] + [Theory] + [InlineData("yield")] + [InlineData("partial")] + [InlineData("from")] + [InlineData("group")] + [InlineData("join")] + [InlineData("into")] + [InlineData("let")] + [InlineData("by")] + [InlineData("where")] + [InlineData("select")] + [InlineData("get")] + [InlineData("set")] + [InlineData("add")] + [InlineData("remove")] + [InlineData("orderby")] + [InlineData("alias")] + [InlineData("on")] + [InlineData("equals")] + [InlineData("ascending")] + [InlineData("descending")] + [InlineData("assembly")] + [InlineData("module")] + [InlineData("type")] + [InlineData("global")] + [InlineData("field")] + [InlineData("method")] + [InlineData("param")] + [InlineData("property")] + [InlineData("typevar")] + [InlineData("nameof")] + [InlineData("async")] + [InlineData("await")] + [InlineData("when")] + [InlineData("_")] + [InlineData("var")] + [InlineData("or")] + [InlineData("and")] + [InlineData("not")] + [InlineData("with")] + [InlineData("init")] + [InlineData("record")] + [InlineData("managed")] + [InlineData("unmanaged")] + [InlineData("dynamic")] + public async Task TestContextualKeywordsInReturnStatement(string keyword) + { + await TestInRegularAndScriptAsync( +$@"class C +{{ + int M() + {{ + [|return {keyword}|]; + }} +}}", +$@"class C +{{ + private int {keyword}; + + int M() + {{ + return {keyword}; + }} +}}"); + } } } diff --git a/src/Features/CSharp/Portable/GenerateMember/GenerateVariable/CSharpGenerateVariableService.cs b/src/Features/CSharp/Portable/GenerateMember/GenerateVariable/CSharpGenerateVariableService.cs index 6fdd1ec442403..8d5f3dcdc5d75 100644 --- a/src/Features/CSharp/Portable/GenerateMember/GenerateVariable/CSharpGenerateVariableService.cs +++ b/src/Features/CSharp/Portable/GenerateMember/GenerateVariable/CSharpGenerateVariableService.cs @@ -14,7 +14,6 @@ using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.GenerateMember.GenerateVariable; using Microsoft.CodeAnalysis.Host.Mef; -using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Shared.Extensions; namespace Microsoft.CodeAnalysis.CSharp.GenerateMember.GenerateVariable @@ -30,10 +29,12 @@ public CSharpGenerateVariableService() } protected override bool IsExplicitInterfaceGeneration(SyntaxNode node) - => node is PropertyDeclarationSyntax; + => node.IsKind(SyntaxKind.PropertyDeclaration); protected override bool IsIdentifierNameGeneration(SyntaxNode node) - => node is IdentifierNameSyntax identifier && !identifier.Identifier.CouldBeKeyword(); + => node.IsParentKind(SyntaxKind.ReturnStatement) ? + node.IsKind(SyntaxKind.IdentifierName) : + node is IdentifierNameSyntax identifierName && !identifierName.Identifier.CouldBeKeyword(); protected override bool ContainingTypesOrSelfHasUnsafeKeyword(INamedTypeSymbol containingType) => containingType.ContainingTypesOrSelfHasUnsafeKeyword(); @@ -69,7 +70,6 @@ protected override bool TryInitializeIdentifierNameState( { identifierToken = identifierName.Identifier; if (identifierToken.ValueText != string.Empty && - !identifierName.IsVar && !IsProbablyGeneric(identifierName, cancellationToken)) { var memberAccess = identifierName.Parent as MemberAccessExpressionSyntax; From 55aca586b7d214c00349d9b5557b19b9dc771fce Mon Sep 17 00:00:00 2001 From: DoctorKrolic Date: Mon, 11 Apr 2022 19:42:44 +0300 Subject: [PATCH 11/66] PR feedback, added yield return --- .../GenerateVariable/GenerateVariableTests.cs | 71 +++++++++++++++++++ .../CSharpGenerateVariableService.cs | 6 +- 2 files changed, 74 insertions(+), 3 deletions(-) diff --git a/src/EditorFeatures/CSharpTest/GenerateVariable/GenerateVariableTests.cs b/src/EditorFeatures/CSharpTest/GenerateVariable/GenerateVariableTests.cs index fbb7dcc7f6ede..819cf2bf1eadd 100644 --- a/src/EditorFeatures/CSharpTest/GenerateVariable/GenerateVariableTests.cs +++ b/src/EditorFeatures/CSharpTest/GenerateVariable/GenerateVariableTests.cs @@ -9683,6 +9683,77 @@ int M() {{ return {keyword}; }} +}}"); + } + + [WorkItem(27646, "https://github.com/dotnet/roslyn/issues/27646")] + [Theory] + [InlineData("yield")] + [InlineData("partial")] + [InlineData("from")] + [InlineData("group")] + [InlineData("join")] + [InlineData("into")] + [InlineData("let")] + [InlineData("by")] + [InlineData("where")] + [InlineData("select")] + [InlineData("get")] + [InlineData("set")] + [InlineData("add")] + [InlineData("remove")] + [InlineData("orderby")] + [InlineData("alias")] + [InlineData("on")] + [InlineData("equals")] + [InlineData("ascending")] + [InlineData("descending")] + [InlineData("assembly")] + [InlineData("module")] + [InlineData("type")] + [InlineData("global")] + [InlineData("field")] + [InlineData("method")] + [InlineData("param")] + [InlineData("property")] + [InlineData("typevar")] + [InlineData("nameof")] + [InlineData("async")] + [InlineData("await")] + [InlineData("when")] + [InlineData("_")] + [InlineData("var")] + [InlineData("or")] + [InlineData("and")] + [InlineData("not")] + [InlineData("with")] + [InlineData("init")] + [InlineData("record")] + [InlineData("managed")] + [InlineData("unmanaged")] + [InlineData("dynamic")] + public async Task TestContextualKeywordsInYieldReturnStatement(string keyword) + { + await TestInRegularAndScriptAsync( +$@"using System.Collections.Generic; + +class C +{{ + IEnumerable M() + {{ + [|yield return {keyword}|]; + }} +}}", +$@"using System.Collections.Generic; + +class C +{{ + private int {keyword}; + + IEnumerable M() + {{ + yield return {keyword}; + }} }}"); } } diff --git a/src/Features/CSharp/Portable/GenerateMember/GenerateVariable/CSharpGenerateVariableService.cs b/src/Features/CSharp/Portable/GenerateMember/GenerateVariable/CSharpGenerateVariableService.cs index 8d5f3dcdc5d75..329c41c3ab359 100644 --- a/src/Features/CSharp/Portable/GenerateMember/GenerateVariable/CSharpGenerateVariableService.cs +++ b/src/Features/CSharp/Portable/GenerateMember/GenerateVariable/CSharpGenerateVariableService.cs @@ -32,9 +32,9 @@ protected override bool IsExplicitInterfaceGeneration(SyntaxNode node) => node.IsKind(SyntaxKind.PropertyDeclaration); protected override bool IsIdentifierNameGeneration(SyntaxNode node) - => node.IsParentKind(SyntaxKind.ReturnStatement) ? - node.IsKind(SyntaxKind.IdentifierName) : - node is IdentifierNameSyntax identifierName && !identifierName.Identifier.CouldBeKeyword(); + => node.IsParentKind(SyntaxKind.ReturnStatement, SyntaxKind.YieldReturnStatement) + ? node.IsKind(SyntaxKind.IdentifierName) + : node is IdentifierNameSyntax identifierName && !identifierName.Identifier.CouldBeKeyword(); protected override bool ContainingTypesOrSelfHasUnsafeKeyword(INamedTypeSymbol containingType) => containingType.ContainingTypesOrSelfHasUnsafeKeyword(); From 2e4fb4102a0e16c956996d2d8139783ad0a78f22 Mon Sep 17 00:00:00 2001 From: DoctorKrolic Date: Mon, 11 Apr 2022 19:45:45 +0300 Subject: [PATCH 12/66] Revert --- .../GenerateVariable/CSharpGenerateVariableService.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Features/CSharp/Portable/GenerateMember/GenerateVariable/CSharpGenerateVariableService.cs b/src/Features/CSharp/Portable/GenerateMember/GenerateVariable/CSharpGenerateVariableService.cs index 329c41c3ab359..baf3e36e70273 100644 --- a/src/Features/CSharp/Portable/GenerateMember/GenerateVariable/CSharpGenerateVariableService.cs +++ b/src/Features/CSharp/Portable/GenerateMember/GenerateVariable/CSharpGenerateVariableService.cs @@ -29,7 +29,7 @@ public CSharpGenerateVariableService() } protected override bool IsExplicitInterfaceGeneration(SyntaxNode node) - => node.IsKind(SyntaxKind.PropertyDeclaration); + => node is PropertyDeclarationSyntax; protected override bool IsIdentifierNameGeneration(SyntaxNode node) => node.IsParentKind(SyntaxKind.ReturnStatement, SyntaxKind.YieldReturnStatement) From fc36f3e0ee8969b499b9e4e82ac183a102075e5d Mon Sep 17 00:00:00 2001 From: DoctorKrolic Date: Mon, 11 Apr 2022 20:38:06 +0300 Subject: [PATCH 13/66] Changed logic --- .../GenerateVariable/GenerateVariableTests.cs | 81 ++----------------- .../CSharpGenerateVariableService.cs | 14 +++- 2 files changed, 17 insertions(+), 78 deletions(-) diff --git a/src/EditorFeatures/CSharpTest/GenerateVariable/GenerateVariableTests.cs b/src/EditorFeatures/CSharpTest/GenerateVariable/GenerateVariableTests.cs index 819cf2bf1eadd..d509f9258e325 100644 --- a/src/EditorFeatures/CSharpTest/GenerateVariable/GenerateVariableTests.cs +++ b/src/EditorFeatures/CSharpTest/GenerateVariable/GenerateVariableTests.cs @@ -4078,18 +4078,6 @@ static void Goo(IEnumerable s) index: LocalIndex); } - [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsGenerateVariable)] - public async Task TestLocalMissingForVar() - { - await TestMissingInRegularAndScriptAsync( -@"class Program -{ - void Main() - { - var x = [|var|]; - }"); - } - [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsGenerateVariable)] public async Task TestOutLocal1() { @@ -9623,7 +9611,6 @@ void M(bool expected) [Theory] [InlineData("yield")] [InlineData("partial")] - [InlineData("from")] [InlineData("group")] [InlineData("join")] [InlineData("into")] @@ -9650,9 +9637,6 @@ void M(bool expected) [InlineData("param")] [InlineData("property")] [InlineData("typevar")] - [InlineData("nameof")] - [InlineData("async")] - [InlineData("await")] [InlineData("when")] [InlineData("_")] [InlineData("var")] @@ -9665,7 +9649,7 @@ void M(bool expected) [InlineData("managed")] [InlineData("unmanaged")] [InlineData("dynamic")] - public async Task TestContextualKeywordsInReturnStatement(string keyword) + public async Task TestContextualKeywordsThatDoNotProbablyStartSyntacticConstructs(string keyword) { await TestInRegularAndScriptAsync( $@"class C @@ -9688,71 +9672,18 @@ int M() [WorkItem(27646, "https://github.com/dotnet/roslyn/issues/27646")] [Theory] - [InlineData("yield")] - [InlineData("partial")] [InlineData("from")] - [InlineData("group")] - [InlineData("join")] - [InlineData("into")] - [InlineData("let")] - [InlineData("by")] - [InlineData("where")] - [InlineData("select")] - [InlineData("get")] - [InlineData("set")] - [InlineData("add")] - [InlineData("remove")] - [InlineData("orderby")] - [InlineData("alias")] - [InlineData("on")] - [InlineData("equals")] - [InlineData("ascending")] - [InlineData("descending")] - [InlineData("assembly")] - [InlineData("module")] - [InlineData("type")] - [InlineData("global")] - [InlineData("field")] - [InlineData("method")] - [InlineData("param")] - [InlineData("property")] - [InlineData("typevar")] [InlineData("nameof")] [InlineData("async")] [InlineData("await")] - [InlineData("when")] - [InlineData("_")] - [InlineData("var")] - [InlineData("or")] - [InlineData("and")] - [InlineData("not")] - [InlineData("with")] - [InlineData("init")] - [InlineData("record")] - [InlineData("managed")] - [InlineData("unmanaged")] - [InlineData("dynamic")] - public async Task TestContextualKeywordsInYieldReturnStatement(string keyword) + public async Task TestContextualKeywordsThatCanProbablyStartSyntacticConstructs(string keyword) { - await TestInRegularAndScriptAsync( -$@"using System.Collections.Generic; - -class C -{{ - IEnumerable M() - {{ - [|yield return {keyword}|]; - }} -}}", -$@"using System.Collections.Generic; - -class C + await TestMissingInRegularAndScriptAsync( +$@"class C {{ - private int {keyword}; - - IEnumerable M() + int M() {{ - yield return {keyword}; + [|return {keyword}|]; }} }}"); } diff --git a/src/Features/CSharp/Portable/GenerateMember/GenerateVariable/CSharpGenerateVariableService.cs b/src/Features/CSharp/Portable/GenerateMember/GenerateVariable/CSharpGenerateVariableService.cs index baf3e36e70273..d009a589e9c08 100644 --- a/src/Features/CSharp/Portable/GenerateMember/GenerateVariable/CSharpGenerateVariableService.cs +++ b/src/Features/CSharp/Portable/GenerateMember/GenerateVariable/CSharpGenerateVariableService.cs @@ -32,9 +32,17 @@ protected override bool IsExplicitInterfaceGeneration(SyntaxNode node) => node is PropertyDeclarationSyntax; protected override bool IsIdentifierNameGeneration(SyntaxNode node) - => node.IsParentKind(SyntaxKind.ReturnStatement, SyntaxKind.YieldReturnStatement) - ? node.IsKind(SyntaxKind.IdentifierName) - : node is IdentifierNameSyntax identifierName && !identifierName.Identifier.CouldBeKeyword(); + => node is IdentifierNameSyntax identifierName && !IsProbablySyntacticConstruct(identifierName.Identifier); + + private static bool IsProbablySyntacticConstruct(SyntaxToken token) + { + var contextualKind = SyntaxFacts.GetContextualKeywordKind(token.ValueText); + + return contextualKind is SyntaxKind.FromKeyword or + SyntaxKind.NameOfKeyword or + SyntaxKind.AsyncKeyword or + SyntaxKind.AwaitKeyword; + } protected override bool ContainingTypesOrSelfHasUnsafeKeyword(INamedTypeSymbol containingType) => containingType.ContainingTypesOrSelfHasUnsafeKeyword(); From d9c36105e47e14f202338131a421b8a923d7535a Mon Sep 17 00:00:00 2001 From: tmat Date: Mon, 11 Apr 2022 11:44:44 -0700 Subject: [PATCH 14/66] Add TS external access API for ICommentSelectionService --- ...iptCommentSlectionServiceImplementation.cs | 19 ++++++++++ .../Api/VSTypeScriptCommentSelectionInfo.cs | 32 ++++++++++++++++ .../VSTypeScriptCommentSelectionService.cs | 37 +++++++++++++++++++ 3 files changed, 88 insertions(+) create mode 100644 src/Features/Core/Portable/ExternalAccess/VSTypeScript/Api/IVSTypeScriptCommentSlectionServiceImplementation.cs create mode 100644 src/Features/Core/Portable/ExternalAccess/VSTypeScript/Api/VSTypeScriptCommentSelectionInfo.cs create mode 100644 src/Features/Core/Portable/ExternalAccess/VSTypeScript/VSTypeScriptCommentSelectionService.cs diff --git a/src/Features/Core/Portable/ExternalAccess/VSTypeScript/Api/IVSTypeScriptCommentSlectionServiceImplementation.cs b/src/Features/Core/Portable/ExternalAccess/VSTypeScript/Api/IVSTypeScriptCommentSlectionServiceImplementation.cs new file mode 100644 index 0000000000000..c87538e6e1721 --- /dev/null +++ b/src/Features/Core/Portable/ExternalAccess/VSTypeScript/Api/IVSTypeScriptCommentSlectionServiceImplementation.cs @@ -0,0 +1,19 @@ +// 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.Collections.Immutable; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Host; +using Microsoft.CodeAnalysis.Text; + +namespace Microsoft.CodeAnalysis.ExternalAccess.VSTypeScript.Api +{ + internal interface IVSTypeScriptCommentSelectionServiceImplementation : ILanguageService + { + Task GetInfoAsync(Document document, TextSpan textSpan, CancellationToken cancellationToken); + + Task FormatAsync(Document document, ImmutableArray changes, CancellationToken cancellationToken); + } +} diff --git a/src/Features/Core/Portable/ExternalAccess/VSTypeScript/Api/VSTypeScriptCommentSelectionInfo.cs b/src/Features/Core/Portable/ExternalAccess/VSTypeScript/Api/VSTypeScriptCommentSelectionInfo.cs new file mode 100644 index 0000000000000..f68ef72abc08b --- /dev/null +++ b/src/Features/Core/Portable/ExternalAccess/VSTypeScript/Api/VSTypeScriptCommentSelectionInfo.cs @@ -0,0 +1,32 @@ +// 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 Microsoft.CodeAnalysis.CommentSelection; + +namespace Microsoft.CodeAnalysis.ExternalAccess.VSTypeScript.Api +{ + internal readonly struct VSTypeScriptCommentSelectionInfo + { + internal readonly CommentSelectionInfo UnderlyingObject; + + internal VSTypeScriptCommentSelectionInfo(CommentSelectionInfo underlyingObject) + { + UnderlyingObject = underlyingObject; + } + + public VSTypeScriptCommentSelectionInfo( + bool supportsSingleLineComment, + bool supportsBlockComment, + string singleLineCommentString, + string blockCommentStartString, + string blockCommentEndString) : this(new( + supportsSingleLineComment, + supportsBlockComment, + singleLineCommentString, + blockCommentStartString, + blockCommentEndString)) + { + } + } +} diff --git a/src/Features/Core/Portable/ExternalAccess/VSTypeScript/VSTypeScriptCommentSelectionService.cs b/src/Features/Core/Portable/ExternalAccess/VSTypeScript/VSTypeScriptCommentSelectionService.cs new file mode 100644 index 0000000000000..8de86e75c343a --- /dev/null +++ b/src/Features/Core/Portable/ExternalAccess/VSTypeScript/VSTypeScriptCommentSelectionService.cs @@ -0,0 +1,37 @@ +// 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; +using System.Collections.Immutable; +using System.Composition; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.CommentSelection; +using Microsoft.CodeAnalysis.ExternalAccess.VSTypeScript.Api; +using Microsoft.CodeAnalysis.Formatting; +using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.CodeAnalysis.Text; + +namespace Microsoft.CodeAnalysis.ExternalAccess.VSTypeScript +{ + [ExportLanguageService(typeof(ICommentSelectionService), InternalLanguageNames.TypeScript), Shared] + internal sealed class VSTypeScriptCommentSelectionService : ICommentSelectionService + { + private readonly IVSTypeScriptCommentSelectionServiceImplementation _impl; + + [ImportingConstructor] + [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] + public VSTypeScriptCommentSelectionService(IVSTypeScriptCommentSelectionServiceImplementation impl) + => _impl = impl; + + public async Task GetInfoAsync(Document document, TextSpan textSpan, CancellationToken cancellationToken) + { + var info = await _impl.GetInfoAsync(document, textSpan, cancellationToken).ConfigureAwait(false); + return info.UnderlyingObject; + } + + public Task FormatAsync(Document document, ImmutableArray changes, SyntaxFormattingOptions formattingOptions, CancellationToken cancellationToken) + => _impl.FormatAsync(document, changes, cancellationToken); + } +} From 903521b1bec26251c3e473fa0c96863bbb90a63a Mon Sep 17 00:00:00 2001 From: DoctorKrolic Date: Mon, 11 Apr 2022 21:50:52 +0300 Subject: [PATCH 15/66] Put var to syntactic constructs --- .../CSharpTest/GenerateVariable/GenerateVariableTests.cs | 2 +- .../GenerateVariable/CSharpGenerateVariableService.cs | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/EditorFeatures/CSharpTest/GenerateVariable/GenerateVariableTests.cs b/src/EditorFeatures/CSharpTest/GenerateVariable/GenerateVariableTests.cs index d509f9258e325..2bcffe0af9a32 100644 --- a/src/EditorFeatures/CSharpTest/GenerateVariable/GenerateVariableTests.cs +++ b/src/EditorFeatures/CSharpTest/GenerateVariable/GenerateVariableTests.cs @@ -9639,7 +9639,6 @@ void M(bool expected) [InlineData("typevar")] [InlineData("when")] [InlineData("_")] - [InlineData("var")] [InlineData("or")] [InlineData("and")] [InlineData("not")] @@ -9676,6 +9675,7 @@ int M() [InlineData("nameof")] [InlineData("async")] [InlineData("await")] + [InlineData("var")] public async Task TestContextualKeywordsThatCanProbablyStartSyntacticConstructs(string keyword) { await TestMissingInRegularAndScriptAsync( diff --git a/src/Features/CSharp/Portable/GenerateMember/GenerateVariable/CSharpGenerateVariableService.cs b/src/Features/CSharp/Portable/GenerateMember/GenerateVariable/CSharpGenerateVariableService.cs index d009a589e9c08..abf15b683fd67 100644 --- a/src/Features/CSharp/Portable/GenerateMember/GenerateVariable/CSharpGenerateVariableService.cs +++ b/src/Features/CSharp/Portable/GenerateMember/GenerateVariable/CSharpGenerateVariableService.cs @@ -41,7 +41,8 @@ private static bool IsProbablySyntacticConstruct(SyntaxToken token) return contextualKind is SyntaxKind.FromKeyword or SyntaxKind.NameOfKeyword or SyntaxKind.AsyncKeyword or - SyntaxKind.AwaitKeyword; + SyntaxKind.AwaitKeyword or + SyntaxKind.VarKeyword; } protected override bool ContainingTypesOrSelfHasUnsafeKeyword(INamedTypeSymbol containingType) From e074504bfcfd8b45a611c613fba263e733c4f9a1 Mon Sep 17 00:00:00 2001 From: DoctorKrolic Date: Mon, 11 Apr 2022 22:19:04 +0300 Subject: [PATCH 16/66] Add test --- .../GenerateVariable/GenerateVariableTests.cs | 23 +++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/src/EditorFeatures/CSharpTest/GenerateVariable/GenerateVariableTests.cs b/src/EditorFeatures/CSharpTest/GenerateVariable/GenerateVariableTests.cs index 2bcffe0af9a32..2b158ad4d4ab3 100644 --- a/src/EditorFeatures/CSharpTest/GenerateVariable/GenerateVariableTests.cs +++ b/src/EditorFeatures/CSharpTest/GenerateVariable/GenerateVariableTests.cs @@ -9648,7 +9648,7 @@ void M(bool expected) [InlineData("managed")] [InlineData("unmanaged")] [InlineData("dynamic")] - public async Task TestContextualKeywordsThatDoNotProbablyStartSyntacticConstructs(string keyword) + public async Task TestContextualKeywordsThatDoNotProbablyStartSyntacticConstructs_ReturnStatement(string keyword) { await TestInRegularAndScriptAsync( $@"class C @@ -9676,7 +9676,7 @@ int M() [InlineData("async")] [InlineData("await")] [InlineData("var")] - public async Task TestContextualKeywordsThatCanProbablyStartSyntacticConstructs(string keyword) + public async Task TestContextualKeywordsThatCanProbablyStartSyntacticConstructs_ReturnStatement(string keyword) { await TestMissingInRegularAndScriptAsync( $@"class C @@ -9685,6 +9685,25 @@ int M() {{ [|return {keyword}|]; }} +}}"); + } + + [WorkItem(27646, "https://github.com/dotnet/roslyn/issues/27646")] + [Theory] + [InlineData("from")] + [InlineData("nameof")] + [InlineData("async")] + [InlineData("await")] + [InlineData("var")] + public async Task TestContextualKeywordsThatCanProbablyStartSyntacticConstructs_OnTheirOwn(string keyword) + { + await TestMissingInRegularAndScriptAsync( +$@"class C +{{ + int M() + {{ + [|{keyword}|] + }} }}"); } } From 03c76e860aa1faec7b5de0b3999a8a50ed0b59d5 Mon Sep 17 00:00:00 2001 From: DoctorKrolic Date: Mon, 11 Apr 2022 22:26:01 +0300 Subject: [PATCH 17/66] Reintroduced old test --- .../GenerateVariable/GenerateVariableTests.cs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/EditorFeatures/CSharpTest/GenerateVariable/GenerateVariableTests.cs b/src/EditorFeatures/CSharpTest/GenerateVariable/GenerateVariableTests.cs index 2b158ad4d4ab3..2c398c21e05e5 100644 --- a/src/EditorFeatures/CSharpTest/GenerateVariable/GenerateVariableTests.cs +++ b/src/EditorFeatures/CSharpTest/GenerateVariable/GenerateVariableTests.cs @@ -9706,5 +9706,23 @@ int M() }} }}"); } + + [WorkItem(27646, "https://github.com/dotnet/roslyn/issues/27646")] + [Theory] + [InlineData("from")] + [InlineData("nameof")] + [InlineData("async")] + [InlineData("await")] + [InlineData("var")] + public async Task TestContextualKeywordsThatCanProbablyStartSyntacticConstructs_Local(string keyword) + { + await TestMissingInRegularAndScriptAsync( +$@"class Program +{{ + void Main() + {{ + var x = [|{keyword}|]; + }}"); + } } } From e48bc26f7555c72921ac3e5dc13705601355b9e7 Mon Sep 17 00:00:00 2001 From: DoctorKrolic Date: Mon, 11 Apr 2022 22:56:02 +0300 Subject: [PATCH 18/66] Reintroduced old test --- .../GenerateVariable/GenerateVariableTests.cs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/EditorFeatures/CSharpTest/GenerateVariable/GenerateVariableTests.cs b/src/EditorFeatures/CSharpTest/GenerateVariable/GenerateVariableTests.cs index 2b158ad4d4ab3..2c398c21e05e5 100644 --- a/src/EditorFeatures/CSharpTest/GenerateVariable/GenerateVariableTests.cs +++ b/src/EditorFeatures/CSharpTest/GenerateVariable/GenerateVariableTests.cs @@ -9706,5 +9706,23 @@ int M() }} }}"); } + + [WorkItem(27646, "https://github.com/dotnet/roslyn/issues/27646")] + [Theory] + [InlineData("from")] + [InlineData("nameof")] + [InlineData("async")] + [InlineData("await")] + [InlineData("var")] + public async Task TestContextualKeywordsThatCanProbablyStartSyntacticConstructs_Local(string keyword) + { + await TestMissingInRegularAndScriptAsync( +$@"class Program +{{ + void Main() + {{ + var x = [|{keyword}|]; + }}"); + } } } From 7120f9d09651535a260ff55e0ab5d6bf0ad931e5 Mon Sep 17 00:00:00 2001 From: DoctorKrolic Date: Mon, 11 Apr 2022 23:30:58 +0300 Subject: [PATCH 19/66] Doc --- .../GenerateVariable/CSharpGenerateVariableService.cs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/Features/CSharp/Portable/GenerateMember/GenerateVariable/CSharpGenerateVariableService.cs b/src/Features/CSharp/Portable/GenerateMember/GenerateVariable/CSharpGenerateVariableService.cs index abf15b683fd67..4f7d9de8d8a9c 100644 --- a/src/Features/CSharp/Portable/GenerateMember/GenerateVariable/CSharpGenerateVariableService.cs +++ b/src/Features/CSharp/Portable/GenerateMember/GenerateVariable/CSharpGenerateVariableService.cs @@ -36,6 +36,16 @@ protected override bool IsIdentifierNameGeneration(SyntaxNode node) private static bool IsProbablySyntacticConstruct(SyntaxToken token) { + // Technically all C# contextual keywords are valid member names. + // However some of them start various syntactic constructs + // and we don't want to show "Generate " codefix for them: + // 1. "from" starts LINQ expression + // 2. "nameof" is probably nameof(some_name) + // 3. "async" can start a delegate declaration + // 4. "await" starts await expression + // 5. "var" is used in constructions like "var x = ..." + // The list can be expanded in the future if necessary + // This method tells if the given SyntaxToken is one of the cases above var contextualKind = SyntaxFacts.GetContextualKeywordKind(token.ValueText); return contextualKind is SyntaxKind.FromKeyword or From 710ae570c57f211d6830a284a4eeead799fba8a1 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Mon, 11 Apr 2022 15:16:01 -0700 Subject: [PATCH 20/66] Fix feature name to match published name --- src/VisualStudio/Core/Def/ServicesVSResources.resx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/VisualStudio/Core/Def/ServicesVSResources.resx b/src/VisualStudio/Core/Def/ServicesVSResources.resx index 9a93ced7db7b5..7974be1221743 100644 --- a/src/VisualStudio/Core/Def/ServicesVSResources.resx +++ b/src/VisualStudio/Core/Def/ServicesVSResources.resx @@ -1938,6 +1938,6 @@ Additional information: {1} Always use default symbol servers for navigation - Prefer top level statements + Prefer top-level statements \ No newline at end of file From e3cabdc85b41eb03648828f74a6edf3c2dba190b Mon Sep 17 00:00:00 2001 From: tmat Date: Mon, 11 Apr 2022 15:35:46 -0700 Subject: [PATCH 21/66] Workaround --- .../VSTypeScriptCommentSelectionService.cs | 21 +++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/src/Features/Core/Portable/ExternalAccess/VSTypeScript/VSTypeScriptCommentSelectionService.cs b/src/Features/Core/Portable/ExternalAccess/VSTypeScript/VSTypeScriptCommentSelectionService.cs index 8de86e75c343a..86c991686eb9e 100644 --- a/src/Features/Core/Portable/ExternalAccess/VSTypeScript/VSTypeScriptCommentSelectionService.cs +++ b/src/Features/Core/Portable/ExternalAccess/VSTypeScript/VSTypeScriptCommentSelectionService.cs @@ -12,26 +12,39 @@ using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Text; +using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.ExternalAccess.VSTypeScript { [ExportLanguageService(typeof(ICommentSelectionService), InternalLanguageNames.TypeScript), Shared] internal sealed class VSTypeScriptCommentSelectionService : ICommentSelectionService { - private readonly IVSTypeScriptCommentSelectionServiceImplementation _impl; + private readonly IVSTypeScriptCommentSelectionServiceImplementation? _impl; [ImportingConstructor] [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - public VSTypeScriptCommentSelectionService(IVSTypeScriptCommentSelectionServiceImplementation impl) - => _impl = impl; + public VSTypeScriptCommentSelectionService( + // Optional to work around test issue: https://github.com/dotnet/roslyn/issues/60690 + [Import(AllowDefault = true)] IVSTypeScriptCommentSelectionServiceImplementation? impl) + { + _impl = impl; + } public async Task GetInfoAsync(Document document, TextSpan textSpan, CancellationToken cancellationToken) { + // Will never be null in product. + Contract.ThrowIfNull(_impl); + var info = await _impl.GetInfoAsync(document, textSpan, cancellationToken).ConfigureAwait(false); return info.UnderlyingObject; } public Task FormatAsync(Document document, ImmutableArray changes, SyntaxFormattingOptions formattingOptions, CancellationToken cancellationToken) - => _impl.FormatAsync(document, changes, cancellationToken); + { + // Will never be null in product. + Contract.ThrowIfNull(_impl); + + return _impl.FormatAsync(document, changes, cancellationToken); + } } } From aa32a0757d19dc3eb264286744bef579627b90fd Mon Sep 17 00:00:00 2001 From: Jason Malinowski Date: Mon, 11 Apr 2022 15:38:31 -0700 Subject: [PATCH 22/66] Stop switching /langver to preview for generator tests We don't need to do this anymore. --- .../SolutionWithSourceGeneratorTests.cs | 35 ++++++++----------- 1 file changed, 14 insertions(+), 21 deletions(-) diff --git a/src/Workspaces/CoreTest/SolutionTests/SolutionWithSourceGeneratorTests.cs b/src/Workspaces/CoreTest/SolutionTests/SolutionWithSourceGeneratorTests.cs index 6be0da7b7f88c..236e0bb40bc5a 100644 --- a/src/Workspaces/CoreTest/SolutionTests/SolutionWithSourceGeneratorTests.cs +++ b/src/Workspaces/CoreTest/SolutionTests/SolutionWithSourceGeneratorTests.cs @@ -24,13 +24,6 @@ namespace Microsoft.CodeAnalysis.UnitTests [UseExportProvider] public class SolutionWithSourceGeneratorTests : TestBase { - // This is used to add on the preview language version which controls incremental generators being allowed. - // TODO: remove this method entirely and the calls once incremental generators are no longer preview - private static Project WithPreviewLanguageVersion(Project project) - { - return project.WithParseOptions(((CSharpParseOptions)project.ParseOptions!).WithLanguageVersion(LanguageVersion.Preview)); - } - [Theory] [CombinatorialData] public async Task SourceGeneratorBasedOnAdditionalFileGeneratesSyntaxTrees( @@ -42,7 +35,7 @@ public async Task SourceGeneratorBasedOnAdditionalFileGeneratesSyntaxTrees( using var workspace = useRecoverableTrees ? CreateWorkspaceWithRecoverableSyntaxTreesAndWeakCompilations() : CreateWorkspace(); var analyzerReference = new TestGeneratorReference(new GenerateFileForEachAdditionalFileWithContentsCommented()); - var project = WithPreviewLanguageVersion(AddEmptyProject(workspace.CurrentSolution)) + var project = AddEmptyProject(workspace.CurrentSolution) .AddAnalyzerReference(analyzerReference); // Optionally fetch the compilation first, which validates that we handle both running the generator @@ -82,7 +75,7 @@ public async Task WithReferencesMethodCorrectlyUpdatesRunningGenerators() var generatorReferenceToKeep = new TestGeneratorReference(new SingleFileTestGenerator("// StaticContent", hintName: "generatorReferenceToKeep")); var analyzerReferenceToAddAndRemove = new TestGeneratorReference(new SingleFileTestGenerator2("// More Static Content", hintName: "analyzerReferenceToAddAndRemove")); - var project = WithPreviewLanguageVersion(AddEmptyProject(workspace.CurrentSolution)) + var project = AddEmptyProject(workspace.CurrentSolution) .AddAnalyzerReference(generatorReferenceToKeep); Assert.Single((await project.GetRequiredCompilationAsync(CancellationToken.None)).SyntaxTrees); @@ -104,7 +97,7 @@ public async Task IncrementalSourceGeneratorInvokedCorrectNumberOfTimes() using var workspace = CreateWorkspace(new[] { typeof(TestCSharpCompilationFactoryServiceWithIncrementalGeneratorTracking) }); var generator = new GenerateFileForEachAdditionalFileWithContentsCommented(); var analyzerReference = new TestGeneratorReference(generator); - var project = WithPreviewLanguageVersion(AddEmptyProject(workspace.CurrentSolution)) + var project = AddEmptyProject(workspace.CurrentSolution) .AddAnalyzerReference(analyzerReference) .AddAdditionalDocument("Test.txt", "Hello, world!").Project .AddAdditionalDocument("Test2.txt", "Hello, world!").Project; @@ -178,7 +171,7 @@ public async Task SourceGeneratorContentStillIncludedAfterSourceFileChange() { using var workspace = CreateWorkspace(); var analyzerReference = new TestGeneratorReference(new GenerateFileForEachAdditionalFileWithContentsCommented()); - var project = WithPreviewLanguageVersion(AddEmptyProject(workspace.CurrentSolution)) + var project = AddEmptyProject(workspace.CurrentSolution) .AddAnalyzerReference(analyzerReference) .AddDocument("Hello.cs", "// Source File").Project .AddAdditionalDocument("Test.txt", "Hello, world!").Project; @@ -218,7 +211,7 @@ public async Task SourceGeneratorContentChangesAfterAdditionalFileChanges( { using var workspace = CreateWorkspace(); var analyzerReference = new TestGeneratorReference(new GenerateFileForEachAdditionalFileWithContentsCommented()); - var project = WithPreviewLanguageVersion(AddEmptyProject(workspace.CurrentSolution)) + var project = AddEmptyProject(workspace.CurrentSolution) .AddAnalyzerReference(analyzerReference); if (assertRightAway) @@ -261,7 +254,7 @@ public async Task PartialCompilationsIncludeGeneratedFilesAfterFullGeneration() { using var workspace = CreateWorkspaceWithPartialSemantics(); var analyzerReference = new TestGeneratorReference(new GenerateFileForEachAdditionalFileWithContentsCommented()); - var project = WithPreviewLanguageVersion(AddEmptyProject(workspace.CurrentSolution)) + var project = AddEmptyProject(workspace.CurrentSolution) .AddAnalyzerReference(analyzerReference) .AddDocument("Hello.cs", "// Source File").Project .AddAdditionalDocument("Test.txt", "Hello, world!").Project; @@ -282,7 +275,7 @@ public async Task DocumentIdOfGeneratedDocumentsIsStable() { using var workspace = CreateWorkspace(); var analyzerReference = new TestGeneratorReference(new GenerateFileForEachAdditionalFileWithContentsCommented()); - var projectBeforeChange = WithPreviewLanguageVersion(AddEmptyProject(workspace.CurrentSolution)) + var projectBeforeChange = AddEmptyProject(workspace.CurrentSolution) .AddAnalyzerReference(analyzerReference) .AddAdditionalDocument("Test.txt", "Hello, world!").Project; @@ -321,7 +314,7 @@ public async Task DocumentIdGuidInDifferentProjectsIsDifferent() static Solution AddProjectWithReference(Solution solution, TestGeneratorReference analyzerReference) { - var project = WithPreviewLanguageVersion(AddEmptyProject(solution)); + var project = AddEmptyProject(solution); project = project.AddAnalyzerReference(analyzerReference); project = project.AddAdditionalDocument("Test.txt", "Hello, world!").Project; @@ -334,7 +327,7 @@ public async Task CompilationsInCompilationReferencesIncludeGeneratedSourceFiles { using var workspace = CreateWorkspace(); var analyzerReference = new TestGeneratorReference(new GenerateFileForEachAdditionalFileWithContentsCommented()); - var solution = WithPreviewLanguageVersion(AddEmptyProject(workspace.CurrentSolution)) + var solution = AddEmptyProject(workspace.CurrentSolution) .AddAnalyzerReference(analyzerReference) .AddAdditionalDocument("Test.txt", "Hello, world!").Project.Solution; @@ -361,7 +354,7 @@ public async Task RequestingGeneratedDocumentsTwiceGivesSameInstance() var generatorRan = false; var analyzerReference = new TestGeneratorReference(new CallbackGenerator(_ => { }, onExecute: _ => { generatorRan = true; }, source: "// Hello World!")); - var project = WithPreviewLanguageVersion(AddEmptyProject(workspace.CurrentSolution)) + var project = AddEmptyProject(workspace.CurrentSolution) .AddAnalyzerReference(analyzerReference) .AddAdditionalDocument("Test.txt", "Hello, world!").Project; @@ -387,7 +380,7 @@ public async Task GetDocumentWithGeneratedTreeReturnsGeneratedDocument() { using var workspace = CreateWorkspace(); var analyzerReference = new TestGeneratorReference(new GenerateFileForEachAdditionalFileWithContentsCommented()); - var project = WithPreviewLanguageVersion(AddEmptyProject(workspace.CurrentSolution)) + var project = AddEmptyProject(workspace.CurrentSolution) .AddAnalyzerReference(analyzerReference) .AddAdditionalDocument("Test.txt", "Hello, world!").Project; @@ -401,7 +394,7 @@ public async Task GetDocumentWithGeneratedTreeForInProgressReturnsGeneratedDocum { using var workspace = CreateWorkspaceWithPartialSemantics(); var analyzerReference = new TestGeneratorReference(new GenerateFileForEachAdditionalFileWithContentsCommented()); - var project = WithPreviewLanguageVersion(AddEmptyProject(workspace.CurrentSolution)) + var project = AddEmptyProject(workspace.CurrentSolution) .AddAnalyzerReference(analyzerReference) .AddDocument("RegularDocument.cs", "// Source File", filePath: "RegularDocument.cs").Project .AddAdditionalDocument("Test.txt", "Hello, world!").Project; @@ -575,7 +568,7 @@ public async Task OpenSourceGeneratedFileMatchesBufferContentsEvenIfGeneratedFil { using var workspace = CreateWorkspace(); var analyzerReference = new TestGeneratorReference(new GenerateFileForEachAdditionalFileWithContentsCommented()); - var originalAdditionalFile = WithPreviewLanguageVersion(AddEmptyProject(workspace.CurrentSolution)) + var originalAdditionalFile = AddEmptyProject(workspace.CurrentSolution) .AddAnalyzerReference(analyzerReference) .AddAdditionalDocument("Test.txt", SourceText.From("")); @@ -752,7 +745,7 @@ public async Task ChangesToAdditionalFilesCorrectlyAppliedEvenIfCompilationFalls { using var workspace = CreateWorkspaceWithRecoverableSyntaxTreesAndWeakCompilations(); var analyzerReference = new TestGeneratorReference(new GenerateFileForEachAdditionalFileWithContentsCommented()); - var project = WithPreviewLanguageVersion(AddEmptyProject(workspace.CurrentSolution)) + var project = AddEmptyProject(workspace.CurrentSolution) .AddAnalyzerReference(analyzerReference) .AddAdditionalDocument("Test.txt", "Hello, world!").Project; From 760586f087fe227531239b39042e18eb3c72ee29 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Mon, 11 Apr 2022 15:46:51 -0700 Subject: [PATCH 23/66] Update loc strings --- src/VisualStudio/Core/Def/xlf/ServicesVSResources.cs.xlf | 4 ++-- src/VisualStudio/Core/Def/xlf/ServicesVSResources.de.xlf | 4 ++-- src/VisualStudio/Core/Def/xlf/ServicesVSResources.es.xlf | 4 ++-- src/VisualStudio/Core/Def/xlf/ServicesVSResources.fr.xlf | 4 ++-- src/VisualStudio/Core/Def/xlf/ServicesVSResources.it.xlf | 4 ++-- src/VisualStudio/Core/Def/xlf/ServicesVSResources.ja.xlf | 4 ++-- src/VisualStudio/Core/Def/xlf/ServicesVSResources.ko.xlf | 4 ++-- src/VisualStudio/Core/Def/xlf/ServicesVSResources.pl.xlf | 4 ++-- src/VisualStudio/Core/Def/xlf/ServicesVSResources.pt-BR.xlf | 4 ++-- src/VisualStudio/Core/Def/xlf/ServicesVSResources.ru.xlf | 4 ++-- src/VisualStudio/Core/Def/xlf/ServicesVSResources.tr.xlf | 4 ++-- src/VisualStudio/Core/Def/xlf/ServicesVSResources.zh-Hans.xlf | 4 ++-- src/VisualStudio/Core/Def/xlf/ServicesVSResources.zh-Hant.xlf | 4 ++-- 13 files changed, 26 insertions(+), 26 deletions(-) diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.cs.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.cs.xlf index 6f1ef1d80a10c..c1bcb73fcaab4 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.cs.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.cs.xlf @@ -1078,8 +1078,8 @@ - Prefer top level statements - Prefer top level statements + Prefer top-level statements + Prefer top-level statements diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.de.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.de.xlf index 7cffe9c17f3c6..4eae4aeaa2ea0 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.de.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.de.xlf @@ -1078,8 +1078,8 @@ - Prefer top level statements - Prefer top level statements + Prefer top-level statements + Prefer top-level statements diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.es.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.es.xlf index fccaea45de299..bf24d72391c30 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.es.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.es.xlf @@ -1078,8 +1078,8 @@ - Prefer top level statements - Prefer top level statements + Prefer top-level statements + Prefer top-level statements diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.fr.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.fr.xlf index 6d718a6544626..5d29a86dac65b 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.fr.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.fr.xlf @@ -1078,8 +1078,8 @@ - Prefer top level statements - Prefer top level statements + Prefer top-level statements + Prefer top-level statements diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.it.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.it.xlf index 1bbe83fe1983c..391b9ae17ae9f 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.it.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.it.xlf @@ -1078,8 +1078,8 @@ - Prefer top level statements - Prefer top level statements + Prefer top-level statements + Prefer top-level statements diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ja.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ja.xlf index 05deb8400d303..6cddbbf13c628 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ja.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ja.xlf @@ -1078,8 +1078,8 @@ - Prefer top level statements - Prefer top level statements + Prefer top-level statements + Prefer top-level statements diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ko.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ko.xlf index ef66eadee3b70..81b93f4868c74 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ko.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ko.xlf @@ -1078,8 +1078,8 @@ - Prefer top level statements - Prefer top level statements + Prefer top-level statements + Prefer top-level statements diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.pl.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.pl.xlf index b52552be92ad2..be7ae9a4ccc9d 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.pl.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.pl.xlf @@ -1078,8 +1078,8 @@ - Prefer top level statements - Prefer top level statements + Prefer top-level statements + Prefer top-level statements diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.pt-BR.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.pt-BR.xlf index e9f342f0f1b7e..04e2c81f2a662 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.pt-BR.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.pt-BR.xlf @@ -1078,8 +1078,8 @@ - Prefer top level statements - Prefer top level statements + Prefer top-level statements + Prefer top-level statements diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ru.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ru.xlf index 21f0723c66859..49050dd33f680 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ru.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ru.xlf @@ -1078,8 +1078,8 @@ - Prefer top level statements - Prefer top level statements + Prefer top-level statements + Prefer top-level statements diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.tr.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.tr.xlf index f949a5292940d..4a5bb21f5b8d3 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.tr.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.tr.xlf @@ -1078,8 +1078,8 @@ - Prefer top level statements - Prefer top level statements + Prefer top-level statements + Prefer top-level statements diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.zh-Hans.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.zh-Hans.xlf index dcbfcf0d61ecc..a4f72045e662c 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.zh-Hans.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.zh-Hans.xlf @@ -1078,8 +1078,8 @@ - Prefer top level statements - Prefer top level statements + Prefer top-level statements + Prefer top-level statements diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.zh-Hant.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.zh-Hant.xlf index a09283791296f..18c583899c399 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.zh-Hant.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.zh-Hant.xlf @@ -1078,8 +1078,8 @@ - Prefer top level statements - Prefer top level statements + Prefer top-level statements + Prefer top-level statements From d2eec2366ff341290a74ce64653730a700105deb Mon Sep 17 00:00:00 2001 From: Jonathon Marolf Date: Mon, 11 Apr 2022 17:10:32 -0700 Subject: [PATCH 24/66] add comment explaining implementation divergence --- .../CSharp/Impl/ProjectSystemShim/EntryPointFinder.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/VisualStudio/CSharp/Impl/ProjectSystemShim/EntryPointFinder.cs b/src/VisualStudio/CSharp/Impl/ProjectSystemShim/EntryPointFinder.cs index 1cd3897ba2abf..ec37ee38cbafd 100644 --- a/src/VisualStudio/CSharp/Impl/ProjectSystemShim/EntryPointFinder.cs +++ b/src/VisualStudio/CSharp/Impl/ProjectSystemShim/EntryPointFinder.cs @@ -15,6 +15,10 @@ protected override bool MatchesMainMethodName(string name) public static IEnumerable FindEntryPoints(INamespaceSymbol symbol) { + // This differs from the VB implementation (Microsoft.VisualStudio.LanguageServices.VisualBasic.ProjectSystemShim.EntryPointFinder) + // because we don't ever consider forms entry points. + // Techinically, this is wrong but it just doesn't matter since the + // ref assemblies are unlikely to have a random Main() method that matches var visitor = new EntryPointFinder(); visitor.Visit(symbol); return visitor.EntryPoints; From 39b44cb20d27ce578cd1e6cf636d4bdcc49fb6c0 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Tue, 12 Apr 2022 14:46:30 -0700 Subject: [PATCH 25/66] Fix 'move to namespace' with file scoped namespaces. --- .../MoveToNamespace/MoveToNamespaceTests.cs | 47 +++++++++++++++++++ .../CSharpMoveToNamespaceService.cs | 20 ++++---- 2 files changed, 58 insertions(+), 9 deletions(-) diff --git a/src/EditorFeatures/CSharpTest/MoveToNamespace/MoveToNamespaceTests.cs b/src/EditorFeatures/CSharpTest/MoveToNamespace/MoveToNamespaceTests.cs index 17acdb0203654..61e03c09be2da 100644 --- a/src/EditorFeatures/CSharpTest/MoveToNamespace/MoveToNamespaceTests.cs +++ b/src/EditorFeatures/CSharpTest/MoveToNamespace/MoveToNamespaceTests.cs @@ -56,6 +56,19 @@ class MyClass { } }", +expectedSuccess: false); + + [Fact, Trait(Traits.Feature, Traits.Features.MoveToNamespace)] + public Task MoveToNamespace_MoveItems_CaretAboveNamespace_FileScopedNamespace() + => TestMoveToNamespaceAsync( +@"using System; +[||] +namespace A; + +class MyClass +{ +} +", expectedSuccess: false); [Fact, Trait(Traits.Feature, Traits.Features.MoveToNamespace)] @@ -195,6 +208,18 @@ class MyClass void Method() { } } }", +expectedSuccess: false); + + [Fact, Trait(Traits.Feature, Traits.Features.MoveToNamespace)] + public Task MoveToNamespace_MoveItems_CaretAfterFileScopedNamespaceSemicolon() + => TestMoveToNamespaceAsync( +@"namespace A; [||] + +class MyClass +{ + void Method() { } +} +", expectedSuccess: false); [Fact, Trait(Traits.Feature, Traits.Features.MoveToNamespace)] @@ -374,6 +399,28 @@ public Task MoveToNamespace_MoveType_Single(string typeKeyword) }}", targetNamespace: "B", expectedSymbolChanges: new Dictionary() +{ + {"A.MyType", "B.MyType" } +}); + + [Theory, Trait(Traits.Feature, Traits.Features.MoveToNamespace)] + [MemberData(nameof(SupportedKeywords))] + public Task MoveToNamespace_MoveType_Single_FileScopedNamespace(string typeKeyword) + => TestMoveToNamespaceAsync( +@$"namespace A; + +{typeKeyword} MyType[||] +{{ +}} +", +expectedMarkup: @$"namespace {{|Warning:B|}}; + +{typeKeyword} MyType +{{ +}} +", +targetNamespace: "B", +expectedSymbolChanges: new Dictionary() { {"A.MyType", "B.MyType" } }); diff --git a/src/Features/CSharp/Portable/MoveToNamespace/CSharpMoveToNamespaceService.cs b/src/Features/CSharp/Portable/MoveToNamespace/CSharpMoveToNamespaceService.cs index 1dd99cc978d68..e399968da803e 100644 --- a/src/Features/CSharp/Portable/MoveToNamespace/CSharpMoveToNamespaceService.cs +++ b/src/Features/CSharp/Portable/MoveToNamespace/CSharpMoveToNamespaceService.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System; using System.Composition; using Microsoft.CodeAnalysis.CSharp.Syntax; @@ -15,7 +13,7 @@ namespace Microsoft.CodeAnalysis.CSharp.MoveToNamespace { [ExportLanguageService(typeof(IMoveToNamespaceService), LanguageNames.CSharp), Shared] internal class CSharpMoveToNamespaceService : - AbstractMoveToNamespaceService + AbstractMoveToNamespaceService { [ImportingConstructor] [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] @@ -28,18 +26,22 @@ public CSharpMoveToNamespaceService( protected override string GetNamespaceName(SyntaxNode container) => container switch { - NamespaceDeclarationSyntax namespaceSyntax => namespaceSyntax.Name.ToString(), + BaseNamespaceDeclarationSyntax namespaceSyntax => namespaceSyntax.Name.ToString(), CompilationUnitSyntax _ => string.Empty, _ => throw ExceptionUtilities.UnexpectedValue(container) }; - protected override bool IsContainedInNamespaceDeclaration(NamespaceDeclarationSyntax namespaceDeclaration, int position) + protected override bool IsContainedInNamespaceDeclaration(BaseNamespaceDeclarationSyntax baseNamespace, int position) { - var namespaceDeclarationStart = namespaceDeclaration.NamespaceKeyword.SpanStart; - var namespaceDeclarationEnd = namespaceDeclaration.OpenBraceToken.SpanStart; + var namespaceDeclarationStart = baseNamespace.NamespaceKeyword.SpanStart; + var namespaceDeclarationEnd = baseNamespace switch + { + NamespaceDeclarationSyntax namespaceDeclaration => namespaceDeclaration.OpenBraceToken.SpanStart, + FileScopedNamespaceDeclarationSyntax fileScopedNamespace => fileScopedNamespace.SemicolonToken.Span.End, + _ => throw ExceptionUtilities.UnexpectedValue(baseNamespace.Kind()), + }; - return position >= namespaceDeclarationStart && - position < namespaceDeclarationEnd; + return position >= namespaceDeclarationStart && position < namespaceDeclarationEnd; } } } From 64b7c52293e54f80fcf844d49ead365edc4349ba Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Tue, 12 Apr 2022 14:47:25 -0700 Subject: [PATCH 26/66] Add workitem --- .../CSharpTest/MoveToNamespace/MoveToNamespaceTests.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/EditorFeatures/CSharpTest/MoveToNamespace/MoveToNamespaceTests.cs b/src/EditorFeatures/CSharpTest/MoveToNamespace/MoveToNamespaceTests.cs index 61e03c09be2da..01c56d4628746 100644 --- a/src/EditorFeatures/CSharpTest/MoveToNamespace/MoveToNamespaceTests.cs +++ b/src/EditorFeatures/CSharpTest/MoveToNamespace/MoveToNamespaceTests.cs @@ -59,6 +59,7 @@ class MyClass expectedSuccess: false); [Fact, Trait(Traits.Feature, Traits.Features.MoveToNamespace)] + [WorkItem(59716, "https://github.com/dotnet/roslyn/issues/59716")] public Task MoveToNamespace_MoveItems_CaretAboveNamespace_FileScopedNamespace() => TestMoveToNamespaceAsync( @"using System; @@ -211,6 +212,7 @@ void Method() { } expectedSuccess: false); [Fact, Trait(Traits.Feature, Traits.Features.MoveToNamespace)] + [WorkItem(59716, "https://github.com/dotnet/roslyn/issues/59716")] public Task MoveToNamespace_MoveItems_CaretAfterFileScopedNamespaceSemicolon() => TestMoveToNamespaceAsync( @"namespace A; [||] @@ -404,6 +406,7 @@ public Task MoveToNamespace_MoveType_Single(string typeKeyword) }); [Theory, Trait(Traits.Feature, Traits.Features.MoveToNamespace)] + [WorkItem(59716, "https://github.com/dotnet/roslyn/issues/59716")] [MemberData(nameof(SupportedKeywords))] public Task MoveToNamespace_MoveType_Single_FileScopedNamespace(string typeKeyword) => TestMoveToNamespaceAsync( From a655f50e413a4436b2af0ce7af3a8138a21a1056 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Tue, 12 Apr 2022 16:13:36 -0700 Subject: [PATCH 27/66] NRT enable C# EditorFeatures project. --- .../CloseBlockCommentCommandHandler.cs | 2 - .../AbstractCSharpBraceMatcher.cs | 2 - .../CSharpDirectiveTriviaBraceMatcher.cs | 4 +- .../CSharpEmbeddedLanguageBraceMatcher.cs | 2 - .../LessThanGreaterThanBraceMatcher.cs | 2 - .../OpenCloseBraceBraceMatcher.cs | 2 - .../OpenCloseBracketBraceMatcher.cs | 2 - .../OpenCloseParenBraceMatcher.cs | 2 - .../StringLiteralBraceMatcher.cs | 5 +- .../CSharpChangeSignatureCommandHandler.cs | 2 - .../CSharpToggleBlockCommentCommandHandler.cs | 5 +- .../CompleteStatementCommandHandler.cs | 77 ++++++++++--------- .../ContentType/ContentTypeDefinitions.cs | 6 +- .../XmlTagCompletionCommandHandler.cs | 10 +-- .../EncapsulateFieldCommandHandler.cs | 2 - .../CSharpEndConstructGenerationService.cs | 2 - .../ExtractInterfaceCommandHandler.cs | 2 - .../ExtractMethodCommandHandler.cs | 2 - ...nterpolatedVerbatimStringCommandHandler.cs | 5 +- ...harpSendToInteractiveSubmissionProvider.cs | 16 ++-- .../CSharpContentTypeLanguageService.cs | 2 - ...RenameTrackingLanguageHeuristicsService.cs | 2 - .../SplitStringLiteralCommandHandler.cs | 4 +- 23 files changed, 59 insertions(+), 101 deletions(-) diff --git a/src/EditorFeatures/CSharp/BlockCommentEditing/CloseBlockCommentCommandHandler.cs b/src/EditorFeatures/CSharp/BlockCommentEditing/CloseBlockCommentCommandHandler.cs index 1ba9332213877..b71145dc62201 100644 --- a/src/EditorFeatures/CSharp/BlockCommentEditing/CloseBlockCommentCommandHandler.cs +++ b/src/EditorFeatures/CSharp/BlockCommentEditing/CloseBlockCommentCommandHandler.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System; using System.ComponentModel.Composition; using Microsoft.CodeAnalysis.Editor.Shared.Extensions; diff --git a/src/EditorFeatures/CSharp/BraceMatching/AbstractCSharpBraceMatcher.cs b/src/EditorFeatures/CSharp/BraceMatching/AbstractCSharpBraceMatcher.cs index d8f72ea040d82..0a3ec3be5557b 100644 --- a/src/EditorFeatures/CSharp/BraceMatching/AbstractCSharpBraceMatcher.cs +++ b/src/EditorFeatures/CSharp/BraceMatching/AbstractCSharpBraceMatcher.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using Microsoft.CodeAnalysis.BraceMatching; using Microsoft.CodeAnalysis.CSharp; diff --git a/src/EditorFeatures/CSharp/BraceMatching/CSharpDirectiveTriviaBraceMatcher.cs b/src/EditorFeatures/CSharp/BraceMatching/CSharpDirectiveTriviaBraceMatcher.cs index 8cf2569c33bcc..0da4f21b82113 100644 --- a/src/EditorFeatures/CSharp/BraceMatching/CSharpDirectiveTriviaBraceMatcher.cs +++ b/src/EditorFeatures/CSharp/BraceMatching/CSharpDirectiveTriviaBraceMatcher.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System; using System.Collections.Generic; using System.ComponentModel.Composition; @@ -28,7 +26,7 @@ public CSharpDirectiveTriviaBraceMatcher() { } - internal override List GetMatchingConditionalDirectives(DirectiveTriviaSyntax directive, CancellationToken cancellationToken) + internal override List? GetMatchingConditionalDirectives(DirectiveTriviaSyntax directive, CancellationToken cancellationToken) => directive.GetMatchingConditionalDirectives(cancellationToken)?.ToList(); internal override DirectiveTriviaSyntax GetMatchingDirective(DirectiveTriviaSyntax directive, CancellationToken cancellationToken) diff --git a/src/EditorFeatures/CSharp/BraceMatching/CSharpEmbeddedLanguageBraceMatcher.cs b/src/EditorFeatures/CSharp/BraceMatching/CSharpEmbeddedLanguageBraceMatcher.cs index c423a5e88cb55..2710389ffca55 100644 --- a/src/EditorFeatures/CSharp/BraceMatching/CSharpEmbeddedLanguageBraceMatcher.cs +++ b/src/EditorFeatures/CSharp/BraceMatching/CSharpEmbeddedLanguageBraceMatcher.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System; using System.ComponentModel.Composition; using Microsoft.CodeAnalysis.BraceMatching; diff --git a/src/EditorFeatures/CSharp/BraceMatching/LessThanGreaterThanBraceMatcher.cs b/src/EditorFeatures/CSharp/BraceMatching/LessThanGreaterThanBraceMatcher.cs index 02bec62518ab1..fed2cc8824250 100644 --- a/src/EditorFeatures/CSharp/BraceMatching/LessThanGreaterThanBraceMatcher.cs +++ b/src/EditorFeatures/CSharp/BraceMatching/LessThanGreaterThanBraceMatcher.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System; using System.ComponentModel.Composition; using Microsoft.CodeAnalysis.CSharp; diff --git a/src/EditorFeatures/CSharp/BraceMatching/OpenCloseBraceBraceMatcher.cs b/src/EditorFeatures/CSharp/BraceMatching/OpenCloseBraceBraceMatcher.cs index 0feb4c854be5e..5366d280ceec8 100644 --- a/src/EditorFeatures/CSharp/BraceMatching/OpenCloseBraceBraceMatcher.cs +++ b/src/EditorFeatures/CSharp/BraceMatching/OpenCloseBraceBraceMatcher.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System; using System.ComponentModel.Composition; using Microsoft.CodeAnalysis.CSharp; diff --git a/src/EditorFeatures/CSharp/BraceMatching/OpenCloseBracketBraceMatcher.cs b/src/EditorFeatures/CSharp/BraceMatching/OpenCloseBracketBraceMatcher.cs index 716f0127df181..e2128113ffef2 100644 --- a/src/EditorFeatures/CSharp/BraceMatching/OpenCloseBracketBraceMatcher.cs +++ b/src/EditorFeatures/CSharp/BraceMatching/OpenCloseBracketBraceMatcher.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System; using System.ComponentModel.Composition; using Microsoft.CodeAnalysis.CSharp; diff --git a/src/EditorFeatures/CSharp/BraceMatching/OpenCloseParenBraceMatcher.cs b/src/EditorFeatures/CSharp/BraceMatching/OpenCloseParenBraceMatcher.cs index c97b911923fe2..9348ba4a95ace 100644 --- a/src/EditorFeatures/CSharp/BraceMatching/OpenCloseParenBraceMatcher.cs +++ b/src/EditorFeatures/CSharp/BraceMatching/OpenCloseParenBraceMatcher.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System; using System.ComponentModel.Composition; using Microsoft.CodeAnalysis.CSharp; diff --git a/src/EditorFeatures/CSharp/BraceMatching/StringLiteralBraceMatcher.cs b/src/EditorFeatures/CSharp/BraceMatching/StringLiteralBraceMatcher.cs index aadd11b6a2b89..33d6a3c616271 100644 --- a/src/EditorFeatures/CSharp/BraceMatching/StringLiteralBraceMatcher.cs +++ b/src/EditorFeatures/CSharp/BraceMatching/StringLiteralBraceMatcher.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System; using System.ComponentModel.Composition; using System.Threading; @@ -12,6 +10,7 @@ using Microsoft.CodeAnalysis.CSharp.Extensions; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; namespace Microsoft.CodeAnalysis.Editor.CSharp.BraceMatching @@ -27,7 +26,7 @@ public StringLiteralBraceMatcher() public async Task FindBracesAsync(Document document, int position, BraceMatchingOptions options, CancellationToken cancellationToken) { - var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); + var root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); var token = root.FindToken(position); if (!token.ContainsDiagnostics) diff --git a/src/EditorFeatures/CSharp/ChangeSignature/CSharpChangeSignatureCommandHandler.cs b/src/EditorFeatures/CSharp/ChangeSignature/CSharpChangeSignatureCommandHandler.cs index cdd64710822b8..732b1a4b430f4 100644 --- a/src/EditorFeatures/CSharp/ChangeSignature/CSharpChangeSignatureCommandHandler.cs +++ b/src/EditorFeatures/CSharp/ChangeSignature/CSharpChangeSignatureCommandHandler.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System; using System.ComponentModel.Composition; using Microsoft.CodeAnalysis.ChangeSignature; diff --git a/src/EditorFeatures/CSharp/CommentSelection/CSharpToggleBlockCommentCommandHandler.cs b/src/EditorFeatures/CSharp/CommentSelection/CSharpToggleBlockCommentCommandHandler.cs index d8f4eebc7bb31..70ffae9f54998 100644 --- a/src/EditorFeatures/CSharp/CommentSelection/CSharpToggleBlockCommentCommandHandler.cs +++ b/src/EditorFeatures/CSharp/CommentSelection/CSharpToggleBlockCommentCommandHandler.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System; using System.Collections.Immutable; using System.ComponentModel.Composition; @@ -13,6 +11,7 @@ using Microsoft.CodeAnalysis.CommentSelection; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.Commanding; using Microsoft.VisualStudio.Text; @@ -45,7 +44,7 @@ public CSharpToggleBlockCommentCommandHandler( protected override async Task> GetBlockCommentsInDocumentAsync(Document document, ITextSnapshot snapshot, TextSpan linesContainingSelections, CommentSelectionInfo commentInfo, CancellationToken cancellationToken) { - var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); + var root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); // Only search for block comments intersecting the lines in the selections. return root.DescendantTrivia(linesContainingSelections) .Where(trivia => trivia.IsKind(SyntaxKind.MultiLineCommentTrivia) || trivia.IsKind(SyntaxKind.MultiLineDocumentationCommentTrivia)) diff --git a/src/EditorFeatures/CSharp/CompleteStatement/CompleteStatementCommandHandler.cs b/src/EditorFeatures/CSharp/CompleteStatement/CompleteStatementCommandHandler.cs index 341bfd4d31b33..e9023d6a70ab9 100644 --- a/src/EditorFeatures/CSharp/CompleteStatement/CompleteStatementCommandHandler.cs +++ b/src/EditorFeatures/CSharp/CompleteStatement/CompleteStatementCommandHandler.cs @@ -2,16 +2,14 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System; using System.ComponentModel.Composition; -using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Threading; +using Microsoft.CodeAnalysis.AutomaticCompletion; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Extensions; using Microsoft.CodeAnalysis.CSharp.Syntax; -using Microsoft.CodeAnalysis.AutomaticCompletion; using Microsoft.CodeAnalysis.Editor.Shared.Extensions; using Microsoft.CodeAnalysis.Editor.Shared.Options; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; @@ -79,7 +77,7 @@ public void ExecuteCommand(TypeCharCommandArgs args, Action nextCommandHandler, // Insert the semicolon using next command handler nextCommandHandler(); - transaction.Complete(); + transaction?.Complete(); } private bool BeforeExecuteCommand(bool speculative, TypeCharCommandArgs args, CommandExecutionContext executionContext) @@ -108,8 +106,8 @@ private bool BeforeExecuteCommand(bool speculative, TypeCharCommandArgs args, Co } var cancellationToken = executionContext.OperationContext.UserCancellationToken; - var syntaxFacts = document.GetLanguageService(); - var root = document.GetSyntaxRootSynchronously(cancellationToken); + var syntaxFacts = document.GetRequiredLanguageService(); + var root = document.GetRequiredSyntaxRootSynchronously(cancellationToken); if (!TryGetStartingNode(root, caret, out var currentNode, cancellationToken)) { @@ -124,13 +122,11 @@ private bool BeforeExecuteCommand(bool speculative, TypeCharCommandArgs args, Co /// Determines which node the caret is in. /// Must be called on the UI thread. /// - /// - /// - /// - /// - /// - private static bool TryGetStartingNode(SyntaxNode root, SnapshotPoint caret, - out SyntaxNode startingNode, CancellationToken cancellationToken) + private static bool TryGetStartingNode( + SyntaxNode root, + SnapshotPoint caret, + [NotNullWhen(true)] out SyntaxNode? startingNode, + CancellationToken cancellationToken) { // on the UI thread startingNode = null; @@ -144,7 +140,7 @@ private static bool TryGetStartingNode(SyntaxNode root, SnapshotPoint caret, return false; } - startingNode = token.Parent; + startingNode = token.GetRequiredParent(); // If the caret is before an opening delimiter or after a closing delimeter, // start analysis with node outside of delimiters. @@ -163,7 +159,7 @@ private static bool TryGetStartingNode(SyntaxNode root, SnapshotPoint caret, if (!openingDelimiter.IsKind(SyntaxKind.None) && openingDelimiter.Span.Start >= caretPosition || !closingDelimiter.IsKind(SyntaxKind.None) && closingDelimiter.Span.End <= caretPosition) { - startingNode = startingNode.Parent; + startingNode = startingNode.GetRequiredParent(); } return true; @@ -177,7 +173,7 @@ private static bool MoveCaretToSemicolonPosition( SnapshotPoint originalCaret, SnapshotPoint caret, ISyntaxFactsService syntaxFacts, - SyntaxNode currentNode, + SyntaxNode? currentNode, bool isInsideDelimiters, CancellationToken cancellationToken) { @@ -216,12 +212,10 @@ private static bool MoveCaretToSemicolonPosition( var newCaret = args.SubjectBuffer.CurrentSnapshot.GetPoint(newCaretPosition); if (!TryGetStartingNode(root, newCaret, out currentNode, cancellationToken)) - { return false; - } - return MoveCaretToSemicolonPosition(speculative, args, document, root, originalCaret, newCaret, syntaxFacts, currentNode, - isInsideDelimiters: true, cancellationToken); + return MoveCaretToSemicolonPosition( + speculative, args, document, root, originalCaret, newCaret, syntaxFacts, currentNode, isInsideDelimiters: true, cancellationToken); } else if (currentNode.IsKind(SyntaxKind.DoStatement)) { @@ -241,8 +235,8 @@ private static bool MoveCaretToSemicolonPosition( { // keep caret the same, but continue analyzing with the parent of the current node currentNode = currentNode.Parent; - return MoveCaretToSemicolonPosition(speculative, args, document, root, originalCaret, caret, syntaxFacts, currentNode, - isInsideDelimiters, cancellationToken); + return MoveCaretToSemicolonPosition( + speculative, args, document, root, originalCaret, caret, syntaxFacts, currentNode, isInsideDelimiters, cancellationToken); } } @@ -282,7 +276,7 @@ private static bool CanHaveSemicolon(SyntaxNode currentNode) private static bool IsInConditionOfDoStatement(SyntaxNode currentNode, SnapshotPoint caret) { - if (!currentNode.IsKind(SyntaxKind.DoStatement, out DoStatementSyntax doStatement)) + if (!currentNode.IsKind(SyntaxKind.DoStatement, out DoStatementSyntax? doStatement)) { return false; } @@ -360,13 +354,13 @@ private static bool TryGetCaretPositionToMove(SyntaxNode statementNode, Snapshot private static bool TryGetForStatementCaret(SnapshotPoint originalCaret, ForStatementSyntax forStatement, out SnapshotPoint forStatementCaret) { - if (CaretIsInForStatementCondition(originalCaret, forStatement)) + if (CaretIsInForStatementCondition(originalCaret, forStatement, out var condition)) { - forStatementCaret = GetCaretAtPosition(forStatement.Condition.Span.End); + forStatementCaret = GetCaretAtPosition(condition.Span.End); } - else if (CaretIsInForStatementDeclaration(originalCaret, forStatement)) + else if (CaretIsInForStatementDeclaration(originalCaret, forStatement, out var declaration)) { - forStatementCaret = GetCaretAtPosition(forStatement.Declaration.Span.End); + forStatementCaret = GetCaretAtPosition(declaration.Span.End); } else if (CaretIsInForStatementInitializers(originalCaret, forStatement)) { @@ -384,18 +378,25 @@ private static bool TryGetForStatementCaret(SnapshotPoint originalCaret, ForStat SnapshotPoint GetCaretAtPosition(int position) => originalCaret.Snapshot.GetPoint(position); } - private static bool CaretIsInForStatementCondition(int caretPosition, ForStatementSyntax forStatementSyntax) + private static bool CaretIsInForStatementCondition(int caretPosition, ForStatementSyntax forStatementSyntax, [NotNullWhen(true)] out ExpressionSyntax? condition) + { + condition = forStatementSyntax.Condition; + if (condition == null) + return false; + // If condition is null and caret is in the condition section, as in `for ( ; $$; )`, // we will have bailed earlier due to not being inside supported delimiters - => forStatementSyntax.Condition == null - ? false - : caretPosition > forStatementSyntax.Condition.SpanStart && - caretPosition <= forStatementSyntax.Condition.Span.End; - - private static bool CaretIsInForStatementDeclaration(int caretPosition, ForStatementSyntax forStatementSyntax) - => forStatementSyntax.Declaration != null && - caretPosition > forStatementSyntax.Declaration.Span.Start && - caretPosition <= forStatementSyntax.Declaration.Span.End; + return caretPosition > condition.SpanStart && caretPosition <= condition.Span.End; + } + + private static bool CaretIsInForStatementDeclaration(int caretPosition, ForStatementSyntax forStatementSyntax, [NotNullWhen(true)] out VariableDeclarationSyntax? declaration) + { + declaration = forStatementSyntax.Declaration; + if (declaration == null) + return false; + + return caretPosition > declaration.Span.Start && caretPosition <= declaration.Span.End; + } private static bool CaretIsInForStatementInitializers(int caretPosition, ForStatementSyntax forStatementSyntax) => forStatementSyntax.Initializers.Count != 0 && diff --git a/src/EditorFeatures/CSharp/ContentType/ContentTypeDefinitions.cs b/src/EditorFeatures/CSharp/ContentType/ContentTypeDefinitions.cs index a48534ec0c5e0..ea636d1fd21d8 100644 --- a/src/EditorFeatures/CSharp/ContentType/ContentTypeDefinitions.cs +++ b/src/EditorFeatures/CSharp/ContentType/ContentTypeDefinitions.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System.ComponentModel.Composition; using Microsoft.VisualStudio.Utilities; @@ -21,11 +19,11 @@ internal static class ContentTypeDefinitions // From Microsoft.VisualStudio.LanguageServer.Client.CodeRemoteContentDefinition.CodeRemoteBaseTypeName // We cannot directly reference the LSP client package in EditorFeatures as it is a VS dependency. [BaseDefinition("code-languageserver-base")] - public static readonly ContentTypeDefinition CSharpContentTypeDefinition; + public static readonly ContentTypeDefinition CSharpContentTypeDefinition = null!; [Export] [Name(ContentTypeNames.CSharpSignatureHelpContentType)] [BaseDefinition("sighelp")] - public static readonly ContentTypeDefinition SignatureHelpContentTypeDefinition; + public static readonly ContentTypeDefinition SignatureHelpContentTypeDefinition = null!; } } diff --git a/src/EditorFeatures/CSharp/DocumentationComments/XmlTagCompletionCommandHandler.cs b/src/EditorFeatures/CSharp/DocumentationComments/XmlTagCompletionCommandHandler.cs index 8e44628e6fa91..52f4b671c719b 100644 --- a/src/EditorFeatures/CSharp/DocumentationComments/XmlTagCompletionCommandHandler.cs +++ b/src/EditorFeatures/CSharp/DocumentationComments/XmlTagCompletionCommandHandler.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System; using System.ComponentModel.Composition; using System.Threading; @@ -37,7 +35,7 @@ public XmlTagCompletionCommandHandler(ITextUndoHistoryRegistry undoHistory) protected override void TryCompleteTag(ITextView textView, ITextBuffer subjectBuffer, Document document, SnapshotPoint position, CancellationToken cancellationToken) { - var tree = document.GetSyntaxTreeSynchronously(cancellationToken); + var tree = document.GetRequiredSyntaxTreeSynchronously(cancellationToken); var token = tree.FindTokenOnLeftOfPosition(position, cancellationToken, includeDocumentationComments: true); if (token.IsKind(SyntaxKind.GreaterThanToken)) @@ -72,7 +70,7 @@ protected override void TryCompleteTag(ITextView textView, ITextBuffer subjectBu // We need to check for non-trivia XML text tokens after $$ that match the expected end tag text. if (token.Parent.IsKind(SyntaxKind.XmlElementEndTag) && - token.Parent.IsParentKind(SyntaxKind.XmlElement, out XmlElementSyntax parentElement) && + token.Parent.IsParentKind(SyntaxKind.XmlElement, out XmlElementSyntax? parentElement) && !HasFollowingEndTagTrivia(parentElement, token)) { CheckNameAndInsertText(textView, subjectBuffer, position, parentElement.StartTag, null, "{0}>"); @@ -100,7 +98,7 @@ private static bool HasFollowingEndTagTrivia(XmlElementSyntax parentElement, Syn private bool HasUnmatchedIdenticalParent(XmlElementStartTagSyntax parentStartTag) { - if (parentStartTag.Parent.Parent is XmlElementSyntax grandParentElement) + if (parentStartTag.Parent?.Parent is XmlElementSyntax grandParentElement) { if (grandParentElement.StartTag.Name.LocalName.ValueText == parentStartTag.Name.LocalName.ValueText) { @@ -143,7 +141,7 @@ private void CheckNameAndInsertText(ITextView textView, ITextBuffer subjectBuffe if (elementName.Length > 0) { - var parentElement = startTag.Parent as XmlElementSyntax; + var parentElement = (XmlElementSyntax)startTag.GetRequiredParent(); if (parentElement.EndTag.Name.LocalName.ValueText != elementName) { InsertTextAndMoveCaret(textView, subjectBuffer, position, string.Format(formatString, elementName), finalCaretPosition); diff --git a/src/EditorFeatures/CSharp/EncapsulateField/EncapsulateFieldCommandHandler.cs b/src/EditorFeatures/CSharp/EncapsulateField/EncapsulateFieldCommandHandler.cs index 2323f3ce78a98..74af10b1f1e32 100644 --- a/src/EditorFeatures/CSharp/EncapsulateField/EncapsulateFieldCommandHandler.cs +++ b/src/EditorFeatures/CSharp/EncapsulateField/EncapsulateFieldCommandHandler.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System; using System.ComponentModel.Composition; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; diff --git a/src/EditorFeatures/CSharp/EndConstruct/CSharpEndConstructGenerationService.cs b/src/EditorFeatures/CSharp/EndConstruct/CSharpEndConstructGenerationService.cs index d0444196bb3a5..32b394789c129 100644 --- a/src/EditorFeatures/CSharp/EndConstruct/CSharpEndConstructGenerationService.cs +++ b/src/EditorFeatures/CSharp/EndConstruct/CSharpEndConstructGenerationService.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System; using System.Composition; using System.Diagnostics.CodeAnalysis; diff --git a/src/EditorFeatures/CSharp/ExtractInterface/ExtractInterfaceCommandHandler.cs b/src/EditorFeatures/CSharp/ExtractInterface/ExtractInterfaceCommandHandler.cs index 928c9af2440d8..385b6614a5629 100644 --- a/src/EditorFeatures/CSharp/ExtractInterface/ExtractInterfaceCommandHandler.cs +++ b/src/EditorFeatures/CSharp/ExtractInterface/ExtractInterfaceCommandHandler.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System; using System.ComponentModel.Composition; using Microsoft.CodeAnalysis.Editor; diff --git a/src/EditorFeatures/CSharp/ExtractMethod/ExtractMethodCommandHandler.cs b/src/EditorFeatures/CSharp/ExtractMethod/ExtractMethodCommandHandler.cs index 64ac5347727bc..f666c7d23edb4 100644 --- a/src/EditorFeatures/CSharp/ExtractMethod/ExtractMethodCommandHandler.cs +++ b/src/EditorFeatures/CSharp/ExtractMethod/ExtractMethodCommandHandler.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System; using System.ComponentModel.Composition; using Microsoft.CodeAnalysis.Editor; diff --git a/src/EditorFeatures/CSharp/FixInterpolatedVerbatimString/FixInterpolatedVerbatimStringCommandHandler.cs b/src/EditorFeatures/CSharp/FixInterpolatedVerbatimString/FixInterpolatedVerbatimStringCommandHandler.cs index f25f9383685e7..f4ef71f269715 100644 --- a/src/EditorFeatures/CSharp/FixInterpolatedVerbatimString/FixInterpolatedVerbatimStringCommandHandler.cs +++ b/src/EditorFeatures/CSharp/FixInterpolatedVerbatimString/FixInterpolatedVerbatimStringCommandHandler.cs @@ -2,14 +2,13 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System; using System.ComponentModel.Composition; using System.Threading; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.Editor.Shared.Extensions; using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.Commanding; using Microsoft.VisualStudio.Text; @@ -76,7 +75,7 @@ private static void ExecuteCommandWorker(TypeCharCommandArgs args, CancellationT var document = snapshot.GetOpenDocumentInCurrentContextWithChanges(); if (document != null) { - var root = document.GetSyntaxRootSynchronously(cancellationToken); + var root = document.GetRequiredSyntaxRootSynchronously(cancellationToken); var token = root.FindToken(position - 3); if (token.IsKind(SyntaxKind.InterpolatedVerbatimStringStartToken)) { diff --git a/src/EditorFeatures/CSharp/Interactive/CSharpSendToInteractiveSubmissionProvider.cs b/src/EditorFeatures/CSharp/Interactive/CSharpSendToInteractiveSubmissionProvider.cs index 0a2cf45eee45c..bbba2c42e0e39 100644 --- a/src/EditorFeatures/CSharp/Interactive/CSharpSendToInteractiveSubmissionProvider.cs +++ b/src/EditorFeatures/CSharp/Interactive/CSharpSendToInteractiveSubmissionProvider.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System; using System.Collections.Generic; using System.ComponentModel.Composition; @@ -48,24 +46,22 @@ protected override IEnumerable GetExecutableSyntaxTreeNodeSelection(Te /// /// Selection that user has originally made. /// Root of the syntax tree. - private static SyntaxNode GetSyntaxNodeForSubmission(TextSpan selectionSpan, SyntaxNode root) + private static SyntaxNode? GetSyntaxNodeForSubmission(TextSpan selectionSpan, SyntaxNode root) { GetSelectedTokens(selectionSpan, root, out var startToken, out var endToken); // Ensure that the first token comes before the last token. // Otherwise selection did not contain any tokens. if (startToken != endToken && startToken.Span.End > endToken.SpanStart) - { return null; - } if (startToken == endToken) { - return GetSyntaxNodeForSubmission(startToken.Parent); + return GetSyntaxNodeForSubmission(startToken.GetRequiredParent()); } - var startNode = GetSyntaxNodeForSubmission(startToken.Parent); - var endNode = GetSyntaxNodeForSubmission(endToken.Parent); + var startNode = GetSyntaxNodeForSubmission(startToken.GetRequiredParent()); + var endNode = GetSyntaxNodeForSubmission(endToken.GetRequiredParent()); // If there is no SyntaxNode worth sending to the REPL return null. if (startNode == null || endNode == null) @@ -92,9 +88,9 @@ private static SyntaxNode GetSyntaxNodeForSubmission(TextSpan selectionSpan, Syn /// Finds a that should be submitted to REPL. /// /// The currently selected node. - private static SyntaxNode GetSyntaxNodeForSubmission(SyntaxNode node) + private static SyntaxNode? GetSyntaxNodeForSubmission(SyntaxNode node) { - SyntaxNode candidate = node.GetAncestorOrThis(); + SyntaxNode? candidate = node.GetAncestorOrThis(); if (candidate != null) { return candidate; diff --git a/src/EditorFeatures/CSharp/LanguageServices/CSharpContentTypeLanguageService.cs b/src/EditorFeatures/CSharp/LanguageServices/CSharpContentTypeLanguageService.cs index 5cf6f1c7fc649..c35db7ce9c6ee 100644 --- a/src/EditorFeatures/CSharp/LanguageServices/CSharpContentTypeLanguageService.cs +++ b/src/EditorFeatures/CSharp/LanguageServices/CSharpContentTypeLanguageService.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System; using System.Composition; using Microsoft.CodeAnalysis.Host.Mef; diff --git a/src/EditorFeatures/CSharp/RenameTracking/CSharpRenameTrackingLanguageHeuristicsService.cs b/src/EditorFeatures/CSharp/RenameTracking/CSharpRenameTrackingLanguageHeuristicsService.cs index a84e44cbf3447..2a68f4d712439 100644 --- a/src/EditorFeatures/CSharp/RenameTracking/CSharpRenameTrackingLanguageHeuristicsService.cs +++ b/src/EditorFeatures/CSharp/RenameTracking/CSharpRenameTrackingLanguageHeuristicsService.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System; using System.Composition; using Microsoft.CodeAnalysis.Editor.Implementation.RenameTracking; diff --git a/src/EditorFeatures/CSharp/SplitStringLiteral/SplitStringLiteralCommandHandler.cs b/src/EditorFeatures/CSharp/SplitStringLiteral/SplitStringLiteralCommandHandler.cs index 105b872f0a785..00fe968b26d8a 100644 --- a/src/EditorFeatures/CSharp/SplitStringLiteral/SplitStringLiteralCommandHandler.cs +++ b/src/EditorFeatures/CSharp/SplitStringLiteral/SplitStringLiteralCommandHandler.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System; using System.ComponentModel.Composition; using System.Linq; @@ -148,7 +146,7 @@ private bool SplitString(ITextView textView, ITextBuffer subjectBuffer, int posi textView.Caret.MoveTo(newCaretPoint.Value); } - transaction.Complete(); + transaction?.Complete(); return true; } From c6f71781a807ab0ace093ed3a29d6fc827d37bbe Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Tue, 12 Apr 2022 16:16:16 -0700 Subject: [PATCH 28/66] NRT enable C# feature. --- .../CSharpAddAnonymousTypeMemberNameCodeFixProvider.cs | 4 +--- .../AbstractAddAnonymousTypeMemberNameCodeFixProvider.cs | 4 ---- 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/src/Features/CSharp/Portable/AddAnonymousTypeMemberName/CSharpAddAnonymousTypeMemberNameCodeFixProvider.cs b/src/Features/CSharp/Portable/AddAnonymousTypeMemberName/CSharpAddAnonymousTypeMemberNameCodeFixProvider.cs index 5a892f25197c2..f85e08c779c26 100644 --- a/src/Features/CSharp/Portable/AddAnonymousTypeMemberName/CSharpAddAnonymousTypeMemberNameCodeFixProvider.cs +++ b/src/Features/CSharp/Portable/AddAnonymousTypeMemberName/CSharpAddAnonymousTypeMemberNameCodeFixProvider.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System.Collections.Generic; using System.Collections.Immutable; using System.Composition; @@ -45,6 +43,6 @@ protected override AnonymousObjectMemberDeclaratorSyntax WithName(AnonymousObjec SyntaxFactory.IdentifierName(name))); protected override IEnumerable GetAnonymousObjectMemberNames(AnonymousObjectCreationExpressionSyntax initializer) - => initializer.Initializers.Where(i => i.NameEquals != null).Select(i => i.NameEquals.Name.Identifier.ValueText); + => initializer.Initializers.Where(i => i.NameEquals != null).Select(i => i.NameEquals!.Name.Identifier.ValueText); } } diff --git a/src/Features/Core/Portable/AddAnonymousTypeMemberName/AbstractAddAnonymousTypeMemberNameCodeFixProvider.cs b/src/Features/Core/Portable/AddAnonymousTypeMemberName/AbstractAddAnonymousTypeMemberNameCodeFixProvider.cs index 40d3072f29da7..4ae114dd518fc 100644 --- a/src/Features/Core/Portable/AddAnonymousTypeMemberName/AbstractAddAnonymousTypeMemberNameCodeFixProvider.cs +++ b/src/Features/Core/Portable/AddAnonymousTypeMemberName/AbstractAddAnonymousTypeMemberNameCodeFixProvider.cs @@ -25,10 +25,6 @@ internal abstract class AbstractAddAnonymousTypeMemberNameCodeFixProvider< where TAnonymousObjectInitializer : SyntaxNode where TAnonymousObjectMemberDeclaratorSyntax : SyntaxNode { - protected AbstractAddAnonymousTypeMemberNameCodeFixProvider() - { - } - protected abstract bool HasName(TAnonymousObjectMemberDeclaratorSyntax declarator); protected abstract TExpressionSyntax GetExpression(TAnonymousObjectMemberDeclaratorSyntax declarator); protected abstract TAnonymousObjectMemberDeclaratorSyntax WithName(TAnonymousObjectMemberDeclaratorSyntax declarator, SyntaxToken name); From 4042b12b0303feb3f64e89e3e065ce004a23da0a Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Tue, 12 Apr 2022 16:19:07 -0700 Subject: [PATCH 29/66] NRT enable C# feature. --- .../AddFileBanner/CSharpAddFileBannerCodeRefactoringProvider.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Features/CSharp/Portable/AddFileBanner/CSharpAddFileBannerCodeRefactoringProvider.cs b/src/Features/CSharp/Portable/AddFileBanner/CSharpAddFileBannerCodeRefactoringProvider.cs index 8d404835bbc8f..b77f0640b0d46 100644 --- a/src/Features/CSharp/Portable/AddFileBanner/CSharpAddFileBannerCodeRefactoringProvider.cs +++ b/src/Features/CSharp/Portable/AddFileBanner/CSharpAddFileBannerCodeRefactoringProvider.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System.Composition; using System.Diagnostics.CodeAnalysis; using Microsoft.CodeAnalysis.AddFileBanner; From 49f54c18341abdbc42c5dd715406ac36ac1c33b6 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Tue, 12 Apr 2022 16:22:41 -0700 Subject: [PATCH 30/66] NRT enable C# feature. --- ...ToExpressionDiagnosticAnalyzer.Analyzer.cs | 44 ++++++++++--------- 1 file changed, 24 insertions(+), 20 deletions(-) diff --git a/src/Analyzers/CSharp/Analyzers/ConvertSwitchStatementToExpression/ConvertSwitchStatementToExpressionDiagnosticAnalyzer.Analyzer.cs b/src/Analyzers/CSharp/Analyzers/ConvertSwitchStatementToExpression/ConvertSwitchStatementToExpressionDiagnosticAnalyzer.Analyzer.cs index e4ef97b6340ee..ad8fd1f143d55 100644 --- a/src/Analyzers/CSharp/Analyzers/ConvertSwitchStatementToExpression/ConvertSwitchStatementToExpressionDiagnosticAnalyzer.Analyzer.cs +++ b/src/Analyzers/CSharp/Analyzers/ConvertSwitchStatementToExpression/ConvertSwitchStatementToExpressionDiagnosticAnalyzer.Analyzer.cs @@ -2,16 +2,14 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System; using System.Diagnostics; using System.Linq; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Extensions; -using Microsoft.CodeAnalysis.CSharp.Shared.Extensions; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Shared.Extensions; +using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CSharp.ConvertSwitchStatementToExpression { @@ -23,14 +21,14 @@ private sealed class Analyzer : CSharpSyntaxVisitor { private readonly bool _supportsOrPatterns; - private ExpressionSyntax _assignmentTargetOpt; + private ExpressionSyntax? _assignmentTargetOpt; private Analyzer(bool supportsOrPatterns) { _supportsOrPatterns = supportsOrPatterns; } - public static (SyntaxKind nodeToGenerate, VariableDeclaratorSyntax declaratorToRemoveOpt) Analyze( + public static (SyntaxKind nodeToGenerate, VariableDeclaratorSyntax? declaratorToRemoveOpt) Analyze( SwitchStatementSyntax node, SemanticModel semanticModel, out bool shouldRemoveNextStatement) @@ -41,29 +39,35 @@ public static (SyntaxKind nodeToGenerate, VariableDeclaratorSyntax declaratorToR if (nodeToGenerate == SyntaxKind.SimpleAssignmentExpression && analyzer.TryGetVariableDeclaratorAndSymbol(semanticModel) is var (declarator, symbol)) { - if (shouldRemoveNextStatement && - semanticModel.AnalyzeDataFlow(node.GetNextStatement()).DataFlowsIn.Contains(symbol)) + if (shouldRemoveNextStatement && node.GetNextStatement() is StatementSyntax nextStatement) { - // Bail out if data flows into the next statement that we want to move - // For example: - // - // string name = ""; - // switch (index) - // { - // case 0: name = "0"; break; - // case 1: name = "1"; break; - // } - // throw new Exception(name); - // - return default; + var dataFlow = semanticModel.AnalyzeDataFlow(nextStatement); + Contract.ThrowIfNull(dataFlow); + if (dataFlow.DataFlowsIn.Contains(symbol)) + { + // Bail out if data flows into the next statement that we want to move + // For example: + // + // string name = ""; + // switch (index) + // { + // case 0: name = "0"; break; + // case 1: name = "1"; break; + // } + // throw new Exception(name); + // + return default; + } } var declaration = declarator.GetAncestor(); + Contract.ThrowIfNull(declaration); if (declaration.Parent == node.Parent && declarator.Initializer is null) { var beforeSwitch = node.GetPreviousStatement() is StatementSyntax previousStatement ? semanticModel.AnalyzeDataFlow(declaration, previousStatement) : semanticModel.AnalyzeDataFlow(declaration); + Contract.ThrowIfNull(beforeSwitch); if (!beforeSwitch.WrittenInside.Contains(symbol)) { // Move declarator only if it has no initializer and it's not used before switch @@ -204,7 +208,7 @@ private static SyntaxKind Intersect(SyntaxKind left, SyntaxKind right) return default; } - private SyntaxKind AnalyzeNextStatement(StatementSyntax nextStatement) + private SyntaxKind AnalyzeNextStatement(StatementSyntax? nextStatement) { // Only the following "throw" and "return" can be moved into the switch expression. return nextStatement.IsKind(SyntaxKind.ThrowStatement, SyntaxKind.ReturnStatement) From d4df15ab34ff2c271b039e42681224e2b25cad6f Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Tue, 12 Apr 2022 16:25:33 -0700 Subject: [PATCH 31/66] NRT enable C# feature. --- ...SharpInlineDeclarationDiagnosticAnalyzer.cs | 18 +++++++++++------- .../UseCompoundAssignment/Utilities.cs | 2 -- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/src/Analyzers/CSharp/Analyzers/InlineDeclaration/CSharpInlineDeclarationDiagnosticAnalyzer.cs b/src/Analyzers/CSharp/Analyzers/InlineDeclaration/CSharpInlineDeclarationDiagnosticAnalyzer.cs index 997d2a9d21ed7..f7e2a83c723e5 100644 --- a/src/Analyzers/CSharp/Analyzers/InlineDeclaration/CSharpInlineDeclarationDiagnosticAnalyzer.cs +++ b/src/Analyzers/CSharp/Analyzers/InlineDeclaration/CSharpInlineDeclarationDiagnosticAnalyzer.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System.Collections.Immutable; using System.Linq; using System.Linq.Expressions; @@ -14,6 +12,7 @@ using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Shared.Extensions; +using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CSharp.InlineDeclaration { @@ -58,7 +57,7 @@ protected override void InitializeWorker(AnalysisContext context) }); } - private void AnalyzeSyntaxNode(SyntaxNodeAnalysisContext context, INamedTypeSymbol expressionTypeOpt) + private void AnalyzeSyntaxNode(SyntaxNodeAnalysisContext context, INamedTypeSymbol? expressionTypeOpt) { var argumentNode = (ArgumentSyntax)context.Node; var csOptions = (CSharpParseOptions)context.Node.SyntaxTree.Options; @@ -87,7 +86,7 @@ private void AnalyzeSyntaxNode(SyntaxNodeAnalysisContext context, INamedTypeSymb } var argumentExpression = argumentNode.Expression; - if (!argumentExpression.IsKind(SyntaxKind.IdentifierName, out IdentifierNameSyntax identifierName)) + if (!argumentExpression.IsKind(SyntaxKind.IdentifierName, out IdentifierNameSyntax? identifierName)) { // has to be exactly the form "out i". i.e. "out this.i" or "out v[i]" are legal // cases for out-arguments, but could not be converted to an out-variable-declaration. @@ -186,6 +185,8 @@ private void AnalyzeSyntaxNode(SyntaxNodeAnalysisContext context, INamedTypeSymb // Find the scope that the out-declaration variable will live in after we // rewrite things. var outArgumentScope = GetOutArgumentScope(argumentExpression); + if (outArgumentScope == null) + return; if (!outLocalSymbol.CanSafelyMoveLocalToBlock(enclosingBlockOfLocalStatement, outArgumentScope)) { @@ -256,14 +257,17 @@ private static bool WouldCauseDefiniteAssignmentErrors( // // In this case, inlining the 'i' would cause it to longer be definitely // assigned in the WriteLine invocation. + var nextStatement = localStatement.GetNextStatement(); + Contract.ThrowIfNull(nextStatement); var dataFlow = semanticModel.AnalyzeDataFlow( - localStatement.GetNextStatement(), + nextStatement, enclosingBlock.Statements.Last()); + Contract.ThrowIfNull(dataFlow); return dataFlow.DataFlowsIn.Contains(outLocalSymbol); } - private static SyntaxNode GetOutArgumentScope(SyntaxNode argumentExpression) + private static SyntaxNode? GetOutArgumentScope(SyntaxNode argumentExpression) { for (var current = argumentExpression; current != null; current = current.Parent) { @@ -346,7 +350,7 @@ private static bool IsAccessed( break; } - if (descendentNode.IsKind(SyntaxKind.IdentifierName, out IdentifierNameSyntax identifierName)) + if (descendentNode.IsKind(SyntaxKind.IdentifierName, out IdentifierNameSyntax? identifierName)) { // See if this looks like an accessor to the local variable syntactically. if (identifierName.Identifier.ValueText == variableName) diff --git a/src/Analyzers/CSharp/Analyzers/UseCompoundAssignment/Utilities.cs b/src/Analyzers/CSharp/Analyzers/UseCompoundAssignment/Utilities.cs index 33aed0265f62d..80357bd238fc7 100644 --- a/src/Analyzers/CSharp/Analyzers/UseCompoundAssignment/Utilities.cs +++ b/src/Analyzers/CSharp/Analyzers/UseCompoundAssignment/Utilities.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System.Collections.Immutable; using Roslyn.Utilities; From 49a4a6645ec477e52798f0116d61fa404e1804a2 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Tue, 12 Apr 2022 16:32:10 -0700 Subject: [PATCH 32/66] NRT enable C# feature. --- ...AndNullCheckDiagnosticAnalyzer.Analyzer.cs | 19 ++++++++++--------- .../CSharpIsAndCastCheckDiagnosticAnalyzer.cs | 16 ++++++++-------- .../Extensions/SemanticModelExtensions.cs | 12 ++++++++++++ 3 files changed, 30 insertions(+), 17 deletions(-) diff --git a/src/Analyzers/CSharp/Analyzers/UsePatternMatching/CSharpAsAndNullCheckDiagnosticAnalyzer.Analyzer.cs b/src/Analyzers/CSharp/Analyzers/UsePatternMatching/CSharpAsAndNullCheckDiagnosticAnalyzer.Analyzer.cs index fd1f05e8907c9..50f5fb70c5dda 100644 --- a/src/Analyzers/CSharp/Analyzers/UsePatternMatching/CSharpAsAndNullCheckDiagnosticAnalyzer.Analyzer.cs +++ b/src/Analyzers/CSharp/Analyzers/UsePatternMatching/CSharpAsAndNullCheckDiagnosticAnalyzer.Analyzer.cs @@ -2,13 +2,12 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System.Diagnostics; using System.Threading; using Microsoft.CodeAnalysis.CSharp.Extensions; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Shared.Extensions; +using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CSharp.UsePatternMatching { @@ -148,7 +147,7 @@ private bool CanSafelyConvertToPatternMatching() case SyntaxKind.ForStatement: var forStatement = (ForStatementSyntax)current; - if (!forStatement.Condition.Span.Contains(_comparison.Span)) + if (forStatement.Condition is null || !forStatement.Condition.Span.Contains(_comparison.Span)) { // In a for-statement, only the condition expression // can make this definitely assigned in the loop body. @@ -169,7 +168,7 @@ private bool CanSafelyConvertToPatternMatching() if (oppositeStatement != null) { - var dataFlow = _semanticModel.AnalyzeDataFlow(oppositeStatement); + var dataFlow = _semanticModel.AnalyzeRequiredDataFlow(oppositeStatement); if (dataFlow.DataFlowsIn.Contains(_localSymbol)) { // Access before assignment is not safe in the opposite branch @@ -196,7 +195,7 @@ private bool CanSafelyConvertToPatternMatching() } if (!defAssignedWhenTrue && - !_semanticModel.AnalyzeControlFlow(ifStatement.Statement).EndPointIsReachable) + !_semanticModel.AnalyzeRequiredControlFlow(ifStatement.Statement).EndPointIsReachable) { // Access before assignment here is only valid if we have a negative // pattern-matching in an if-statement with an unreachable endpoint. @@ -286,7 +285,7 @@ private bool CheckStatement(StatementSyntax statement) // This is either an embedded statement or parented by a block. // If we're parented by a block, then that block will be the scope // of the new variable. Otherwise the scope is the statement itself. - if (statement.Parent.IsKind(SyntaxKind.Block, out BlockSyntax block)) + if (statement.Parent.IsKind(SyntaxKind.Block, out BlockSyntax? block)) { // Check if the local is accessed before assignment // in the subsequent statements. If so, this can't @@ -332,7 +331,7 @@ private bool IsAccessedOutOfScope(SyntaxNode scope) continue; } - if (descendentNode.IsKind(SyntaxKind.IdentifierName, out IdentifierNameSyntax identifierName) && + if (descendentNode.IsKind(SyntaxKind.IdentifierName, out IdentifierNameSyntax? identifierName) && identifierName.Identifier.ValueText == variableName && _localSymbol.Equals(_semanticModel.GetSymbolInfo(identifierName, _cancellationToken).Symbol)) { @@ -362,7 +361,7 @@ private bool LocalFlowsIn(SyntaxNode statementOrExpression) return _semanticModel.AnalyzeDataFlow(statementOrExpression).DataFlowsIn.Contains(_localSymbol); } - private bool LocalFlowsIn(StatementSyntax firstStatement, StatementSyntax lastStatement) + private bool LocalFlowsIn(StatementSyntax? firstStatement, StatementSyntax? lastStatement) { if (firstStatement == null || lastStatement == null) { @@ -374,7 +373,9 @@ private bool LocalFlowsIn(StatementSyntax firstStatement, StatementSyntax lastSt return false; } - return _semanticModel.AnalyzeDataFlow(firstStatement, lastStatement).DataFlowsIn.Contains(_localSymbol); + var dataFlow = _semanticModel.AnalyzeDataFlow(firstStatement, lastStatement); + Contract.ThrowIfNull(dataFlow); + return dataFlow.DataFlowsIn.Contains(_localSymbol); } } } diff --git a/src/Analyzers/CSharp/Analyzers/UsePatternMatching/CSharpIsAndCastCheckDiagnosticAnalyzer.cs b/src/Analyzers/CSharp/Analyzers/UsePatternMatching/CSharpIsAndCastCheckDiagnosticAnalyzer.cs index 7a66739e9247c..099d356174092 100644 --- a/src/Analyzers/CSharp/Analyzers/UsePatternMatching/CSharpIsAndCastCheckDiagnosticAnalyzer.cs +++ b/src/Analyzers/CSharp/Analyzers/UsePatternMatching/CSharpIsAndCastCheckDiagnosticAnalyzer.cs @@ -2,9 +2,8 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System.Collections.Immutable; +using System.Diagnostics.CodeAnalysis; using System.Linq; using Microsoft.CodeAnalysis.CodeStyle; using Microsoft.CodeAnalysis.CSharp.CodeStyle; @@ -12,6 +11,7 @@ using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Shared.Extensions; +using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CSharp.UsePatternMatching { @@ -102,7 +102,7 @@ private void SyntaxNodeAction(SyntaxNodeAnalysisContext syntaxContext) } var semanticModel = syntaxContext.SemanticModel; - var localSymbol = (ILocalSymbol)semanticModel.GetDeclaredSymbol(declarator); + var localSymbol = (ILocalSymbol)semanticModel.GetRequiredDeclaredSymbol(declarator, cancellationToken); var isType = semanticModel.GetTypeInfo(castExpression.Type).Type; if (isType.IsNullable()) @@ -153,10 +153,10 @@ private void SyntaxNodeAction(SyntaxNodeAnalysisContext syntaxContext) public static bool TryGetPatternPieces( BinaryExpressionSyntax isExpression, - out IfStatementSyntax ifStatement, - out LocalDeclarationStatementSyntax localDeclarationStatement, - out VariableDeclaratorSyntax declarator, - out CastExpressionSyntax castExpression) + [NotNullWhen(true)] out IfStatementSyntax? ifStatement, + [NotNullWhen(true)] out LocalDeclarationStatementSyntax? localDeclarationStatement, + [NotNullWhen(true)] out VariableDeclaratorSyntax? declarator, + [NotNullWhen(true)] out CastExpressionSyntax? castExpression) { localDeclarationStatement = null; declarator = null; @@ -168,7 +168,7 @@ public static bool TryGetPatternPieces( return false; } - if (!ifStatement.Statement.IsKind(SyntaxKind.Block, out BlockSyntax ifBlock)) + if (!ifStatement.Statement.IsKind(SyntaxKind.Block, out BlockSyntax? ifBlock)) { return false; } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/SemanticModelExtensions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/SemanticModelExtensions.cs index 5f12697502048..60b0d549a077a 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/SemanticModelExtensions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/SemanticModelExtensions.cs @@ -23,6 +23,18 @@ internal static partial class SemanticModelExtensions public static SymbolInfo GetSymbolInfo(this SemanticModel semanticModel, SyntaxToken token, CancellationToken cancellationToken) => semanticModel.GetSymbolInfo(token.Parent!, cancellationToken); + public static DataFlowAnalysis AnalyzeRequiredDataFlow(this SemanticModel semanticModel, SyntaxNode statementOrExpression) + => semanticModel.AnalyzeDataFlow(statementOrExpression) ?? throw new InvalidOperationException(); + + public static DataFlowAnalysis AnalyzeRequiredDataFlow(this SemanticModel semanticModel, SyntaxNode firstStatement, SyntaxNode lastStatement) + => semanticModel.AnalyzeDataFlow(firstStatement, lastStatement) ?? throw new InvalidOperationException(); + + public static ControlFlowAnalysis AnalyzeRequiredControlFlow(this SemanticModel semanticModel, SyntaxNode statement) + => semanticModel.AnalyzeControlFlow(statement) ?? throw new InvalidOperationException(); + + public static ControlFlowAnalysis AnalyzeRequiredControlFlow(this SemanticModel semanticModel, SyntaxNode firstStatement, SyntaxNode lastStatement) + => semanticModel.AnalyzeControlFlow(firstStatement, lastStatement) ?? throw new InvalidOperationException(); + public static ISymbol GetRequiredDeclaredSymbol(this SemanticModel semanticModel, SyntaxNode declaration, CancellationToken cancellationToken) { return semanticModel.GetDeclaredSymbol(declaration, cancellationToken) From 737b3f563cd423a85d2f88f81665f5dd67f91db9 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Tue, 12 Apr 2022 16:33:01 -0700 Subject: [PATCH 33/66] NRT enable C# feature. --- .../CSharpIsAndCastCheckDiagnosticAnalyzer.cs | 1 - .../CodeFixes/AddBraces/CSharpAddBracesCodeFixProvider.cs | 7 +------ 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/src/Analyzers/CSharp/Analyzers/UsePatternMatching/CSharpIsAndCastCheckDiagnosticAnalyzer.cs b/src/Analyzers/CSharp/Analyzers/UsePatternMatching/CSharpIsAndCastCheckDiagnosticAnalyzer.cs index 099d356174092..1cd16f268b061 100644 --- a/src/Analyzers/CSharp/Analyzers/UsePatternMatching/CSharpIsAndCastCheckDiagnosticAnalyzer.cs +++ b/src/Analyzers/CSharp/Analyzers/UsePatternMatching/CSharpIsAndCastCheckDiagnosticAnalyzer.cs @@ -11,7 +11,6 @@ using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Shared.Extensions; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CSharp.UsePatternMatching { diff --git a/src/Analyzers/CSharp/CodeFixes/AddBraces/CSharpAddBracesCodeFixProvider.cs b/src/Analyzers/CSharp/CodeFixes/AddBraces/CSharpAddBracesCodeFixProvider.cs index ef8087a9916c6..cd24fd5a1cac5 100644 --- a/src/Analyzers/CSharp/CodeFixes/AddBraces/CSharpAddBracesCodeFixProvider.cs +++ b/src/Analyzers/CSharp/CodeFixes/AddBraces/CSharpAddBracesCodeFixProvider.cs @@ -2,13 +2,9 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - -using System; using System.Collections.Immutable; using System.Composition; using System.Diagnostics.CodeAnalysis; -using System.Linq; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeActions; @@ -16,7 +12,6 @@ using Microsoft.CodeAnalysis.CSharp.Extensions; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Editing; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CSharp.Diagnostics.AddBraces { @@ -54,7 +49,7 @@ protected override Task FixAllAsync( editor.ReplaceNode(statement, (currentStatement, g) => { var embeddedStatement = currentStatement.GetEmbeddedStatement(); - return currentStatement.ReplaceNode(embeddedStatement, SyntaxFactory.Block(embeddedStatement)); + return embeddedStatement is null ? currentStatement : currentStatement.ReplaceNode(embeddedStatement, SyntaxFactory.Block(embeddedStatement)); }); } From 2c6f7d80676f90c2910358a8746afc43f84a0bde Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Tue, 12 Apr 2022 16:33:13 -0700 Subject: [PATCH 34/66] NRT enable C# feature. --- .../CSharpAddObsoleteAttributeCodeFixProvider.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Analyzers/CSharp/CodeFixes/AddObsoleteAttribute/CSharpAddObsoleteAttributeCodeFixProvider.cs b/src/Analyzers/CSharp/CodeFixes/AddObsoleteAttribute/CSharpAddObsoleteAttributeCodeFixProvider.cs index 9725a9d8aaad7..a038658dc1c77 100644 --- a/src/Analyzers/CSharp/CodeFixes/AddObsoleteAttribute/CSharpAddObsoleteAttributeCodeFixProvider.cs +++ b/src/Analyzers/CSharp/CodeFixes/AddObsoleteAttribute/CSharpAddObsoleteAttributeCodeFixProvider.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System; using System.Collections.Immutable; using System.Composition; From 296f1b6a6953e6336c0e2d8b22464ec80407e5bb Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Tue, 12 Apr 2022 16:35:14 -0700 Subject: [PATCH 35/66] NRT enable C# feature. --- ...pAsAndNullCheckDiagnosticAnalyzer.Analyzer.cs | 16 ++++++++-------- .../CSharpAliasAmbiguousTypeCodeFixProvider.cs | 2 -- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/src/Analyzers/CSharp/Analyzers/UsePatternMatching/CSharpAsAndNullCheckDiagnosticAnalyzer.Analyzer.cs b/src/Analyzers/CSharp/Analyzers/UsePatternMatching/CSharpAsAndNullCheckDiagnosticAnalyzer.Analyzer.cs index 50f5fb70c5dda..e3f2b380be52e 100644 --- a/src/Analyzers/CSharp/Analyzers/UsePatternMatching/CSharpAsAndNullCheckDiagnosticAnalyzer.Analyzer.cs +++ b/src/Analyzers/CSharp/Analyzers/UsePatternMatching/CSharpAsAndNullCheckDiagnosticAnalyzer.Analyzer.cs @@ -32,10 +32,10 @@ private Analyzer( SyntaxNode enclosingBlock, CancellationToken cancellationToken) { - Debug.Assert(semanticModel != null); - Debug.Assert(localSymbol != null); - Debug.Assert(comparison != null); - Debug.Assert(operand != null); + Contract.ThrowIfNull(semanticModel); + Contract.ThrowIfNull(localSymbol); + Contract.ThrowIfNull(comparison); + Contract.ThrowIfNull(operand); Debug.Assert(localStatement.IsKind(SyntaxKind.LocalDeclarationStatement)); Debug.Assert(enclosingBlock.IsKind(SyntaxKind.Block, SyntaxKind.SwitchSection)); @@ -172,7 +172,7 @@ private bool CanSafelyConvertToPatternMatching() if (dataFlow.DataFlowsIn.Contains(_localSymbol)) { // Access before assignment is not safe in the opposite branch - // as the variable is not definitely assgined at this point. + // as the variable is not definitely assigned at this point. // For example: // // if (o is string x) { } @@ -280,7 +280,7 @@ private bool CheckExpression(ExpressionSyntax exprsesion) private bool CheckStatement(StatementSyntax statement) { - Debug.Assert(statement != null); + Contract.ThrowIfNull(statement); // This is either an embedded statement or parented by a block. // If we're parented by a block, then that block will be the scope @@ -306,14 +306,14 @@ private bool CheckStatement(StatementSyntax statement) private bool IsAccessedOutOfScope(SyntaxNode scope) { - Debug.Assert(scope != null); + Contract.ThrowIfNull(scope); var localStatementStart = _localStatement.SpanStart; var comparisonSpanStart = _comparison.SpanStart; var variableName = _localSymbol.Name; var scopeSpan = scope.Span; - // Iterate over all descendent nodes to find possible out-of-scope references. + // Iterate over all descendant nodes to find possible out-of-scope references. foreach (var descendentNode in _enclosingBlock.DescendantNodes()) { var descendentNodeSpanStart = descendentNode.SpanStart; diff --git a/src/Analyzers/CSharp/CodeFixes/AliasAmbiguousType/CSharpAliasAmbiguousTypeCodeFixProvider.cs b/src/Analyzers/CSharp/CodeFixes/AliasAmbiguousType/CSharpAliasAmbiguousTypeCodeFixProvider.cs index c4e8d672b8c6d..132a4e7d27b8e 100644 --- a/src/Analyzers/CSharp/CodeFixes/AliasAmbiguousType/CSharpAliasAmbiguousTypeCodeFixProvider.cs +++ b/src/Analyzers/CSharp/CodeFixes/AliasAmbiguousType/CSharpAliasAmbiguousTypeCodeFixProvider.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System.Collections.Immutable; using System.Composition; using System.Diagnostics.CodeAnalysis; From 307e74f0e30c51efd9c4736c3a245eedd72da5e3 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Tue, 12 Apr 2022 16:36:28 -0700 Subject: [PATCH 36/66] NRT enable C# feature. --- .../HideBase/HideBaseCodeFixProvider.AddNewKeywordAction.cs | 5 ++--- .../CSharp/Services/SyntaxFacts/CSharpSyntaxFacts.cs | 1 + 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Analyzers/CSharp/CodeFixes/HideBase/HideBaseCodeFixProvider.AddNewKeywordAction.cs b/src/Analyzers/CSharp/CodeFixes/HideBase/HideBaseCodeFixProvider.AddNewKeywordAction.cs index d63145094df67..8c2e1915c9af0 100644 --- a/src/Analyzers/CSharp/CodeFixes/HideBase/HideBaseCodeFixProvider.AddNewKeywordAction.cs +++ b/src/Analyzers/CSharp/CodeFixes/HideBase/HideBaseCodeFixProvider.AddNewKeywordAction.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System.Linq; using System.Threading.Tasks; using System.Threading; @@ -13,6 +11,7 @@ using Roslyn.Utilities; using Microsoft.CodeAnalysis.CSharp.LanguageServices; using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Shared.Extensions; #if CODE_STYLE using OptionSet = Microsoft.CodeAnalysis.Diagnostics.AnalyzerConfigOptions; @@ -39,7 +38,7 @@ public AddNewKeywordAction(Document document, SyntaxNode node) protected override async Task GetChangedDocumentAsync(CancellationToken cancellationToken) { - var root = await _document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); + var root = await _document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); #if CODE_STYLE var options = _document.Project.AnalyzerOptions.GetAnalyzerOptionSet(_node.SyntaxTree, cancellationToken); diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Services/SyntaxFacts/CSharpSyntaxFacts.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Services/SyntaxFacts/CSharpSyntaxFacts.cs index 8167de3bf00cd..c5ca7b07f2086 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Services/SyntaxFacts/CSharpSyntaxFacts.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Services/SyntaxFacts/CSharpSyntaxFacts.cs @@ -1381,6 +1381,7 @@ public bool ContainsInterleavedDirective(TextSpan span, SyntaxToken token, Cance public SyntaxTokenList GetModifiers(SyntaxNode? node) => node.GetModifiers(); + [return: NotNullIfNotNull("node")] public SyntaxNode? WithModifiers(SyntaxNode? node, SyntaxTokenList modifiers) => node.WithModifiers(modifiers); From f90082153a7996ffd900abef42280dd5e8bdfd68 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Tue, 12 Apr 2022 16:37:41 -0700 Subject: [PATCH 37/66] NRT enable C# feature. --- .../HideBase/HideBaseCodeFixProvider.cs | 19 ++++--------------- 1 file changed, 4 insertions(+), 15 deletions(-) diff --git a/src/Analyzers/CSharp/CodeFixes/HideBase/HideBaseCodeFixProvider.cs b/src/Analyzers/CSharp/CodeFixes/HideBase/HideBaseCodeFixProvider.cs index 0ba96c6ebf6f3..91f4ad6c7aee0 100644 --- a/src/Analyzers/CSharp/CodeFixes/HideBase/HideBaseCodeFixProvider.cs +++ b/src/Analyzers/CSharp/CodeFixes/HideBase/HideBaseCodeFixProvider.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System.Collections.Immutable; using System.Composition; using System.Diagnostics.CodeAnalysis; @@ -33,28 +31,19 @@ public override FixAllProvider GetFixAllProvider() public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) { - var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false); + var root = await context.Document.GetRequiredSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false); var diagnostic = context.Diagnostics.First(); var diagnosticSpan = diagnostic.Location.SourceSpan; var token = root.FindToken(diagnosticSpan.Start); - SyntaxNode originalNode = token.GetAncestor(); - - if (originalNode == null) - { - originalNode = token.GetAncestor(); - } - if (originalNode == null) - { - originalNode = token.GetAncestor(); - } + var originalNode = token.GetAncestor() ?? + token.GetAncestor() ?? + (SyntaxNode?)token.GetAncestor(); if (originalNode == null) - { return; - } context.RegisterCodeFix(new AddNewKeywordAction(context.Document, originalNode), context.Diagnostics); } From c7124ea967eabb776483bf2669f22744f614ab99 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Tue, 12 Apr 2022 16:40:09 -0700 Subject: [PATCH 38/66] NRT enable C# feature. --- ...SharpChangeToIEnumerableCodeFixProvider.cs | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/src/Analyzers/CSharp/CodeFixes/Iterator/CSharpChangeToIEnumerableCodeFixProvider.cs b/src/Analyzers/CSharp/CodeFixes/Iterator/CSharpChangeToIEnumerableCodeFixProvider.cs index 2a038c1581ccc..23fe6f1c0a2a3 100644 --- a/src/Analyzers/CSharp/CodeFixes/Iterator/CSharpChangeToIEnumerableCodeFixProvider.cs +++ b/src/Analyzers/CSharp/CodeFixes/Iterator/CSharpChangeToIEnumerableCodeFixProvider.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System.Collections; using System.Collections.Generic; using System.Collections.Immutable; @@ -41,9 +39,9 @@ public override ImmutableArray FixableDiagnosticIds get { return ImmutableArray.Create(CS1624); } } - protected override async Task GetCodeFixAsync(SyntaxNode root, SyntaxNode node, Document document, Diagnostic diagnostics, CancellationToken cancellationToken) + protected override async Task GetCodeFixAsync(SyntaxNode root, SyntaxNode node, Document document, Diagnostic diagnostics, CancellationToken cancellationToken) { - var model = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); + var model = await document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false); var methodSymbol = model.GetDeclaredSymbol(node, cancellationToken) as IMethodSymbol; // IMethod symbol can either be a regular method or an accessor if (methodSymbol?.ReturnType == null || methodSymbol.ReturnsVoid) @@ -65,9 +63,9 @@ protected override async Task GetCodeFixAsync(SyntaxNode root, Synta var typeArg = type.GetTypeArguments().First(); ienumerableGenericSymbol = ienumerableGenericSymbol.Construct(typeArg); } - else if (arity == 0 && type is IArrayTypeSymbol) + else if (arity == 0 && type is IArrayTypeSymbol arrayType) { - ienumerableGenericSymbol = ienumerableGenericSymbol.Construct((type as IArrayTypeSymbol).ElementType); + ienumerableGenericSymbol = ienumerableGenericSymbol.Construct(arrayType.ElementType); } else { @@ -80,7 +78,7 @@ protected override async Task GetCodeFixAsync(SyntaxNode root, Synta } var newReturnType = ienumerableGenericSymbol.GenerateTypeSyntax(); - Document newDocument = null; + Document? newDocument = null; var newMethodDeclarationSyntax = (node as MethodDeclarationSyntax)?.WithReturnType(newReturnType); if (newMethodDeclarationSyntax != null) { @@ -93,13 +91,13 @@ protected override async Task GetCodeFixAsync(SyntaxNode root, Synta newDocument = document.WithSyntaxRoot(root.ReplaceNode(node, newOperator)); } - var oldAccessor = (node?.Parent?.Parent as PropertyDeclarationSyntax); + var oldAccessor = node.Parent?.Parent as PropertyDeclarationSyntax; if (oldAccessor != null) { newDocument = document.WithSyntaxRoot(root.ReplaceNode(oldAccessor, oldAccessor.WithType(newReturnType))); } - var oldIndexer = (node?.Parent?.Parent as IndexerDeclarationSyntax); + var oldIndexer = node.Parent?.Parent as IndexerDeclarationSyntax; if (oldIndexer != null) { newDocument = document.WithSyntaxRoot(root.ReplaceNode(oldIndexer, oldIndexer.WithType(newReturnType))); @@ -117,7 +115,10 @@ protected override async Task GetCodeFixAsync(SyntaxNode root, Synta return CodeAction.Create(title, _ => Task.FromResult(newDocument), title); } - private static bool TryGetIEnumerableSymbols(SemanticModel model, out INamedTypeSymbol ienumerableSymbol, out INamedTypeSymbol ienumerableGenericSymbol) + private static bool TryGetIEnumerableSymbols( + SemanticModel model, + [NotNullWhen(true)] out INamedTypeSymbol? ienumerableSymbol, + [NotNullWhen(true)] out INamedTypeSymbol? ienumerableGenericSymbol) { ienumerableSymbol = model.Compilation.GetTypeByMetadataName(typeof(IEnumerable).FullName); ienumerableGenericSymbol = model.Compilation.GetTypeByMetadataName(typeof(IEnumerable<>).FullName); From cd563f1a25b09b14257a285793c1a2e6105112bb Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Tue, 12 Apr 2022 16:41:49 -0700 Subject: [PATCH 39/66] NRT enable C# feature. --- .../CSharpAliasAmbiguousTypeCodeFixProvider.cs | 2 +- .../CSharpMakeFieldReadonlyCodeFixProvider.cs | 4 +--- .../AbstractMakeFieldReadonlyCodeFixProvider.cs | 2 +- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/Analyzers/CSharp/CodeFixes/AliasAmbiguousType/CSharpAliasAmbiguousTypeCodeFixProvider.cs b/src/Analyzers/CSharp/CodeFixes/AliasAmbiguousType/CSharpAliasAmbiguousTypeCodeFixProvider.cs index 132a4e7d27b8e..634a261600da3 100644 --- a/src/Analyzers/CSharp/CodeFixes/AliasAmbiguousType/CSharpAliasAmbiguousTypeCodeFixProvider.cs +++ b/src/Analyzers/CSharp/CodeFixes/AliasAmbiguousType/CSharpAliasAmbiguousTypeCodeFixProvider.cs @@ -30,6 +30,6 @@ public override ImmutableArray FixableDiagnosticIds => ImmutableArray.Create(CS0104); protected override string GetTextPreviewOfChange(string alias, ITypeSymbol typeSymbol) - => $"using { alias } = { typeSymbol.ToNameDisplayString() };"; + => $"using {alias} = {typeSymbol.ToNameDisplayString()};"; } } diff --git a/src/Analyzers/CSharp/CodeFixes/MakeFieldReadonly/CSharpMakeFieldReadonlyCodeFixProvider.cs b/src/Analyzers/CSharp/CodeFixes/MakeFieldReadonly/CSharpMakeFieldReadonlyCodeFixProvider.cs index a84889c6802b1..f4d6fcf13e19a 100644 --- a/src/Analyzers/CSharp/CodeFixes/MakeFieldReadonly/CSharpMakeFieldReadonlyCodeFixProvider.cs +++ b/src/Analyzers/CSharp/CodeFixes/MakeFieldReadonly/CSharpMakeFieldReadonlyCodeFixProvider.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System.Collections.Immutable; using System.Composition; using System.Diagnostics.CodeAnalysis; @@ -23,7 +21,7 @@ public CSharpMakeFieldReadonlyCodeFixProvider() { } - protected override SyntaxNode GetInitializerNode(VariableDeclaratorSyntax declaration) + protected override SyntaxNode? GetInitializerNode(VariableDeclaratorSyntax declaration) => declaration.Initializer?.Value; protected override ImmutableList GetVariableDeclarators(FieldDeclarationSyntax fieldDeclaration) diff --git a/src/Analyzers/Core/CodeFixes/MakeFieldReadonly/AbstractMakeFieldReadonlyCodeFixProvider.cs b/src/Analyzers/Core/CodeFixes/MakeFieldReadonly/AbstractMakeFieldReadonlyCodeFixProvider.cs index 585148d8e5855..b7895ec24c303 100644 --- a/src/Analyzers/Core/CodeFixes/MakeFieldReadonly/AbstractMakeFieldReadonlyCodeFixProvider.cs +++ b/src/Analyzers/Core/CodeFixes/MakeFieldReadonly/AbstractMakeFieldReadonlyCodeFixProvider.cs @@ -26,7 +26,7 @@ internal abstract class AbstractMakeFieldReadonlyCodeFixProvider FixableDiagnosticIds => ImmutableArray.Create(IDEDiagnosticIds.MakeFieldReadonlyDiagnosticId); - protected abstract SyntaxNode GetInitializerNode(TSymbolSyntax declaration); + protected abstract SyntaxNode? GetInitializerNode(TSymbolSyntax declaration); protected abstract ImmutableList GetVariableDeclarators(TFieldDeclarationSyntax declaration); public override Task RegisterCodeFixesAsync(CodeFixContext context) From b9038b17effc96c498019f3c81346966b6204beb Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Tue, 12 Apr 2022 16:42:36 -0700 Subject: [PATCH 40/66] NRT enable C# feature. --- .../CSharpMakeStatementAsynchronousCodeFixProvider.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/Analyzers/CSharp/CodeFixes/MakeStatementAsynchronous/CSharpMakeStatementAsynchronousCodeFixProvider.cs b/src/Analyzers/CSharp/CodeFixes/MakeStatementAsynchronous/CSharpMakeStatementAsynchronousCodeFixProvider.cs index 988594019b8fb..1b831d8fcd095 100644 --- a/src/Analyzers/CSharp/CodeFixes/MakeStatementAsynchronous/CSharpMakeStatementAsynchronousCodeFixProvider.cs +++ b/src/Analyzers/CSharp/CodeFixes/MakeStatementAsynchronous/CSharpMakeStatementAsynchronousCodeFixProvider.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System; using System.Collections.Immutable; using System.Composition; @@ -37,7 +35,7 @@ public CSharpMakeStatementAsynchronousCodeFixProvider() public override async Task RegisterCodeFixesAsync(CodeFixContext context) { var diagnostic = context.Diagnostics.First(); - var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false); + var root = await context.Document.GetRequiredSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false); var node = root.FindNode(diagnostic.Location.SourceSpan, getInnermostNodeForTie: true); var constructToFix = TryGetStatementToFix(node); @@ -98,7 +96,7 @@ private static void MakeStatementAsynchronous(SyntaxEditor editor, SyntaxNode st editor.ReplaceNode(statementToFix, newStatement); } - private static SyntaxNode TryGetStatementToFix(SyntaxNode node) + private static SyntaxNode? TryGetStatementToFix(SyntaxNode node) { if (node.IsParentKind(SyntaxKind.ForEachStatement, SyntaxKind.ForEachVariableStatement, SyntaxKind.UsingStatement)) { From 1cc79d67fef4aed4fb1398b5580d7676fe4a7ecf Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Tue, 12 Apr 2022 16:43:08 -0700 Subject: [PATCH 41/66] NRT enable C# feature. --- .../CSharpMakeStructFieldsWritableCodeFixProvider.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Analyzers/CSharp/CodeFixes/MakeStructFieldsWritable/CSharpMakeStructFieldsWritableCodeFixProvider.cs b/src/Analyzers/CSharp/CodeFixes/MakeStructFieldsWritable/CSharpMakeStructFieldsWritableCodeFixProvider.cs index 4b4aed30248fa..e2af2bda286e2 100644 --- a/src/Analyzers/CSharp/CodeFixes/MakeStructFieldsWritable/CSharpMakeStructFieldsWritableCodeFixProvider.cs +++ b/src/Analyzers/CSharp/CodeFixes/MakeStructFieldsWritable/CSharpMakeStructFieldsWritableCodeFixProvider.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System; using System.Collections.Immutable; using System.Composition; From 9c176d37240018f4403fb34742aba34b6fbe68c4 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Tue, 12 Apr 2022 16:43:32 -0700 Subject: [PATCH 42/66] NRT enable C# feature. --- .../OrderModifiers/CSharpOrderModifiersCodeFixProvider.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Analyzers/CSharp/CodeFixes/OrderModifiers/CSharpOrderModifiersCodeFixProvider.cs b/src/Analyzers/CSharp/CodeFixes/OrderModifiers/CSharpOrderModifiersCodeFixProvider.cs index edde1e1bdca2d..61753e17ce410 100644 --- a/src/Analyzers/CSharp/CodeFixes/OrderModifiers/CSharpOrderModifiersCodeFixProvider.cs +++ b/src/Analyzers/CSharp/CodeFixes/OrderModifiers/CSharpOrderModifiersCodeFixProvider.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System.Collections.Immutable; using System.Composition; using System.Diagnostics.CodeAnalysis; From 2158cef0d0c56653346162d7cd229fee681388bb Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Tue, 12 Apr 2022 16:44:25 -0700 Subject: [PATCH 43/66] NRT enable C# feature. --- .../CSharpQualifyMemberAccessCodeFixProvider.cs | 4 +--- .../AbstractQualifyMemberAccessCodeFixProvider.cs | 3 +-- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/src/Analyzers/CSharp/CodeFixes/QualifyMemberAccess/CSharpQualifyMemberAccessCodeFixProvider.cs b/src/Analyzers/CSharp/CodeFixes/QualifyMemberAccess/CSharpQualifyMemberAccessCodeFixProvider.cs index 6a10ad7db6352..81c2b7d769bdc 100644 --- a/src/Analyzers/CSharp/CodeFixes/QualifyMemberAccess/CSharpQualifyMemberAccessCodeFixProvider.cs +++ b/src/Analyzers/CSharp/CodeFixes/QualifyMemberAccess/CSharpQualifyMemberAccessCodeFixProvider.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System.Composition; using System.Diagnostics.CodeAnalysis; using System.Threading; @@ -24,7 +22,7 @@ public CSharpQualifyMemberAccessCodeFixProvider() { } - protected override SimpleNameSyntax GetNode(Diagnostic diagnostic, CancellationToken cancellationToken) + protected override SimpleNameSyntax? GetNode(Diagnostic diagnostic, CancellationToken cancellationToken) { var node = diagnostic.Location.FindNode(getInnermostNodeForTie: true, cancellationToken); switch (node) diff --git a/src/Analyzers/Core/CodeFixes/QualifyMemberAccess/AbstractQualifyMemberAccessCodeFixProvider.cs b/src/Analyzers/Core/CodeFixes/QualifyMemberAccess/AbstractQualifyMemberAccessCodeFixProvider.cs index 30b912a1be580..53f0e7b7d8986 100644 --- a/src/Analyzers/Core/CodeFixes/QualifyMemberAccess/AbstractQualifyMemberAccessCodeFixProvider.cs +++ b/src/Analyzers/Core/CodeFixes/QualifyMemberAccess/AbstractQualifyMemberAccessCodeFixProvider.cs @@ -20,6 +20,7 @@ internal abstract class AbstractQualifyMemberAccessCodeFixprovider FixableDiagnosticIds => ImmutableArray.Create(IDEDiagnosticIds.AddQualificationDiagnosticId); @@ -54,7 +55,5 @@ protected override Task FixAllAsync( return Task.CompletedTask; } - - protected abstract TSimpleNameSyntax GetNode(Diagnostic diagnostic, CancellationToken cancellationToken); } } From 0c1f29343b651e5bd26e2af3d46bf76c2b62ec9d Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Wed, 13 Apr 2022 01:23:34 -0700 Subject: [PATCH 44/66] NRT --- .../CSharpChangeToIEnumerableCodeFixProvider.cs | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/src/Analyzers/CSharp/CodeFixes/Iterator/CSharpChangeToIEnumerableCodeFixProvider.cs b/src/Analyzers/CSharp/CodeFixes/Iterator/CSharpChangeToIEnumerableCodeFixProvider.cs index 23fe6f1c0a2a3..ea43a55cfdc0d 100644 --- a/src/Analyzers/CSharp/CodeFixes/Iterator/CSharpChangeToIEnumerableCodeFixProvider.cs +++ b/src/Analyzers/CSharp/CodeFixes/Iterator/CSharpChangeToIEnumerableCodeFixProvider.cs @@ -120,16 +120,10 @@ private static bool TryGetIEnumerableSymbols( [NotNullWhen(true)] out INamedTypeSymbol? ienumerableSymbol, [NotNullWhen(true)] out INamedTypeSymbol? ienumerableGenericSymbol) { - ienumerableSymbol = model.Compilation.GetTypeByMetadataName(typeof(IEnumerable).FullName); - ienumerableGenericSymbol = model.Compilation.GetTypeByMetadataName(typeof(IEnumerable<>).FullName); + ienumerableSymbol = model.Compilation.GetTypeByMetadataName(typeof(IEnumerable).FullName!); + ienumerableGenericSymbol = model.Compilation.GetTypeByMetadataName(typeof(IEnumerable<>).FullName!); - if (ienumerableGenericSymbol == null || - ienumerableSymbol == null) - { - return false; - } - - return true; + return ienumerableGenericSymbol != null && ienumerableSymbol != null; } } } From 51bb5e5f2e7683d65c5f796039f542b8065f8ab5 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Wed, 13 Apr 2022 01:24:32 -0700 Subject: [PATCH 45/66] NRT --- .../CSharpInlineDeclarationDiagnosticAnalyzer.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Analyzers/CSharp/Analyzers/InlineDeclaration/CSharpInlineDeclarationDiagnosticAnalyzer.cs b/src/Analyzers/CSharp/Analyzers/InlineDeclaration/CSharpInlineDeclarationDiagnosticAnalyzer.cs index f7e2a83c723e5..958e0a7e64a85 100644 --- a/src/Analyzers/CSharp/Analyzers/InlineDeclaration/CSharpInlineDeclarationDiagnosticAnalyzer.cs +++ b/src/Analyzers/CSharp/Analyzers/InlineDeclaration/CSharpInlineDeclarationDiagnosticAnalyzer.cs @@ -51,13 +51,13 @@ protected override void InitializeWorker(AnalysisContext context) context.RegisterCompilationStartAction(compilationContext => { var compilation = compilationContext.Compilation; - var expressionTypeOpt = compilation.GetTypeByMetadataName(typeof(Expression<>).FullName); + var expressionType = compilation.GetTypeByMetadataName(typeof(Expression<>).FullName!); compilationContext.RegisterSyntaxNodeAction( - syntaxContext => AnalyzeSyntaxNode(syntaxContext, expressionTypeOpt), SyntaxKind.Argument); + syntaxContext => AnalyzeSyntaxNode(syntaxContext, expressionType), SyntaxKind.Argument); }); } - private void AnalyzeSyntaxNode(SyntaxNodeAnalysisContext context, INamedTypeSymbol? expressionTypeOpt) + private void AnalyzeSyntaxNode(SyntaxNodeAnalysisContext context, INamedTypeSymbol? expressionType) { var argumentNode = (ArgumentSyntax)context.Node; var csOptions = (CSharpParseOptions)context.Node.SyntaxTree.Options; @@ -175,7 +175,7 @@ private void AnalyzeSyntaxNode(SyntaxNodeAnalysisContext context, INamedTypeSymb return; } - if (argumentExpression.IsInExpressionTree(semanticModel, expressionTypeOpt, cancellationToken)) + if (argumentExpression.IsInExpressionTree(semanticModel, expressionType, cancellationToken)) { // out-vars are not allowed inside expression-trees. So don't offer to // fix if we're inside one. From 66f8aeb9bf650337e9246d1eed83366c3e93e541 Mon Sep 17 00:00:00 2001 From: CyrusNajmabadi Date: Wed, 13 Apr 2022 13:42:43 -0700 Subject: [PATCH 46/66] Share the indices we create for files that do not have PP directives in them (#60693) * Share the indices we create for files that do not have PP directives in them * Perf tests * Use syntax kinds * Cleanup * Cleanup * fix comment * Update comment * Update syntax kinds * Fix --- .../IdeCoreBenchmarks/NavigateToBenchmarks.cs | 9 +- .../FindSymbols/Shared/AbstractSyntaxIndex.cs | 66 ++++++++++++- .../Shared/AbstractSyntaxIndex_Persistence.cs | 95 ++++++++++++++----- .../Storage/PersistentStorageExtensions.cs | 3 +- .../Services/SyntaxFacts/CSharpSyntaxKinds.cs | 1 + .../Core/Services/SyntaxFacts/ISyntaxKinds.cs | 2 + .../SyntaxFacts/VisualBasicSyntaxKinds.vb | 2 + 7 files changed, 148 insertions(+), 30 deletions(-) diff --git a/src/Tools/IdeCoreBenchmarks/NavigateToBenchmarks.cs b/src/Tools/IdeCoreBenchmarks/NavigateToBenchmarks.cs index 20ccc3f080ca7..64abbca13ab43 100644 --- a/src/Tools/IdeCoreBenchmarks/NavigateToBenchmarks.cs +++ b/src/Tools/IdeCoreBenchmarks/NavigateToBenchmarks.cs @@ -7,6 +7,7 @@ using System; using System.Collections.Generic; using System.Collections.Immutable; +using System.Composition; using System.Diagnostics; using System.IO; using System.Linq; @@ -18,6 +19,7 @@ using Microsoft.Build.Locator; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.FindSymbols; +using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.MSBuild; using Microsoft.CodeAnalysis.NavigateTo; @@ -88,6 +90,7 @@ private async Task LoadSolutionAsync() Console.WriteLine("Opening roslyn. Attach to: " + Process.GetCurrentProcess().Id); var start = DateTime.Now; + var solution = _workspace.OpenSolutionAsync(_solutionPath, progress: null, CancellationToken.None).Result; Console.WriteLine("Finished opening roslyn: " + (DateTime.Now - start)); @@ -110,7 +113,7 @@ public void IterationCleanup() _workspace = null; } - // [Benchmark] + [Benchmark] public async Task RunSerialIndexing() { Console.WriteLine("start profiling now"); @@ -126,6 +129,8 @@ public async Task RunSerialIndexing() } } Console.WriteLine("Serial: " + (DateTime.Now - start)); + Console.WriteLine("Precalculated count: " + SyntaxTreeIndex.PrecalculatedCount); + Console.WriteLine("Computed count: " + SyntaxTreeIndex.ComputedCount); Console.ReadLine(); } @@ -141,7 +146,7 @@ private static async Task WalkTree(Document document) } } - [Benchmark] + // [Benchmark] public async Task RunProjectParallelIndexing() { Console.WriteLine("start profiling now"); diff --git a/src/Workspaces/Core/Portable/FindSymbols/Shared/AbstractSyntaxIndex.cs b/src/Workspaces/Core/Portable/FindSymbols/Shared/AbstractSyntaxIndex.cs index 80d43eb2746c6..5d8fdc2911ada 100644 --- a/src/Workspaces/Core/Portable/FindSymbols/Shared/AbstractSyntaxIndex.cs +++ b/src/Workspaces/Core/Portable/FindSymbols/Shared/AbstractSyntaxIndex.cs @@ -2,9 +2,11 @@ // 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; using System.Runtime.CompilerServices; using System.Threading; using System.Threading.Tasks; +using Microsoft.CodeAnalysis.LanguageServices; using Microsoft.CodeAnalysis.Shared.Extensions; using Roslyn.Utilities; @@ -76,12 +78,12 @@ protected static async ValueTask GetRequiredIndexAsync(Document document if (!document.SupportsSyntaxTree) return null; - var checksum = await GetChecksumAsync(document, cancellationToken).ConfigureAwait(false); + var (textChecksum, textAndDirectivesChecksum) = await GetChecksumsAsync(document, cancellationToken).ConfigureAwait(false); // Check if we have an index for a previous version of this document. If our // checksums match, we can just use that. if (s_documentIdToIndex.TryGetValue(document.Id, out var index) && - index?.Checksum == checksum) + (index?.Checksum == textChecksum || index?.Checksum == textAndDirectivesChecksum)) { // The previous index we stored with this documentId is still valid. Just // return that. @@ -89,12 +91,12 @@ protected static async ValueTask GetRequiredIndexAsync(Document document } // What we have in memory isn't valid. Try to load from the persistence service. - index = await LoadAsync(document, checksum, read, cancellationToken).ConfigureAwait(false); + index = await LoadAsync(document, textChecksum, textAndDirectivesChecksum, read, cancellationToken).ConfigureAwait(false); if (index != null || loadOnly) return index; // alright, we don't have cached information, re-calculate them here. - index = await CreateIndexAsync(document, checksum, create, cancellationToken).ConfigureAwait(false); + index = await CreateIndexAsync(document, textChecksum, textAndDirectivesChecksum, create, cancellationToken).ConfigureAwait(false); // okay, persist this info await index.SaveAsync(document, cancellationToken).ConfigureAwait(false); @@ -103,12 +105,66 @@ protected static async ValueTask GetRequiredIndexAsync(Document document } private static async Task CreateIndexAsync( - Document document, Checksum checksum, IndexCreator create, CancellationToken cancellationToken) + Document document, + Checksum textChecksum, + Checksum textAndDirectivesChecksum, + IndexCreator create, + CancellationToken cancellationToken) { Contract.ThrowIfFalse(document.SupportsSyntaxTree); var root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); + var syntaxKinds = document.GetRequiredLanguageService(); + + // if the tree contains `#if`-directives, then include the directives-checksum info in the checksum we + // produce. We don't want to consider the data reusable if the user changes their parse-option pp-directives + // as this could change the root generated for this file. + // + // It's trivial for us to determine the checksum to use at the index-creation/writing point because we have + // to have computed the syntax tree anyways to produce the index. The tradeoff of this design though is + // that at the reading point we may have to issue two reads to determine which case we're in. However, this + // still let's us avoid parsing the doc at the point we're reading in the indices (which would defeat a + // major reason for having the index in the first place). Actual measurements show that double reads do not + // impose any noticeable perf overhead for the features. + var ifDirectiveKind = syntaxKinds.IfDirectiveTrivia; + + var checksum = root.ContainsDirectives && ContainsIfDirective(root, ifDirectiveKind) ? textAndDirectivesChecksum : textChecksum; + return create(document, root, checksum, cancellationToken); } + + private static bool ContainsIfDirective(SyntaxNode node, int ifDirectiveKind) + { + foreach (var child in node.ChildNodesAndTokens()) + { + if (!child.ContainsDirectives) + continue; + + if (child.IsNode) + { + if (ContainsIfDirective(child.AsNode()!, ifDirectiveKind)) + return true; + } + else + { + if (ContainsIfDirective(child.AsToken(), ifDirectiveKind)) + return true; + } + } + + return false; + } + + private static bool ContainsIfDirective(SyntaxToken token, int ifDirectiveKind) + { + // Only need to check leading trivia as directives can never appear in trailing trivia. + foreach (var trivia in token.LeadingTrivia) + { + if (trivia.RawKind == ifDirectiveKind) + return true; + } + + return false; + } } } diff --git a/src/Workspaces/Core/Portable/FindSymbols/Shared/AbstractSyntaxIndex_Persistence.cs b/src/Workspaces/Core/Portable/FindSymbols/Shared/AbstractSyntaxIndex_Persistence.cs index 4ab1a380d0ba1..84ecefc3d0842 100644 --- a/src/Workspaces/Core/Portable/FindSymbols/Shared/AbstractSyntaxIndex_Persistence.cs +++ b/src/Workspaces/Core/Portable/FindSymbols/Shared/AbstractSyntaxIndex_Persistence.cs @@ -4,6 +4,7 @@ using System; using System.Diagnostics; +using System.Runtime.CompilerServices; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Host; @@ -20,16 +21,39 @@ internal partial class AbstractSyntaxIndex : IObjectWritable private static readonly string s_persistenceName = typeof(TIndex).Name; private static readonly Checksum s_serializationFormatChecksum = Checksum.Create("29"); + /// + /// Cache of ParseOptions to a checksum for the contained + /// within. Useful so we don't have to continually reenumerate and regenerate the checksum given how rarely + /// these ever change. + /// + private static readonly ConditionalWeakTable s_ppDirectivesToChecksum = new(); + public readonly Checksum? Checksum; - protected static Task LoadAsync( + public static int PrecalculatedCount; + public static int ComputedCount; + + protected static async Task LoadAsync( Document document, - Checksum checksum, + Checksum textChecksum, + Checksum textAndDirectivesChecksum, IndexReader read, CancellationToken cancellationToken) { var storageService = document.Project.Solution.Workspace.Services.GetPersistentStorageService(); - return LoadAsync(storageService, DocumentKey.ToDocumentKey(document), checksum, SyntaxTreeIndex.GetStringTable(document.Project), read, cancellationToken); + var documentKey = DocumentKey.ToDocumentKey(document); + var stringTable = SyntaxTreeIndex.GetStringTable(document.Project); + + // Try to read from the DB using either checksum. If the writer determined there were no pp-directives, + // then we may match it using textChecksum. If there were pp directives, then we may match is using + // textAndDirectivesChecksum. if we match neither that means that either the data is not in the persistence + // service, or it was written against genuinely different doc/pp-directive contents than before and we have + // to recompute and store again. + // + // This does mean we have to potentially do two reads here. However, that is cheap, and still nicer than + // trying to produce the index again in the common case where we don't have to. + return await LoadAsync(storageService, documentKey, textChecksum, stringTable, read, cancellationToken).ConfigureAwait(false) ?? + await LoadAsync(storageService, documentKey, textAndDirectivesChecksum, stringTable, read, cancellationToken).ConfigureAwait(false); } protected static async Task LoadAsync( @@ -59,23 +83,44 @@ internal partial class AbstractSyntaxIndex : IObjectWritable return null; } - public static async Task GetChecksumAsync( + public static async ValueTask<(Checksum textOnlyChecksum, Checksum textAndDirectivesChecksum)> GetChecksumsAsync( Document document, CancellationToken cancellationToken) { - // Since we build the SyntaxTreeIndex from a SyntaxTree, we need our checksum to change - // any time the SyntaxTree could have changed. Right now, that can only happen if the - // text of the document changes, or the ParseOptions change. So we get the checksums - // for both of those, and merge them together to make the final checksum. + // Since we build the SyntaxTreeIndex from a SyntaxTree, we need our checksum to change any time the + // SyntaxTree could have changed. Right now, that can only happen if the text of the document changes, or + // the preprocessor directives change. So we get the checksums for both of those, and merge them together + // to make the final checksum. + // + // Note: this intentionally ignores *other* ParseOption changes. This may look like it could cause us to + // get innacurate results, but here's why it's ok. The other ParseOption changes include: // - // We also want the checksum to change any time our serialization format changes. If - // the format has changed, all previous versions should be invalidated. + // 1. LanguageVersion changes. It's ok to ignore that as for practically all language versions we don't + // produce different trees. And, while there are some lang versions that produce different trees (for + // example around how records are parsed), it's not realistic that the user would somehow have a + // document that did *not* include pp directives, which somehow had one of those constructs *and* + // somehow had the code produce different trees across different language versions. e.g. no code out + // there is realistically depending on `record` parsing as a method in C# X and as an actual record in + // C# X+1. If code is using constructs that are actually parsing differently downlevel, they will have + // pp directives to avoid even using that construct downlevel. + // + // 2. DocComment parsing mode changes. However, in the IDE we always at least parse doc comments (though we + // have options to control if we report errors in it or not). Since we're always parsing, we're always + // at least getting the same syntax tree shape at the end of the day. + // + // We also want the checksum to change any time our serialization format changes. If the format has + // changed, all previous versions should be invalidated. var project = document.Project; - var parseOptionsChecksum = project.State.GetParseOptionsChecksum(); var documentChecksumState = await document.State.GetStateChecksumsAsync(cancellationToken).ConfigureAwait(false); - var textChecksum = documentChecksumState.Text; - return Checksum.Create(textChecksum, parseOptionsChecksum, s_serializationFormatChecksum); + var directivesChecksum = s_ppDirectivesToChecksum.GetValue( + project.ParseOptions!, + static parseOptions => Checksum.Create(parseOptions.PreprocessorSymbolNames)); + + var textChecksum = Checksum.Create(documentChecksumState.Text, s_serializationFormatChecksum); + var textAndDirectivesChecksum = Checksum.Create(textChecksum, directivesChecksum); + + return (textChecksum, textAndDirectivesChecksum); } private async Task SaveAsync( @@ -115,25 +160,27 @@ protected static async Task PrecalculateAsync(Document document, IndexCreator cr { Debug.Assert(document.IsFromPrimaryBranch()); - var checksum = await GetChecksumAsync(document, cancellationToken).ConfigureAwait(false); + var (textChecksum, textAndDirectivesChecksum) = await GetChecksumsAsync(document, cancellationToken).ConfigureAwait(false); // Check if we've already created and persisted the index for this document. - if (await PrecalculatedAsync(document, checksum, cancellationToken).ConfigureAwait(false)) + if (await PrecalculatedAsync(document, textChecksum, textAndDirectivesChecksum, cancellationToken).ConfigureAwait(false)) { + PrecalculatedCount++; return; } using (Logger.LogBlock(FunctionId.SyntaxTreeIndex_Precalculate_Create, cancellationToken)) { // If not, create and save the index. - var data = await CreateIndexAsync(document, checksum, create, cancellationToken).ConfigureAwait(false); + var data = await CreateIndexAsync(document, textChecksum, textAndDirectivesChecksum, create, cancellationToken).ConfigureAwait(false); await data.SaveAsync(document, cancellationToken).ConfigureAwait(false); + ComputedCount++; } } } private static async Task PrecalculatedAsync( - Document document, Checksum checksum, CancellationToken cancellationToken) + Document document, Checksum textChecksum, Checksum textAndDirectivesChecksum, CancellationToken cancellationToken) { var solution = document.Project.Solution; var persistentStorageService = solution.Workspace.Services.GetPersistentStorageService(); @@ -143,11 +190,15 @@ private static async Task PrecalculatedAsync( { var storage = await persistentStorageService.GetStorageAsync(SolutionKey.ToSolutionKey(solution), cancellationToken).ConfigureAwait(false); await using var _ = storage.ConfigureAwait(false); - // Check if we've already stored a checksum and it matches the checksum we - // expect. If so, we're already precalculated and don't have to recompute - // this index. Otherwise if we don't have a checksum, or the checksums don't - // match, go ahead and recompute it. - return await storage.ChecksumMatchesAsync(document, s_persistenceName, checksum, cancellationToken).ConfigureAwait(false); + + // Check if we've already stored a checksum and it matches the checksum we expect. If so, we're already + // precalculated and don't have to recompute this index. Otherwise if we don't have a checksum, or the + // checksums don't match, go ahead and recompute it. + // + // Check with both checksums as we don't know at this reading point if the document has pp-directives in + // it or not, and we don't want parse the document to find out. + return await storage.ChecksumMatchesAsync(document, s_persistenceName, textChecksum, cancellationToken).ConfigureAwait(false) || + await storage.ChecksumMatchesAsync(document, s_persistenceName, textAndDirectivesChecksum, cancellationToken).ConfigureAwait(false); } catch (Exception e) when (IOUtilities.IsNormalIOException(e)) { diff --git a/src/Workspaces/Core/Portable/Storage/PersistentStorageExtensions.cs b/src/Workspaces/Core/Portable/Storage/PersistentStorageExtensions.cs index 7c974a1e47ff3..38c2e6cfda46e 100644 --- a/src/Workspaces/Core/Portable/Storage/PersistentStorageExtensions.cs +++ b/src/Workspaces/Core/Portable/Storage/PersistentStorageExtensions.cs @@ -18,7 +18,8 @@ public static IChecksummedPersistentStorageService GetPersistentStorageService(t var workspaceConfiguration = services.GetService(); var configuration = services.GetRequiredService(); - return workspaceConfiguration?.Options.CacheStorage switch + var cacheStorage = workspaceConfiguration?.Options.CacheStorage; + return cacheStorage switch { #if !DOTNET_BUILD_FROM_SOURCE StorageDatabase.SQLite diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Services/SyntaxFacts/CSharpSyntaxKinds.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Services/SyntaxFacts/CSharpSyntaxKinds.cs index ff19e00ede4ec..8a75d07297e83 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Services/SyntaxFacts/CSharpSyntaxKinds.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Services/SyntaxFacts/CSharpSyntaxKinds.cs @@ -28,6 +28,7 @@ public TSyntaxKind Convert(int kind) where TSyntaxKind : struct public int SingleLineDocCommentTrivia => (int)SyntaxKind.SingleLineDocumentationCommentTrivia; public int? MultiLineDocCommentTrivia => (int)SyntaxKind.MultiLineDocumentationCommentTrivia; public int? ShebangDirectiveTrivia => (int)SyntaxKind.ShebangDirectiveTrivia; + public int IfDirectiveTrivia => (int)SyntaxKind.IfDirectiveTrivia; public int CloseBraceToken => (int)SyntaxKind.CloseBraceToken; public int ColonToken => (int)SyntaxKind.ColonToken; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Services/SyntaxFacts/ISyntaxKinds.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Services/SyntaxFacts/ISyntaxKinds.cs index c1a18cc3079af..724be53fe366e 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Services/SyntaxFacts/ISyntaxKinds.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Services/SyntaxFacts/ISyntaxKinds.cs @@ -34,6 +34,8 @@ internal interface ISyntaxKinds int? MultiLineDocCommentTrivia { get; } int? ShebangDirectiveTrivia { get; } + int IfDirectiveTrivia { get; } + #endregion #region keywords diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/VisualBasic/Services/SyntaxFacts/VisualBasicSyntaxKinds.vb b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/VisualBasic/Services/SyntaxFacts/VisualBasicSyntaxKinds.vb index 42360d126b069..74eca068b2f95 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/VisualBasic/Services/SyntaxFacts/VisualBasicSyntaxKinds.vb +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/VisualBasic/Services/SyntaxFacts/VisualBasicSyntaxKinds.vb @@ -30,6 +30,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.LanguageServices Public ReadOnly Property MultiLineDocCommentTrivia As Integer? Implements ISyntaxKinds.MultiLineDocCommentTrivia Public ReadOnly Property ShebangDirectiveTrivia As Integer? Implements ISyntaxKinds.ShebangDirectiveTrivia + Public ReadOnly Property IfDirectiveTrivia As Integer = SyntaxKind.IfDirectiveTrivia Implements ISyntaxKinds.IfDirectiveTrivia + Public ReadOnly Property CloseBraceToken As Integer = SyntaxKind.CloseBraceToken Implements ISyntaxKinds.CloseBraceToken Public ReadOnly Property ColonToken As Integer = SyntaxKind.ColonToken Implements ISyntaxKinds.ColonToken Public ReadOnly Property CharacterLiteralToken As Integer = SyntaxKind.CharacterLiteralToken Implements ISyntaxKinds.CharacterLiteralToken From 49dedd3d8167b0cdbc0ad0f9cbdb4514386703f3 Mon Sep 17 00:00:00 2001 From: David Barbet Date: Wed, 13 Apr 2022 13:43:34 -0700 Subject: [PATCH 47/66] Fix flaky VSTypeScriptHandlerTests (#60706) * Fix flaky test + add run iterations to verify * Remove run iterations --- .../ProtocolUnitTests/VSTypeScriptHandlerTests.cs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/Features/LanguageServer/ProtocolUnitTests/VSTypeScriptHandlerTests.cs b/src/Features/LanguageServer/ProtocolUnitTests/VSTypeScriptHandlerTests.cs index e4cefb78e85b8..a5cfc214141f1 100644 --- a/src/Features/LanguageServer/ProtocolUnitTests/VSTypeScriptHandlerTests.cs +++ b/src/Features/LanguageServer/ProtocolUnitTests/VSTypeScriptHandlerTests.cs @@ -8,6 +8,7 @@ using System.Composition; using System.IO; using System.Linq; +using System.ServiceModel.Syndication; using System.Text; using System.Threading; using System.Threading.Tasks; @@ -70,13 +71,16 @@ public async Task TestRoslynTypeScriptHandlerInvoked() Assert.Empty(response); } - private Task CreateTsTestLspServerAsync(string workspaceXml) + private async Task CreateTsTestLspServerAsync(string workspaceXml) { var (clientStream, serverStream) = FullDuplexStream.CreatePair(); var testWorkspace = TestWorkspace.Create(workspaceXml, composition: Composition); + + // Ensure workspace operations are completed so we don't get unexpected workspace changes while running. + await WaitForWorkspaceOperationsAsync(testWorkspace); var languageServerTarget = CreateLanguageServer(serverStream, serverStream, testWorkspace); - return TestLspServer.CreateAsync(testWorkspace, new ClientCapabilities(), languageServerTarget, clientStream); + return await TestLspServer.CreateAsync(testWorkspace, new ClientCapabilities(), languageServerTarget, clientStream); } private static LanguageServerTarget CreateLanguageServer(Stream inputStream, Stream outputStream, TestWorkspace workspace) From c31382c31dfa948705b47d07b94b0b32e8ff4b14 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Matou=C5=A1ek?= Date: Wed, 13 Apr 2022 13:50:41 -0700 Subject: [PATCH 48/66] Allow code actions to retrieve options for any language (#60697) --- .../Suppression/SuppressionTests.cs | 2 +- .../CSharpTest/Formatting/CodeCleanupTests.cs | 2 +- .../AsyncSuggestedActionsSource.cs | 2 +- .../Suggestions/SuggestedActionsSource.cs | 12 +++++----- .../CodeActions/CodeActionOptionsStorage.cs | 6 +++++ .../Handlers/CodeActions/CodeActionHelpers.cs | 6 ++--- .../CodeActions/CodeActionResolveHandler.cs | 2 +- .../CodeActions/CodeActionsHandler.cs | 2 +- .../CodeActions/RunCodeActionHandler.cs | 2 +- .../CodeActions/AbstractCodeActionTest.cs | 2 +- .../CSharpCodeFixVerifier`2+Test.cs | 2 +- .../Diagnostics/AbstractUserDiagnosticTest.cs | 2 +- .../Test/CodeFixes/CodeFixServiceTests.cs | 18 +++++++-------- .../CodeRefactoringServiceTest.cs | 4 ++-- .../Test2/CodeFixes/CodeFixServiceTests.vb | 10 ++++----- .../SyncNamespacesServiceTests.vb | 10 ++++----- .../Formatting/CodeCleanUpTests.vb | 2 +- ...CSharpImplementInterfaceCodeFixProvider.cs | 2 +- .../AbstractAddImportCodeFixProvider.cs | 4 ++-- .../AbstractAddPackageCodeFixProvider.cs | 2 +- ...actAddMissingImportsRefactoringProvider.cs | 2 +- .../CodeRefactoringService.cs | 6 ++--- ...actExtractMethodCodeRefactoringProvider.cs | 2 +- .../ICodeRefactoringService.cs | 6 ++--- .../AbstractFullyQualifyCodeFixProvider.cs | 2 +- ...ctImplementAbstractClassCodeFixProvider.cs | 2 +- .../AbstractSpellCheckCodeFixProvider.cs | 2 +- .../AbstractSyncNamespacesSevice.cs | 6 ++--- .../SyncNamespaces/ISyncNamespacesService.cs | 2 +- ...AbstractWrappingCodeRefactoringProvider.cs | 2 +- .../CodeCleanup/AbstractCodeCleanupService.cs | 8 +++---- .../CodeCleanup/ICodeCleanupService.cs | 2 +- .../Features/CodeFixes/CodeFixService.cs | 20 +++++++---------- .../Features/CodeFixes/ICodeFixService.cs | 12 +++++----- .../UnifiedSuggestedActionsSource.cs | 4 ++-- ...lBasicImplementInterfaceCodeFixProvider.vb | 2 +- .../OmniSharpCodeFixContextFactory.cs | 4 ++-- .../CodeCleanup/AbstractCodeCleanUpFixer.cs | 2 +- .../SyncNamespacesCommandHandler.cs | 2 +- .../Core/Portable/CodeFixes/CodeFixContext.cs | 22 ++++++++++++++----- .../FixAllOccurrences/BatchFixAllProvider.cs | 2 +- .../CodeRefactoringContext.cs | 14 ++++++++---- .../VSTypeScriptCodeFixContextExtensions.cs | 11 +++++++--- .../SyntaxEditorBasedCodeFixProvider.cs | 2 +- 44 files changed, 129 insertions(+), 104 deletions(-) diff --git a/src/EditorFeatures/CSharpTest/Diagnostics/Suppression/SuppressionTests.cs b/src/EditorFeatures/CSharpTest/Diagnostics/Suppression/SuppressionTests.cs index 264ef12fda63f..5f660b4ef5fbe 100644 --- a/src/EditorFeatures/CSharpTest/Diagnostics/Suppression/SuppressionTests.cs +++ b/src/EditorFeatures/CSharpTest/Diagnostics/Suppression/SuppressionTests.cs @@ -468,7 +468,7 @@ void Method() Assert.Equal(2, diagnostics.Where(d => d.Id == "CS0219").Count()); var options = CodeActionOptions.Default; - var allFixes = (await fixService.GetFixesAsync(document, span, options, CancellationToken.None)) + var allFixes = (await fixService.GetFixesAsync(document, span, _ => options, CancellationToken.None)) .SelectMany(fixCollection => fixCollection.Fixes); var cs0219Fixes = allFixes.Where(fix => fix.PrimaryDiagnostic.Id == "CS0219").ToArray(); diff --git a/src/EditorFeatures/CSharpTest/Formatting/CodeCleanupTests.cs b/src/EditorFeatures/CSharpTest/Formatting/CodeCleanupTests.cs index 79e99b0d5c3c9..41f18c56889b9 100644 --- a/src/EditorFeatures/CSharpTest/Formatting/CodeCleanupTests.cs +++ b/src/EditorFeatures/CSharpTest/Formatting/CodeCleanupTests.cs @@ -659,7 +659,7 @@ private protected static async Task AssertCodeCleanupResult(string expected, str var enabledDiagnostics = codeCleanupService.GetAllDiagnostics(); var newDoc = await codeCleanupService.CleanupAsync( - document, enabledDiagnostics, new ProgressTracker(), options, formattingOptions, CancellationToken.None); + document, enabledDiagnostics, new ProgressTracker(), _ => options, formattingOptions, CancellationToken.None); var actual = await newDoc.GetTextAsync(); diff --git a/src/EditorFeatures/Core.Wpf/Suggestions/AsyncSuggestedActionsSource.cs b/src/EditorFeatures/Core.Wpf/Suggestions/AsyncSuggestedActionsSource.cs index d95cb66d77b25..c31d60df922a9 100644 --- a/src/EditorFeatures/Core.Wpf/Suggestions/AsyncSuggestedActionsSource.cs +++ b/src/EditorFeatures/Core.Wpf/Suggestions/AsyncSuggestedActionsSource.cs @@ -162,7 +162,7 @@ private async IAsyncEnumerable GetCodeFixesAndRefactoringsAs var workspace = document.Project.Solution.Workspace; var supportsFeatureService = workspace.Services.GetRequiredService(); - var options = GlobalOptions.GetCodeActionOptions(document.Project.Language); + var options = GlobalOptions.GetCodeActionOptionsProvider(); var fixesTask = GetCodeFixesAsync( state, supportsFeatureService, requestedActionCategories, workspace, document, range, diff --git a/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSource.cs b/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSource.cs index 1b5d86630fdce..c2ef69da65011 100644 --- a/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSource.cs +++ b/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSource.cs @@ -177,7 +177,7 @@ public bool TryGetTelemetryId(out Guid telemetryId) Func addOperationScope = description => operationContext?.AddScope(allowCancellation: true, string.Format(EditorFeaturesResources.Gathering_Suggestions_0, description)); - var options = GlobalOptions.GetBlockingCodeActionOptions(document.Project.Language); + var options = GlobalOptions.GetBlockingCodeActionOptionsProvider(); // We convert the code fixes and refactorings to UnifiedSuggestedActionSets instead of // SuggestedActionSets so that we can share logic between local Roslyn and LSP. @@ -266,7 +266,7 @@ protected static Task> GetCodeFixesAsy SnapshotSpan range, Func addOperationScope, CodeActionRequestPriority priority, - CodeActionOptions options, + CodeActionOptionsProvider options, CancellationToken cancellationToken) { if (state.Target.Owner._codeFixService == null || @@ -306,7 +306,7 @@ protected static Task> GetRefactorings TextSpan? selection, Func addOperationScope, CodeActionRequestPriority priority, - CodeActionOptions options, + CodeActionOptionsProvider options, CancellationToken cancellationToken) { if (!selection.HasValue) @@ -414,7 +414,7 @@ await InvokeBelowInputPriorityAsync(() => ReferenceCountedDisposable state, Document document, SnapshotSpan range, - CodeActionOptions options, + CodeActionOptionsProvider options, CancellationToken cancellationToken) { foreach (var order in Orderings) @@ -458,7 +458,7 @@ await InvokeBelowInputPriorityAsync(() => private async Task TryGetRefactoringSuggestedActionCategoryAsync( Document document, TextSpan? selection, - CodeActionOptions options, + CodeActionOptionsProvider options, CancellationToken cancellationToken) { using var state = _state.TryAddReference(); @@ -630,7 +630,7 @@ private void OnSuggestedActionsChanged(Workspace currentWorkspace, DocumentId? c if (document == null) return null; - var options = GlobalOptions.GetCodeActionOptions(document.Project.Language); + var options = GlobalOptions.GetCodeActionOptionsProvider(); using var linkedTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken); var linkedToken = linkedTokenSource.Token; diff --git a/src/EditorFeatures/Core/CodeActions/CodeActionOptionsStorage.cs b/src/EditorFeatures/Core/CodeActions/CodeActionOptionsStorage.cs index 6597b935ba6ca..3c453445d267d 100644 --- a/src/EditorFeatures/Core/CodeActions/CodeActionOptionsStorage.cs +++ b/src/EditorFeatures/Core/CodeActions/CodeActionOptionsStorage.cs @@ -32,5 +32,11 @@ internal static CodeActionOptionsProvider GetCodeActionOptionsProvider(this IGlo var cache = ImmutableDictionary.Empty; return language => ImmutableInterlocked.GetOrAdd(ref cache, language, (language, options) => GetCodeActionOptions(options, language), globalOptions); } + + internal static CodeActionOptionsProvider GetBlockingCodeActionOptionsProvider(this IGlobalOptionService globalOptions) + { + var cache = ImmutableDictionary.Empty; + return language => ImmutableInterlocked.GetOrAdd(ref cache, language, (language, options) => GetBlockingCodeActionOptions(options, language), globalOptions); + } } } diff --git a/src/EditorFeatures/Core/LanguageServer/Handlers/CodeActions/CodeActionHelpers.cs b/src/EditorFeatures/Core/LanguageServer/Handlers/CodeActions/CodeActionHelpers.cs index 3b12bbabee444..b1b91e3e78fe3 100644 --- a/src/EditorFeatures/Core/LanguageServer/Handlers/CodeActions/CodeActionHelpers.cs +++ b/src/EditorFeatures/Core/LanguageServer/Handlers/CodeActions/CodeActionHelpers.cs @@ -35,7 +35,7 @@ public static async Task GetVSCodeActionsAsync( CodeActionParams request, CodeActionsCache codeActionsCache, Document document, - CodeActionOptions options, + CodeActionOptionsProvider options, ICodeFixService codeFixService, ICodeRefactoringService codeRefactoringService, CancellationToken cancellationToken) @@ -186,7 +186,7 @@ public static async Task> GetCodeActionsAsync( CodeActionsCache codeActionsCache, Document document, LSP.Range selection, - CodeActionOptions options, + CodeActionOptionsProvider options, ICodeFixService codeFixService, ICodeRefactoringService codeRefactoringService, CancellationToken cancellationToken) @@ -242,7 +242,7 @@ private static CodeAction GetNestedActionsFromActionSet(IUnifiedSuggestedAction private static async ValueTask> GetActionSetsAsync( Document document, - CodeActionOptions options, + CodeActionOptionsProvider options, ICodeFixService codeFixService, ICodeRefactoringService codeRefactoringService, LSP.Range selection, diff --git a/src/EditorFeatures/Core/LanguageServer/Handlers/CodeActions/CodeActionResolveHandler.cs b/src/EditorFeatures/Core/LanguageServer/Handlers/CodeActions/CodeActionResolveHandler.cs index 46b40d708f983..a6f1aee4fb089 100644 --- a/src/EditorFeatures/Core/LanguageServer/Handlers/CodeActions/CodeActionResolveHandler.cs +++ b/src/EditorFeatures/Core/LanguageServer/Handlers/CodeActions/CodeActionResolveHandler.cs @@ -66,7 +66,7 @@ public CodeActionResolveHandler( var data = ((JToken)codeAction.Data!).ToObject(); Assumes.Present(data); - var options = _globalOptions.GetCodeActionOptions(document.Project.Language); + var options = _globalOptions.GetCodeActionOptionsProvider(); var codeActions = await CodeActionHelpers.GetCodeActionsAsync( _codeActionsCache, diff --git a/src/EditorFeatures/Core/LanguageServer/Handlers/CodeActions/CodeActionsHandler.cs b/src/EditorFeatures/Core/LanguageServer/Handlers/CodeActions/CodeActionsHandler.cs index c059f005a7ee0..065082667a321 100644 --- a/src/EditorFeatures/Core/LanguageServer/Handlers/CodeActions/CodeActionsHandler.cs +++ b/src/EditorFeatures/Core/LanguageServer/Handlers/CodeActions/CodeActionsHandler.cs @@ -57,7 +57,7 @@ public CodeActionsHandler( var document = context.Document; Contract.ThrowIfNull(document); - var options = _globalOptions.GetCodeActionOptions(document.Project.Language); + var options = _globalOptions.GetCodeActionOptionsProvider(); var codeActions = await CodeActionHelpers.GetVSCodeActionsAsync( request, _codeActionsCache, document, options, _codeFixService, _codeRefactoringService, cancellationToken).ConfigureAwait(false); diff --git a/src/EditorFeatures/Core/LanguageServer/Handlers/CodeActions/RunCodeActionHandler.cs b/src/EditorFeatures/Core/LanguageServer/Handlers/CodeActions/RunCodeActionHandler.cs index 1e82bc010dc39..2529f8a318e1c 100644 --- a/src/EditorFeatures/Core/LanguageServer/Handlers/CodeActions/RunCodeActionHandler.cs +++ b/src/EditorFeatures/Core/LanguageServer/Handlers/CodeActions/RunCodeActionHandler.cs @@ -74,7 +74,7 @@ public override async Task HandleRequestAsync(LSP.ExecuteCommandParams r var runRequest = ((JToken)request.Arguments.Single()).ToObject(); Assumes.Present(runRequest); - var options = _globalOptions.GetCodeActionOptions(document.Project.Language); + var options = _globalOptions.GetCodeActionOptionsProvider(); var codeActions = await CodeActionHelpers.GetCodeActionsAsync( _codeActionsCache, document, runRequest.Range, options, _codeFixService, _codeRefactoringService, cancellationToken).ConfigureAwait(false); diff --git a/src/EditorFeatures/DiagnosticsTestUtilities/CodeActions/AbstractCodeActionTest.cs b/src/EditorFeatures/DiagnosticsTestUtilities/CodeActions/AbstractCodeActionTest.cs index 023b11dcc86d1..1b7958ac53889 100644 --- a/src/EditorFeatures/DiagnosticsTestUtilities/CodeActions/AbstractCodeActionTest.cs +++ b/src/EditorFeatures/DiagnosticsTestUtilities/CodeActions/AbstractCodeActionTest.cs @@ -56,7 +56,7 @@ internal async Task GetCodeRefactoringAsync( var span = documentsWithSelections.Single().SelectedSpans.Single(); var actions = ArrayBuilder<(CodeAction, TextSpan?)>.GetInstance(); var document = workspace.CurrentSolution.GetDocument(documentsWithSelections.Single().Id); - var context = new CodeRefactoringContext(document, span, (a, t) => actions.Add((a, t)), parameters.codeActionOptions, CancellationToken.None); + var context = new CodeRefactoringContext(document, span, (a, t) => actions.Add((a, t)), _ => parameters.codeActionOptions, CancellationToken.None); await provider.ComputeRefactoringsAsync(context); var result = actions.Count > 0 ? new CodeRefactoring(provider, actions.ToImmutable()) : null; diff --git a/src/EditorFeatures/DiagnosticsTestUtilities/CodeActions/CSharpCodeFixVerifier`2+Test.cs b/src/EditorFeatures/DiagnosticsTestUtilities/CodeActions/CSharpCodeFixVerifier`2+Test.cs index 0faa7975eae94..5f93510ae57a1 100644 --- a/src/EditorFeatures/DiagnosticsTestUtilities/CodeActions/CSharpCodeFixVerifier`2+Test.cs +++ b/src/EditorFeatures/DiagnosticsTestUtilities/CodeActions/CSharpCodeFixVerifier`2+Test.cs @@ -109,7 +109,7 @@ protected override AnalyzerOptions GetAnalyzerOptions(Project project) => new WorkspaceAnalyzerOptions(base.GetAnalyzerOptions(project), project.Solution, _sharedState.IdeAnalyzerOptions); protected override CodeFixContext CreateCodeFixContext(Document document, TextSpan span, ImmutableArray diagnostics, Action> registerCodeFix, CancellationToken cancellationToken) - => new(document, span, diagnostics, registerCodeFix, _sharedState.CodeActionOptions, cancellationToken); + => new(document, span, diagnostics, registerCodeFix, _ => _sharedState.CodeActionOptions, cancellationToken); protected override FixAllContext CreateFixAllContext( Document? document, diff --git a/src/EditorFeatures/DiagnosticsTestUtilities/Diagnostics/AbstractUserDiagnosticTest.cs b/src/EditorFeatures/DiagnosticsTestUtilities/Diagnostics/AbstractUserDiagnosticTest.cs index 3ac1980cbdccf..6b7caeb9cd7d9 100644 --- a/src/EditorFeatures/DiagnosticsTestUtilities/Diagnostics/AbstractUserDiagnosticTest.cs +++ b/src/EditorFeatures/DiagnosticsTestUtilities/Diagnostics/AbstractUserDiagnosticTest.cs @@ -210,7 +210,7 @@ protected static Document GetDocumentAndAnnotatedSpan(TestWorkspace workspace, o diagnostic.Location.SourceSpan, ImmutableArray.Create(diagnostic), (a, d) => fixes.Add(new CodeFix(document.Project, a, d)), - options, + _ => options, CancellationToken.None); await fixer.RegisterCodeFixesAsync(context); diff --git a/src/EditorFeatures/Test/CodeFixes/CodeFixServiceTests.cs b/src/EditorFeatures/Test/CodeFixes/CodeFixServiceTests.cs index 1d52b68e86a61..b31a5166a4a26 100644 --- a/src/EditorFeatures/Test/CodeFixes/CodeFixServiceTests.cs +++ b/src/EditorFeatures/Test/CodeFixes/CodeFixServiceTests.cs @@ -62,7 +62,7 @@ public async Task TestGetFirstDiagnosticWithFixAsync() var project = workspace.CurrentSolution.Projects.Single().AddAnalyzerReference(reference); var document = project.Documents.Single(); var unused = await fixService.GetMostSevereFixAsync( - document, TextSpan.FromBounds(0, 0), CodeActionRequestPriority.None, CodeActionOptions.Default, CancellationToken.None); + document, TextSpan.FromBounds(0, 0), CodeActionRequestPriority.None, _ => CodeActionOptions.Default, CancellationToken.None); var fixer1 = (MockFixer)fixers.Single().Value; var fixer2 = (MockFixer)reference.Fixer!; @@ -91,7 +91,7 @@ public async Task TestGetFixesAsyncWithDuplicateDiagnostics() // Verify that we do not crash when computing fixes. var options = CodeActionOptions.Default; - _ = await tuple.codeFixService.GetFixesAsync(document, TextSpan.FromBounds(0, 0), options, CancellationToken.None); + _ = await tuple.codeFixService.GetFixesAsync(document, TextSpan.FromBounds(0, 0), _ => options, CancellationToken.None); // Verify that code fix is invoked with both the diagnostics in the context, // i.e. duplicate diagnostics are not silently discarded by the CodeFixService. @@ -118,7 +118,7 @@ public async Task TestGetFixesAsyncHasNoDuplicateConfigurationActions() // Verify registered configuration code actions do not have duplicates. var options = CodeActionOptions.Default; - var fixCollections = await tuple.codeFixService.GetFixesAsync(document, TextSpan.FromBounds(0, 0), options, CancellationToken.None); + var fixCollections = await tuple.codeFixService.GetFixesAsync(document, TextSpan.FromBounds(0, 0), _ => options, CancellationToken.None); var codeActions = fixCollections.SelectMany(c => c.Fixes.Select(f => f.Action)).ToImmutableArray(); Assert.Equal(7, codeActions.Length); var uniqueTitles = new HashSet(); @@ -152,14 +152,14 @@ public async Task TestGetFixesAsyncForFixableAndNonFixableAnalyzersAsync() // Verify only analyzerWithFix is executed when GetFixesAsync is invoked with 'CodeActionRequestPriority.Normal'. _ = await tuple.codeFixService.GetFixesAsync(document, TextSpan.FromBounds(0, 0), - priority: CodeActionRequestPriority.Normal, options, + priority: CodeActionRequestPriority.Normal, _ => options, addOperationScope: _ => null, cancellationToken: CancellationToken.None); Assert.True(analyzerWithFix.ReceivedCallback); Assert.False(analyzerWithoutFix.ReceivedCallback); // Verify both analyzerWithFix and analyzerWithoutFix are executed when GetFixesAsync is invoked with 'CodeActionRequestPriority.Lowest'. _ = await tuple.codeFixService.GetFixesAsync(document, TextSpan.FromBounds(0, 0), - priority: CodeActionRequestPriority.Lowest, options, + priority: CodeActionRequestPriority.Lowest, _ => options, addOperationScope: _ => null, cancellationToken: CancellationToken.None); Assert.True(analyzerWithFix.ReceivedCallback); Assert.True(analyzerWithoutFix.ReceivedCallback); @@ -190,7 +190,7 @@ public async Task TestGetFixesAsyncForDocumentDiagnosticAnalyzerAsync() var options = CodeActionOptions.Default; _ = await tuple.codeFixService.GetFixesAsync(document, TextSpan.FromBounds(0, 0), - priority: CodeActionRequestPriority.Normal, options, + priority: CodeActionRequestPriority.Normal, _ => options, addOperationScope: _ => null, cancellationToken: CancellationToken.None); Assert.True(documentDiagnosticAnalyzer.ReceivedCallback); } @@ -275,7 +275,7 @@ private static async Task> GetAddedFixesAsync( var project = workspace.CurrentSolution.Projects.Single().AddAnalyzerReference(reference); document = project.Documents.Single(); var options = CodeActionOptions.Default; - var fixes = await tuple.codeFixService.GetFixesAsync(document, TextSpan.FromBounds(0, 0), options, CancellationToken.None); + var fixes = await tuple.codeFixService.GetFixesAsync(document, TextSpan.FromBounds(0, 0), _ => options, CancellationToken.None); if (exception) { @@ -300,7 +300,7 @@ private static async Task GetFirstDiagnosticWithFixWithExceptionValidationAsync( GetDocumentAndExtensionManager(tuple.analyzerService, workspace, out var document, out var extensionManager); var unused = await tuple.codeFixService.GetMostSevereFixAsync( - document, TextSpan.FromBounds(0, 0), CodeActionRequestPriority.None, CodeActionOptions.Default, CancellationToken.None); + document, TextSpan.FromBounds(0, 0), CodeActionRequestPriority.None, _ => CodeActionOptions.Default, CancellationToken.None); Assert.True(extensionManager.IsDisabled(codefix)); Assert.False(extensionManager.IsIgnored(codefix)); Assert.True(errorReported); @@ -692,7 +692,7 @@ private static async Task> GetNuGetAndVsixCode var document = project.Documents.Single(); var options = CodeActionOptions.Default; - return await fixService.GetFixesAsync(document, TextSpan.FromBounds(0, 0), options, CancellationToken.None); + return await fixService.GetFixesAsync(document, TextSpan.FromBounds(0, 0), _ => options, CancellationToken.None); } private sealed class NuGetCodeFixProvider : AbstractNuGetOrVsixCodeFixProvider diff --git a/src/EditorFeatures/Test/CodeRefactorings/CodeRefactoringServiceTest.cs b/src/EditorFeatures/Test/CodeRefactorings/CodeRefactoringServiceTest.cs index 43d84445e200f..26631818d7ff2 100644 --- a/src/EditorFeatures/Test/CodeRefactorings/CodeRefactoringServiceTest.cs +++ b/src/EditorFeatures/Test/CodeRefactorings/CodeRefactoringServiceTest.cs @@ -45,7 +45,7 @@ public async Task TestProjectRefactoringAsync() var project = workspace.CurrentSolution.Projects.Single().AddAnalyzerReference(reference); var document = project.Documents.Single(); var options = CodeActionOptions.Default; - var refactorings = await refactoringService.GetRefactoringsAsync(document, TextSpan.FromBounds(0, 0), options, CancellationToken.None); + var refactorings = await refactoringService.GetRefactoringsAsync(document, TextSpan.FromBounds(0, 0), _ => options, CancellationToken.None); var stubRefactoringAction = refactorings.Single(refactoring => refactoring.CodeActions.FirstOrDefault().action?.Title == nameof(StubRefactoring)); Assert.True(stubRefactoringAction is object); @@ -69,7 +69,7 @@ private static async Task VerifyRefactoringDisabledAsync() var document = project.Documents.Single(); var extensionManager = (EditorLayerExtensionManager.ExtensionManager)document.Project.Solution.Workspace.Services.GetRequiredService(); var options = CodeActionOptions.Default; - var result = await refactoringService.GetRefactoringsAsync(document, TextSpan.FromBounds(0, 0), options, CancellationToken.None); + var result = await refactoringService.GetRefactoringsAsync(document, TextSpan.FromBounds(0, 0), _ => options, CancellationToken.None); Assert.True(extensionManager.IsDisabled(codeRefactoring)); Assert.False(extensionManager.IsIgnored(codeRefactoring)); diff --git a/src/EditorFeatures/Test2/CodeFixes/CodeFixServiceTests.vb b/src/EditorFeatures/Test2/CodeFixes/CodeFixServiceTests.vb index cc37902c4d5e1..bfd0869878f87 100644 --- a/src/EditorFeatures/Test2/CodeFixes/CodeFixServiceTests.vb +++ b/src/EditorFeatures/Test2/CodeFixes/CodeFixServiceTests.vb @@ -77,7 +77,7 @@ Namespace Microsoft.CodeAnalysis.Editor.Implementation.CodeFixes.UnitTests Dim fixes = Await codefixService.GetFixesAsync( document, (Await document.GetSyntaxRootAsync()).FullSpan, - options, + Function(language) options, CancellationToken.None) Assert.Equal(0, fixes.Count()) @@ -93,7 +93,7 @@ Namespace Microsoft.CodeAnalysis.Editor.Implementation.CodeFixes.UnitTests fixes = Await codefixService.GetFixesAsync( document, (Await document.GetSyntaxRootAsync()).FullSpan, - options, + Function(language) options, CancellationToken.None) Assert.Equal(1, fixes.Count()) @@ -103,7 +103,7 @@ Namespace Microsoft.CodeAnalysis.Editor.Implementation.CodeFixes.UnitTests fixes = Await codefixService.GetFixesAsync( document, (Await document.GetSyntaxRootAsync()).FullSpan, - options, + Function(language) options, CancellationToken.None) Assert.Equal(0, fixes.Count()) @@ -154,7 +154,7 @@ Namespace Microsoft.CodeAnalysis.Editor.Implementation.CodeFixes.UnitTests Dim fixes = Await codefixService.GetFixesAsync( document, (Await document.GetSyntaxRootAsync()).FullSpan, - options, + Function(language) options, CancellationToken.None) Assert.Equal(0, fixes.Count()) @@ -170,7 +170,7 @@ Namespace Microsoft.CodeAnalysis.Editor.Implementation.CodeFixes.UnitTests fixes = Await codefixService.GetFixesAsync( document, (Await document.GetSyntaxRootAsync()).FullSpan, - options, + Function(language) options, CancellationToken.None) Assert.Equal(0, fixes.Count()) diff --git a/src/EditorFeatures/Test2/SyncNamespaces/SyncNamespacesServiceTests.vb b/src/EditorFeatures/Test2/SyncNamespaces/SyncNamespacesServiceTests.vb index 19e4ca34cac16..ec88c170c044a 100644 --- a/src/EditorFeatures/Test2/SyncNamespaces/SyncNamespacesServiceTests.vb +++ b/src/EditorFeatures/Test2/SyncNamespaces/SyncNamespacesServiceTests.vb @@ -40,7 +40,7 @@ namespace Test.Namespace.App Dim document = project.Documents.Single() Dim syncService = project.GetLanguageService(Of ISyncNamespacesService)() - Dim newSolution = Await syncService.SyncNamespacesAsync(ImmutableArray.Create(project), CodeActionOptions.Default, CancellationToken.None) + Dim newSolution = Await syncService.SyncNamespacesAsync(ImmutableArray.Create(project), Function(language) CodeActionOptions.Default, CancellationToken.None) Dim solutionChanges = workspace.CurrentSolution.GetChanges(newSolution) @@ -76,7 +76,7 @@ namespace Test Dim document = project.Documents.Single() Dim syncService = project.GetLanguageService(Of ISyncNamespacesService)() - Dim newSolution = Await syncService.SyncNamespacesAsync(projects, CodeActionOptions.Default, CancellationToken.None) + Dim newSolution = Await syncService.SyncNamespacesAsync(projects, Function(language) CodeActionOptions.Default, CancellationToken.None) Dim solutionChanges = workspace.CurrentSolution.GetChanges(newSolution) Dim projectChanges = solutionChanges.GetProjectChanges().Single() @@ -133,7 +133,7 @@ namespace Test2.Namespace.App Dim project = projects(0) Dim syncService = project.GetLanguageService(Of ISyncNamespacesService)() - Dim newSolution = Await syncService.SyncNamespacesAsync(projects, CodeActionOptions.Default, CancellationToken.None) + Dim newSolution = Await syncService.SyncNamespacesAsync(projects, Function(language) CodeActionOptions.Default, CancellationToken.None) Dim solutionChanges = workspace.CurrentSolution.GetChanges(newSolution) @@ -187,7 +187,7 @@ namespace Test2.Namespace.App Dim document = project.Documents.Single() Dim syncService = project.GetLanguageService(Of ISyncNamespacesService)() - Dim newSolution = Await syncService.SyncNamespacesAsync(projects, CodeActionOptions.Default, CancellationToken.None) + Dim newSolution = Await syncService.SyncNamespacesAsync(projects, Function(language) CodeActionOptions.Default, CancellationToken.None) Dim solutionChanges = workspace.CurrentSolution.GetChanges(newSolution) Dim projectChanges = solutionChanges.GetProjectChanges().Single() @@ -252,7 +252,7 @@ namespace Test2.Namespace Dim document2 = project2.Documents.Single() Dim syncService = project.GetLanguageService(Of ISyncNamespacesService)() - Dim newSolution = Await syncService.SyncNamespacesAsync(projects, CodeActionOptions.Default, CancellationToken.None) + Dim newSolution = Await syncService.SyncNamespacesAsync(projects, Function(language) CodeActionOptions.Default, CancellationToken.None) Dim solutionChanges = workspace.CurrentSolution.GetChanges(newSolution) Dim projectChanges = solutionChanges.GetProjectChanges().ToImmutableArray() diff --git a/src/EditorFeatures/VisualBasicTest/Formatting/CodeCleanUpTests.vb b/src/EditorFeatures/VisualBasicTest/Formatting/CodeCleanUpTests.vb index 52a83d318c9f8..060c2eae8e2c1 100644 --- a/src/EditorFeatures/VisualBasicTest/Formatting/CodeCleanUpTests.vb +++ b/src/EditorFeatures/VisualBasicTest/Formatting/CodeCleanUpTests.vb @@ -365,7 +365,7 @@ End Class document, enabledDiagnostics, New ProgressTracker, - options, + Function(language) options, formattingOptions, CancellationToken.None) diff --git a/src/Features/CSharp/Portable/ImplementInterface/CSharpImplementInterfaceCodeFixProvider.cs b/src/Features/CSharp/Portable/ImplementInterface/CSharpImplementInterfaceCodeFixProvider.cs index 34e68a1f1bd02..676af4f7ba025 100644 --- a/src/Features/CSharp/Portable/ImplementInterface/CSharpImplementInterfaceCodeFixProvider.cs +++ b/src/Features/CSharp/Portable/ImplementInterface/CSharpImplementInterfaceCodeFixProvider.cs @@ -54,7 +54,7 @@ public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) var actions = token.Parent.GetAncestorsOrThis() .Where(_interfaceName) - .Select(n => service.GetCodeActions(document, context.Options.ImplementTypeOptions, model, n, cancellationToken)) + .Select(n => service.GetCodeActions(document, context.Options(document.Project.Language).ImplementTypeOptions, model, n, cancellationToken)) .FirstOrDefault(a => !a.IsEmpty); if (actions.IsDefaultOrEmpty) diff --git a/src/Features/Core/Portable/AddImport/AbstractAddImportCodeFixProvider.cs b/src/Features/Core/Portable/AddImport/AbstractAddImportCodeFixProvider.cs index 25fcf19a4d6f3..2d12603c7e556 100644 --- a/src/Features/Core/Portable/AddImport/AbstractAddImportCodeFixProvider.cs +++ b/src/Features/Core/Portable/AddImport/AbstractAddImportCodeFixProvider.cs @@ -55,7 +55,7 @@ public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) var addImportService = document.GetRequiredLanguageService(); var services = document.Project.Solution.Workspace.Services; - var searchOptions = context.Options.SearchOptions; + var searchOptions = context.Options(document.Project.Language).SearchOptions; var symbolSearchService = _symbolSearchService ?? services.GetRequiredService(); @@ -75,7 +75,7 @@ public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) var addImportOptions = new AddImportOptions( searchOptions, - context.Options.HideAdvancedMembers, + context.Options(document.Project.Language).HideAdvancedMembers, placement); var fixesForDiagnostic = await addImportService.GetFixesForDiagnosticsAsync( diff --git a/src/Features/Core/Portable/AddPackage/AbstractAddPackageCodeFixProvider.cs b/src/Features/Core/Portable/AddPackage/AbstractAddPackageCodeFixProvider.cs index 376f536c68e23..94c8901b70553 100644 --- a/src/Features/Core/Portable/AddPackage/AbstractAddPackageCodeFixProvider.cs +++ b/src/Features/Core/Portable/AddPackage/AbstractAddPackageCodeFixProvider.cs @@ -52,7 +52,7 @@ protected async Task> GetAddPackagesCodeActionsAsync( var codeActions = ArrayBuilder.GetInstance(); if (symbolSearchService != null && installerService != null && - context.Options.SearchOptions.SearchNuGetPackages && + context.Options(document.Project.Language).SearchOptions.SearchNuGetPackages && installerService.IsEnabled(document.Project.Id)) { var packageSources = PackageSourceHelper.GetPackageSources(installerService.TryGetPackageSources()); diff --git a/src/Features/Core/Portable/CodeRefactorings/AddMissingImports/AbstractAddMissingImportsRefactoringProvider.cs b/src/Features/Core/Portable/CodeRefactorings/AddMissingImports/AbstractAddMissingImportsRefactoringProvider.cs index b7f78d536b1ea..df26d9b289e2b 100644 --- a/src/Features/Core/Portable/CodeRefactorings/AddMissingImports/AbstractAddMissingImportsRefactoringProvider.cs +++ b/src/Features/Core/Portable/CodeRefactorings/AddMissingImports/AbstractAddMissingImportsRefactoringProvider.cs @@ -40,7 +40,7 @@ public override async Task ComputeRefactoringsAsync(CodeRefactoringContext conte var addMissingImportsService = document.GetLanguageService(); var placement = await AddImportPlacementOptions.FromDocumentAsync(document, cancellationToken).ConfigureAwait(false); - var options = new AddMissingImportsOptions(context.Options.HideAdvancedMembers, placement); + var options = new AddMissingImportsOptions(context.Options(document.Project.Language).HideAdvancedMembers, placement); var analysis = await addMissingImportsService.AnalyzeAsync(document, textSpan, options, cancellationToken).ConfigureAwait(false); if (!analysis.CanAddMissingImports) diff --git a/src/Features/Core/Portable/CodeRefactorings/CodeRefactoringService.cs b/src/Features/Core/Portable/CodeRefactorings/CodeRefactoringService.cs index 66211617436c9..fd5b54aa4c790 100644 --- a/src/Features/Core/Portable/CodeRefactorings/CodeRefactoringService.cs +++ b/src/Features/Core/Portable/CodeRefactorings/CodeRefactoringService.cs @@ -84,7 +84,7 @@ private ConcatImmutableArray GetProviders(Document docu public async Task HasRefactoringsAsync( Document document, TextSpan state, - CodeActionOptions options, + CodeActionOptionsProvider options, CancellationToken cancellationToken) { var extensionManager = document.Project.Solution.Workspace.Services.GetRequiredService(); @@ -110,7 +110,7 @@ public async Task> GetRefactoringsAsync( Document document, TextSpan state, CodeActionRequestPriority priority, - CodeActionOptions options, + CodeActionOptionsProvider options, Func addOperationScope, CancellationToken cancellationToken) { @@ -149,7 +149,7 @@ public async Task> GetRefactoringsAsync( CodeRefactoringProvider provider, CodeChangeProviderMetadata? providerMetadata, IExtensionManager extensionManager, - CodeActionOptions options, + CodeActionOptionsProvider options, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); diff --git a/src/Features/Core/Portable/CodeRefactorings/ExtractMethod/AbstractExtractMethodCodeRefactoringProvider.cs b/src/Features/Core/Portable/CodeRefactorings/ExtractMethod/AbstractExtractMethodCodeRefactoringProvider.cs index f06b818d280c8..aae685a87be61 100644 --- a/src/Features/Core/Portable/CodeRefactorings/ExtractMethod/AbstractExtractMethodCodeRefactoringProvider.cs +++ b/src/Features/Core/Portable/CodeRefactorings/ExtractMethod/AbstractExtractMethodCodeRefactoringProvider.cs @@ -56,7 +56,7 @@ public override async Task ComputeRefactoringsAsync(CodeRefactoringContext conte return; } - var options = context.Options.ExtractMethodOptions; + var options = context.Options(document.Project.Language).ExtractMethodOptions; var actions = await GetCodeActionsAsync(document, textSpan, options, cancellationToken).ConfigureAwait(false); context.RegisterRefactorings(actions); } diff --git a/src/Features/Core/Portable/CodeRefactorings/ICodeRefactoringService.cs b/src/Features/Core/Portable/CodeRefactorings/ICodeRefactoringService.cs index 0e43a48d39e56..2bae2385a216f 100644 --- a/src/Features/Core/Portable/CodeRefactorings/ICodeRefactoringService.cs +++ b/src/Features/Core/Portable/CodeRefactorings/ICodeRefactoringService.cs @@ -13,14 +13,14 @@ namespace Microsoft.CodeAnalysis.CodeRefactorings { internal interface ICodeRefactoringService { - Task HasRefactoringsAsync(Document document, TextSpan textSpan, CodeActionOptions options, CancellationToken cancellationToken); + Task HasRefactoringsAsync(Document document, TextSpan textSpan, CodeActionOptionsProvider options, CancellationToken cancellationToken); - Task> GetRefactoringsAsync(Document document, TextSpan textSpan, CodeActionRequestPriority priority, CodeActionOptions options, Func addOperationScope, CancellationToken cancellationToken); + Task> GetRefactoringsAsync(Document document, TextSpan textSpan, CodeActionRequestPriority priority, CodeActionOptionsProvider options, Func addOperationScope, CancellationToken cancellationToken); } internal static class ICodeRefactoringServiceExtensions { - public static Task> GetRefactoringsAsync(this ICodeRefactoringService service, Document document, TextSpan state, CodeActionOptions options, CancellationToken cancellationToken) + public static Task> GetRefactoringsAsync(this ICodeRefactoringService service, Document document, TextSpan state, CodeActionOptionsProvider options, CancellationToken cancellationToken) => service.GetRefactoringsAsync(document, state, CodeActionRequestPriority.None, options, addOperationScope: _ => null, cancellationToken); } } diff --git a/src/Features/Core/Portable/FullyQualify/AbstractFullyQualifyCodeFixProvider.cs b/src/Features/Core/Portable/FullyQualify/AbstractFullyQualifyCodeFixProvider.cs index 9fb65c4415f99..6b7f4a4bb3cf6 100644 --- a/src/Features/Core/Portable/FullyQualify/AbstractFullyQualifyCodeFixProvider.cs +++ b/src/Features/Core/Portable/FullyQualify/AbstractFullyQualifyCodeFixProvider.cs @@ -63,7 +63,7 @@ public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) return; } - var hideAdvancedMembers = context.Options.HideAdvancedMembers; + var hideAdvancedMembers = context.Options(document.Project.Language).HideAdvancedMembers; var semanticModel = await document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false); var matchingTypes = await GetMatchingTypesAsync(document, semanticModel, node, hideAdvancedMembers, cancellationToken).ConfigureAwait(false); diff --git a/src/Features/Core/Portable/ImplementAbstractClass/AbstractImplementAbstractClassCodeFixProvider.cs b/src/Features/Core/Portable/ImplementAbstractClass/AbstractImplementAbstractClassCodeFixProvider.cs index 6ffd69cef3acb..b15c4fd3d2640 100644 --- a/src/Features/Core/Portable/ImplementAbstractClass/AbstractImplementAbstractClassCodeFixProvider.cs +++ b/src/Features/Core/Portable/ImplementAbstractClass/AbstractImplementAbstractClassCodeFixProvider.cs @@ -42,7 +42,7 @@ public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) return; var data = await ImplementAbstractClassData.TryGetDataAsync( - document, classNode, GetClassIdentifier(classNode), context.Options.ImplementTypeOptions, cancellationToken).ConfigureAwait(false); + document, classNode, GetClassIdentifier(classNode), context.Options(document.Project.Language).ImplementTypeOptions, cancellationToken).ConfigureAwait(false); if (data == null) return; diff --git a/src/Features/Core/Portable/SpellCheck/AbstractSpellCheckCodeFixProvider.cs b/src/Features/Core/Portable/SpellCheck/AbstractSpellCheckCodeFixProvider.cs index e2dca078ac380..d2752c63438fc 100644 --- a/src/Features/Core/Portable/SpellCheck/AbstractSpellCheckCodeFixProvider.cs +++ b/src/Features/Core/Portable/SpellCheck/AbstractSpellCheckCodeFixProvider.cs @@ -118,7 +118,7 @@ private async Task CreateSpellCheckCodeIssueAsync( // - We believe spell-check should only compare what you have typed to what symbol would be offered here. var options = CompletionOptions.Default with { - HideAdvancedMembers = context.Options.HideAdvancedMembers, + HideAdvancedMembers = context.Options(document.Project.Language).HideAdvancedMembers, SnippetsBehavior = SnippetsRule.NeverInclude, ShowItemsFromUnimportedNamespaces = false, TargetTypedCompletionFilter = false, diff --git a/src/Features/Core/Portable/SyncNamespaces/AbstractSyncNamespacesSevice.cs b/src/Features/Core/Portable/SyncNamespaces/AbstractSyncNamespacesSevice.cs index 7be9e5ac3a36d..8c416119c0c31 100644 --- a/src/Features/Core/Portable/SyncNamespaces/AbstractSyncNamespacesSevice.cs +++ b/src/Features/Core/Portable/SyncNamespaces/AbstractSyncNamespacesSevice.cs @@ -30,7 +30,7 @@ internal abstract class AbstractSyncNamespacesSevice public async Task SyncNamespacesAsync( ImmutableArray projects, - CodeActionOptions options, + CodeActionOptionsProvider options, CancellationToken cancellationToken) { // all projects must be of the same language @@ -92,7 +92,7 @@ private static async Task GetFixAllContextAsync( Solution solution, CodeFixProvider codeFixProvider, ImmutableDictionary> diagnosticsByProject, - CodeActionOptions options, + CodeActionOptionsProvider options, CancellationToken cancellationToken) { var diagnosticProvider = new DiagnosticProvider(diagnosticsByProject); @@ -126,7 +126,7 @@ private static async Task GetFixAllContextAsync( codeActionEquivalenceKey: action?.EquivalenceKey!, // FixAllState supports null equivalence key. This should still be supported. diagnosticIds: codeFixProvider.FixableDiagnosticIds, fixAllDiagnosticProvider: diagnosticProvider, - _ => options), + options), new ProgressTracker(), cancellationToken); } diff --git a/src/Features/Core/Portable/SyncNamespaces/ISyncNamespacesService.cs b/src/Features/Core/Portable/SyncNamespaces/ISyncNamespacesService.cs index a408b4f60b5c7..25b6accc6c5ba 100644 --- a/src/Features/Core/Portable/SyncNamespaces/ISyncNamespacesService.cs +++ b/src/Features/Core/Portable/SyncNamespaces/ISyncNamespacesService.cs @@ -16,6 +16,6 @@ internal interface ISyncNamespacesService : ILanguageService /// This will update documents in the specified projects so that their namespace matches the RootNamespace /// and their relative folder path. /// - Task SyncNamespacesAsync(ImmutableArray projects, CodeActionOptions options, CancellationToken cancellationToken); + Task SyncNamespacesAsync(ImmutableArray projects, CodeActionOptionsProvider options, CancellationToken cancellationToken); } } diff --git a/src/Features/Core/Portable/Wrapping/AbstractWrappingCodeRefactoringProvider.cs b/src/Features/Core/Portable/Wrapping/AbstractWrappingCodeRefactoringProvider.cs index e252c490e5dd1..f0e74dbfd704b 100644 --- a/src/Features/Core/Portable/Wrapping/AbstractWrappingCodeRefactoringProvider.cs +++ b/src/Features/Core/Portable/Wrapping/AbstractWrappingCodeRefactoringProvider.cs @@ -45,7 +45,7 @@ public override async Task ComputeRefactoringsAsync(CodeRefactoringContext conte var token = root.FindToken(position); var configOptions = await document.GetAnalyzerConfigOptionsAsync(cancellationToken).ConfigureAwait(false); - var options = GetWrappingOptions(configOptions, context.Options); + var options = GetWrappingOptions(configOptions, context.Options(document.Project.Language)); foreach (var node in token.GetRequiredParent().AncestorsAndSelf()) { diff --git a/src/Features/LanguageServer/Protocol/Features/CodeCleanup/AbstractCodeCleanupService.cs b/src/Features/LanguageServer/Protocol/Features/CodeCleanup/AbstractCodeCleanupService.cs index 869c6252a9aee..e33dc3fa44493 100644 --- a/src/Features/LanguageServer/Protocol/Features/CodeCleanup/AbstractCodeCleanupService.cs +++ b/src/Features/LanguageServer/Protocol/Features/CodeCleanup/AbstractCodeCleanupService.cs @@ -33,7 +33,7 @@ public async Task CleanupAsync( Document document, EnabledDiagnosticOptions enabledDiagnostics, IProgressTracker progressTracker, - CodeActionOptions options, + CodeActionOptionsProvider options, SyntaxFormattingOptions formattingOptions, CancellationToken cancellationToken) { @@ -104,7 +104,7 @@ private static async Task RemoveSortUsingsAsync( private async Task ApplyCodeFixesAsync( Document document, ImmutableArray enabledDiagnosticSets, - IProgressTracker progressTracker, CodeActionOptions options, CancellationToken cancellationToken) + IProgressTracker progressTracker, CodeActionOptionsProvider options, CancellationToken cancellationToken) { // Add a progress item for each enabled option we're going to fixup. progressTracker.AddItems(enabledDiagnosticSets.Length); @@ -125,7 +125,7 @@ private async Task ApplyCodeFixesAsync( } private async Task ApplyCodeFixesForSpecificDiagnosticIdsAsync( - Document document, ImmutableArray diagnosticIds, IProgressTracker progressTracker, CodeActionOptions options, CancellationToken cancellationToken) + Document document, ImmutableArray diagnosticIds, IProgressTracker progressTracker, CodeActionOptionsProvider options, CancellationToken cancellationToken) { foreach (var diagnosticId in diagnosticIds) { @@ -139,7 +139,7 @@ private async Task ApplyCodeFixesForSpecificDiagnosticIdsAsync( return document; } - private async Task ApplyCodeFixesForSpecificDiagnosticIdAsync(Document document, string diagnosticId, IProgressTracker progressTracker, CodeActionOptions options, CancellationToken cancellationToken) + private async Task ApplyCodeFixesForSpecificDiagnosticIdAsync(Document document, string diagnosticId, IProgressTracker progressTracker, CodeActionOptionsProvider options, CancellationToken cancellationToken) { var tree = await document.GetRequiredSyntaxTreeAsync(cancellationToken).ConfigureAwait(false); var textSpan = new TextSpan(0, tree.Length); diff --git a/src/Features/LanguageServer/Protocol/Features/CodeCleanup/ICodeCleanupService.cs b/src/Features/LanguageServer/Protocol/Features/CodeCleanup/ICodeCleanupService.cs index f4f09fde674be..970ea7f08dd7f 100644 --- a/src/Features/LanguageServer/Protocol/Features/CodeCleanup/ICodeCleanupService.cs +++ b/src/Features/LanguageServer/Protocol/Features/CodeCleanup/ICodeCleanupService.cs @@ -13,7 +13,7 @@ namespace Microsoft.CodeAnalysis.CodeCleanup { internal interface ICodeCleanupService : ILanguageService { - Task CleanupAsync(Document document, EnabledDiagnosticOptions enabledDiagnostics, IProgressTracker progressTracker, CodeActionOptions options, SyntaxFormattingOptions formattingOptions, CancellationToken cancellationToken); + Task CleanupAsync(Document document, EnabledDiagnosticOptions enabledDiagnostics, IProgressTracker progressTracker, CodeActionOptionsProvider options, SyntaxFormattingOptions formattingOptions, CancellationToken cancellationToken); EnabledDiagnosticOptions GetAllDiagnostics(); } } diff --git a/src/Features/LanguageServer/Protocol/Features/CodeFixes/CodeFixService.cs b/src/Features/LanguageServer/Protocol/Features/CodeFixes/CodeFixService.cs index a6a97a32601fc..28ba566834b18 100644 --- a/src/Features/LanguageServer/Protocol/Features/CodeFixes/CodeFixService.cs +++ b/src/Features/LanguageServer/Protocol/Features/CodeFixes/CodeFixService.cs @@ -98,7 +98,7 @@ public CodeFixService( } public async Task GetMostSevereFixAsync( - Document document, TextSpan range, CodeActionRequestPriority priority, CodeActionOptions options, CancellationToken cancellationToken) + Document document, TextSpan range, CodeActionRequestPriority priority, CodeActionOptionsProvider options, CancellationToken cancellationToken) { var (allDiagnostics, upToDate) = await _diagnosticService.TryGetDiagnosticsForSpanAsync( document, range, GetShouldIncludeDiagnosticPredicate(document, priority), @@ -155,7 +155,7 @@ public async IAsyncEnumerable StreamFixesAsync( Document document, TextSpan range, CodeActionRequestPriority priority, - CodeActionOptions options, + CodeActionOptionsProvider options, Func addOperationScope, [EnumeratorCancellation] CancellationToken cancellationToken) { @@ -231,7 +231,7 @@ private static SortedDictionary> ConvertToMap( } public async Task GetDocumentFixAllForIdInSpanAsync( - Document document, TextSpan range, string diagnosticId, CodeActionOptions options, CancellationToken cancellationToken) + Document document, TextSpan range, string diagnosticId, CodeActionOptionsProvider options, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); @@ -326,7 +326,7 @@ private async IAsyncEnumerable StreamFixesAsync( SortedDictionary> spanToDiagnostics, bool fixAllForInSpan, CodeActionRequestPriority priority, - CodeActionOptions options, + CodeActionOptionsProvider options, Func addOperationScope, [EnumeratorCancellation] CancellationToken cancellationToken) { @@ -489,7 +489,7 @@ void AddAllFixers( } private static async Task> GetCodeFixesAsync( - Document document, TextSpan span, CodeFixProvider fixer, CodeChangeProviderMetadata? fixerMetadata, CodeActionOptions options, + Document document, TextSpan span, CodeFixProvider fixer, CodeChangeProviderMetadata? fixerMetadata, CodeActionOptionsProvider options, ImmutableArray diagnostics, Dictionary> uniqueDiagosticToEquivalenceKeysMap, Dictionary<(Diagnostic diagnostic, string? equivalenceKey), CodeFixProvider> diagnosticAndEquivalenceKeyToFixersMap, @@ -574,7 +574,7 @@ private async IAsyncEnumerable StreamConfigurationFixesAsync( TextSpan diagnosticsSpan, IEnumerable diagnostics, PooledHashSet registeredConfigurationFixTitles, - CodeActionOptions options, + CodeActionOptionsProvider options, [EnumeratorCancellation] CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); @@ -614,7 +614,7 @@ private async IAsyncEnumerable StreamConfigurationFixesAsync( TCodeFixProvider fixer, Func hasFix, Func, Task>> getFixes, - CodeActionOptions options, + CodeActionOptionsProvider options, CancellationToken cancellationToken) where TCodeFixProvider : notnull { @@ -666,11 +666,7 @@ await diagnosticsWithSameSpan.OrderByDescending(d => d.Severity) fixes[0].Action.EquivalenceKey, diagnosticIds, diagnosticProvider, - codeActionOptionsProvider: language => - { - Contract.ThrowIfFalse(language == document.Project.Language); - return options; - }); + options); supportedScopes = fixAllProviderInfo.SupportedScopes; } diff --git a/src/Features/LanguageServer/Protocol/Features/CodeFixes/ICodeFixService.cs b/src/Features/LanguageServer/Protocol/Features/CodeFixes/ICodeFixService.cs index 381d37b9a6639..0a872e0815ebe 100644 --- a/src/Features/LanguageServer/Protocol/Features/CodeFixes/ICodeFixService.cs +++ b/src/Features/LanguageServer/Protocol/Features/CodeFixes/ICodeFixService.cs @@ -16,28 +16,28 @@ namespace Microsoft.CodeAnalysis.CodeFixes { internal interface ICodeFixService { - IAsyncEnumerable StreamFixesAsync(Document document, TextSpan textSpan, CodeActionRequestPriority priority, CodeActionOptions options, Func addOperationScope, CancellationToken cancellationToken); + IAsyncEnumerable StreamFixesAsync(Document document, TextSpan textSpan, CodeActionRequestPriority priority, CodeActionOptionsProvider options, Func addOperationScope, CancellationToken cancellationToken); /// /// Similar to except that instead of streaming all results, this ends with the /// first. This will also attempt to return a fix for an error first, but will fall back to any fix if that /// does not succeed. /// - Task GetMostSevereFixAsync(Document document, TextSpan range, CodeActionRequestPriority priority, CodeActionOptions options, CancellationToken cancellationToken); + Task GetMostSevereFixAsync(Document document, TextSpan range, CodeActionRequestPriority priority, CodeActionOptionsProvider options, CancellationToken cancellationToken); - Task GetDocumentFixAllForIdInSpanAsync(Document document, TextSpan textSpan, string diagnosticId, CodeActionOptions options, CancellationToken cancellationToken); + Task GetDocumentFixAllForIdInSpanAsync(Document document, TextSpan textSpan, string diagnosticId, CodeActionOptionsProvider options, CancellationToken cancellationToken); CodeFixProvider? GetSuppressionFixer(string language, IEnumerable diagnosticIds); } internal static class ICodeFixServiceExtensions { - public static IAsyncEnumerable StreamFixesAsync(this ICodeFixService service, Document document, TextSpan range, CodeActionOptions options, CancellationToken cancellationToken) + public static IAsyncEnumerable StreamFixesAsync(this ICodeFixService service, Document document, TextSpan range, CodeActionOptionsProvider options, CancellationToken cancellationToken) => service.StreamFixesAsync(document, range, CodeActionRequestPriority.None, options, addOperationScope: _ => null, cancellationToken); - public static Task> GetFixesAsync(this ICodeFixService service, Document document, TextSpan range, CodeActionOptions options, CancellationToken cancellationToken) + public static Task> GetFixesAsync(this ICodeFixService service, Document document, TextSpan range, CodeActionOptionsProvider options, CancellationToken cancellationToken) => service.StreamFixesAsync(document, range, options, cancellationToken).ToImmutableArrayAsync(cancellationToken); - public static Task> GetFixesAsync(this ICodeFixService service, Document document, TextSpan textSpan, CodeActionRequestPriority priority, CodeActionOptions options, Func addOperationScope, CancellationToken cancellationToken) + public static Task> GetFixesAsync(this ICodeFixService service, Document document, TextSpan textSpan, CodeActionRequestPriority priority, CodeActionOptionsProvider options, Func addOperationScope, CancellationToken cancellationToken) => service.StreamFixesAsync(document, textSpan, priority, options, addOperationScope, cancellationToken).ToImmutableArrayAsync(cancellationToken); } } diff --git a/src/Features/LanguageServer/Protocol/Features/UnifiedSuggestions/UnifiedSuggestedActionsSource.cs b/src/Features/LanguageServer/Protocol/Features/UnifiedSuggestions/UnifiedSuggestedActionsSource.cs index 2a71deeebb727..488b5a9656ebe 100644 --- a/src/Features/LanguageServer/Protocol/Features/UnifiedSuggestions/UnifiedSuggestedActionsSource.cs +++ b/src/Features/LanguageServer/Protocol/Features/UnifiedSuggestions/UnifiedSuggestedActionsSource.cs @@ -36,7 +36,7 @@ public static async ValueTask> GetFilt Document document, TextSpan selection, CodeActionRequestPriority priority, - CodeActionOptions options, + CodeActionOptionsProvider options, Func addOperationScope, CancellationToken cancellationToken) { @@ -411,7 +411,7 @@ public static async Task> GetFilterAnd Document document, TextSpan selection, CodeActionRequestPriority priority, - CodeActionOptions options, + CodeActionOptionsProvider options, Func addOperationScope, bool filterOutsideSelection, CancellationToken cancellationToken) diff --git a/src/Features/VisualBasic/Portable/ImplementInterface/VisualBasicImplementInterfaceCodeFixProvider.vb b/src/Features/VisualBasic/Portable/ImplementInterface/VisualBasicImplementInterfaceCodeFixProvider.vb index 07412631d3d9c..41e153d3a8c24 100644 --- a/src/Features/VisualBasic/Portable/ImplementInterface/VisualBasicImplementInterfaceCodeFixProvider.vb +++ b/src/Features/VisualBasic/Portable/ImplementInterface/VisualBasicImplementInterfaceCodeFixProvider.vb @@ -61,7 +61,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ImplementInterface Dim service = document.GetLanguageService(Of IImplementInterfaceService)() Dim actions = service.GetCodeActions( document, - context.Options.ImplementTypeOptions, + context.Options(document.Project.Language).ImplementTypeOptions, Await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(False), typeNode, cancellationToken) diff --git a/src/Tools/ExternalAccess/OmniSharp/CodeActions/OmniSharpCodeFixContextFactory.cs b/src/Tools/ExternalAccess/OmniSharp/CodeActions/OmniSharpCodeFixContextFactory.cs index 091695050adb7..65dc921a7f9f3 100644 --- a/src/Tools/ExternalAccess/OmniSharp/CodeActions/OmniSharpCodeFixContextFactory.cs +++ b/src/Tools/ExternalAccess/OmniSharp/CodeActions/OmniSharpCodeFixContextFactory.cs @@ -23,7 +23,7 @@ public static CodeFixContext CreateCodeFixContext( Action> registerCodeFix, OmniSharpCodeActionOptions options, CancellationToken cancellationToken) - => new(document, span, diagnostics, registerCodeFix, options.GetCodeActionOptions(), cancellationToken); + => new(document, span, diagnostics, registerCodeFix, _ => options.GetCodeActionOptions(), cancellationToken); public static CodeRefactoringContext CreateCodeRefactoringContext( Document document, @@ -31,7 +31,7 @@ public static CodeRefactoringContext CreateCodeRefactoringContext( Action registerRefactoring, OmniSharpCodeActionOptions options, CancellationToken cancellationToken) - => new(document, span, registerRefactoring, options.GetCodeActionOptions(), cancellationToken); + => new(document, span, registerRefactoring, _ => options.GetCodeActionOptions(), cancellationToken); public static FixAllContext CreateFixAllContext( Document? document, diff --git a/src/VisualStudio/Core/Def/CodeCleanup/AbstractCodeCleanUpFixer.cs b/src/VisualStudio/Core/Def/CodeCleanup/AbstractCodeCleanUpFixer.cs index 262cf75512eec..f235a0fc5db71 100644 --- a/src/VisualStudio/Core/Def/CodeCleanup/AbstractCodeCleanUpFixer.cs +++ b/src/VisualStudio/Core/Def/CodeCleanup/AbstractCodeCleanUpFixer.cs @@ -355,7 +355,7 @@ private static async Task FixDocumentAsync( var formattingOptions = await SyntaxFormattingOptions.FromDocumentAsync(document, cancellationToken).ConfigureAwait(false); return await codeCleanupService.CleanupAsync( - document, enabledDiagnostics, progressTracker, ideOptions, formattingOptions, cancellationToken).ConfigureAwait(false); + document, enabledDiagnostics, progressTracker, _ => ideOptions, formattingOptions, cancellationToken).ConfigureAwait(false); } } } diff --git a/src/VisualStudio/Core/Def/SyncNamespaces/SyncNamespacesCommandHandler.cs b/src/VisualStudio/Core/Def/SyncNamespaces/SyncNamespacesCommandHandler.cs index b5b17572123e8..42862d66cca04 100644 --- a/src/VisualStudio/Core/Def/SyncNamespaces/SyncNamespacesCommandHandler.cs +++ b/src/VisualStudio/Core/Def/SyncNamespaces/SyncNamespacesCommandHandler.cs @@ -132,7 +132,7 @@ private void SyncNamespaces(ImmutableArray projects) } var syncService = projects[0].GetRequiredLanguageService(); - var options = _globalOptions.GetCodeActionOptions(projects[0].Language); + var options = _globalOptions.GetCodeActionOptionsProvider(); Solution? solution = null; var status = _threadOperationExecutor.Execute(ServicesVSResources.Sync_Namespaces, ServicesVSResources.Updating_namspaces, allowCancellation: true, showProgress: true, (operationContext) => diff --git a/src/Workspaces/Core/Portable/CodeFixes/CodeFixContext.cs b/src/Workspaces/Core/Portable/CodeFixes/CodeFixContext.cs index 47a020c75426f..62ebe6c86ce69 100644 --- a/src/Workspaces/Core/Portable/CodeFixes/CodeFixContext.cs +++ b/src/Workspaces/Core/Portable/CodeFixes/CodeFixContext.cs @@ -16,7 +16,9 @@ namespace Microsoft.CodeAnalysis.CodeFixes /// /// Context for code fixes provided by a . /// +#pragma warning disable CS0612 // Type or member is obsolete public readonly struct CodeFixContext : ITypeScriptCodeFixContext +#pragma warning restore { private readonly Document _document; private readonly TextSpan _span; @@ -45,8 +47,17 @@ namespace Microsoft.CodeAnalysis.CodeFixes /// public CancellationToken CancellationToken => _cancellationToken; - internal readonly CodeActionOptions Options; - bool ITypeScriptCodeFixContext.IsBlocking => Options.IsBlocking; + /// + /// IDE supplied options to use for settings not specified in the corresponding editorconfig file. + /// + /// + /// Provider to allow code fix to update documents across multiple projects that differ in language (and hence language specific options). + /// + internal readonly CodeActionOptionsProvider Options; + + [Obsolete] + bool ITypeScriptCodeFixContext.IsBlocking + => Options("TypeScript").IsBlocking; /// /// Creates a code fix context to be passed into method. @@ -75,7 +86,7 @@ public CodeFixContext( span, VerifyDiagnosticsArgument(diagnostics, span), registerCodeFix ?? throw new ArgumentNullException(nameof(registerCodeFix)), - CodeActionOptions.Default, + _ => CodeActionOptions.Default, cancellationToken) { } @@ -100,7 +111,7 @@ public CodeFixContext( (diagnostic ?? throw new ArgumentNullException(nameof(diagnostic))).Location.SourceSpan, ImmutableArray.Create(diagnostic), registerCodeFix ?? throw new ArgumentNullException(nameof(registerCodeFix)), - CodeActionOptions.Default, + _ => CodeActionOptions.Default, cancellationToken) { } @@ -110,7 +121,7 @@ internal CodeFixContext( TextSpan span, ImmutableArray diagnostics, Action> registerCodeFix, - CodeActionOptions options, + CodeActionOptionsProvider options, CancellationToken cancellationToken) { Debug.Assert(diagnostics.Any(d => d.Location.SourceSpan == span)); @@ -201,6 +212,7 @@ private static ImmutableArray VerifyDiagnosticsArgument(ImmutableArr } } + [Obsolete] internal interface ITypeScriptCodeFixContext { bool IsBlocking { get; } diff --git a/src/Workspaces/Core/Portable/CodeFixes/FixAllOccurrences/BatchFixAllProvider.cs b/src/Workspaces/Core/Portable/CodeFixes/FixAllOccurrences/BatchFixAllProvider.cs index f6c139870894b..334020fdc431a 100644 --- a/src/Workspaces/Core/Portable/CodeFixes/FixAllOccurrences/BatchFixAllProvider.cs +++ b/src/Workspaces/Core/Portable/CodeFixes/FixAllOccurrences/BatchFixAllProvider.cs @@ -146,7 +146,7 @@ private static async Task> GetAllChangedDocumentsInDiag foreach (var diagnostic in orderedDiagnostics) { var document = solution.GetRequiredDocument(diagnostic.Location.SourceTree!); - var options = fixAllContext.State.CodeActionOptionsProvider(document.Project.Language) with { IsBlocking = false }; + var options = new CodeActionOptionsProvider(language => fixAllContext.State.CodeActionOptionsProvider(language) with { IsBlocking = false }); cancellationToken.ThrowIfCancellationRequested(); tasks.Add(Task.Run(async () => diff --git a/src/Workspaces/Core/Portable/CodeRefactorings/CodeRefactoringContext.cs b/src/Workspaces/Core/Portable/CodeRefactorings/CodeRefactoringContext.cs index 09e1442f9d76b..c2a3f38862c1d 100644 --- a/src/Workspaces/Core/Portable/CodeRefactorings/CodeRefactoringContext.cs +++ b/src/Workspaces/Core/Portable/CodeRefactorings/CodeRefactoringContext.cs @@ -12,7 +12,9 @@ namespace Microsoft.CodeAnalysis.CodeRefactorings /// /// Context for code refactorings provided by a . /// +#pragma warning disable CS0612 // Type or member is obsolete public readonly struct CodeRefactoringContext : ITypeScriptCodeRefactoringContext +#pragma warning restore { /// /// Document corresponding to the to refactor. @@ -29,8 +31,11 @@ namespace Microsoft.CodeAnalysis.CodeRefactorings /// public CancellationToken CancellationToken { get; } - internal readonly CodeActionOptions Options; - bool ITypeScriptCodeRefactoringContext.IsBlocking => Options.IsBlocking; + internal readonly CodeActionOptionsProvider Options; + + [Obsolete] + bool ITypeScriptCodeRefactoringContext.IsBlocking + => Options("TypeScript").IsBlocking; private readonly Action _registerRefactoring; @@ -42,7 +47,7 @@ public CodeRefactoringContext( TextSpan span, Action registerRefactoring, CancellationToken cancellationToken) - : this(document, span, (action, textSpan) => registerRefactoring(action), CodeActionOptions.Default, cancellationToken) + : this(document, span, (action, textSpan) => registerRefactoring(action), _ => CodeActionOptions.Default, cancellationToken) { } /// @@ -52,7 +57,7 @@ internal CodeRefactoringContext( Document document, TextSpan span, Action registerRefactoring, - CodeActionOptions options, + CodeActionOptionsProvider options, CancellationToken cancellationToken) { // NOTE/TODO: Don't make this overload public & obsolete the `Action registerRefactoring` @@ -99,6 +104,7 @@ internal void Deconstruct(out Document document, out TextSpan span, out Cancella } } + [Obsolete] internal interface ITypeScriptCodeRefactoringContext { bool IsBlocking { get; } diff --git a/src/Workspaces/Core/Portable/ExternalAccess/VSTypeScript/Api/VSTypeScriptCodeFixContextExtensions.cs b/src/Workspaces/Core/Portable/ExternalAccess/VSTypeScript/Api/VSTypeScriptCodeFixContextExtensions.cs index 3dd5d9a7150cc..d1e9c7113d511 100644 --- a/src/Workspaces/Core/Portable/ExternalAccess/VSTypeScript/Api/VSTypeScriptCodeFixContextExtensions.cs +++ b/src/Workspaces/Core/Portable/ExternalAccess/VSTypeScript/Api/VSTypeScriptCodeFixContextExtensions.cs @@ -2,16 +2,21 @@ // 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; -using System.Collections.Generic; -using System.Text; using Microsoft.CodeAnalysis.CodeFixes; +using Microsoft.CodeAnalysis.CodeRefactorings; namespace Microsoft.CodeAnalysis.ExternalAccess.VSTypeScript.Api { internal static class VSTypeScriptCodeFixContextExtensions { public static bool IsBlocking(this CodeFixContext context) +#pragma warning disable CS0612 // Type or member is obsolete => ((ITypeScriptCodeFixContext)context).IsBlocking; +#pragma warning restore + + public static bool IsBlocking(this CodeRefactoringContext context) +#pragma warning disable CS0612 // Type or member is obsolete + => ((ITypeScriptCodeRefactoringContext)context).IsBlocking; +#pragma warning restore } } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeFixes/SyntaxEditorBasedCodeFixProvider.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeFixes/SyntaxEditorBasedCodeFixProvider.cs index 299f2931ad2f8..58c129b2e3e05 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeFixes/SyntaxEditorBasedCodeFixProvider.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeFixes/SyntaxEditorBasedCodeFixProvider.cs @@ -70,7 +70,7 @@ protected Func> GetDocumentUpdater(CodeFixCont #if CODE_STYLE var optionsProvider = s_codeStyleOptionsProvider; #else - var optionsProvider = new CodeActionOptionsProvider(_ => context.Options); + var optionsProvider = context.Options; #endif var diagnostics = ImmutableArray.Create(diagnostic ?? context.Diagnostics[0]); From a96c8ac8c06187f0d5347639a1ce6decb062a4d4 Mon Sep 17 00:00:00 2001 From: David Wengier Date: Thu, 14 Apr 2022 06:52:25 +1000 Subject: [PATCH 49/66] Grab bag of UTF8 string support in IDE features (#60599) --- .../StringLiteralBraceMatcher.cs | 33 ++-- .../CSharpTextStructureNavigatorProvider.cs | 27 +++- .../BraceMatching/CSharpBraceMatcherTests.cs | 117 ++++++++++++++ ...nvertToFileScopedNamespaceAnalyzerTests.cs | 96 ++++++++++++ .../SplitStringLiteralCommandHandlerTests.cs | 148 ++++++++++++++++++ .../TextStructureNavigatorTests.cs | 61 ++++++++ .../SimpleStringSplitter.cs | 16 +- .../SplitStringLiteral/StringSplitter.cs | 3 +- .../CSharpHelpContextService.cs | 15 ++ .../CSharp/Test/F1Help/F1HelpTests.cs | 45 ++++++ .../CSharp/Extensions/SyntaxTreeExtensions.cs | 7 +- 11 files changed, 548 insertions(+), 20 deletions(-) diff --git a/src/EditorFeatures/CSharp/BraceMatching/StringLiteralBraceMatcher.cs b/src/EditorFeatures/CSharp/BraceMatching/StringLiteralBraceMatcher.cs index aadd11b6a2b89..5d95adebcb969 100644 --- a/src/EditorFeatures/CSharp/BraceMatching/StringLiteralBraceMatcher.cs +++ b/src/EditorFeatures/CSharp/BraceMatching/StringLiteralBraceMatcher.cs @@ -34,18 +34,11 @@ public StringLiteralBraceMatcher() { if (token.IsKind(SyntaxKind.StringLiteralToken)) { - if (token.IsVerbatimStringLiteral()) - { - return new BraceMatchingResult( - new TextSpan(token.SpanStart, 2), - new TextSpan(token.Span.End - 1, 1)); - } - else - { - return new BraceMatchingResult( - new TextSpan(token.SpanStart, 1), - new TextSpan(token.Span.End - 1, 1)); - } + return GetSimpleStringBraceMatchingResult(token, endTokenLength: 1); + } + else if (token.IsKind(SyntaxKind.UTF8StringLiteralToken)) + { + return GetSimpleStringBraceMatchingResult(token, endTokenLength: 3); } else if (token.IsKind(SyntaxKind.InterpolatedStringStartToken, SyntaxKind.InterpolatedVerbatimStringStartToken)) { @@ -65,5 +58,21 @@ public StringLiteralBraceMatcher() return null; } + + private static BraceMatchingResult GetSimpleStringBraceMatchingResult(SyntaxToken token, int endTokenLength) + { + if (token.IsVerbatimStringLiteral()) + { + return new BraceMatchingResult( + new TextSpan(token.SpanStart, 2), + new TextSpan(token.Span.End - endTokenLength, endTokenLength)); + } + else + { + return new BraceMatchingResult( + new TextSpan(token.SpanStart, 1), + new TextSpan(token.Span.End - endTokenLength, endTokenLength)); + } + } } } diff --git a/src/EditorFeatures/CSharp/TextStructureNavigation/CSharpTextStructureNavigatorProvider.cs b/src/EditorFeatures/CSharp/TextStructureNavigation/CSharpTextStructureNavigatorProvider.cs index 8cef5deb3a2b4..2bf8763b7eb7f 100644 --- a/src/EditorFeatures/CSharp/TextStructureNavigation/CSharpTextStructureNavigatorProvider.cs +++ b/src/EditorFeatures/CSharp/TextStructureNavigation/CSharpTextStructureNavigatorProvider.cs @@ -11,6 +11,7 @@ using Microsoft.VisualStudio.Text; using Microsoft.VisualStudio.Text.Operations; using Microsoft.VisualStudio.Utilities; +using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Editor.CSharp.TextStructureNavigation { @@ -36,12 +37,15 @@ protected override bool IsWithinNaturalLanguage(SyntaxToken token, int position) switch (token.Kind()) { case SyntaxKind.StringLiteralToken: + case SyntaxKind.UTF8StringLiteralToken: // This, in combination with the override of GetExtentOfWordFromToken() below, treats the closing // quote as a separate token. This maintains behavior with VS2013. return !IsAtClosingQuote(token, position); case SyntaxKind.SingleLineRawStringLiteralToken: case SyntaxKind.MultiLineRawStringLiteralToken: + case SyntaxKind.UTF8SingleLineRawStringLiteralToken: + case SyntaxKind.UTF8MultiLineRawStringLiteralToken: { // Like with normal string literals, treat the closing quotes as as the end of the string so that // navigation ends there and doesn't go past them. @@ -66,6 +70,13 @@ private static int GetStartOfRawStringLiteralEndDelimiter(SyntaxToken token) var text = token.ToString(); var start = 0; var end = text.Length; + + if (token.IsKind(SyntaxKind.UTF8MultiLineRawStringLiteralToken, SyntaxKind.UTF8SingleLineRawStringLiteralToken)) + { + // Skip past the u8 suffix + end -= "u8".Length; + } + while (start < end && text[start] == '"') start++; @@ -76,19 +87,27 @@ private static int GetStartOfRawStringLiteralEndDelimiter(SyntaxToken token) } private static bool IsAtClosingQuote(SyntaxToken token, int position) - => position == token.Span.End - 1 && token.Text[^1] == '"'; + => token.Kind() switch + { + SyntaxKind.StringLiteralToken => position == token.Span.End - 1 && token.Text[^1] == '"', + SyntaxKind.UTF8StringLiteralToken => position == token.Span.End - 3 && token.Text is [.., '"', 'u' or 'U', '8'], + _ => throw ExceptionUtilities.Unreachable + }; protected override TextExtent GetExtentOfWordFromToken(SyntaxToken token, SnapshotPoint position) { - if (token.Kind() == SyntaxKind.StringLiteralToken && IsAtClosingQuote(token, position.Position)) + if (token.IsKind(SyntaxKind.StringLiteralToken, SyntaxKind.UTF8StringLiteralToken) && IsAtClosingQuote(token, position.Position)) { // Special case to treat the closing quote of a string literal as a separate token. This allows the // cursor to stop during word navigation (Ctrl+LeftArrow, etc.) immediately before AND after the // closing quote, just like it did in VS2013 and like it currently does for interpolated strings. - var span = new Span(position.Position, 1); + var span = new Span(position.Position, token.Span.End - position.Position); return new TextExtent(new SnapshotSpan(position.Snapshot, span), isSignificant: true); } - else if (token.Kind() is SyntaxKind.SingleLineRawStringLiteralToken or SyntaxKind.MultiLineRawStringLiteralToken) + else if (token.IsKind(SyntaxKind.SingleLineRawStringLiteralToken, + SyntaxKind.MultiLineRawStringLiteralToken, + SyntaxKind.UTF8SingleLineRawStringLiteralToken, + SyntaxKind.UTF8MultiLineRawStringLiteralToken)) { var delimiterStart = GetStartOfRawStringLiteralEndDelimiter(token); return new TextExtent(new SnapshotSpan(position.Snapshot, Span.FromBounds(delimiterStart, token.Span.End)), isSignificant: true); diff --git a/src/EditorFeatures/CSharpTest/BraceMatching/CSharpBraceMatcherTests.cs b/src/EditorFeatures/CSharpTest/BraceMatching/CSharpBraceMatcherTests.cs index 8df3c36ae251c..27aa83f07adb2 100644 --- a/src/EditorFeatures/CSharpTest/BraceMatching/CSharpBraceMatcherTests.cs +++ b/src/EditorFeatures/CSharpTest/BraceMatching/CSharpBraceMatcherTests.cs @@ -505,6 +505,123 @@ public async Task TestInterpolatedString13() await TestAsync(code, expected); } + [Fact, Trait(Traits.Feature, Traits.Features.BraceMatching)] + public async Task TestUTF8String1() + { + var code = @"public class C { string s = $$""Goo""u8; }"; + var expected = @"public class C { string s = ""Goo[|""u8|]; }"; + + await TestAsync(code, expected); + } + + [Fact, Trait(Traits.Feature, Traits.Features.BraceMatching)] + public async Task TestUTF8String2() + { + var code = @"public class C { string s = ""$$Goo""u8; }"; + var expected = @"public class C { string s = ""Goo[|""u8|]; }"; + + await TestAsync(code, expected); + } + + [Fact, Trait(Traits.Feature, Traits.Features.BraceMatching)] + public async Task TestUTF8String3() + { + var code = @"public class C { string s = ""Goo$$""u8; }"; + var expected = @"public class C { string s = [|""|]Goo""u8; }"; + + await TestAsync(code, expected); + } + + [Fact, Trait(Traits.Feature, Traits.Features.BraceMatching)] + public async Task TestUTF8String4() + { + var code = @"public class C { string s = ""Goo""$$u8; }"; + var expected = @"public class C { string s = [|""|]Goo""u8; }"; + + await TestAsync(code, expected); + } + + [Fact, Trait(Traits.Feature, Traits.Features.BraceMatching)] + public async Task TestUTF8String5() + { + var code = @"public class C { string s = ""Goo""u$$8; }"; + var expected = @"public class C { string s = [|""|]Goo""u8; }"; + + await TestAsync(code, expected); + } + + [Fact, Trait(Traits.Feature, Traits.Features.BraceMatching)] + public async Task TestUTF8String6() + { + var code = @"public class C { string s = ""Goo""u8$$; }"; + var expected = @"public class C { string s = [|""|]Goo""u8; }"; + + await TestAsync(code, expected); + } + + [Fact, Trait(Traits.Feature, Traits.Features.BraceMatching)] + public async Task TestVerbatimUTF8String1() + { + var code = @"public class C { string s = $$@""Goo""u8; }"; + var expected = @"public class C { string s = @""Goo[|""u8|]; }"; + + await TestAsync(code, expected); + } + + [Fact, Trait(Traits.Feature, Traits.Features.BraceMatching)] + public async Task TestVerbatimUTF8String2() + { + var code = @"public class C { string s = @$$""Goo""u8; }"; + var expected = @"public class C { string s = @""Goo[|""u8|]; }"; + + await TestAsync(code, expected); + } + + [Fact, Trait(Traits.Feature, Traits.Features.BraceMatching)] + public async Task TestVerbatimUTF8String3() + { + var code = @"public class C { string s = @""$$Goo""u8; }"; + var expected = @"public class C { string s = @""Goo[|""u8|]; }"; + + await TestAsync(code, expected); + } + + [Fact, Trait(Traits.Feature, Traits.Features.BraceMatching)] + public async Task TestVerbatimUTF8String4() + { + var code = @"public class C { string s = @""Goo$$""u8; }"; + var expected = @"public class C { string s = [|@""|]Goo""u8; }"; + + await TestAsync(code, expected); + } + + [Fact, Trait(Traits.Feature, Traits.Features.BraceMatching)] + public async Task TestVerbatimUTF8String5() + { + var code = @"public class C { string s = @""Goo""$$u8; }"; + var expected = @"public class C { string s = [|@""|]Goo""u8; }"; + + await TestAsync(code, expected); + } + + [Fact, Trait(Traits.Feature, Traits.Features.BraceMatching)] + public async Task TestVerbatimUTF8String6() + { + var code = @"public class C { string s = @""Goo""u$$8; }"; + var expected = @"public class C { string s = [|@""|]Goo""u8; }"; + + await TestAsync(code, expected); + } + + [Fact, Trait(Traits.Feature, Traits.Features.BraceMatching)] + public async Task TestVerbatimUTF8String7() + { + var code = @"public class C { string s = @""Goo""u8$$; }"; + var expected = @"public class C { string s = [|@""|]Goo""u8; }"; + + await TestAsync(code, expected); + } + [WorkItem(7120, "https://github.com/dotnet/roslyn/issues/7120")] [WpfFact, Trait(Traits.Feature, Traits.Features.BraceMatching)] public async Task TestConditionalDirectiveWithSingleMatchingDirective() diff --git a/src/EditorFeatures/CSharpTest/ConvertNamespace/ConvertToFileScopedNamespaceAnalyzerTests.cs b/src/EditorFeatures/CSharpTest/ConvertNamespace/ConvertToFileScopedNamespaceAnalyzerTests.cs index b35b1f88e270d..55e701b957214 100644 --- a/src/EditorFeatures/CSharpTest/ConvertNamespace/ConvertToFileScopedNamespaceAnalyzerTests.cs +++ b/src/EditorFeatures/CSharpTest/ConvertNamespace/ConvertToFileScopedNamespaceAnalyzerTests.cs @@ -677,6 +677,102 @@ void M() }.RunAsync(); } + [Fact] + public async Task TestConvertToFileScopedWithMultiLineRawString() + { + await new VerifyCS.Test + { + TestCode = @" +[|namespace N|] +{ + class C + { + void M() + { + System.Console.WriteLine("""""" + a + b + c + d + e + """"""); + } + } +} +", + FixedCode = @" +namespace $$N; + +class C +{ + void M() + { + System.Console.WriteLine("""""" + a + b + c + d + e + """"""); + } +} +", + LanguageVersion = LanguageVersion.Preview, + Options = + { + { CSharpCodeStyleOptions.NamespaceDeclarations, NamespaceDeclarationPreference.FileScoped } + } + }.RunAsync(); + } + + [Fact] + public async Task TestConvertToFileScopedWithUTF8MultiLineRawString() + { + await new VerifyCS.Test + { + TestCode = @" +[|namespace N|] +{ + class C + { + void M() + { + System.Console.WriteLine("""""" + a + b + c + d + e + """"""u8); + } + } +} +", + FixedCode = @" +namespace $$N; + +class C +{ + void M() + { + System.Console.WriteLine("""""" + a + b + c + d + e + """"""u8); + } +} +", + LanguageVersion = LanguageVersion.Preview, + Options = + { + { CSharpCodeStyleOptions.NamespaceDeclarations, NamespaceDeclarationPreference.FileScoped } + } + }.RunAsync(); + } + [Fact] public async Task TestConvertToFileScopedSingleLineNamespace1() { diff --git a/src/EditorFeatures/CSharpTest/SplitStringLiteral/SplitStringLiteralCommandHandlerTests.cs b/src/EditorFeatures/CSharpTest/SplitStringLiteral/SplitStringLiteralCommandHandlerTests.cs index 850b60b06f653..5759ffa2d5234 100644 --- a/src/EditorFeatures/CSharpTest/SplitStringLiteral/SplitStringLiteralCommandHandlerTests.cs +++ b/src/EditorFeatures/CSharpTest/SplitStringLiteral/SplitStringLiteralCommandHandlerTests.cs @@ -149,6 +149,19 @@ void M() }"); } + [WpfFact, Trait(Traits.Feature, Traits.Features.SplitStringLiteral)] + public void TestMissingBeforeUTF8String() + { + TestNotHandled( +@"class C +{ + void M() + { + var v = [||]""""u8; + } +}"); + } + [WpfFact, Trait(Traits.Feature, Traits.Features.SplitStringLiteral)] public void TestMissingBeforeInterpolatedString() { @@ -266,6 +279,71 @@ void M() }"); } + [WpfFact, Trait(Traits.Feature, Traits.Features.SplitStringLiteral)] + public void TestMissingAfterUTF8String_1() + { + TestNotHandled( +@"class C +{ + void M() + { + var v = """"[||]u8; + } +}"); + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.SplitStringLiteral)] + public void TestMissingAfterUTF8String_2() + { + TestNotHandled( +@"class C +{ + void M() + { + var v = """"u8[||]; + } +}"); + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.SplitStringLiteral)] + public void TestMissingAfterUTF8String_3() + { + TestNotHandled( +@"class C +{ + void M() + { + var v = """"u8[||] + } +}"); + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.SplitStringLiteral)] + public void TestMissingAfterUTF8String_4() + { + TestNotHandled( +@"class C +{ + void M() + { + var v = $""""u8 [||] + } +}"); + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.SplitStringLiteral)] + public void TestMissingAfterUTF8String_5() + { + TestNotHandled( +@"class C +{ + void M() + { + var v = """"u[||]8; + } +}"); + } + [WpfFact, Trait(Traits.Feature, Traits.Features.SplitStringLiteral)] public void TestMissingInVerbatimString() { @@ -279,6 +357,19 @@ void M() }"); } + [WpfFact, Trait(Traits.Feature, Traits.Features.SplitStringLiteral)] + public void TestMissingInUTF8VerbatimString() + { + TestNotHandled( +@"class C +{ + void M() + { + var v = @""a[||]b""u8; + } +}"); + } + [WpfFact, Trait(Traits.Feature, Traits.Features.SplitStringLiteral)] public void TestMissingInInterpolatedVerbatimString() { @@ -450,6 +541,48 @@ void M() }"); } + [WpfFact, Trait(Traits.Feature, Traits.Features.SplitStringLiteral)] + public void TestUTF8String_1() + { + TestHandled( +@"class C +{ + void M() + { + var v = ""now is [||]the time""u8; + } +}", +@"class C +{ + void M() + { + var v = ""now is ""u8 + + ""[||]the time""u8; + } +}"); + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.SplitStringLiteral)] + public void TestUTF8String_2() + { + TestHandled( +@"class C +{ + void M() + { + var v = ""now is [||]the time""U8; + } +}", +@"class C +{ + void M() + { + var v = ""now is ""U8 + + ""[||]the time""U8; + } +}"); + } + [WpfFact, Trait(Traits.Feature, Traits.Features.SplitStringLiteral)] public void TestInterpolatedString1() { @@ -944,6 +1077,21 @@ void M() world """"""; } +}"); + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.SplitStringLiteral)] + public void TestMissingInRawUTF8StringLiteral() + { + TestNotHandled( +@"class C +{ + void M() + { + var v = """"""Hello[||]there +world +""""""u8; + } }"); } } diff --git a/src/EditorFeatures/CSharpTest/TextStructureNavigation/TextStructureNavigatorTests.cs b/src/EditorFeatures/CSharpTest/TextStructureNavigation/TextStructureNavigatorTests.cs index 4c431f1d41e9a..f1d3e82a3264f 100644 --- a/src/EditorFeatures/CSharpTest/TextStructureNavigation/TextStructureNavigatorTests.cs +++ b/src/EditorFeatures/CSharpTest/TextStructureNavigation/TextStructureNavigatorTests.cs @@ -249,6 +249,28 @@ public void String() @"class Test { private string s1 = "" () test ""{|Significant:$$;|} }"); } + [WpfFact, Trait(Traits.Feature, Traits.Features.TextStructureNavigator)] + public void UTF8String() + { + AssertExtent( + @"class Test { private string s1 = {|Significant:$$""|} () test ""u8; }"); + + AssertExtent( + @"class Test { private string s1 = ""{|Insignificant:$$ |}() test ""u8; }"); + + AssertExtent( + @"class Test { private string s1 = "" {|Significant:$$()|} test ""u8; }"); + + AssertExtent( + @"class Test { private string s1 = "" () test{|Insignificant:$$ |}""u8; }"); + + AssertExtent( + @"class Test { private string s1 = "" () test {|Significant:$$""u8|}; }"); + + AssertExtent( + @"class Test { private string s1 = "" () test ""u8{|Significant:$$;|} }"); + } + [WpfFact, Trait(Traits.Feature, Traits.Features.TextStructureNavigator)] public void InterpolatedString1() { @@ -382,6 +404,45 @@ public void TestRawStringDelimeter2() {|Significant:""""$$""|};"); } + [WpfFact, Trait(Traits.Feature, Traits.Features.TextStructureNavigator)] + public void TestUTF8RawStringDelimeter() + { + AssertExtent( + @"string s = """""" + Hello + World! + :) + {|Significant:$$""""""u8|};"); + + AssertExtent( + @"string s = """""" + Hello + World! + :) + {|Significant:""$$""""u8|};"); + + AssertExtent( + @"string s = """""" + Hello + World! + :) + {|Significant:""""$$""u8|};"); + + AssertExtent( + @"string s = """""" + Hello + World! + :) + {|Significant:""""""$$u8|};"); + + AssertExtent( + @"string s = """""" + Hello + World! + :) + {|Significant:""""""u$$8|};"); + } + private static void TestNavigator( string code, Func func, diff --git a/src/Features/CSharp/Portable/SplitStringLiteral/SimpleStringSplitter.cs b/src/Features/CSharp/Portable/SplitStringLiteral/SimpleStringSplitter.cs index 5ed690b31fe9c..0573e92b3dd00 100644 --- a/src/Features/CSharp/Portable/SplitStringLiteral/SimpleStringSplitter.cs +++ b/src/Features/CSharp/Portable/SplitStringLiteral/SimpleStringSplitter.cs @@ -29,8 +29,14 @@ public SimpleStringSplitter( } // Don't split @"" strings. They already support directly embedding newlines. + // Don't split UTF8 strings if the cursor is after the quote. protected override bool CheckToken() - => !_token.IsVerbatimStringLiteral(); + => !_token.IsVerbatimStringLiteral() && !CursorIsAfterQuotesInUTF8String(); + + private bool CursorIsAfterQuotesInUTF8String() + { + return _token.IsKind(SyntaxKind.UTF8StringLiteralToken) && CursorPosition >= _token.Span.End - "u8".Length; + } protected override SyntaxNode GetNodeToReplace() => _token.Parent; @@ -40,10 +46,16 @@ protected override BinaryExpressionSyntax CreateSplitString() var prefix = SourceText.GetSubText(TextSpan.FromBounds(_token.SpanStart, CursorPosition)).ToString(); var suffix = SourceText.GetSubText(TextSpan.FromBounds(CursorPosition, _token.Span.End)).ToString(); + // If we're spliting a UTF8 string we need to keep the u8 suffix on the first part. We copy whatever + // the user had on the second part, for consistency. + var firstTokenSuffix = _token.Kind() == SyntaxKind.UTF8StringLiteralToken + ? SourceText.GetSubText(TextSpan.FromBounds(_token.Span.End - "u8".Length, _token.Span.End)).ToString() + : ""; + var firstToken = SyntaxFactory.Token( _token.LeadingTrivia, _token.Kind(), - text: prefix + QuoteCharacter, + text: prefix + QuoteCharacter + firstTokenSuffix, valueText: "", trailing: SyntaxFactory.TriviaList(SyntaxFactory.ElasticSpace)); diff --git a/src/Features/CSharp/Portable/SplitStringLiteral/StringSplitter.cs b/src/Features/CSharp/Portable/SplitStringLiteral/StringSplitter.cs index 9062054e2faa0..dd6e37afd7d45 100644 --- a/src/Features/CSharp/Portable/SplitStringLiteral/StringSplitter.cs +++ b/src/Features/CSharp/Portable/SplitStringLiteral/StringSplitter.cs @@ -58,7 +58,8 @@ public static StringSplitter TryCreate( var token = root.FindToken(position); - if (token.IsKind(SyntaxKind.StringLiteralToken)) + if (token.IsKind(SyntaxKind.StringLiteralToken) || + token.IsKind(SyntaxKind.UTF8StringLiteralToken)) { return new SimpleStringSplitter( document, position, root, diff --git a/src/VisualStudio/CSharp/Impl/LanguageService/CSharpHelpContextService.cs b/src/VisualStudio/CSharp/Impl/LanguageService/CSharpHelpContextService.cs index f573e365c371d..65fc71ee8dc02 100644 --- a/src/VisualStudio/CSharp/Impl/LanguageService/CSharpHelpContextService.cs +++ b/src/VisualStudio/CSharp/Impl/LanguageService/CSharpHelpContextService.cs @@ -133,6 +133,21 @@ private static bool TryGetTextForSpecialCharacters(SyntaxToken token, [NotNullWh return true; } + if (token.IsKind(SyntaxKind.UTF8StringLiteralToken) || + token.IsKind(SyntaxKind.UTF8SingleLineRawStringLiteralToken) || + token.IsKind(SyntaxKind.UTF8MultiLineRawStringLiteralToken)) + { + text = Keyword("UTF8StringLiteral"); + return true; + } + + if (token.IsKind(SyntaxKind.SingleLineRawStringLiteralToken) || + token.IsKind(SyntaxKind.MultiLineRawStringLiteralToken)) + { + text = Keyword("RawStringLiteral"); + return true; + } + text = null; return false; } diff --git a/src/VisualStudio/CSharp/Test/F1Help/F1HelpTests.cs b/src/VisualStudio/CSharp/Test/F1Help/F1HelpTests.cs index e2b8609e5555d..e7ae818178945 100644 --- a/src/VisualStudio/CSharp/Test/F1Help/F1HelpTests.cs +++ b/src/VisualStudio/CSharp/Test/F1Help/F1HelpTests.cs @@ -942,6 +942,51 @@ static void Main(string[] args) }", "$_CSharpKeyword"); } + [Fact, Trait(Traits.Feature, Traits.Features.F1Help)] + public async Task TestUTF8String() + { + await TestAsync( +@"using System; + +class Program +{ + static void Main(string[] args) + { + var x = ""Hel[||]lo""u8; + } +}", "UTF8StringLiteral_CSharpKeyword"); + } + + [Fact, Trait(Traits.Feature, Traits.Features.F1Help)] + public async Task TestRawString() + { + await TestAsync( +@"using System; + +class Program +{ + static void Main(string[] args) + { + var x = """"""Hel[||]lo""""""; + } +}", "RawStringLiteral_CSharpKeyword"); + } + + [Fact, Trait(Traits.Feature, Traits.Features.F1Help)] + public async Task TestUTF8RawString() + { + await TestAsync( +@"using System; + +class Program +{ + static void Main(string[] args) + { + var x = """"""Hel[||]lo""""""u8; + } +}", "UTF8StringLiteral_CSharpKeyword"); + } + [WorkItem(46986, "https://github.com/dotnet/roslyn/issues/46986")] [Fact, Trait(Traits.Feature, Traits.Features.F1Help)] public async Task TestVerbatimString() diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Extensions/SyntaxTreeExtensions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Extensions/SyntaxTreeExtensions.cs index 0c1615e89cc9a..f884f905f3025 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Extensions/SyntaxTreeExtensions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Extensions/SyntaxTreeExtensions.cs @@ -417,7 +417,12 @@ public static bool IsEntirelyWithinStringLiteral( token = token.GetPreviousToken(includeSkipped: true, includeDirectives: true); } - if (token.Kind() is SyntaxKind.StringLiteralToken or SyntaxKind.SingleLineRawStringLiteralToken or SyntaxKind.MultiLineRawStringLiteralToken) + if (token.IsKind(SyntaxKind.StringLiteralToken, + SyntaxKind.SingleLineRawStringLiteralToken, + SyntaxKind.MultiLineRawStringLiteralToken, + SyntaxKind.UTF8StringLiteralToken, + SyntaxKind.UTF8SingleLineRawStringLiteralToken, + SyntaxKind.UTF8MultiLineRawStringLiteralToken)) { var span = token.Span; From 243fcf394671a6bd8047b4a606a4e8bd06ab449d Mon Sep 17 00:00:00 2001 From: Rikki Gibson Date: Wed, 13 Apr 2022 13:54:00 -0700 Subject: [PATCH 50/66] Update csc.dll path in launch.json (#60663) --- .vscode/launch.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.vscode/launch.json b/.vscode/launch.json index ed98c2caad160..623dd170dfb88 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -56,7 +56,7 @@ "request": "launch", "preLaunchTask": "build", // If you have changed target frameworks, make sure to update the program path. - "program": "${workspaceFolder}/src/Compilers/CSharp/csc/bin/Debug/netcoreapp2.1/csc.dll", + "program": "${workspaceFolder}/artifacts/bin/csc/Debug/net6.0/csc.dll", "args": [], "cwd": "${workspaceFolder}/src/Compilers/CSharp/csc", // For more information about the 'console' field, see https://aka.ms/VSCode-CS-LaunchJson-Console From d0749d81967b0f1e550f5f0b12960585d5b6ad70 Mon Sep 17 00:00:00 2001 From: David Barbet Date: Wed, 13 Apr 2022 14:02:09 -0700 Subject: [PATCH 51/66] Add implement interface support for checked operators and cast operators (#60719) --- .../ImplementInterfaceTests.cs | 273 ++++++++++++++++-- .../CodeGeneration/ConversionGenerator.cs | 7 + .../CodeGeneration/OperatorGenerator.cs | 4 + .../Extensions/INamedTypeSymbolExtensions.cs | 2 +- 4 files changed, 261 insertions(+), 25 deletions(-) diff --git a/src/EditorFeatures/CSharpTest/ImplementInterface/ImplementInterfaceTests.cs b/src/EditorFeatures/CSharpTest/ImplementInterface/ImplementInterfaceTests.cs index f3380570364e8..5b0b6c355c7b2 100644 --- a/src/EditorFeatures/CSharpTest/ImplementInterface/ImplementInterfaceTests.cs +++ b/src/EditorFeatures/CSharpTest/ImplementInterface/ImplementInterfaceTests.cs @@ -9934,12 +9934,12 @@ public int Foo } [WorkItem(53925, "https://github.com/dotnet/roslyn/issues/53925")] - [Fact(Skip = "https://github.com/dotnet/roslyn/issues/56171"), Trait(Traits.Feature, Traits.Features.CodeActionsImplementInterface)] + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsImplementInterface)] public async Task TestStaticAbstractInterfaceMember() { await new VerifyCS.Test { - ReferenceAssemblies = ReferenceAssemblies.Net.Net50, + ReferenceAssemblies = ReferenceAssemblies.Net.Net60, LanguageVersion = LanguageVersion.Preview, TestCode = @" interface ITest @@ -9972,12 +9972,12 @@ public static void M1() } [WorkItem(53925, "https://github.com/dotnet/roslyn/issues/53925")] - [Fact(Skip = "https://github.com/dotnet/roslyn/issues/56171"), Trait(Traits.Feature, Traits.Features.CodeActionsImplementInterface)] + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsImplementInterface)] public async Task TestStaticAbstractInterfaceMemberExplicitly() { await new VerifyCS.Test { - ReferenceAssemblies = ReferenceAssemblies.Net.Net50, + ReferenceAssemblies = ReferenceAssemblies.Net.Net60, LanguageVersion = LanguageVersion.Preview, TestCode = @" interface ITest @@ -10010,12 +10010,12 @@ static void ITest.M1() } [WorkItem(53925, "https://github.com/dotnet/roslyn/issues/53925")] - [Fact(Skip = "https://github.com/dotnet/roslyn/issues/56171"), Trait(Traits.Feature, Traits.Features.CodeActionsImplementInterface)] + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsImplementInterface)] public async Task TestStaticAbstractInterfaceMember_ImplementAbstractly() { await new VerifyCS.Test { - ReferenceAssemblies = ReferenceAssemblies.Net.Net50, + ReferenceAssemblies = ReferenceAssemblies.Net.Net60, LanguageVersion = LanguageVersion.Preview, TestCode = @" interface ITest @@ -10048,12 +10048,12 @@ public static void M1() } [WorkItem(53927, "https://github.com/dotnet/roslyn/issues/53927")] - [Fact(Skip = "https://github.com/dotnet/roslyn/issues/56171"), Trait(Traits.Feature, Traits.Features.CodeActionsImplementInterface)] + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsImplementInterface)] public async Task TestStaticAbstractInterfaceOperator_OnlyExplicitlyImplementable() { await new VerifyCS.Test { - ReferenceAssemblies = ReferenceAssemblies.Net.Net50, + ReferenceAssemblies = ReferenceAssemblies.Net.Net60, LanguageVersion = LanguageVersion.Preview, TestCode = @" interface ITest @@ -10084,12 +10084,12 @@ class C : ITest } [WorkItem(53927, "https://github.com/dotnet/roslyn/issues/53927")] - [Fact(Skip = "https://github.com/dotnet/roslyn/issues/56171"), Trait(Traits.Feature, Traits.Features.CodeActionsImplementInterface)] + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsImplementInterface)] public async Task TestStaticAbstractInterfaceOperator_ImplementImplicitly() { await new VerifyCS.Test { - ReferenceAssemblies = ReferenceAssemblies.Net.Net50, + ReferenceAssemblies = ReferenceAssemblies.Net.Net60, LanguageVersion = LanguageVersion.Preview, TestCode = @" interface ITest where T : ITest @@ -10127,12 +10127,12 @@ class C : ITest } [WorkItem(53927, "https://github.com/dotnet/roslyn/issues/53927")] - [Fact(Skip = "https://github.com/dotnet/roslyn/issues/56171"), Trait(Traits.Feature, Traits.Features.CodeActionsImplementInterface)] + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsImplementInterface)] public async Task TestStaticAbstractInterfaceOperator_ImplementExplicitly() { await new VerifyCS.Test { - ReferenceAssemblies = ReferenceAssemblies.Net.Net50, + ReferenceAssemblies = ReferenceAssemblies.Net.Net60, LanguageVersion = LanguageVersion.Preview, TestCode = @" interface ITest where T : ITest @@ -10163,12 +10163,12 @@ class C : ITest } [WorkItem(53927, "https://github.com/dotnet/roslyn/issues/53927")] - [Fact(Skip = "https://github.com/dotnet/roslyn/issues/56171"), Trait(Traits.Feature, Traits.Features.CodeActionsImplementInterface)] + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsImplementInterface)] public async Task TestStaticAbstractInterfaceOperator_ImplementAbstractly() { await new VerifyCS.Test { - ReferenceAssemblies = ReferenceAssemblies.Net.Net50, + ReferenceAssemblies = ReferenceAssemblies.Net.Net60, LanguageVersion = LanguageVersion.Preview, TestCode = @" interface ITest where T : ITest @@ -10200,12 +10200,12 @@ abstract class C : ITest } [WorkItem(53927, "https://github.com/dotnet/roslyn/issues/53927")] - [Fact(Skip = "https://github.com/dotnet/roslyn/issues/56171"), Trait(Traits.Feature, Traits.Features.CodeActionsImplementInterface)] + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsImplementInterface)] public async Task TestStaticAbstractInterface_Explicitly() { await new VerifyCS.Test { - ReferenceAssemblies = ReferenceAssemblies.Net.Net50, + ReferenceAssemblies = ReferenceAssemblies.Net.Net60, LanguageVersion = LanguageVersion.Preview, TestCode = @" interface ITest @@ -10237,12 +10237,12 @@ static int ITest.M(ITest x) } [WorkItem(53927, "https://github.com/dotnet/roslyn/issues/53927")] - [Fact(Skip = "https://github.com/dotnet/roslyn/issues/56171"), Trait(Traits.Feature, Traits.Features.CodeActionsImplementInterface)] + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsImplementInterface)] public async Task TestStaticAbstractInterface_Implicitly() { await new VerifyCS.Test { - ReferenceAssemblies = ReferenceAssemblies.Net.Net50, + ReferenceAssemblies = ReferenceAssemblies.Net.Net60, LanguageVersion = LanguageVersion.Preview, TestCode = @" interface ITest @@ -10274,12 +10274,12 @@ public static int M(ITest x) } [WorkItem(53927, "https://github.com/dotnet/roslyn/issues/53927")] - [Fact(Skip = "https://github.com/dotnet/roslyn/issues/56171"), Trait(Traits.Feature, Traits.Features.CodeActionsImplementInterface)] + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsImplementInterface)] public async Task TestStaticAbstractInterface_ImplementImplicitly() { await new VerifyCS.Test { - ReferenceAssemblies = ReferenceAssemblies.Net.Net50, + ReferenceAssemblies = ReferenceAssemblies.Net.Net60, LanguageVersion = LanguageVersion.Preview, TestCode = @" interface ITest where T : ITest @@ -10311,12 +10311,12 @@ public static int M(C x) } [WorkItem(53927, "https://github.com/dotnet/roslyn/issues/53927")] - [Fact(Skip = "https://github.com/dotnet/roslyn/issues/56171"), Trait(Traits.Feature, Traits.Features.CodeActionsImplementInterface)] + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsImplementInterface)] public async Task TestStaticAbstractInterface_ImplementExplicitly() { await new VerifyCS.Test { - ReferenceAssemblies = ReferenceAssemblies.Net.Net50, + ReferenceAssemblies = ReferenceAssemblies.Net.Net60, LanguageVersion = LanguageVersion.Preview, TestCode = @" interface ITest where T : ITest @@ -10348,12 +10348,12 @@ static int ITest.M(C x) } [WorkItem(53927, "https://github.com/dotnet/roslyn/issues/53927")] - [Fact(Skip = "https://github.com/dotnet/roslyn/issues/56171"), Trait(Traits.Feature, Traits.Features.CodeActionsImplementInterface)] + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsImplementInterface)] public async Task TestStaticAbstractInterface_ImplementAbstractly() { await new VerifyCS.Test { - ReferenceAssemblies = ReferenceAssemblies.Net.Net50, + ReferenceAssemblies = ReferenceAssemblies.Net.Net60, LanguageVersion = LanguageVersion.Preview, TestCode = @" interface ITest where T : ITest @@ -10383,5 +10383,230 @@ public static int M(C x) }.RunAsync(); } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsImplementInterface)] + [WorkItem(60214, "https://github.com/dotnet/roslyn/issues/60214")] + public async Task TestImplementCheckedOperators_Explicitly() + { + await new VerifyCS.Test + { + ReferenceAssemblies = ReferenceAssemblies.Net.Net60, + LanguageVersion = LanguageVersion.Preview, + TestCode = @" +interface I1 where T : I1 +{ + abstract static explicit operator checked string(T x); + abstract static explicit operator string(T x); + + abstract static T operator checked -(T x); + abstract static T operator -(T x); + + abstract static T operator checked +(T x, T y); + abstract static T operator +(T x, T y); +} + +class C3 : {|CS0535:{|CS0535:{|CS0535:{|CS0535:{|CS0535:{|CS0535:I1|}|}|}|}|}|} +{ +}", + FixedCode = @" +interface I1 where T : I1 +{ + abstract static explicit operator checked string(T x); + abstract static explicit operator string(T x); + + abstract static T operator checked -(T x); + abstract static T operator -(T x); + + abstract static T operator checked +(T x, T y); + abstract static T operator +(T x, T y); +} + +class C3 : I1 +{ + static C3 I1.operator checked +(C3 x, C3 y) + { + throw new System.NotImplementedException(); + } + + static C3 I1.operator +(C3 x, C3 y) + { + throw new System.NotImplementedException(); + } + + static C3 I1.operator checked -(C3 x) + { + throw new System.NotImplementedException(); + } + + static C3 I1.operator -(C3 x) + { + throw new System.NotImplementedException(); + } + + public static explicit operator checked string(C3 x) + { + throw new System.NotImplementedException(); + } + + public static explicit operator string(C3 x) + { + throw new System.NotImplementedException(); + } +}", + CodeActionVerifier = (codeAction, verifier) => verifier.Equal(FeaturesResources.Implement_all_members_explicitly, codeAction.Title), + CodeActionEquivalenceKey = "True;False;False:global::I1;TestProject;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", + CodeActionIndex = 1, + }.RunAsync(); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsImplementInterface)] + [WorkItem(60214, "https://github.com/dotnet/roslyn/issues/60214")] + public async Task TestImplementCheckedOperators_Implicitly() + { + await new VerifyCS.Test + { + ReferenceAssemblies = ReferenceAssemblies.Net.Net60, + LanguageVersion = LanguageVersion.Preview, + TestCode = @" +interface I1 where T : I1 +{ + abstract static explicit operator checked string(T x); + abstract static explicit operator string(T x); + + abstract static T operator checked -(T x); + abstract static T operator -(T x); + + abstract static T operator checked +(T x, T y); + abstract static T operator +(T x, T y); +} + +class C3 : {|CS0535:{|CS0535:{|CS0535:{|CS0535:{|CS0535:{|CS0535:I1|}|}|}|}|}|} +{ +}", + FixedCode = @" +interface I1 where T : I1 +{ + abstract static explicit operator checked string(T x); + abstract static explicit operator string(T x); + + abstract static T operator checked -(T x); + abstract static T operator -(T x); + + abstract static T operator checked +(T x, T y); + abstract static T operator +(T x, T y); +} + +class C3 : I1 +{ + public static C3 operator checked +(C3 x, C3 y) + { + throw new System.NotImplementedException(); + } + + public static C3 operator +(C3 x, C3 y) + { + throw new System.NotImplementedException(); + } + + public static C3 operator checked -(C3 x) + { + throw new System.NotImplementedException(); + } + + public static C3 operator -(C3 x) + { + throw new System.NotImplementedException(); + } + + public static explicit operator checked string(C3 x) + { + throw new System.NotImplementedException(); + } + + public static explicit operator string(C3 x) + { + throw new System.NotImplementedException(); + } +}", + CodeActionVerifier = (codeAction, verifier) => verifier.Equal(FeaturesResources.Implement_interface, codeAction.Title), + CodeActionEquivalenceKey = "False;False;True:global::I1;TestProject;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", + CodeActionIndex = 0, + }.RunAsync(); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsImplementInterface)] + [WorkItem(60214, "https://github.com/dotnet/roslyn/issues/60214")] + public async Task TestImplementCheckedOperators_Abstractly() + { + await new VerifyCS.Test + { + ReferenceAssemblies = ReferenceAssemblies.Net.Net60, + LanguageVersion = LanguageVersion.Preview, + TestCode = @" +interface I1 where T : I1 +{ + abstract static explicit operator checked string(T x); + abstract static explicit operator string(T x); + + abstract static T operator checked -(T x); + abstract static T operator -(T x); + + abstract static T operator checked +(T x, T y); + abstract static T operator +(T x, T y); +} + +abstract class C3 : {|CS0535:{|CS0535:{|CS0535:{|CS0535:{|CS0535:{|CS0535:I1|}|}|}|}|}|} +{ +}", + FixedCode = @" +interface I1 where T : I1 +{ + abstract static explicit operator checked string(T x); + abstract static explicit operator string(T x); + + abstract static T operator checked -(T x); + abstract static T operator -(T x); + + abstract static T operator checked +(T x, T y); + abstract static T operator +(T x, T y); +} + +abstract class C3 : I1 +{ + public static C3 operator checked +(C3 x, C3 y) + { + throw new System.NotImplementedException(); + } + + public static C3 operator +(C3 x, C3 y) + { + throw new System.NotImplementedException(); + } + + public static C3 operator checked -(C3 x) + { + throw new System.NotImplementedException(); + } + + public static C3 operator -(C3 x) + { + throw new System.NotImplementedException(); + } + + public static explicit operator checked string(C3 x) + { + throw new System.NotImplementedException(); + } + + public static explicit operator string(C3 x) + { + throw new System.NotImplementedException(); + } +}", + CodeActionVerifier = (codeAction, verifier) => verifier.Equal(FeaturesResources.Implement_interface_abstractly, codeAction.Title), + CodeActionEquivalenceKey = "False;True;True:global::I1;TestProject;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", + CodeActionIndex = 1, + }.RunAsync(); + } } } diff --git a/src/Workspaces/CSharp/Portable/CodeGeneration/ConversionGenerator.cs b/src/Workspaces/CSharp/Portable/CodeGeneration/ConversionGenerator.cs index d31e66edb4257..450bfe852460d 100644 --- a/src/Workspaces/CSharp/Portable/CodeGeneration/ConversionGenerator.cs +++ b/src/Workspaces/CSharp/Portable/CodeGeneration/ConversionGenerator.cs @@ -55,14 +55,21 @@ private static ConversionOperatorDeclarationSyntax GenerateConversionDeclaration ? SyntaxFactory.Token(SyntaxKind.ImplicitKeyword) : SyntaxFactory.Token(SyntaxKind.ExplicitKeyword); + var checkedToken = SyntaxFacts.IsCheckedOperator(method.MetadataName) + ? SyntaxFactory.Token(SyntaxKind.CheckedKeyword) + : default; + var declaration = SyntaxFactory.ConversionOperatorDeclaration( attributeLists: AttributeGenerator.GenerateAttributeLists(method.GetAttributes(), options), modifiers: GenerateModifiers(), implicitOrExplicitKeyword: keyword, + explicitInterfaceSpecifier: null, operatorKeyword: SyntaxFactory.Token(SyntaxKind.OperatorKeyword), + checkedKeyword: checkedToken, type: method.ReturnType.GenerateTypeSyntax(), parameterList: ParameterGenerator.GenerateParameterList(method.Parameters, isExplicit: false, options: options), body: hasNoBody ? null : StatementGenerator.GenerateBlock(method), + expressionBody: null, semicolonToken: hasNoBody ? SyntaxFactory.Token(SyntaxKind.SemicolonToken) : new SyntaxToken()); declaration = UseExpressionBodyIfDesired(options, declaration); diff --git a/src/Workspaces/CSharp/Portable/CodeGeneration/OperatorGenerator.cs b/src/Workspaces/CSharp/Portable/CodeGeneration/OperatorGenerator.cs index 0da359866f515..20871168574ec 100644 --- a/src/Workspaces/CSharp/Portable/CodeGeneration/OperatorGenerator.cs +++ b/src/Workspaces/CSharp/Portable/CodeGeneration/OperatorGenerator.cs @@ -80,6 +80,9 @@ private static OperatorDeclarationSyntax GenerateOperatorDeclarationWorker( } var operatorToken = SyntaxFactory.Token(operatorSyntaxKind); + var checkedToken = SyntaxFacts.IsCheckedOperator(method.MetadataName) + ? SyntaxFactory.Token(SyntaxKind.CheckedKeyword) + : default; var operatorDecl = SyntaxFactory.OperatorDeclaration( attributeLists: AttributeGenerator.GenerateAttributeLists(method.GetAttributes(), options), @@ -87,6 +90,7 @@ private static OperatorDeclarationSyntax GenerateOperatorDeclarationWorker( returnType: method.ReturnType.GenerateTypeSyntax(), explicitInterfaceSpecifier: GenerateExplicitInterfaceSpecifier(method.ExplicitInterfaceImplementations), operatorKeyword: SyntaxFactory.Token(SyntaxKind.OperatorKeyword), + checkedKeyword: checkedToken, operatorToken: operatorToken, parameterList: ParameterGenerator.GenerateParameterList(method.Parameters, isExplicit: false, options: options), body: hasNoBody ? null : StatementGenerator.GenerateBlock(method), diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/INamedTypeSymbolExtensions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/INamedTypeSymbolExtensions.cs index dd3b4c38cd049..bb2582965ce29 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/INamedTypeSymbolExtensions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/INamedTypeSymbolExtensions.cs @@ -413,7 +413,7 @@ private static ImmutableArray GetUnimplementedMembers( { var q = from m in interfaceMemberGetter(interfaceType, classOrStructType) where m.Kind != SymbolKind.NamedType - where m.Kind != SymbolKind.Method || ((IMethodSymbol)m).MethodKind is MethodKind.Ordinary or MethodKind.UserDefinedOperator + where m.Kind != SymbolKind.Method || ((IMethodSymbol)m).MethodKind is MethodKind.Ordinary or MethodKind.UserDefinedOperator or MethodKind.Conversion where m.Kind != SymbolKind.Property || ((IPropertySymbol)m).IsIndexer || ((IPropertySymbol)m).CanBeReferencedByName where m.Kind != SymbolKind.Event || ((IEventSymbol)m).CanBeReferencedByName where !isImplemented(classOrStructType, m, isValidImplementation, cancellationToken) From 5d87d57efaba3a40fa4786dea9fcb347cc80b87b Mon Sep 17 00:00:00 2001 From: David Barbet Date: Wed, 13 Apr 2022 14:02:51 -0700 Subject: [PATCH 52/66] Fix FAR on checked operators (#60698) * Fix FAR on checked operators * fix formatting --- .../FindReferencesTests.OperatorSymbols.vb | 171 ++++++++++++++++++ .../Extensions/IMethodSymbolExtensions.cs | 46 ++--- 2 files changed, 194 insertions(+), 23 deletions(-) diff --git a/src/EditorFeatures/Test2/FindReferences/FindReferencesTests.OperatorSymbols.vb b/src/EditorFeatures/Test2/FindReferences/FindReferencesTests.OperatorSymbols.vb index 847bd34707da8..16505a4e8cebd 100644 --- a/src/EditorFeatures/Test2/FindReferences/FindReferencesTests.OperatorSymbols.vb +++ b/src/EditorFeatures/Test2/FindReferences/FindReferencesTests.OperatorSymbols.vb @@ -752,5 +752,176 @@ class C4_2 : I4 Await TestStreamingFeature(input, host) End Function + + + + Public Async Function TestCSharpFindReferencesOnCheckedAdditionOperator(kind As TestKind, host As TestHost) As Task + Dim input = + + + throw new System.Exception(); + public static C operator checked {|Definition:$$+|}(C x, C y) => throw new System.Exception(); + + void M() + { + var a = checked(new C() [|+|] new C()); + var b = unchecked(new C() + new C()); + } +}]]> + + + + Await TestAPIAndFeature(input, kind, host) + End Function + + + + Public Async Function TestCSharpFindReferencesOnCheckedDecrementOperator(kind As TestKind, host As TestHost) As Task + Dim input = + + + throw new System.Exception(); + public static C operator checked {|Definition:$$--|}(C x) => throw new System.Exception(); + + void M() + { + var c = new C(); + var a = checked(c[|--|]); + var b = unchecked(c--); + } +}]]> + + + + Await TestAPIAndFeature(input, kind, host) + End Function + + + + Public Async Function TestCSharpFindReferencesOnCheckedDivisionOperator(kind As TestKind, host As TestHost) As Task + Dim input = + + + throw new System.Exception(); + public static C operator checked {|Definition:$$/|}(C x, C y) => throw new System.Exception(); + + void M() + { + var a = checked(new C() [|/|] new C()); + var b = unchecked(new C() / new C()); + } +}]]> + + + + Await TestAPIAndFeature(input, kind, host) + End Function + + + + Public Async Function TestCSharpFindReferencesOnCheckedIncrementOperator(kind As TestKind, host As TestHost) As Task + Dim input = + + + throw new System.Exception(); + public static C operator checked {|Definition:$$++|}(C x) => throw new System.Exception(); + + void M() + { + var c = new C(); + var a = checked(c[|++|]); + var b = unchecked(c++); + } +}]]> + + + + Await TestAPIAndFeature(input, kind, host) + End Function + + + + Public Async Function TestCSharpFindReferencesOnCheckedMultiplyOperator(kind As TestKind, host As TestHost) As Task + Dim input = + + + throw new System.Exception(); + public static C operator checked {|Definition:$$*|}(C x, C y) => throw new System.Exception(); + + void M() + { + var a = checked(new C() [|*|] new C()); + var b = unchecked(new C() * new C()); + } +}]]> + + + + Await TestAPIAndFeature(input, kind, host) + End Function + + + + Public Async Function TestCSharpFindReferencesOnCheckedSubtractionOperator(kind As TestKind, host As TestHost) As Task + Dim input = + + + throw new System.Exception(); + public static C operator checked {|Definition:$$-|}(C x, C y) => throw new System.Exception(); + + void M() + { + var a = checked(new C() [|-|] new C()); + var b = unchecked(new C() - new C()); + } +}]]> + + + + Await TestAPIAndFeature(input, kind, host) + End Function + + + + Public Async Function TestCSharpFindReferencesOnCheckedUnaryNegationOperator(kind As TestKind, host As TestHost) As Task + Dim input = + + + throw new System.Exception(); + public static C operator checked {|Definition:$$-|}(C x) => throw new System.Exception(); + + void M() + { + var c = new C(); + var a = checked([|-|]c); + var b = unchecked(-c); + } +}]]> + + + + Await TestAPIAndFeature(input, kind, host) + End Function End Class End Namespace diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/IMethodSymbolExtensions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/IMethodSymbolExtensions.cs index 923f603901323..27a230223e81d 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/IMethodSymbolExtensions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/IMethodSymbolExtensions.cs @@ -71,29 +71,29 @@ public static bool TryGetPredefinedComparisonOperator(this IMethodSymbol symbol, public static PredefinedOperator GetPredefinedOperator(this IMethodSymbol symbol) => symbol.Name switch { - "op_Addition" or "op_UnaryPlus" => PredefinedOperator.Addition, - "op_BitwiseAnd" => PredefinedOperator.BitwiseAnd, - "op_BitwiseOr" => PredefinedOperator.BitwiseOr, - "op_Concatenate" => PredefinedOperator.Concatenate, - "op_Decrement" => PredefinedOperator.Decrement, - "op_Division" => PredefinedOperator.Division, - "op_Equality" => PredefinedOperator.Equality, - "op_ExclusiveOr" => PredefinedOperator.ExclusiveOr, - "op_Exponent" => PredefinedOperator.Exponent, - "op_GreaterThan" => PredefinedOperator.GreaterThan, - "op_GreaterThanOrEqual" => PredefinedOperator.GreaterThanOrEqual, - "op_Increment" => PredefinedOperator.Increment, - "op_Inequality" => PredefinedOperator.Inequality, - "op_IntegerDivision" => PredefinedOperator.IntegerDivision, - "op_LeftShift" => PredefinedOperator.LeftShift, - "op_LessThan" => PredefinedOperator.LessThan, - "op_LessThanOrEqual" => PredefinedOperator.LessThanOrEqual, - "op_Like" => PredefinedOperator.Like, - "op_LogicalNot" or "op_OnesComplement" => PredefinedOperator.Complement, - "op_Modulus" => PredefinedOperator.Modulus, - "op_Multiply" => PredefinedOperator.Multiplication, - "op_RightShift" => PredefinedOperator.RightShift, - "op_Subtraction" or "op_UnaryNegation" => PredefinedOperator.Subtraction, + WellKnownMemberNames.AdditionOperatorName or WellKnownMemberNames.CheckedAdditionOperatorName or WellKnownMemberNames.UnaryPlusOperatorName => PredefinedOperator.Addition, + WellKnownMemberNames.BitwiseAndOperatorName => PredefinedOperator.BitwiseAnd, + WellKnownMemberNames.BitwiseOrOperatorName => PredefinedOperator.BitwiseOr, + WellKnownMemberNames.ConcatenateOperatorName => PredefinedOperator.Concatenate, + WellKnownMemberNames.DecrementOperatorName or WellKnownMemberNames.CheckedDecrementOperatorName => PredefinedOperator.Decrement, + WellKnownMemberNames.DivisionOperatorName or WellKnownMemberNames.CheckedDivisionOperatorName => PredefinedOperator.Division, + WellKnownMemberNames.EqualityOperatorName => PredefinedOperator.Equality, + WellKnownMemberNames.ExclusiveOrOperatorName => PredefinedOperator.ExclusiveOr, + WellKnownMemberNames.ExponentOperatorName => PredefinedOperator.Exponent, + WellKnownMemberNames.GreaterThanOperatorName => PredefinedOperator.GreaterThan, + WellKnownMemberNames.GreaterThanOrEqualOperatorName => PredefinedOperator.GreaterThanOrEqual, + WellKnownMemberNames.IncrementOperatorName or WellKnownMemberNames.CheckedIncrementOperatorName => PredefinedOperator.Increment, + WellKnownMemberNames.InequalityOperatorName => PredefinedOperator.Inequality, + WellKnownMemberNames.IntegerDivisionOperatorName => PredefinedOperator.IntegerDivision, + WellKnownMemberNames.LeftShiftOperatorName => PredefinedOperator.LeftShift, + WellKnownMemberNames.LessThanOperatorName => PredefinedOperator.LessThan, + WellKnownMemberNames.LessThanOrEqualOperatorName => PredefinedOperator.LessThanOrEqual, + WellKnownMemberNames.LikeOperatorName => PredefinedOperator.Like, + WellKnownMemberNames.LogicalNotOperatorName or WellKnownMemberNames.OnesComplementOperatorName => PredefinedOperator.Complement, + WellKnownMemberNames.ModulusOperatorName => PredefinedOperator.Modulus, + WellKnownMemberNames.MultiplyOperatorName or WellKnownMemberNames.CheckedMultiplyOperatorName => PredefinedOperator.Multiplication, + WellKnownMemberNames.RightShiftOperatorName => PredefinedOperator.RightShift, + WellKnownMemberNames.SubtractionOperatorName or WellKnownMemberNames.CheckedSubtractionOperatorName or WellKnownMemberNames.UnaryNegationOperatorName or WellKnownMemberNames.CheckedUnaryNegationOperatorName => PredefinedOperator.Subtraction, _ => PredefinedOperator.None, }; From bcb777208f1f6c35134d9ef79793523f4c554bb3 Mon Sep 17 00:00:00 2001 From: dotnet bot Date: Wed, 13 Apr 2022 14:03:27 -0700 Subject: [PATCH 53/66] Merge release/dev17.2 to main (#60682) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Update versions for preview 4 * Update Typescript VS interface (#60635) * Update Typescript VS interface * Restore method signatures in completion provider * Move completion override to completion service with providers * Remove duplicate override Co-authored-by: Maria Solano Co-authored-by: David Barbet Co-authored-by: Joey Robichaud Co-authored-by: Maria José Solano Co-authored-by: Maria Solano --- .../Portable/Completion/CommonCompletionService.cs | 12 ------------ .../Completion/CompletionServiceWithProviders.cs | 13 +++++++++++++ 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/src/Features/Core/Portable/Completion/CommonCompletionService.cs b/src/Features/Core/Portable/Completion/CommonCompletionService.cs index 6f54d8db5db78..b2e19f484c10e 100644 --- a/src/Features/Core/Portable/Completion/CommonCompletionService.cs +++ b/src/Features/Core/Portable/Completion/CommonCompletionService.cs @@ -36,18 +36,6 @@ protected override CompletionItem GetBetterItem(CompletionItem item, CompletionI return base.GetBetterItem(item, existingItem); } - internal override Task GetCompletionsAsync( - Document document, - int caretPosition, - CompletionOptions options, - OptionSet passThroughOptions, - CompletionTrigger trigger, - ImmutableHashSet? roles, - CancellationToken cancellationToken) - { - return GetCompletionsWithAvailabilityOfExpandedItemsAsync(document, caretPosition, options, passThroughOptions, trigger, roles, cancellationToken); - } - protected static bool IsKeywordItem(CompletionItem item) => item.Tags.Contains(WellKnownTags.Keyword); diff --git a/src/Features/Core/Portable/Completion/CompletionServiceWithProviders.cs b/src/Features/Core/Portable/Completion/CompletionServiceWithProviders.cs index 45496d108fc91..a943c021ace2c 100644 --- a/src/Features/Core/Portable/Completion/CompletionServiceWithProviders.cs +++ b/src/Features/Core/Portable/Completion/CompletionServiceWithProviders.cs @@ -102,6 +102,19 @@ protected virtual ImmutableArray GetProviders(ImmutableHashS return await GetCompletionsWithAvailabilityOfExpandedItemsAsync(document, caretPosition, completionOptions, passThroughOptions, trigger, roles, cancellationToken).ConfigureAwait(false); } + /// + internal override Task GetCompletionsAsync( + Document document, + int caretPosition, + CompletionOptions options, + OptionSet passThroughOptions, + CompletionTrigger trigger, + ImmutableHashSet? roles, + CancellationToken cancellationToken) + { + return GetCompletionsWithAvailabilityOfExpandedItemsAsync(document, caretPosition, options, passThroughOptions, trigger, roles, cancellationToken); + } + private protected async Task GetCompletionsWithAvailabilityOfExpandedItemsAsync( Document document, int caretPosition, From d4c3cb9609676c6fc1e3376a729e422d6e5c45e2 Mon Sep 17 00:00:00 2001 From: David Wengier Date: Thu, 14 Apr 2022 07:19:39 +1000 Subject: [PATCH 54/66] Generate static abstract interface members correctly (#60618) --- .../ExtractMethod/ExtractMethodTests.cs | 21 +++++++++ ...stractMetadataAsSourceTests.TestContext.cs | 11 +++-- .../AbstractMetadataAsSourceTests.cs | 4 +- .../MetadataAsSourceTests.CSharp.cs | 45 +++++++++++++++++++ ...harpMethodExtractor.CSharpCodeGenerator.cs | 24 ++++++++++ .../Portable/PullMemberUp/MembersPuller.cs | 23 ++++++++-- .../CSharpCodeGenerationService.cs | 4 +- .../CodeGeneration/ConversionGenerator.cs | 19 +++++--- .../Portable/CodeGeneration/EventGenerator.cs | 16 ++++++- .../CodeGeneration/MethodGenerator.cs | 20 +++++++-- .../CodeGeneration/OperatorGenerator.cs | 15 ++++--- .../CodeGeneration/PropertyGenerator.cs | 17 +++++-- .../CodeGenerationSymbolFactory.cs | 15 +++++++ 13 files changed, 203 insertions(+), 31 deletions(-) diff --git a/src/EditorFeatures/CSharpTest/CodeActions/ExtractMethod/ExtractMethodTests.cs b/src/EditorFeatures/CSharpTest/CodeActions/ExtractMethod/ExtractMethodTests.cs index 708f05a97cbf6..c09f0fbe98ad2 100644 --- a/src/EditorFeatures/CSharpTest/CodeActions/ExtractMethod/ExtractMethodTests.cs +++ b/src/EditorFeatures/CSharpTest/CodeActions/ExtractMethod/ExtractMethodTests.cs @@ -4509,6 +4509,27 @@ bool NewMethod() }"); } + [WorkItem(53031, "https://github.com/dotnet/roslyn/issues/53031")] + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsExtractMethod)] + public async Task TestStaticMethodInInterface() + { + await TestInRegularAndScript1Async(@" +interface TestInterface +{ + static bool TestMethod() => [|false|]; +}", +@" +interface TestInterface +{ + static bool TestMethod() => {|Rename:NewMethod|}(); + + static bool NewMethod() + { + return false; + } +}"); + } + [WorkItem(56969, "https://github.com/dotnet/roslyn/issues/56969")] [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsExtractLocalFunction)] public async Task TopLevelStatement_FullStatement() diff --git a/src/EditorFeatures/Test/MetadataAsSource/AbstractMetadataAsSourceTests.TestContext.cs b/src/EditorFeatures/Test/MetadataAsSource/AbstractMetadataAsSourceTests.TestContext.cs index 3012aee3dbdaf..47ac686755e6a 100644 --- a/src/EditorFeatures/Test/MetadataAsSource/AbstractMetadataAsSourceTests.TestContext.cs +++ b/src/EditorFeatures/Test/MetadataAsSource/AbstractMetadataAsSourceTests.TestContext.cs @@ -37,7 +37,8 @@ public static TestContext Create( bool includeXmlDocComments = false, string? sourceWithSymbolReference = null, string? languageVersion = null, - string? metadataLanguageVersion = null) + string? metadataLanguageVersion = null, + string? metadataCommonReferences = null) { projectLanguage ??= LanguageNames.CSharp; metadataSources ??= SpecializedCollections.EmptyEnumerable(); @@ -47,7 +48,7 @@ public static TestContext Create( var workspace = CreateWorkspace( projectLanguage, metadataSources, includeXmlDocComments, - sourceWithSymbolReference, languageVersion, metadataLanguageVersion); + sourceWithSymbolReference, languageVersion, metadataLanguageVersion, metadataCommonReferences); return new TestContext(workspace); } @@ -237,7 +238,8 @@ private static TestWorkspace CreateWorkspace( bool includeXmlDocComments, string? sourceWithSymbolReference, string? languageVersion, - string? metadataLanguageVersion) + string? metadataLanguageVersion, + string? metadataCommonReferences) { var languageVersionAttribute = languageVersion is null ? "" : $@" LanguageVersion=""{languageVersion}"""; @@ -251,10 +253,11 @@ private static TestWorkspace CreateWorkspace( foreach (var source in metadataSources) { + var commonReferencesAttributeName = metadataCommonReferences ?? "CommonReferences"; var metadataLanguage = DeduceLanguageString(source); var metadataLanguageVersionAttribute = metadataLanguageVersion is null ? "" : $@" LanguageVersion=""{metadataLanguageVersion}"""; xmlString = string.Concat(xmlString, $@" - + {SecurityElement.Escape(source)} diff --git a/src/EditorFeatures/Test/MetadataAsSource/AbstractMetadataAsSourceTests.cs b/src/EditorFeatures/Test/MetadataAsSource/AbstractMetadataAsSourceTests.cs index bbeeeda18e349..e211b6232d77c 100644 --- a/src/EditorFeatures/Test/MetadataAsSource/AbstractMetadataAsSourceTests.cs +++ b/src/EditorFeatures/Test/MetadataAsSource/AbstractMetadataAsSourceTests.cs @@ -44,9 +44,9 @@ public virtual Task DisposeAsync() } internal static async Task GenerateAndVerifySourceAsync( - string metadataSource, string symbolName, string projectLanguage, string expected, bool signaturesOnly = true, bool includeXmlDocComments = false, string languageVersion = null, string metadataLanguageVersion = null) + string metadataSource, string symbolName, string projectLanguage, string expected, bool signaturesOnly = true, bool includeXmlDocComments = false, string languageVersion = null, string metadataLanguageVersion = null, string metadataCommonReferences = null) { - using var context = TestContext.Create(projectLanguage, SpecializedCollections.SingletonEnumerable(metadataSource), includeXmlDocComments, languageVersion: languageVersion, metadataLanguageVersion: metadataLanguageVersion); + using var context = TestContext.Create(projectLanguage, SpecializedCollections.SingletonEnumerable(metadataSource), includeXmlDocComments, languageVersion: languageVersion, metadataLanguageVersion: metadataLanguageVersion, metadataCommonReferences: metadataCommonReferences); await context.GenerateAndVerifySourceAsync(symbolName, expected, signaturesOnly: signaturesOnly); } diff --git a/src/EditorFeatures/Test/MetadataAsSource/MetadataAsSourceTests.CSharp.cs b/src/EditorFeatures/Test/MetadataAsSource/MetadataAsSourceTests.CSharp.cs index 8e30c8285a1a0..cc56b91e60e9c 100644 --- a/src/EditorFeatures/Test/MetadataAsSource/MetadataAsSourceTests.CSharp.cs +++ b/src/EditorFeatures/Test/MetadataAsSource/MetadataAsSourceTests.CSharp.cs @@ -555,6 +555,51 @@ public R() await GenerateAndVerifySourceAsync(metadataSource, symbolName, LanguageNames.CSharp, expected: expected, signaturesOnly: signaturesOnly); } + + [Fact, Trait(Traits.Feature, Traits.Features.MetadataAsSource)] + [WorkItem(60567, "https://github.com/dotnet/roslyn/issues/60567")] + public async Task TestStaticInterfaceMembers() + { + var metadataSource = @" +interface I where T : I +{ + static abstract T P { get; set; } + static abstract event System.Action E; + static abstract void M(); + static void NonAbstract() { } + static abstract T operator +(T l, T r); + static abstract bool operator ==(T l, T r); + static abstract bool operator !=(T l, T r); + static abstract implicit operator T(string s); + static abstract explicit operator string(T t); +}"; + var symbolName = "I`1.M"; + + var expected = $@"#region {FeaturesResources.Assembly} ReferencedAssembly, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null +// {CodeAnalysisResources.InMemoryAssembly} +#endregion + +using System; + +internal interface I where T : I +{{ + static abstract T P {{ get; set; }} + + static abstract event Action E; + + static abstract void [|M|](); + static void NonAbstract(); + + static abstract T operator +(T l, T r); + static abstract bool operator ==(T l, T r); + static abstract bool operator !=(T l, T r); + + static abstract implicit operator T(string s); + static abstract explicit operator string(T t); +}}"; + + await GenerateAndVerifySourceAsync(metadataSource, symbolName, LanguageNames.CSharp, languageVersion: "Preview", metadataLanguageVersion: "Preview", expected: expected, signaturesOnly: true, metadataCommonReferences: "CommonReferencesNet6"); + } } } } diff --git a/src/Features/CSharp/Portable/ExtractMethod/CSharpMethodExtractor.CSharpCodeGenerator.cs b/src/Features/CSharp/Portable/ExtractMethod/CSharpMethodExtractor.CSharpCodeGenerator.cs index 0d4390d3bb316..7e161ea9f797c 100644 --- a/src/Features/CSharp/Portable/ExtractMethod/CSharpMethodExtractor.CSharpCodeGenerator.cs +++ b/src/Features/CSharp/Portable/ExtractMethod/CSharpMethodExtractor.CSharpCodeGenerator.cs @@ -237,6 +237,14 @@ private DeclarationModifiers CreateMethodModifiers() isStatic = false; } + // UseInstanceMember will be false for interface members, but extracting a non-static + // member to a static member has a very different meaning for interfaces so we need + // an extra check here. + if (!LocalFunction && IsNonStaticInterfaceMember()) + { + isStatic = false; + } + return new DeclarationModifiers( isUnsafe: isUnsafe, isAsync: isAsync, @@ -244,6 +252,22 @@ private DeclarationModifiers CreateMethodModifiers() isReadOnly: isReadOnly); } + private bool IsNonStaticInterfaceMember() + { + var typeDecl = SelectionResult.GetContainingScopeOf(); + if (typeDecl is null) + return false; + + if (!typeDecl.IsKind(SyntaxKind.InterfaceDeclaration)) + return false; + + var memberDecl = SelectionResult.GetContainingScopeOf(); + if (memberDecl is null) + return false; + + return !memberDecl.Modifiers.Any(SyntaxKind.StaticKeyword); + } + private static SyntaxKind GetParameterRefSyntaxKind(ParameterBehavior parameterBehavior) { return parameterBehavior == ParameterBehavior.Ref ? diff --git a/src/Features/Core/Portable/PullMemberUp/MembersPuller.cs b/src/Features/Core/Portable/PullMemberUp/MembersPuller.cs index ad80e80e80cf5..8f2f68f01922b 100644 --- a/src/Features/Core/Portable/PullMemberUp/MembersPuller.cs +++ b/src/Features/Core/Portable/PullMemberUp/MembersPuller.cs @@ -146,7 +146,10 @@ private static async Task PullMembersIntoInterfaceAsync( private static ISymbol GetSymbolsToPullUp(MemberAnalysisResult analysisResult) { - if (analysisResult.Member is IPropertySymbol propertySymbol) + var member = analysisResult.Member; + // We don't support generating static interface members, so we need to update to non-static before generating. + var modifier = DeclarationModifiers.From(member).WithIsStatic(false); + if (member is IPropertySymbol propertySymbol) { // Property is treated differently since we need to make sure it gives right accessor symbol to ICodeGenerationService, // otherwise ICodeGenerationService won't give the expected declaration. @@ -156,6 +159,7 @@ private static ISymbol GetSymbolsToPullUp(MemberAnalysisResult analysisResult) return CodeGenerationSymbolFactory.CreatePropertySymbol( propertySymbol, accessibility: Accessibility.Public, + modifiers: modifier, getMethod: MakePublicAccessor(propertySymbol.GetMethod), setMethod: MakePublicAccessor(propertySymbol.SetMethod)); } @@ -164,15 +168,26 @@ private static ISymbol GetSymbolsToPullUp(MemberAnalysisResult analysisResult) // We are pulling a public property, filter the non-public getter/setter. return CodeGenerationSymbolFactory.CreatePropertySymbol( propertySymbol, + modifiers: modifier, getMethod: FilterOutNonPublicAccessor(propertySymbol.GetMethod), setMethod: FilterOutNonPublicAccessor(propertySymbol.SetMethod)); } } - else + else if (member is IMethodSymbol methodSymbol) { - // ICodeGenerationService will give the right result if it is method or event - return analysisResult.Member; + return CodeGenerationSymbolFactory.CreateMethodSymbol(methodSymbol, modifiers: modifier); } + else if (member is IEventSymbol eventSymbol) + { + return CodeGenerationSymbolFactory.CreateEventSymbol(eventSymbol, modifiers: modifier); + } + else if (member is IFieldSymbol fieldSymbol) + { + return CodeGenerationSymbolFactory.CreateFieldSymbol(fieldSymbol, modifiers: modifier); + } + + // ICodeGenerationService will give the right result if it is method or event + return member; } private static void ChangeMemberToPublicAndNonStatic( diff --git a/src/Workspaces/CSharp/Portable/CodeGeneration/CSharpCodeGenerationService.cs b/src/Workspaces/CSharp/Portable/CodeGeneration/CSharpCodeGenerationService.cs index 094e314e69a9e..52d0d86c70b87 100644 --- a/src/Workspaces/CSharp/Portable/CodeGeneration/CSharpCodeGenerationService.cs +++ b/src/Workspaces/CSharp/Portable/CodeGeneration/CSharpCodeGenerationService.cs @@ -618,12 +618,12 @@ public override SyntaxNode CreateFieldDeclaration(IFieldSymbol field, CodeGenera if (method.IsUserDefinedOperator()) { - return OperatorGenerator.GenerateOperatorDeclaration(method, csharpOptions, cancellationToken); + return OperatorGenerator.GenerateOperatorDeclaration(method, destination, csharpOptions, cancellationToken); } if (method.IsConversion()) { - return ConversionGenerator.GenerateConversionDeclaration(method, csharpOptions, cancellationToken); + return ConversionGenerator.GenerateConversionDeclaration(method, destination, csharpOptions, cancellationToken); } if (method.IsLocalFunction()) diff --git a/src/Workspaces/CSharp/Portable/CodeGeneration/ConversionGenerator.cs b/src/Workspaces/CSharp/Portable/CodeGeneration/ConversionGenerator.cs index 450bfe852460d..d310dc7c8f9c1 100644 --- a/src/Workspaces/CSharp/Portable/CodeGeneration/ConversionGenerator.cs +++ b/src/Workspaces/CSharp/Portable/CodeGeneration/ConversionGenerator.cs @@ -5,7 +5,6 @@ using System.Collections.Generic; using System.Threading; using Microsoft.CodeAnalysis.CodeGeneration; -using Microsoft.CodeAnalysis.CSharp.CodeStyle; using Microsoft.CodeAnalysis.CSharp.Extensions; using Microsoft.CodeAnalysis.CSharp.Syntax; @@ -23,7 +22,7 @@ internal static TypeDeclarationSyntax AddConversionTo( IList? availableIndices, CancellationToken cancellationToken) { - var methodDeclaration = GenerateConversionDeclaration(method, options, cancellationToken); + var methodDeclaration = GenerateConversionDeclaration(method, GetDestination(destination), options, cancellationToken); var members = Insert(destination.Members, methodDeclaration, options, availableIndices, after: LastOperator); return AddMembersTo(destination, members, cancellationToken); @@ -31,16 +30,18 @@ internal static TypeDeclarationSyntax AddConversionTo( internal static ConversionOperatorDeclarationSyntax GenerateConversionDeclaration( IMethodSymbol method, + CodeGenerationDestination destination, CSharpCodeGenerationOptions options, CancellationToken cancellationToken) { - var declaration = GenerateConversionDeclarationWorker(method, options); + var declaration = GenerateConversionDeclarationWorker(method, destination, options); return AddFormatterAndCodeGeneratorAnnotationsTo(AddAnnotationsTo(method, ConditionallyAddDocumentationCommentTo(declaration, method, options, cancellationToken))); } private static ConversionOperatorDeclarationSyntax GenerateConversionDeclarationWorker( IMethodSymbol method, + CodeGenerationDestination destination, CSharpCodeGenerationOptions options) { var hasNoBody = !options.Context.GenerateMethodBodies || method.IsExtern; @@ -61,7 +62,7 @@ private static ConversionOperatorDeclarationSyntax GenerateConversionDeclaration var declaration = SyntaxFactory.ConversionOperatorDeclaration( attributeLists: AttributeGenerator.GenerateAttributeLists(method.GetAttributes(), options), - modifiers: GenerateModifiers(), + modifiers: GenerateModifiers(destination), implicitOrExplicitKeyword: keyword, explicitInterfaceSpecifier: null, operatorKeyword: SyntaxFactory.Token(SyntaxKind.OperatorKeyword), @@ -95,8 +96,16 @@ private static ConversionOperatorDeclarationSyntax UseExpressionBodyIfDesired( return declaration; } - private static SyntaxTokenList GenerateModifiers() + private static SyntaxTokenList GenerateModifiers(CodeGenerationDestination destination) { + // If these appear in interfaces they must be static abstract + if (destination is CodeGenerationDestination.InterfaceType) + { + return SyntaxFactory.TokenList( + SyntaxFactory.Token(SyntaxKind.StaticKeyword), + SyntaxFactory.Token(SyntaxKind.AbstractKeyword)); + } + return SyntaxFactory.TokenList( SyntaxFactory.Token(SyntaxKind.PublicKeyword), SyntaxFactory.Token(SyntaxKind.StaticKeyword)); diff --git a/src/Workspaces/CSharp/Portable/CodeGeneration/EventGenerator.cs b/src/Workspaces/CSharp/Portable/CodeGeneration/EventGenerator.cs index 3ee60fd8332c3..af0d066b440ba 100644 --- a/src/Workspaces/CSharp/Portable/CodeGeneration/EventGenerator.cs +++ b/src/Workspaces/CSharp/Portable/CodeGeneration/EventGenerator.cs @@ -195,7 +195,21 @@ private static SyntaxTokenList GenerateModifiers( // Most modifiers not allowed if we're an explicit impl. if (!@event.ExplicitInterfaceImplementations.Any()) { - if (destination != CodeGenerationDestination.InterfaceType) + // If we're generating into an interface, then allow modifiers for static abstract members + if (destination is CodeGenerationDestination.InterfaceType) + { + if (@event.IsStatic) + { + tokens.Add(SyntaxFactory.Token(SyntaxKind.StaticKeyword)); + + // We only generate the abstract keyword in interfaces for static abstract members + if (@event.IsAbstract) + { + tokens.Add(SyntaxFactory.Token(SyntaxKind.AbstractKeyword)); + } + } + } + else { AddAccessibilityModifiers(@event.DeclaredAccessibility, tokens, options, Accessibility.Private); diff --git a/src/Workspaces/CSharp/Portable/CodeGeneration/MethodGenerator.cs b/src/Workspaces/CSharp/Portable/CodeGeneration/MethodGenerator.cs index f7f3204a4fe57..42e10cec614d8 100644 --- a/src/Workspaces/CSharp/Portable/CodeGeneration/MethodGenerator.cs +++ b/src/Workspaces/CSharp/Portable/CodeGeneration/MethodGenerator.cs @@ -269,10 +269,22 @@ private static SyntaxTokenList GenerateModifiers( } else { - // If we're generating into an interface, then we don't use any modifiers. - if (destination is not CodeGenerationDestination.CompilationUnit and - not CodeGenerationDestination.Namespace and - not CodeGenerationDestination.InterfaceType) + // If we're generating into an interface, then allow modifiers for static abstract members + if (destination is CodeGenerationDestination.InterfaceType) + { + if (method.IsStatic) + { + tokens.Add(SyntaxFactory.Token(SyntaxKind.StaticKeyword)); + + // We only generate the abstract keyword in interfaces for static abstract members + if (method.IsAbstract) + { + tokens.Add(SyntaxFactory.Token(SyntaxKind.AbstractKeyword)); + } + } + } + else if (destination is not CodeGenerationDestination.CompilationUnit and + not CodeGenerationDestination.Namespace) { AddAccessibilityModifiers(method.DeclaredAccessibility, tokens, options, Accessibility.Private); diff --git a/src/Workspaces/CSharp/Portable/CodeGeneration/OperatorGenerator.cs b/src/Workspaces/CSharp/Portable/CodeGeneration/OperatorGenerator.cs index 20871168574ec..7984f2d79f31b 100644 --- a/src/Workspaces/CSharp/Portable/CodeGeneration/OperatorGenerator.cs +++ b/src/Workspaces/CSharp/Portable/CodeGeneration/OperatorGenerator.cs @@ -5,8 +5,8 @@ using System; using System.Collections.Generic; using System.Threading; +using System.Xml; using Microsoft.CodeAnalysis.CodeGeneration; -using Microsoft.CodeAnalysis.CSharp.CodeStyle; using Microsoft.CodeAnalysis.CSharp.Extensions; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Shared.Collections; @@ -25,7 +25,7 @@ internal static TypeDeclarationSyntax AddOperatorTo( IList? availableIndices, CancellationToken cancellationToken) { - var methodDeclaration = GenerateOperatorDeclaration(method, options, cancellationToken); + var methodDeclaration = GenerateOperatorDeclaration(method, GetDestination(destination), options, cancellationToken); var members = Insert(destination.Members, methodDeclaration, options, availableIndices, after: LastOperator); return AddMembersTo(destination, members, cancellationToken); @@ -33,6 +33,7 @@ internal static TypeDeclarationSyntax AddOperatorTo( internal static OperatorDeclarationSyntax GenerateOperatorDeclaration( IMethodSymbol method, + CodeGenerationDestination destination, CSharpCodeGenerationOptions options, CancellationToken cancellationToken) { @@ -42,7 +43,7 @@ internal static OperatorDeclarationSyntax GenerateOperatorDeclaration( return reusableSyntax; } - var declaration = GenerateOperatorDeclarationWorker(method, options); + var declaration = GenerateOperatorDeclarationWorker(method, destination, options); declaration = UseExpressionBodyIfDesired(options, declaration); return AddAnnotationsTo(method, @@ -69,6 +70,7 @@ private static OperatorDeclarationSyntax UseExpressionBodyIfDesired( private static OperatorDeclarationSyntax GenerateOperatorDeclarationWorker( IMethodSymbol method, + CodeGenerationDestination destination, CSharpCodeGenerationOptions options) { var hasNoBody = !options.Context.GenerateMethodBodies || method.IsExtern || method.IsAbstract; @@ -86,7 +88,7 @@ private static OperatorDeclarationSyntax GenerateOperatorDeclarationWorker( var operatorDecl = SyntaxFactory.OperatorDeclaration( attributeLists: AttributeGenerator.GenerateAttributeLists(method.GetAttributes(), options), - modifiers: GenerateModifiers(method), + modifiers: GenerateModifiers(method, destination, hasNoBody), returnType: method.ReturnType.GenerateTypeSyntax(), explicitInterfaceSpecifier: GenerateExplicitInterfaceSpecifier(method.ExplicitInterfaceImplementations), operatorKeyword: SyntaxFactory.Token(SyntaxKind.OperatorKeyword), @@ -101,11 +103,12 @@ private static OperatorDeclarationSyntax GenerateOperatorDeclarationWorker( return operatorDecl; } - private static SyntaxTokenList GenerateModifiers(IMethodSymbol method) + private static SyntaxTokenList GenerateModifiers(IMethodSymbol method, CodeGenerationDestination destination, bool hasNoBody) { using var tokens = TemporaryArray.Empty; - if (method.ExplicitInterfaceImplementations.Length == 0) + if (method.ExplicitInterfaceImplementations.Length == 0 && + !(destination is CodeGenerationDestination.InterfaceType && hasNoBody)) { tokens.Add(SyntaxFactory.Token(SyntaxKind.PublicKeyword)); } diff --git a/src/Workspaces/CSharp/Portable/CodeGeneration/PropertyGenerator.cs b/src/Workspaces/CSharp/Portable/CodeGeneration/PropertyGenerator.cs index e4639256364d2..bf0e5372afd70 100644 --- a/src/Workspaces/CSharp/Portable/CodeGeneration/PropertyGenerator.cs +++ b/src/Workspaces/CSharp/Portable/CodeGeneration/PropertyGenerator.cs @@ -8,7 +8,6 @@ using System.Threading; using Microsoft.CodeAnalysis.CodeGeneration; using Microsoft.CodeAnalysis.CodeStyle; -using Microsoft.CodeAnalysis.CSharp.CodeStyle; using Microsoft.CodeAnalysis.CSharp.Extensions; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.PooledObjects; @@ -347,8 +346,20 @@ private static SyntaxTokenList GenerateModifiers( // Most modifiers not allowed if we're an explicit impl. if (!property.ExplicitInterfaceImplementations.Any()) { - if (destination is not CodeGenerationDestination.CompilationUnit and - not CodeGenerationDestination.InterfaceType) + // If we're generating into an interface, then allow modifiers for static abstract members + if (destination is CodeGenerationDestination.InterfaceType) + { + if (property.IsStatic) + { + tokens.Add(SyntaxFactory.Token(SyntaxKind.StaticKeyword)); + + if (property.IsAbstract) + { + tokens.Add(SyntaxFactory.Token(SyntaxKind.AbstractKeyword)); + } + } + } + else if (destination is not CodeGenerationDestination.CompilationUnit) { AddAccessibilityModifiers(property.DeclaredAccessibility, tokens, options, Accessibility.Private); diff --git a/src/Workspaces/Core/Portable/CodeGeneration/CodeGenerationSymbolFactory.cs b/src/Workspaces/Core/Portable/CodeGeneration/CodeGenerationSymbolFactory.cs index 2ef60b41f806d..ccad5aa96087c 100644 --- a/src/Workspaces/Core/Portable/CodeGeneration/CodeGenerationSymbolFactory.cs +++ b/src/Workspaces/Core/Portable/CodeGeneration/CodeGenerationSymbolFactory.cs @@ -580,5 +580,20 @@ internal static IEventSymbol CreateEventSymbol( addMethod, removeMethod); } + + internal static IFieldSymbol CreateFieldSymbol( + IFieldSymbol field, + ImmutableArray attributes = default, + Accessibility? accessibility = null, + DeclarationModifiers? modifiers = null, + string? name = null) + { + return CreateFieldSymbol( + attributes, + accessibility ?? field.DeclaredAccessibility, + modifiers ?? field.GetSymbolModifiers(), + field.Type, + name ?? field.Name); + } } } From 99296b4f22721fc003217bd007f3a38202f2acca Mon Sep 17 00:00:00 2001 From: Jason Malinowski Date: Wed, 30 Mar 2022 18:36:14 -0700 Subject: [PATCH 55/66] Add integration test to flag MEF composition breaks --- .../MefCompositionTests.cs | 65 +++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 src/VisualStudio/IntegrationTest/New.IntegrationTests/MefCompositionTests.cs diff --git a/src/VisualStudio/IntegrationTest/New.IntegrationTests/MefCompositionTests.cs b/src/VisualStudio/IntegrationTest/New.IntegrationTests/MefCompositionTests.cs new file mode 100644 index 0000000000000..5e0e4a55be5f3 --- /dev/null +++ b/src/VisualStudio/IntegrationTest/New.IntegrationTests/MefCompositionTests.cs @@ -0,0 +1,65 @@ +// 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; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading.Tasks; +using Castle.Core.Internal; +using Microsoft.VisualStudio.Shell.Interop; +using Roslyn.Test.Utilities; +using Roslyn.VisualStudio.IntegrationTests; +using Xunit; + +namespace Roslyn.VisualStudio.NewIntegrationTests +{ + public class MefCompositionTests : AbstractIntegrationTest + { + [IdeFact] + public async Task AssertNoCompositionFailures() + { + // Read the .err file that contains errors; this isn't a great way to do it but we have no + // better option at this point. + var shell = await TestServices.Shell.GetRequiredGlobalServiceAsync(HangMitigatingCancellationToken); + Marshal.ThrowExceptionForHR(shell.GetApplicationDataFolder((uint)__VsApplicationDataFolder.ApplicationDataFolder_LocalSettings, out var applicationDataFolder)); + + var compositionErrorFileLines = File.ReadAllLines(Path.Combine(applicationDataFolder, @"ComponentModelCache\Microsoft.VisualStudio.Default.err")); + var compositionErrors = new List(); + + for (var i = 0; i < compositionErrorFileLines.Length; i++) + { + var line = compositionErrorFileLines[i]; + + if (line.EndsWith("expected exactly 1 export matching constraints:") && + StartsWithApplicableSymbol(line)) + { + var entireError = string.Join(Environment.NewLine, compositionErrorFileLines.Skip(i).TakeWhile(s => !string.IsNullOrWhiteSpace(s))); + compositionErrors.Add(entireError); + } + } + + // Ideally I'd write Assert.Empty(compositionErrors), but since the string gets truncated we'll do this instead + AssertEx.EqualOrDiff("", string.Join(Environment.NewLine, compositionErrors)); + } + + private static bool StartsWithApplicableSymbol(string s) + { + // ExternalAccess missing exports may mean the langauge isn't installed, or you aren't running + // on fully matched bits; rather than flag them let's keep the noise down. + if (s.StartsWith("Microsoft.CodeAnalysis.ExternalAccess")) + return false; + + // Not actually our code + if (s.StartsWith("Microsoft.CodeAnalysis.Editor.TypeScript")) + return false; + + return s.StartsWith("Microsoft.CodeAnalysis") || + s.StartsWith("Microsoft.VisualStudio.LanguageServices") || + s.StartsWith("Roslyn"); + } + } +} From 334c3d43b43d155d36bb2070991c7d4b5b1d91ef Mon Sep 17 00:00:00 2001 From: Jason Malinowski Date: Wed, 13 Apr 2022 11:46:45 -0700 Subject: [PATCH 56/66] Remove #nullable enable This is now our default. --- src/Features/Core/Portable/Diagnostics/DiagnosticBucket.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Features/Core/Portable/Diagnostics/DiagnosticBucket.cs b/src/Features/Core/Portable/Diagnostics/DiagnosticBucket.cs index 00bb6fb9607fa..61e30f29c3feb 100644 --- a/src/Features/Core/Portable/Diagnostics/DiagnosticBucket.cs +++ b/src/Features/Core/Portable/Diagnostics/DiagnosticBucket.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable enable - namespace Microsoft.CodeAnalysis.Diagnostics { internal readonly struct DiagnosticBucket From 3aed676f7717a880abd89b5226576798e5ab7dfb Mon Sep 17 00:00:00 2001 From: Jason Malinowski Date: Wed, 13 Apr 2022 12:22:04 -0700 Subject: [PATCH 57/66] Clean up IDiagnosticService extension methods This code was a bit strange: 1. The GetPushDiagnostics/GetPullDiagnostics extension methods called a common helper method passing in a boolean, only for that common helper to switch on that boolean again. 2. The common helper worked via enumerating buckets and then calling other helpers to find diagnostics matching those buckets, when instead we can directly call the service and ask it for what we want. --- .../Diagnostics/IDiagnosticService.cs | 4 +- .../IDiagnosticServiceExtensions.cs | 37 +------------------ .../AnalyzerReferenceTests.vb | 8 ++-- 3 files changed, 8 insertions(+), 41 deletions(-) diff --git a/src/Features/LanguageServer/Protocol/Features/Diagnostics/IDiagnosticService.cs b/src/Features/LanguageServer/Protocol/Features/Diagnostics/IDiagnosticService.cs index a562e1893119b..ba294bd07fd50 100644 --- a/src/Features/LanguageServer/Protocol/Features/Diagnostics/IDiagnosticService.cs +++ b/src/Features/LanguageServer/Protocol/Features/Diagnostics/IDiagnosticService.cs @@ -56,7 +56,7 @@ ValueTask> GetPushDiagnosticsAsync( /// /// Get current buckets storing our grouped diagnostics. Specific buckets can be retrieved by calling . + /// cref="IDiagnosticServiceExtensions.GetPullDiagnosticsAsync(IDiagnosticService, DiagnosticBucket, bool, DiagnosticMode, CancellationToken)"/>. /// /// Option controlling if pull diagnostics are allowed for the client. The /// only provides diagnostics for either push or pull purposes (but not both). @@ -68,7 +68,7 @@ ImmutableArray GetPullDiagnosticBuckets( /// /// Get current buckets storing our grouped diagnostics. Specific buckets can be retrieved by calling . + /// cref="IDiagnosticServiceExtensions.GetPushDiagnosticsAsync(IDiagnosticService, DiagnosticBucket, bool, DiagnosticMode, CancellationToken)"/>. /// /// Option controlling if pull diagnostics are allowed for the client. The only provides diagnostics for either push or pull purposes (but not both). If diff --git a/src/Features/LanguageServer/Protocol/Features/Diagnostics/IDiagnosticServiceExtensions.cs b/src/Features/LanguageServer/Protocol/Features/Diagnostics/IDiagnosticServiceExtensions.cs index 4e0215808699e..1cf00faa3df8d 100644 --- a/src/Features/LanguageServer/Protocol/Features/Diagnostics/IDiagnosticServiceExtensions.cs +++ b/src/Features/LanguageServer/Protocol/Features/Diagnostics/IDiagnosticServiceExtensions.cs @@ -25,7 +25,7 @@ public static ValueTask> GetPushDiagnosticsAsync( DiagnosticMode diagnosticMode, CancellationToken cancellationToken) { - return GetDiagnosticsAsync(service, document.Project.Solution.Workspace, document.Project, document, includeSuppressedDiagnostics, forPullDiagnostics: false, diagnosticMode, cancellationToken); + return service.GetPushDiagnosticsAsync(document.Project.Solution.Workspace, document.Project.Id, document.Id, id: null, includeSuppressedDiagnostics, diagnosticMode, cancellationToken); } public static ValueTask> GetPullDiagnosticsAsync( @@ -35,40 +35,7 @@ public static ValueTask> GetPullDiagnosticsAsync( DiagnosticMode diagnosticMode, CancellationToken cancellationToken) { - return GetDiagnosticsAsync(service, document.Project.Solution.Workspace, document.Project, document, includeSuppressedDiagnostics, forPullDiagnostics: true, diagnosticMode, cancellationToken); - } - - public static async ValueTask> GetDiagnosticsAsync( - this IDiagnosticService service, - Workspace workspace, - Project? project, - Document? document, - bool includeSuppressedDiagnostics, - bool forPullDiagnostics, - DiagnosticMode diagnosticMode, - CancellationToken cancellationToken) - { - Contract.ThrowIfTrue(document != null && document.Project != project); - Contract.ThrowIfTrue(project != null && project.Solution.Workspace != workspace); - - using var _ = ArrayBuilder.GetInstance(out var result); - - var buckets = forPullDiagnostics - ? service.GetPullDiagnosticBuckets(workspace, project?.Id, document?.Id, diagnosticMode, cancellationToken) - : service.GetPushDiagnosticBuckets(workspace, project?.Id, document?.Id, diagnosticMode, cancellationToken); - - foreach (var bucket in buckets) - { - Contract.ThrowIfFalse(workspace.Equals(bucket.Workspace)); - Contract.ThrowIfFalse(document?.Id == bucket.DocumentId); - - var diagnostics = forPullDiagnostics - ? await service.GetPullDiagnosticsAsync(bucket, includeSuppressedDiagnostics, diagnosticMode, cancellationToken).ConfigureAwait(false) - : await service.GetPushDiagnosticsAsync(bucket, includeSuppressedDiagnostics, diagnosticMode, cancellationToken).ConfigureAwait(false); - result.AddRange(diagnostics); - } - - return result.ToImmutable(); + return service.GetPullDiagnosticsAsync(document.Project.Solution.Workspace, document.Project.Id, document.Id, id: null, includeSuppressedDiagnostics, diagnosticMode, cancellationToken); } } } diff --git a/src/VisualStudio/Core/Test/ProjectSystemShim/VisualStudioProjectTests/AnalyzerReferenceTests.vb b/src/VisualStudio/Core/Test/ProjectSystemShim/VisualStudioProjectTests/AnalyzerReferenceTests.vb index 710f84cce5f09..f4c412bebb0f3 100644 --- a/src/VisualStudio/Core/Test/ProjectSystemShim/VisualStudioProjectTests/AnalyzerReferenceTests.vb +++ b/src/VisualStudio/Core/Test/ProjectSystemShim/VisualStudioProjectTests/AnalyzerReferenceTests.vb @@ -114,12 +114,12 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.ProjectSystemShim Await waiter.ExpeditedWaitAsync() Dim diagnosticService = environment.ExportProvider.GetExportedValue(Of IDiagnosticService) - Dim diagnostics = Await diagnosticService.GetDiagnosticsAsync( + Dim diagnostics = Await diagnosticService.GetPushDiagnosticsAsync( environment.Workspace, - project:=Nothing, - document:=Nothing, + projectId:=Nothing, + documentId:=Nothing, + id:=Nothing, includeSuppressedDiagnostics:=True, - forPullDiagnostics:=False, DiagnosticMode.Default, CancellationToken.None) Return diagnostics From 99b6ba92a4437c6f489e383eee8e72584af1c1ee Mon Sep 17 00:00:00 2001 From: Youssef Victor Date: Thu, 14 Apr 2022 01:13:27 +0200 Subject: [PATCH 58/66] Make heading levels for warning waves documentation consistent (#60721) --- docs/compilers/CSharp/Warnversion Warning Waves.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/compilers/CSharp/Warnversion Warning Waves.md b/docs/compilers/CSharp/Warnversion Warning Waves.md index 683d44893051d..5cfca6f920311 100644 --- a/docs/compilers/CSharp/Warnversion Warning Waves.md +++ b/docs/compilers/CSharp/Warnversion Warning Waves.md @@ -17,7 +17,7 @@ The compiler shipped with .NET 7 (the C# 11 compiler) contains the following war |------------|-------------| | CS8981 | [Type names only containing lower-cased ascii characters may become reserved for the language](https://github.com/dotnet/roslyn/issues/56653) | -# Warning level 6 +## Warning level 6 The compiler shipped with .NET 6 (the C# 10 compiler) contains the following warnings which are reported only under `/warn:6` or higher. From b73c0cc65d5dd82f0384e5b633da70c2a554bd03 Mon Sep 17 00:00:00 2001 From: Julien Couvreur Date: Wed, 13 Apr 2022 16:13:58 -0700 Subject: [PATCH 59/66] Avoid formatting diagnostics with raw strings (#60655) --- dotnet-tools.json | 2 +- eng/Versions.props | 2 +- .../Semantics/NullableReferenceTypesTests.cs | 12 +++++++----- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/dotnet-tools.json b/dotnet-tools.json index b8d5a0aada491..447b894f9dc94 100644 --- a/dotnet-tools.json +++ b/dotnet-tools.json @@ -2,7 +2,7 @@ "isRoot": true, "tools": { "dotnet-format": { - "version": "6.2.315104", + "version": "6.3.317301", "commands": [ "dotnet-format" ] diff --git a/eng/Versions.props b/eng/Versions.props index e251ca6ebf4bd..be0da208d8055 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -24,7 +24,7 @@ 1.1.2-beta1.22122.4 0.1.132-beta - 4.1.0 + 4.2.0-2.final 17.2.178-preview 17.2.140-preview-ga1e1777dca 5.0.0-alpha1.19409.1 diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/NullableReferenceTypesTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/NullableReferenceTypesTests.cs index caaadc4583465..7c0665475b361 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/NullableReferenceTypesTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/NullableReferenceTypesTests.cs @@ -3133,12 +3133,13 @@ public void RefAssignment_Foreach() void verify(string variableType, string itemType, params DiagnosticDescription[] expected) { - var source = @" + var source = $$""" + class C { void M(RefEnumerable collection) { - foreach (ref VARTYPE item in collection) + foreach (ref {{variableType}} item in collection) { item.ToString(); } @@ -3149,13 +3150,14 @@ class RefEnumerable public StructEnum GetEnumerator() => throw null!; public struct StructEnum { - public ref ITEMTYPE Current => throw null!; + public ref {{itemType}} Current => throw null!; public bool MoveNext() => throw null!; } } -}"; +} +"""; - var comp = CreateCompilation(source.Replace("VARTYPE", variableType).Replace("ITEMTYPE", itemType), options: WithNullableEnable()); + var comp = CreateCompilation(source, options: WithNullableEnable()); comp.VerifyDiagnostics(expected); } } From eb3ccc53688359e3f005cf8b241b4a982dbe39e6 Mon Sep 17 00:00:00 2001 From: David Barbet Date: Wed, 13 Apr 2022 17:38:28 -0700 Subject: [PATCH 60/66] Support checked operators in explicit interface implementation (#60715) --- ...tInterfaceMemberCompletionProviderTests.cs | 105 ++++++++++++++++++ ...pletionProvider.CompletionSymbolDisplay.cs | 13 ++- 2 files changed, 116 insertions(+), 2 deletions(-) diff --git a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/ExplicitInterfaceMemberCompletionProviderTests.cs b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/ExplicitInterfaceMemberCompletionProviderTests.cs index 0748171414e87..8d8f783d7918d 100644 --- a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/ExplicitInterfaceMemberCompletionProviderTests.cs +++ b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/ExplicitInterfaceMemberCompletionProviderTests.cs @@ -888,5 +888,110 @@ void I.M(int x) // TODO: Consider adding the default value too. await VerifyProviderCommitAsync(markup, "M(int x)", expected, '\t'); } + + [Fact, Trait(Traits.Feature, Traits.Features.Completion)] + [WorkItem(60215, "https://github.com/dotnet/roslyn/issues/60215")] + public async Task TestStaticAbstractCheckedUnaryOperator() + { + var markup = @" +interface I1 where T : I1 +{ + abstract static T operator checked -(T x); + + abstract static T operator -(T x); +} + +class C : I1 +{ + static C I1.$$ +} +"; + + var expected = @" +interface I1 where T : I1 +{ + abstract static T operator checked -(T x); + + abstract static T operator -(T x); +} + +class C : I1 +{ + static C I1.operator checked -(C x) +} +"; + + await VerifyProviderCommitAsync(markup, "operator checked -(C x)", expected, '\t'); + } + + [Fact, Trait(Traits.Feature, Traits.Features.Completion)] + [WorkItem(60215, "https://github.com/dotnet/roslyn/issues/60215")] + public async Task TestStaticAbstractCheckedBinaryOperator() + { + var markup = @" +interface I1 where T : I1 +{ + abstract static T operator checked +(T x, T y); + + abstract static T operator +(T x, T y); +} + +class C : I1 +{ + static C I1.$$ +} +"; + + var expected = @" +interface I1 where T : I1 +{ + abstract static T operator checked +(T x, T y); + + abstract static T operator +(T x, T y); +} + +class C : I1 +{ + static C I1.operator checked +(C x, C y) +} +"; + + await VerifyProviderCommitAsync(markup, "operator checked +(C x, C y)", expected, '\t'); + } + + [Fact, Trait(Traits.Feature, Traits.Features.Completion)] + [WorkItem(60215, "https://github.com/dotnet/roslyn/issues/60215")] + public async Task TestStaticAbstractCheckedCastOperator() + { + var markup = @" +interface I1 where T : I1 +{ + abstract static explicit operator checked string(T x); + abstract static explicit operator string(T x); +} + + +class C3 : I1 +{ + static C3 I1.$$ +} +"; + + var expected = @" +interface I1 where T : I1 +{ + abstract static explicit operator checked string(T x); + abstract static explicit operator string(T x); +} + + +class C3 : I1 +{ + static C3 I1.operator checked string(C3 x) +} +"; + + await VerifyProviderCommitAsync(markup, "operator checked string(C3 x)", expected, '\t'); + } } } diff --git a/src/Features/CSharp/Portable/Completion/CompletionProviders/ExplicitInterfaceMemberCompletionProvider.CompletionSymbolDisplay.cs b/src/Features/CSharp/Portable/Completion/CompletionProviders/ExplicitInterfaceMemberCompletionProvider.CompletionSymbolDisplay.cs index 44dac7a5bde72..15844a3ffa07d 100644 --- a/src/Features/CSharp/Portable/Completion/CompletionProviders/ExplicitInterfaceMemberCompletionProvider.CompletionSymbolDisplay.cs +++ b/src/Features/CSharp/Portable/Completion/CompletionProviders/ExplicitInterfaceMemberCompletionProvider.CompletionSymbolDisplay.cs @@ -59,11 +59,11 @@ private static string ToDisplayString(IMethodSymbol symbol) break; case MethodKind.UserDefinedOperator: case MethodKind.BuiltinOperator: - builder.Append("operator "); + AppendOperatorKeywords(symbol, builder); builder.Append(SyntaxFacts.GetText(SyntaxFacts.GetOperatorKind(symbol.MetadataName))); break; case MethodKind.Conversion: - builder.Append("operator "); + AppendOperatorKeywords(symbol, builder); AddType(symbol.ReturnType, builder); break; } @@ -73,6 +73,15 @@ private static string ToDisplayString(IMethodSymbol symbol) AddParameters(symbol.Parameters, builder); builder.Append(')'); return builder.ToString(); + + static void AppendOperatorKeywords(IMethodSymbol symbol, StringBuilder builder) + { + builder.Append("operator "); + if (SyntaxFacts.IsCheckedOperator(symbol.MetadataName)) + { + builder.Append("checked "); + } + } } private static void AddParameters(ImmutableArray parameters, StringBuilder builder) From dbc30912d98f02aa6ee532e89217d7f884a8fc31 Mon Sep 17 00:00:00 2001 From: David Barbet Date: Wed, 13 Apr 2022 19:03:20 -0700 Subject: [PATCH 61/66] add more miscellaneous tests for checked operators (#60727) --- .../MetadataAsSourceTests.CSharp.cs | 97 +++++++++++++++++++ .../NavigationBar/CSharpNavigationBarTests.vb | 60 ++++++++++++ .../ObjectBrowser/CSharp/ObjectBrowerTests.vb | 81 ++++++++++++++++ 3 files changed, 238 insertions(+) diff --git a/src/EditorFeatures/Test/MetadataAsSource/MetadataAsSourceTests.CSharp.cs b/src/EditorFeatures/Test/MetadataAsSource/MetadataAsSourceTests.CSharp.cs index cc56b91e60e9c..ee148212cf10e 100644 --- a/src/EditorFeatures/Test/MetadataAsSource/MetadataAsSourceTests.CSharp.cs +++ b/src/EditorFeatures/Test/MetadataAsSource/MetadataAsSourceTests.CSharp.cs @@ -556,6 +556,103 @@ public R() await GenerateAndVerifySourceAsync(metadataSource, symbolName, LanguageNames.CSharp, expected: expected, signaturesOnly: signaturesOnly); } + /// + /// This test must be updated when we switch to a new version of the decompiler that supports checked ops. + /// + [Theory, CombinatorialData, Trait(Traits.Feature, Traits.Features.MetadataAsSource)] + [WorkItem(42986, "https://github.com/dotnet/roslyn/issues/42986")] + public async Task TestCheckedOperators(bool signaturesOnly) + { + var metadataSource = @" +public class C +{ + public static explicit operator string(C x) => throw new System.Exception(); + + public static explicit operator checked string(C x) => throw new System.Exception(); + + public static C operator -(C x) => throw new System.Exception(); + + public static C operator checked -(C x) => throw new System.Exception(); + + public static C operator +(C x, C y) => throw new System.Exception(); + + public static C operator checked +(C x, C y) => throw new System.Exception(); +}"; + var symbolName = "C"; + + var expected = signaturesOnly switch + { + true => $@"#region {FeaturesResources.Assembly} ReferencedAssembly, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null +// {CodeAnalysisResources.InMemoryAssembly} +#endregion + +public class [|C|] +{{ + public C(); + + public static C operator +(C x, C y); + public static C operator checked +(C x, C y); + public static C operator -(C x); + public static C operator checked -(C x); + + public static explicit operator string(C x); + public static explicit operator checked string(C x); +}}", + false => $@"#region {FeaturesResources.Assembly} ReferencedAssembly, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null +// {CodeAnalysisResources.InMemoryAssembly} +// Decompiled with ICSharpCode.Decompiler {ICSharpCodeDecompilerVersion} +#endregion + +using System; +using System.Runtime.CompilerServices; + +public class [|C|] +{{ + public static explicit operator string(C x) + {{ + throw new Exception(); + }} + + [SpecialName] + public static string op_CheckedExplicit(C x) + {{ + throw new Exception(); + }} + + public static C operator -(C x) + {{ + throw new Exception(); + }} + + [SpecialName] + public static C op_CheckedUnaryNegation(C x) + {{ + throw new Exception(); + }} + + public static C operator +(C x, C y) + {{ + throw new Exception(); + }} + + [SpecialName] + public static C op_CheckedAddition(C x, C y) + {{ + throw new Exception(); + }} +}} +#if false // {CSharpEditorResources.Decompilation_log} +{string.Format(CSharpEditorResources._0_items_in_cache, 6)} +------------------ +{string.Format(CSharpEditorResources.Resolve_0, "mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")} +{string.Format(CSharpEditorResources.Found_single_assembly_0, "mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")} +{string.Format(CSharpEditorResources.Load_from_0, "mscorlib.v4_6_1038_0.dll")} +#endif", + }; + + await GenerateAndVerifySourceAsync(metadataSource, symbolName, LanguageNames.CSharp, languageVersion: "Preview", metadataLanguageVersion: "Preview", expected: expected, signaturesOnly: signaturesOnly); + } + [Fact, Trait(Traits.Feature, Traits.Features.MetadataAsSource)] [WorkItem(60567, "https://github.com/dotnet/roslyn/issues/60567")] public async Task TestStaticInterfaceMembers() diff --git a/src/EditorFeatures/Test2/NavigationBar/CSharpNavigationBarTests.vb b/src/EditorFeatures/Test2/NavigationBar/CSharpNavigationBarTests.vb index 48e2385634ab2..dc1ed9cefec23 100644 --- a/src/EditorFeatures/Test2/NavigationBar/CSharpNavigationBarTests.vb +++ b/src/EditorFeatures/Test2/NavigationBar/CSharpNavigationBarTests.vb @@ -306,5 +306,65 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.NavigationBar Item("C", Glyph.ClassInternal, children:={ Item("M(string? s, IEnumerable e)", Glyph.MethodPrivate)})) End Function + + + Public Async Function TestCheckedBinaryOperator(host As TestHost) As Task + Await AssertSelectedItemsAreAsync( + + + +class C +{ + public static C operator +(C x, C y) => throw new System.Exception(); + + public static C operator checked +(C x, C y) => throw new System.Exception();$$ +} + + + , + host, + Item("C", Glyph.ClassInternal), False, + Item("operator checked +(C x, C y)", Glyph.Operator), False) + End Function + + + Public Async Function TestCheckedUnaryOperator(host As TestHost) As Task + Await AssertSelectedItemsAreAsync( + + + +class C +{ + public static C operator -(C x) => throw new System.Exception(); + + public static C operator checked -(C x) => throw new System.Exception();$$ +} + + + , + host, + Item("C", Glyph.ClassInternal), False, + Item("operator checked -(C x)", Glyph.Operator), False) + End Function + + + Public Async Function TestCheckedCastOperator(host As TestHost) As Task + Await AssertSelectedItemsAreAsync( + + + +class C +{ + public static explicit operator string(C x) => throw new System.Exception(); + + public static explicit operator checked string(C x) => throw new System.Exception();$$ +} + + + , + host, + Item("C", Glyph.ClassInternal), False, + Item("explicit operator checked string(C x)", Glyph.Operator), False) + End Function End Class End Namespace diff --git a/src/VisualStudio/Core/Test/ObjectBrowser/CSharp/ObjectBrowerTests.vb b/src/VisualStudio/Core/Test/ObjectBrowser/CSharp/ObjectBrowerTests.vb index 4bab21daf924a..eb80fc9a8c010 100644 --- a/src/VisualStudio/Core/Test/ObjectBrowser/CSharp/ObjectBrowerTests.vb +++ b/src/VisualStudio/Core/Test/ObjectBrowser/CSharp/ObjectBrowerTests.vb @@ -1526,5 +1526,86 @@ namespace EditorFunctionalityHelper End Using End Sub + + + Public Sub TestCheckedBinaryOperator() + Dim code = + +class C +{ + public static C operator +(C x, C y) => throw new System.Exception(); + + public static C operator checked +(C x, C y) => throw new System.Exception(); +} + + + Using state = CreateLibraryManager(GetWorkspaceDefinition(code)) + Dim library = state.GetLibrary() + + Dim list = library.GetProjectList() + list.VerifyNames("CSharpAssembly1") + + list = list.GetTypeList(0) + list.VerifyNames("C") + + list = list.GetMemberList(0) + list.VerifyNames(AddressOf IsImmediateMember, "operator +(C, C)", "operator checked +(C, C)") + End Using + End Sub + + + + Public Sub TestCheckedUnaryOperator() + Dim code = + +class C +{ + public static C operator -(C x) => throw new System.Exception(); + + public static C operator checked -(C x) => throw new System.Exception(); +} + + + Using state = CreateLibraryManager(GetWorkspaceDefinition(code)) + Dim library = state.GetLibrary() + + Dim list = library.GetProjectList() + list.VerifyNames("CSharpAssembly1") + + list = list.GetTypeList(0) + list.VerifyNames("C") + + list = list.GetMemberList(0) + list.VerifyNames(AddressOf IsImmediateMember, "operator -(C)", "operator checked -(C)") + End Using + End Sub + + + + Public Sub TestCheckedCastOperator() + Dim code = + +class C +{ + public static explicit operator string(C x) => throw new System.Exception(); + + public static explicit operator checked string(C x) => throw new System.Exception();$$ +} + + + Using state = CreateLibraryManager(GetWorkspaceDefinition(code)) + Dim library = state.GetLibrary() + + Dim list = library.GetProjectList() + list.VerifyNames("CSharpAssembly1") + + list = list.GetTypeList(0) + list.VerifyNames("C") + + list = list.GetMemberList(0) + list.VerifyNames(AddressOf IsImmediateMember, "explicit operator string(C)", "explicit operator checked string(C)") + End Using + End Sub + End Class End Namespace From 90d9e7bd19c4d3b90ca384bda9057214c16bd676 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Thu, 14 Apr 2022 10:03:24 -0700 Subject: [PATCH 62/66] Delay symbol-search index updating until solution is fully loaded. --- .../PackageInstallerServiceFactory.cs | 25 +++++++++---------- .../AbstractDelayStartedService.cs | 19 ++++++++++---- .../VisualStudioSymbolSearchService.cs | 9 +++---- 3 files changed, 30 insertions(+), 23 deletions(-) diff --git a/src/VisualStudio/Core/Def/Packaging/PackageInstallerServiceFactory.cs b/src/VisualStudio/Core/Def/Packaging/PackageInstallerServiceFactory.cs index df39b9c379a1e..8352ef5885f92 100644 --- a/src/VisualStudio/Core/Def/Packaging/PackageInstallerServiceFactory.cs +++ b/src/VisualStudio/Core/Def/Packaging/PackageInstallerServiceFactory.cs @@ -55,7 +55,6 @@ internal partial class PackageInstallerService : AbstractDelayStartedService, IP private const string NugetTitle = "NuGet"; private readonly VSUtilities.IUIThreadOperationExecutor _operationExecutor; - private readonly VisualStudioWorkspaceImpl _workspace; private readonly SVsServiceProvider _serviceProvider; private readonly Shell.IAsyncServiceProvider _asyncServiceProvider; private readonly IVsEditorAdaptersFactoryService _editorAdaptersFactoryService; @@ -104,14 +103,14 @@ public PackageInstallerService( [Import(AllowDefault = true)] Lazy? packageInstaller, [Import(AllowDefault = true)] Lazy? packageUninstaller, [Import(AllowDefault = true)] Lazy? packageSourceProvider) - : base(globalOptions, + : base(threadingContext, + globalOptions, + workspace, listenerProvider, - threadingContext, SymbolSearchGlobalOptions.Enabled, ImmutableArray.Create(SymbolSearchOptionsStorage.SearchReferenceAssemblies, SymbolSearchOptionsStorage.SearchNuGetPackages)) { _operationExecutor = operationExecutor; - _workspace = workspace; _serviceProvider = serviceProvider; // MEFv2 doesn't support type based contract for Import above and for this particular contract @@ -234,7 +233,7 @@ protected override async Task EnableServiceAsync(CancellationToken cancellationT var packageSourceProvider = await GetPackageSourceProviderAsync().ConfigureAwait(false); // Start listening to additional events workspace changes. - _workspace.WorkspaceChanged += OnWorkspaceChanged; + Workspace.WorkspaceChanged += OnWorkspaceChanged; packageSourceProvider.SourcesChanged += OnSourceProviderSourcesChanged; // Kick off an initial set of work that will analyze the entire solution. @@ -270,14 +269,14 @@ public async Task TryInstallPackageAsync( // The 'workspace == _workspace' line is probably not necessary. However, we include // it just to make sure that someone isn't trying to install a package into a workspace // other than the VisualStudioWorkspace. - if (workspace == _workspace && _workspace != null && IsEnabled) + if (workspace == Workspace && Workspace != null && IsEnabled) { await this.ThreadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); var projectId = documentId.ProjectId; var dte = (EnvDTE.DTE)_serviceProvider.GetService(typeof(SDTE)); - var dteProject = _workspace.TryGetDTEProject(projectId); - var projectGuid = _workspace.GetProjectGuid(projectId); + var dteProject = Workspace.TryGetDTEProject(projectId); + var projectGuid = Workspace.GetProjectGuid(projectId); if (dteProject != null && projectGuid != Guid.Empty) { var undoManager = _editorAdaptersFactoryService.TryGetUndoManager( @@ -353,7 +352,7 @@ await UpdateStatusBarAsync( await this.ThreadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); dte.StatusBar.Text = string.Format(ServicesVSResources.Package_install_failed_colon_0, e.Message); - var notificationService = _workspace.Services.GetService(); + var notificationService = Workspace.Services.GetService(); notificationService?.SendNotification( string.Format(ServicesVSResources.Installing_0_failed_Additional_information_colon_1, packageName, e.Message), severity: NotificationSeverity.Error); @@ -414,7 +413,7 @@ await UpdateStatusBarAsync( await this.ThreadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); dte.StatusBar.Text = string.Format(ServicesVSResources.Package_uninstall_failed_colon_0, e.Message); - var notificationService = _workspace.Services.GetService(); + var notificationService = Workspace.Services.GetService(); notificationService?.SendNotification( string.Format(ServicesVSResources.Uninstalling_0_failed_Additional_information_colon_1, packageName, e.Message), severity: NotificationSeverity.Error); @@ -463,7 +462,7 @@ private ValueTask ProcessWorkQueueAsync( Contract.ThrowIfNull(_workQueue, "How could we be processing a workqueue change without a workqueue?"); // If we've been disconnected, then there's no point proceeding. - if (_workspace == null || !IsEnabled) + if (Workspace == null || !IsEnabled) return ValueTaskFactory.CompletedTask; return ProcessWorkQueueWorkerAsync(workQueue, cancellationToken); @@ -480,7 +479,7 @@ await PerformNuGetProjectServiceWorkAsync(async (nugetService, cancellat // Figure out the entire set of projects to process. using var _ = PooledHashSet.GetInstance(out var projectsToProcess); - var solution = _workspace.CurrentSolution; + var solution = Workspace.CurrentSolution; AddProjectsToProcess(workQueue, solution, projectsToProcess); // And Process them one at a time. @@ -557,7 +556,7 @@ private async Task ProcessProjectChangeAsync( if (project?.Language is LanguageNames.CSharp or LanguageNames.VisualBasic) { - var projectGuid = _workspace.GetProjectGuid(projectId); + var projectGuid = Workspace.GetProjectGuid(projectId); if (projectGuid != Guid.Empty) { newState = await GetCurrentProjectStateAsync( diff --git a/src/VisualStudio/Core/Def/SymbolSearch/AbstractDelayStartedService.cs b/src/VisualStudio/Core/Def/SymbolSearch/AbstractDelayStartedService.cs index 31e77d792f919..992b5ee00fc22 100644 --- a/src/VisualStudio/Core/Def/SymbolSearch/AbstractDelayStartedService.cs +++ b/src/VisualStudio/Core/Def/SymbolSearch/AbstractDelayStartedService.cs @@ -8,21 +8,23 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; +using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Shared.TestHooks; +using Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem; using Roslyn.Utilities; namespace Microsoft.VisualStudio.LanguageServices.SymbolSearch { /// - /// Base type for services that we want to delay running until certain criteria is met. - /// For example, we don't want to run the core codepath - /// if the user has not enabled the features that need it. That helps us avoid loading - /// dlls unnecessarily and bloating the VS memory space. + /// Base type for services that we want to delay running until certain criteria is met. For example, we don't want + /// to run the core codepath if the user has not enabled the features + /// that need it. That helps us avoid loading dlls unnecessarily and bloating the VS memory space. /// internal abstract class AbstractDelayStartedService : ForegroundThreadAffinitizedObject { private readonly IGlobalOptionService _globalOptions; + protected readonly VisualStudioWorkspaceImpl Workspace; /// /// The set of languages that have loaded that care about this service. If one language loads and has an @@ -47,14 +49,16 @@ internal abstract class AbstractDelayStartedService : ForegroundThreadAffinitize private bool _enabled = false; protected AbstractDelayStartedService( + IThreadingContext threadingContext, IGlobalOptionService globalOptions, + VisualStudioWorkspaceImpl workspace, IAsynchronousOperationListenerProvider listenerProvider, - IThreadingContext threadingContext, Option2 featureEnabledOption, ImmutableArray> perLanguageOptions) : base(threadingContext) { _globalOptions = globalOptions; + Workspace = workspace; _featureEnabledOption = featureEnabledOption; _perLanguageOptions = perLanguageOptions; @@ -97,6 +101,11 @@ private async ValueTask ProcessOptionChangesAsync(CancellationToken arg) _enabled = true; _globalOptions.OptionChanged -= OnOptionChanged; + // Don't both kicking off delay-started services prior to the actual workspace being fully loaded. We don't + // want them using CPU/memory in the BG while we're loading things for the user. + var statusService = this.Workspace.Services.GetRequiredService(); + await statusService.WaitUntilFullyLoadedAsync(this.DisposalToken).ConfigureAwait(false); + await this.EnableServiceAsync(this.DisposalToken).ConfigureAwait(false); } } diff --git a/src/VisualStudio/Core/Def/SymbolSearch/VisualStudioSymbolSearchService.cs b/src/VisualStudio/Core/Def/SymbolSearch/VisualStudioSymbolSearchService.cs index c9dbb3ca7d1f8..9479801ba5bf0 100644 --- a/src/VisualStudio/Core/Def/SymbolSearch/VisualStudioSymbolSearchService.cs +++ b/src/VisualStudio/Core/Def/SymbolSearch/VisualStudioSymbolSearchService.cs @@ -46,7 +46,6 @@ internal partial class VisualStudioSymbolSearchService : AbstractDelayStartedSer // but we want to keep it alive until the VS is closed, so we don't dispose it. private ISymbolSearchUpdateEngine _lazyUpdateEngine; - private readonly VisualStudioWorkspaceImpl _workspace; private readonly SVsServiceProvider _serviceProvider; private readonly IPackageInstallerService _installerService; @@ -61,13 +60,13 @@ public VisualStudioSymbolSearchService( VisualStudioWorkspaceImpl workspace, IGlobalOptionService globalOptions, VSShell.SVsServiceProvider serviceProvider) - : base(globalOptions, + : base(threadingContext, + globalOptions, + workspace, listenerProvider, - threadingContext, SymbolSearchGlobalOptions.Enabled, ImmutableArray.Create(SymbolSearchOptionsStorage.SearchReferenceAssemblies, SymbolSearchOptionsStorage.SearchNuGetPackages)) { - _workspace = workspace; _serviceProvider = serviceProvider; _installerService = workspace.Services.GetService(); } @@ -103,7 +102,7 @@ private async Task GetEngineAsync(CancellationToken c using (await _gate.DisposableWaitAsync(cancellationToken).ConfigureAwait(false)) { return _lazyUpdateEngine ??= await SymbolSearchUpdateEngineFactory.CreateEngineAsync( - _workspace, _logService, cancellationToken).ConfigureAwait(false); + Workspace, _logService, cancellationToken).ConfigureAwait(false); } } From 1dfba6a26b385ac6ed5f337eb888c2b1a091ae76 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Thu, 14 Apr 2022 12:58:53 -0700 Subject: [PATCH 63/66] Do not try to refcount solution syncing when communicating with OOP --- src/Workspaces/Remote/Core/SolutionAssetStorage.cs | 3 +++ .../Remote/ServiceHub/Host/RemoteWorkspace.cs | 13 +++++++++++++ 2 files changed, 16 insertions(+) diff --git a/src/Workspaces/Remote/Core/SolutionAssetStorage.cs b/src/Workspaces/Remote/Core/SolutionAssetStorage.cs index 923a054f55c56..9295bb0840681 100644 --- a/src/Workspaces/Remote/Core/SolutionAssetStorage.cs +++ b/src/Workspaces/Remote/Core/SolutionAssetStorage.cs @@ -104,6 +104,9 @@ public async ValueTask> GetAssetsAs result[Checksum.Null] = SolutionAsset.Null; } + if (!_solutionStates.ContainsKey(scopeId)) + throw new InvalidOperationException($"Request for scopeId '{scopeId}' that was not pinned on the host side."); + await FindAssetsAsync(_solutionStates[scopeId].Solution, checksumsToFind.Object, result, cancellationToken).ConfigureAwait(false); if (result.Count == numberOfChecksumsToSearch) { diff --git a/src/Workspaces/Remote/ServiceHub/Host/RemoteWorkspace.cs b/src/Workspaces/Remote/ServiceHub/Host/RemoteWorkspace.cs index 45bbf67e0abdd..a74a5432108c3 100644 --- a/src/Workspaces/Remote/ServiceHub/Host/RemoteWorkspace.cs +++ b/src/Workspaces/Remote/ServiceHub/Host/RemoteWorkspace.cs @@ -43,6 +43,7 @@ internal sealed partial class RemoteWorkspace : Workspace /// private int _currentRemoteWorkspaceVersion = -1; +#if SHARE_SOLUTIONS_ACROSS_CONCURRENT_CALLS /// /// Mapping from solution checksum to to the solution computed for it. This is used so that we can hold a /// solution around as long as the checksum for it is being used in service of some feature operation (e.g. @@ -50,6 +51,7 @@ internal sealed partial class RemoteWorkspace : Workspace /// share the computation of that particular solution and avoid duplicated concurrent work. /// private readonly Dictionary lazySolution)> _checksumToRefCountAndLazySolution = new(); +#endif // internal for testing purposes. internal RemoteWorkspace(HostServices hostServices, string? workspaceKind) @@ -189,8 +191,13 @@ await SlowGetSolutionAndRunAsync( await DecrementLazySolutionRefcountAsync().ConfigureAwait(false); } +#pragma warning disable CS1998 // Async method lacks 'await' operators and will run synchronously async ValueTask> GetLazySolutionAndIncrementRefCountAsync() { +#if !SHARE_SOLUTIONS_ACROSS_CONCURRENT_CALLS + return + AsyncLazy.Create(c => ComputeSolutionAsync(assetProvider, solutionChecksum, workspaceVersion, fromPrimaryBranch, c), cacheResult: true); +#else using (await _gate.DisposableWaitAsync(cancellationToken).ConfigureAwait(false)) { if (_checksumToRefCountAndLazySolution.TryGetValue(solutionChecksum, out var tuple)) @@ -212,6 +219,7 @@ async ValueTask> GetLazySolutionAndIncrementRefCountAsync() return tuple.lazySolution; } +#endif } async ValueTask SetLastRequestedSolutionAsync(Solution solution) @@ -228,6 +236,9 @@ async ValueTask SetLastRequestedSolutionAsync(Solution solution) async ValueTask DecrementLazySolutionRefcountAsync() { +#if !SHARE_SOLUTIONS_ACROSS_CONCURRENT_CALLS + return; +#else // We use CancellationToken.None here as we have to ensure the refcount is decremented, or else we will // have a memory leak. This should hopefully not ever be an issue as we only ever hold this gate for // very short periods of time in order to set do basic operations on our state. @@ -247,7 +258,9 @@ async ValueTask DecrementLazySolutionRefcountAsync() _checksumToRefCountAndLazySolution[solutionChecksum] = (refCount, lazySolution); } } +#endif } +#pragma warning restore CS1998 // Async method lacks 'await' operators and will run synchronously } /// From 2920959474788600fe16c69f3a4aa107806284c3 Mon Sep 17 00:00:00 2001 From: David Kean Date: Fri, 15 Apr 2022 06:07:03 +1000 Subject: [PATCH 64/66] Remove duplicated asset Roslyn was triggering a watson/fault in https://devdiv.visualstudio.com/DevDiv/_workitems/edit/1505871 due to the duplicated Microsoft.CodeAnalysis.LanguageServer.Protocol.dll asset. This asset is already added 3 lines under this one. --- src/VisualStudio/Setup/source.extension.vsixmanifest | 1 - 1 file changed, 1 deletion(-) diff --git a/src/VisualStudio/Setup/source.extension.vsixmanifest b/src/VisualStudio/Setup/source.extension.vsixmanifest index 01e67e7e60606..1b9aaf715bd16 100644 --- a/src/VisualStudio/Setup/source.extension.vsixmanifest +++ b/src/VisualStudio/Setup/source.extension.vsixmanifest @@ -63,7 +63,6 @@ - From 2b1fbd8d580b275efce5748fb6a7d963bcb0f28b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Matou=C5=A1ek?= Date: Thu, 14 Apr 2022 14:22:05 -0700 Subject: [PATCH 65/66] Simplifier options (#60174) * SimplifierOptions * Public option tests * Serializability * Fallback simplifier options for analyzers * Null annotate * Fallback simplifier options for code actions * Document extension * Avoid calling Reducer APIs that take OptionSet; CodeCleanupOptions * Revert project change * Remove GlobalIdeOptionsProvider * Formatting * Make IsApplicable abstract --- eng/config/BannedSymbols.txt | 4 + .../Analyzers/CSharpAnalyzers.projitems | 1 + ...rpQualifyMemberAccessDiagnosticAnalyzer.cs | 6 +- .../CSharpSimplifierOptionsFactory.cs | 18 ++ ...mplicitObjectCreationDiagnosticAnalyzer.cs | 15 +- .../CSharpTypeStyleDiagnosticAnalyzerBase.cs | 7 +- ...MisplacedUsingDirectivesCodeFixProvider.cs | 42 ++-- .../Helpers/AnalyzerOptionsExtensions.cs | 9 +- ...ctQualifyMemberAccessDiagnosticAnalyzer.cs | 38 ++-- ...derCodeFixProvider.CustomFixAllProvider.cs | 8 +- ...geNamespaceToMatchFolderCodeFixProvider.cs | 17 +- ...icQualifyMemberAccessDiagnosticAnalyzer.vb | 7 +- .../VisualBasicSimplifierOptionsFactory.vb | 19 ++ .../Analyzers/VisualBasicAnalyzers.projitems | 1 + .../EncapsulateFieldCommandHandler.cs | 4 +- ...EventHookupCommandHandler_TabKeyCommand.cs | 3 +- .../CSharpSimplifierOptionsStorage.cs | 43 ++++ .../MoveToNamespace/MoveToNamespaceTests.cs | 2 + .../AbstractSnippetExpansionClient.cs | 14 +- .../CSharpSnippets/SnippetCommandHandler.cs | 2 +- .../CSharpSnippets/SnippetExpansionClient.cs | 5 +- .../SnippetFunctionGenerateSwitchCases.cs | 3 +- .../SnippetFunctionSimpleTypeName.cs | 3 +- .../Core.Wpf/Peek/DefinitionPeekableItem.cs | 2 +- .../AbstractAddImportsPasteCommandHandler.cs | 7 +- .../CodeActions/CodeActionOptionsStorage.cs | 28 +-- .../DefinitionContextTracker.cs | 2 +- .../AbstractEncapsulateFieldCommandHandler.cs | 13 +- .../References/FindUsagesLSPContext.cs | 2 +- .../AbstractCodeActionOrUserDiagnosticTest.cs | 1 - .../AbstractMoveToNamespaceTests.cs | 2 + .../AbstractCodeGenerationTests.cs | 4 +- .../CodeGeneration/CodeGenerationTests.cs | 5 +- .../Test2/Expansion/AbstractExpansionTest.vb | 7 +- .../Test2/NavigationBar/TestHelpers.vb | 2 +- .../AbstractSimplificationTests.vb | 2 + .../ParameterSimplificationTests.vb | 4 +- .../Simplification/SimplifierAPITests.vb | 154 -------------- ...stractNewDocumentFormattingServiceTests.cs | 5 +- .../EncapsulateFieldCommandHandler.vb | 4 +- .../VisualBasic/LineCommit/CommitFormatter.vb | 7 +- ...sualBasicEditorNavigationBarItemService.vb | 6 +- ...NavigationBarItemService_CodeGeneration.vb | 14 +- .../VisualBasicSimplifierOptionsStorage.vb | 40 ++++ ...tAbstractClassOrInterfaceCommandHandler.vb | 3 +- .../CaseCorrectionServiceTests.vb | 5 +- .../EncapsulateFieldCommandHandlerTests.vb | 2 + .../EncapsulateFieldTestState.vb | 1 + .../AbstractParameterWrappingTests.vb | 9 +- .../AbstractUseTypeCodeRefactoringProvider.cs | 9 +- .../UseExplicitTypeCodeRefactoringProvider.cs | 5 +- .../UseImplicitTypeCodeRefactoringProvider.cs | 6 +- ...harpSimplifyTypeNamesDiagnosticAnalyzer.cs | 18 +- .../Analyzers/TypeSyntaxSimplifierWalker.cs | 9 +- ...yModifiersNewDocumentFormattingProvider.cs | 3 +- ...eclarationNewDocumentFormattingProvider.cs | 5 +- ...nizeUsingsNewDocumentFormattingProvider.cs | 18 +- ...rogramMainNewDocumentFormattingProvider.cs | 7 +- ...CSharpImplementInterfaceCodeFixProvider.cs | 2 +- ...SharpSimplifyThisOrMeDiagnosticAnalyzer.cs | 13 +- .../SimplifyTypeNamesCodeFixProvider.cs | 3 +- ...FileBannerNewDocumentFormattingProvider.cs | 5 +- .../AbstractAddImportCodeFixProvider.cs | 9 +- .../AbstractAddImportFeatureService.cs | 5 +- .../AddImport/IAddImportFeatureService.cs | 5 +- .../AddImport/References/AssemblyReference.cs | 3 +- .../References/MetadataSymbolReference.cs | 3 +- .../AddImport/References/PackageReference.cs | 3 +- .../References/ProjectSymbolReference.cs | 3 +- .../AddImport/References/Reference.cs | 10 +- .../AddImport/References/SymbolReference.cs | 13 +- .../AbstractAddPackageCodeFixProvider.cs | 2 +- .../AbstractChangeSignatureService.cs | 11 +- ...r.GlobalSuppressMessageFixAllCodeAction.cs | 7 +- ...AbstractAddMissingImportsFeatureService.cs | 4 +- ...actAddMissingImportsRefactoringProvider.cs | 12 +- .../IAddMissingImportsFeatureService.cs | 7 +- ...actExtractMethodCodeRefactoringProvider.cs | 2 +- .../AbstractChangeNamespaceService.cs | 36 ++-- ...actSyncNamespaceCodeRefactoringProvider.cs | 2 +- ...stractMemberInsertingCompletionProvider.cs | 19 +- .../AbstractEncapsulateFieldService.cs | 56 +++-- .../EncapsulateFieldOptions.cs | 12 ++ .../EncapsulateFieldRefactoringProvider.cs | 6 +- .../IRemoteEncapsulateFieldService.cs | 1 + .../AbstractExtractInterfaceService.cs | 4 +- .../ExtractMethod/ExtractMethodResult.cs | 8 +- .../AbstractNewDocumentFormattingService.cs | 5 +- .../INewDocumentFormattingProvider.cs | 5 +- .../INewDocumentFormattingService.cs | 3 +- .../AbstractFullyQualifyCodeFixProvider.cs | 2 +- .../AbstractGenerateTypeService.Editor.cs | 5 +- ...ctImplementAbstractClassCodeFixProvider.cs | 2 +- ...ice.AbstractIntroduceVariableCodeAction.cs | 3 +- ...ntroduceVariableAllOccurrenceCodeAction.cs | 4 +- .../AbstractMetadataAsSourceService.cs | 23 ++- ...compilationMetadataAsSourceFileProvider.cs | 4 +- .../IMetadataAsSourceService.cs | 3 +- .../MetadataAsSourceOptions.cs | 5 +- ...deAction.MoveItemsToNamespaceCodeAction.cs | 6 +- ...odeAction.MoveTypeToNamespaceCodeAction.cs | 6 +- .../AbstractMoveToNamespaceCodeAction.cs | 12 +- .../AbstractMoveToNamespaceService.cs | 16 +- .../MoveToNamespaceCodeActionProvider.cs | 3 +- .../Shared/Utilities/ExtractTypeHelpers.cs | 9 +- ...tractSimplifyThisOrMeDiagnosticAnalyzer.cs | 18 +- ...bstractSimplifyTypeNamesCodeFixProvider.cs | 25 +-- ...SimplifyTypeNamesDiagnosticAnalyzerBase.cs | 30 +-- .../Snippets/SnippetFunctionService.cs | 15 +- .../AbstractSpellCheckCodeFixProvider.cs | 2 +- ...AbstractWrappingCodeRefactoringProvider.cs | 2 +- .../DefaultDiagnosticAnalyzerService.cs | 2 +- ...cIncrementalAnalyzer.CompilationManager.cs | 2 +- ...osticIncrementalAnalyzer_GetDiagnostics.cs | 2 +- ...crementalAnalyzer_GetDiagnosticsForSpan.cs | 2 +- ...IncrementalAnalyzer_IncrementalAnalyzer.cs | 2 +- .../Options/AutoFormattingOptionsStorage.cs | 2 - .../Options/BlockStructureOptionsStorage.cs | 103 +++++----- .../Options/ClassificationOptionsStorage.cs | 35 ++-- .../Options/CompletionOptionsStorage.cs | 191 +++++++++--------- .../DocumentationCommentOptionsStorage.cs | 2 - .../Options/ExtractMethodOptionsStorage.cs | 1 - .../Options/HighlightingOptionsStorage.cs | 1 - .../Options/IdeAnalyzerOptionsStorage.cs | 17 +- .../Options/IndentationOptionsStorage.cs | 1 - .../Options/InternalDiagnosticsOptions.cs | 11 +- .../Options/MetadataAsSourceOptionsStorage.cs | 35 ++-- .../Options/SignatureHelpOptionsStorage.cs | 13 +- .../Options/SimplifierOptionsStorage.cs | 24 +++ .../Options/SolutionCrawlerOptionsStorage.cs | 77 ++++--- .../WorkspaceConfigurationOptionsStorage.cs | 83 ++++---- .../Options/WorkspaceConfigurationService.cs | 33 ++- .../AbstractGoToDefinitionHandler.cs | 2 +- .../InlineCompletionsHandler.cs | 20 +- .../XmlSnippetParser.ParsedXmlSnippet.cs | 5 +- ...odeAnalysis.LanguageServer.Protocol.csproj | 3 +- .../Analyzers/TypeSyntaxSimplifierWalker.vb | 9 +- ...asicSimplifyTypeNamesDiagnosticAnalyzer.vb | 17 +- ...nizeUsingsNewDocumentFormattingProvider.vb | 3 +- ...lBasicImplementInterfaceCodeFixProvider.vb | 2 +- ...BasicSimplifyThisOrMeDiagnosticAnalyzer.vb | 12 +- .../SimplifyTypeNamesCodeFixProvider.vb | 3 +- ...OmniSharpSyntaxFormattingOptionsFactory.cs | 114 ++++++----- .../CodeActions/OmniSharpCodeActionOptions.cs | 8 +- .../OmniSharpCodeFixContextFactory.cs | 2 +- .../Formatting/OmniSharpFormatter.cs | 2 +- ...OmniSharpSyntaxFormattingOptionsWrapper.cs | 17 +- .../OmniSharpMetadataAsSourceService.cs | 8 +- .../CodeCleanup/AbstractCodeCleanUpFixer.cs | 6 +- .../Implementation/AbstractEditorFactory.cs | 11 +- .../AbstractSnippetExpansionClient.cs | 2 +- .../SnippetFunctionGenerateSwitchCases.cs | 5 +- .../SnippetFunctionSimpleTypeName.cs | 6 +- .../VisualStudioSuppressionFixService.cs | 10 +- .../Def/Venus/ContainedLanguageCodeSupport.cs | 8 +- .../VisualStudioSymbolNavigationService.cs | 2 +- .../CodeModel/AbstractCodeModelService.cs | 12 +- .../Core/Impl/CodeModel/FileCodeModel.cs | 7 +- ...alStudioDiagnosticAnalyzerExecutorTests.cs | 39 ++-- .../Definitions/GoToDefinitionHandler.cs | 2 +- ...nService.NodesAndTokensToReduceComputer.cs | 2 +- .../CSharpSimplificationService.cs | 19 +- ...CSharpReducer.AbstractReductionRewriter.cs | 50 +++-- .../Reducers/AbstractCSharpReducer.cs | 5 + .../Reducers/CSharpCastReducer.cs | 9 +- ...CSharpDefaultExpressionReducer.Rewriter.cs | 7 +- .../CSharpDefaultExpressionReducer.cs | 3 + .../Reducers/CSharpEscapingReducer.cs | 7 +- .../Reducers/CSharpExtensionMethodReducer.cs | 7 +- ...SharpInferredMemberNameReducer.Rewriter.cs | 9 +- .../CSharpInferredMemberNameReducer.cs | 3 + .../Reducers/CSharpMiscellaneousReducer.cs | 19 +- .../Reducers/CSharpNameReducer.cs | 11 +- .../CSharpNullableAnnotationReducer.cs | 8 +- .../CSharpParenthesizedExpressionReducer.cs | 7 +- .../CSharpParenthesizedPatternReducer.cs | 7 +- .../Reducers/CSharpVarReducer.Rewriter.cs | 2 +- .../Reducers/CSharpVarReducer.cs | 10 +- .../Simplifiers/AbstractCSharpSimplifier.cs | 8 +- .../Simplifiers/ExpressionSimplifier.cs | 16 +- .../Simplifiers/NameSimplifier.cs | 10 +- .../Simplifiers/QualifiedCrefSimplifier.cs | 5 +- .../CodeGeneration/AddImportsTests.cs | 5 +- .../CodeGeneration/SymbolEditorTests.cs | 3 +- .../ChangeNamespace/ChangeNamespaceOptions.cs | 47 +++++ .../IChangeNamespaceService.cs | 5 +- .../Core/Portable/CodeActions/CodeAction.cs | 21 +- .../CodeCleanup/AbstractCodeCleanerService.cs | 4 +- .../Core/Portable/CodeCleanup/CodeCleaner.cs | 4 +- .../CodeCleanup/CodeCleanupOptions.cs | 28 +++ .../CodeCleanup/ICodeCleanerService.cs | 2 +- .../Providers/FormatCodeCleanupProvider.cs | 4 +- .../Providers/ICodeCleanupProvider.cs | 2 +- .../SimplificationCodeCleanupProvider.cs | 4 +- .../Core/Portable/CodeFixes/CodeFixContext.cs | 2 +- .../CodeRefactoringContext.cs | 2 +- .../Core/Portable/Editing/SyntaxGenerator.cs | 3 +- .../Portable/Options/IGlobalOptionService.cs | 9 +- .../ConflictEngine/RenamedSpansTracker.cs | 3 +- .../Core/Portable/Rename/RenameOptions.cs | 2 + .../Renamer.SyncNamespaceDocumentAction.cs | 10 +- .../Core/Portable/Rename/Renamer.cs | 21 +- .../AbstractReducer.IExpressionRewriter.cs | 3 +- .../Simplification/AbstractReducer.cs | 3 +- .../AbstractSimplificationService.cs | 54 +++-- .../Simplification/ISimplificationService.cs | 15 +- .../Portable/Simplification/Simplifier.cs | 44 +++- .../Simplifiers/AbstractSimplifier.cs | 6 +- .../CodeCleanup/MockCodeCleanupProvider.cs | 6 +- .../CoreTest/Remote/ServiceDescriptorTests.cs | 14 ++ .../CoreTest/Simplifier/SimplifierTests.cs | 159 +++++++++++++++ .../Serialization/MessagePackFormatters.cs | 14 +- ...vertTupleToStructCodeRefactoringService.cs | 8 +- .../RemoteEncapsulateFieldService.cs | 3 +- .../CSharp/CSharpCompilerExtensions.projitems | 1 + .../Formatting/CSharpSyntaxFormatting.cs | 3 + .../Simplification/CSharpSimplifierOptions.cs | 90 +++++++++ .../TypeStyle/CSharpTypeStyleHelper.State.cs | 9 +- .../TypeStyle/CSharpTypeStyleHelper.cs | 20 +- .../TypeStyle/CSharpUseExplicitTypeHelper.cs | 9 +- .../TypeStyle/CSharpUseImplicitTypeHelper.cs | 11 +- .../Core/CodeStyle/CodeStyleOption2`1.cs | 17 +- .../Core/CodeStyle/CodeStyleOptions2.cs | 1 + .../Core/CompilerExtensions.projitems | 1 + .../AnalyzerConfigOptionsExtensions.cs | 14 +- .../AbstractSyntaxFormattingService.cs | 1 + .../Core/Formatting/ISyntaxFormatting.cs | 2 + .../Core/Simplification/SimplifierOptions.cs | 81 ++++++++ .../VisualBasicSimplifierOptions.vb | 52 +++++ .../VisualBasicCompilerExtensions.projitems | 1 + ...olExtensions.TypeSyntaxGeneratorVisitor.cs | 3 +- .../Core/CodeFixes/CodeActionOptions.cs | 47 +++-- .../AddImports/IAddImportsService.cs | 13 +- .../SimplificationHelpers.cs | 24 +-- .../Core/WorkspaceExtensions.projitems | 2 +- .../AbstractTokensCodeCleanupProvider.vb | 2 +- .../CaseCorrectionCodeCleanupProvider.vb | 2 +- ...ModifiersOrOperatorsCodeCleanupProvider.vb | 4 +- ...saryLineContinuationCodeCleanupProvider.vb | 4 +- .../Formatting/VisualBasicSyntaxFormatting.vb | 6 + ...lBasicReducer.AbstractReductionRewriter.vb | 21 +- .../Reducers/AbstractVisualBasicReducer.vb | 10 +- .../Reducers/VisualBasicCallReducer.vb | 8 +- .../Reducers/VisualBasicCastReducer.vb | 13 +- .../Reducers/VisualBasicEscapingReducer.vb | 6 +- .../VisualBasicExtensionMethodReducer.vb | 8 +- ...BasicInferredMemberNameReducer.Rewriter.vb | 9 +- .../VisualBasicInferredMemberNameReducer.vb | 4 + .../VisualBasicMiscellaneousReducer.vb | 16 +- .../Reducers/VisualBasicNameReducer.vb | 10 +- .../Reducers/VisualBasicParenthesesReducer.vb | 4 + .../VisualBasicVariableDeclaratorReducer.vb | 8 +- .../AbstractVisualBasicSimplifier.vb | 6 +- .../Simplifiers/ExpressionSimplifier.vb | 20 +- .../Simplifiers/NameSimplifier.vb | 10 +- .../VisualBasicSimplificationService.vb | 11 + .../CodeGeneration/AddImportsTests.vb | 4 +- 257 files changed, 2178 insertions(+), 1276 deletions(-) create mode 100644 src/Analyzers/CSharp/Analyzers/Simplification/CSharpSimplifierOptionsFactory.cs create mode 100644 src/Analyzers/VisualBasic/Analyzers/Simplification/VisualBasicSimplifierOptionsFactory.vb create mode 100644 src/EditorFeatures/CSharp/Simplification/CSharpSimplifierOptionsStorage.cs delete mode 100644 src/EditorFeatures/Test2/Simplification/SimplifierAPITests.vb create mode 100644 src/EditorFeatures/VisualBasic/Simplification/VisualBasicSimplifierOptionsStorage.vb create mode 100644 src/Features/Core/Portable/EncapsulateField/EncapsulateFieldOptions.cs rename src/Features/{Core/Portable => LanguageServer/Protocol/Features}/Options/AutoFormattingOptionsStorage.cs (98%) rename src/Features/{Core/Portable => LanguageServer/Protocol/Features}/Options/DocumentationCommentOptionsStorage.cs (98%) rename src/Features/{Core/Portable => LanguageServer/Protocol/Features}/Options/ExtractMethodOptionsStorage.cs (97%) rename src/Features/{Core/Portable => LanguageServer/Protocol/Features}/Options/HighlightingOptionsStorage.cs (98%) rename src/Features/{Core/Portable => LanguageServer/Protocol/Features}/Options/IdeAnalyzerOptionsStorage.cs (88%) rename src/Features/{Core/Portable => LanguageServer/Protocol/Features}/Options/IndentationOptionsStorage.cs (97%) create mode 100644 src/Features/LanguageServer/Protocol/Features/Options/SimplifierOptionsStorage.cs create mode 100644 src/Workspaces/Core/Portable/ChangeNamespace/ChangeNamespaceOptions.cs rename src/Workspaces/Core/Portable/{Rename => ChangeNamespace}/IChangeNamespaceService.cs (93%) create mode 100644 src/Workspaces/Core/Portable/CodeCleanup/CodeCleanupOptions.cs create mode 100644 src/Workspaces/CoreTest/Simplifier/SimplifierTests.cs create mode 100644 src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Simplification/CSharpSimplifierOptions.cs create mode 100644 src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Simplification/SimplifierOptions.cs create mode 100644 src/Workspaces/SharedUtilitiesAndExtensions/Compiler/VisualBasic/Simplification/VisualBasicSimplifierOptions.vb rename src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/{Helpers => Simplification}/SimplificationHelpers.cs (78%) diff --git a/eng/config/BannedSymbols.txt b/eng/config/BannedSymbols.txt index b3f5e5f9afcd1..8a51cac5d9646 100644 --- a/eng/config/BannedSymbols.txt +++ b/eng/config/BannedSymbols.txt @@ -25,3 +25,7 @@ M:Microsoft.CodeAnalysis.Formatting.Formatter.Format(Microsoft.CodeAnalysis.Synt M:Microsoft.CodeAnalysis.Formatting.Formatter.GetFormattedTextChanges(Microsoft.CodeAnalysis.SyntaxNode,Microsoft.CodeAnalysis.Workspace,Microsoft.CodeAnalysis.Options.OptionSet,System.Threading.CancellationToken); Use overload with SyntaxFormattingOptions instead M:Microsoft.CodeAnalysis.Formatting.Formatter.GetFormattedTextChanges(Microsoft.CodeAnalysis.SyntaxNode,Microsoft.CodeAnalysis.Text.TextSpan,Microsoft.CodeAnalysis.Workspace,Microsoft.CodeAnalysis.Options.OptionSet,System.Threading.CancellationToken); Use overload with SyntaxFormattingOptions instead M:Microsoft.CodeAnalysis.Formatting.Formatter.GetFormattedTextChanges(Microsoft.CodeAnalysis.SyntaxNode,System.Collections.Generic.IEnumerable{Microsoft.CodeAnalysis.Text.TextSpan},Microsoft.CodeAnalysis.Workspace,Microsoft.CodeAnalysis.Options.OptionSet,System.Threading.CancellationToken); Use overload with SyntaxFormattingOptions instead +M:Microsoft.CodeAnalysis.Simplification.Simplifier.ReduceAsync(Microsoft.CodeAnalysis.Document,Microsoft.CodeAnalysis.Options.OptionSet,System.Threading.CancellationToken); Use overload that takes SimplifierOptions +M:Microsoft.CodeAnalysis.Simplification.Simplifier.ReduceAsync(Microsoft.CodeAnalysis.Document,Microsoft.CodeAnalysis.SyntaxAnnotation,Microsoft.CodeAnalysis.Options.OptionSet,System.Threading.CancellationToken); Use overload that takes SimplifierOptions +M:Microsoft.CodeAnalysis.Simplification.Simplifier.ReduceAsync(Microsoft.CodeAnalysis.Document,Microsoft.CodeAnalysis.Text.TextSpan,Microsoft.CodeAnalysis.Options.OptionSet,System.Threading.CancellationToken); Use overload that takes SimplifierOptions +M:Microsoft.CodeAnalysis.Simplification.Simplifier.ReduceAsync(Microsoft.CodeAnalysis.Document,System.Collections.Generic.IEnumerable{Microsoft.CodeAnalysis.Text.TextSpan},Microsoft.CodeAnalysis.Options.OptionSet,System.Threading.CancellationToken); Use overload that takes SimplifierOptions diff --git a/src/Analyzers/CSharp/Analyzers/CSharpAnalyzers.projitems b/src/Analyzers/CSharp/Analyzers/CSharpAnalyzers.projitems index 716f188b5bf96..60ed46390e5cd 100644 --- a/src/Analyzers/CSharp/Analyzers/CSharpAnalyzers.projitems +++ b/src/Analyzers/CSharp/Analyzers/CSharpAnalyzers.projitems @@ -60,6 +60,7 @@ + diff --git a/src/Analyzers/CSharp/Analyzers/QualifyMemberAccess/CSharpQualifyMemberAccessDiagnosticAnalyzer.cs b/src/Analyzers/CSharp/Analyzers/QualifyMemberAccess/CSharpQualifyMemberAccessDiagnosticAnalyzer.cs index 1cadc95164172..e180a2c800faa 100644 --- a/src/Analyzers/CSharp/Analyzers/QualifyMemberAccess/CSharpQualifyMemberAccessDiagnosticAnalyzer.cs +++ b/src/Analyzers/CSharp/Analyzers/QualifyMemberAccess/CSharpQualifyMemberAccessDiagnosticAnalyzer.cs @@ -4,6 +4,7 @@ using System.Linq; using Microsoft.CodeAnalysis.CSharp.Extensions; +using Microsoft.CodeAnalysis.CSharp.Simplification; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.QualifyMemberAccess; @@ -13,11 +14,14 @@ namespace Microsoft.CodeAnalysis.CSharp.QualifyMemberAccess { [DiagnosticAnalyzer(LanguageNames.CSharp)] internal sealed class CSharpQualifyMemberAccessDiagnosticAnalyzer - : AbstractQualifyMemberAccessDiagnosticAnalyzer + : AbstractQualifyMemberAccessDiagnosticAnalyzer { protected override string GetLanguageName() => LanguageNames.CSharp; + protected override CSharpSimplifierOptions GetSimplifierOptions(AnalyzerOptions options, SyntaxTree syntaxTree) + => options.GetCSharpSimplifierOptions(syntaxTree); + protected override bool IsAlreadyQualifiedMemberAccess(ExpressionSyntax node) => node.IsKind(SyntaxKind.ThisExpression); diff --git a/src/Analyzers/CSharp/Analyzers/Simplification/CSharpSimplifierOptionsFactory.cs b/src/Analyzers/CSharp/Analyzers/Simplification/CSharpSimplifierOptionsFactory.cs new file mode 100644 index 0000000000000..a065e1ea4bbfc --- /dev/null +++ b/src/Analyzers/CSharp/Analyzers/Simplification/CSharpSimplifierOptionsFactory.cs @@ -0,0 +1,18 @@ +// 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 Microsoft.CodeAnalysis.Diagnostics; + +namespace Microsoft.CodeAnalysis.CSharp.Simplification; + +internal static class CSharpSimplifierOptionsFactory +{ + internal static CSharpSimplifierOptions GetCSharpSimplifierOptions(this AnalyzerOptions options, SyntaxTree syntaxTree) + { + var configOptions = options.AnalyzerConfigOptionsProvider.GetOptions(syntaxTree); + var ideOptions = options.GetIdeOptions(); + + return CSharpSimplifierOptions.Create(configOptions, (CSharpSimplifierOptions?)ideOptions.SimplifierOptions); + } +} diff --git a/src/Analyzers/CSharp/Analyzers/UseImplicitObjectCreation/CSharpUseImplicitObjectCreationDiagnosticAnalyzer.cs b/src/Analyzers/CSharp/Analyzers/UseImplicitObjectCreation/CSharpUseImplicitObjectCreationDiagnosticAnalyzer.cs index 246184e9a442f..71af8d9bad828 100644 --- a/src/Analyzers/CSharp/Analyzers/UseImplicitObjectCreation/CSharpUseImplicitObjectCreationDiagnosticAnalyzer.cs +++ b/src/Analyzers/CSharp/Analyzers/UseImplicitObjectCreation/CSharpUseImplicitObjectCreationDiagnosticAnalyzer.cs @@ -6,11 +6,13 @@ using Microsoft.CodeAnalysis.CodeStyle; using Microsoft.CodeAnalysis.CSharp.CodeStyle; using Microsoft.CodeAnalysis.CSharp.Extensions; +using Microsoft.CodeAnalysis.CSharp.Simplification; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.CSharp.Utilities; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.Utilities; +using Microsoft.CodeAnalysis.Simplification; namespace Microsoft.CodeAnalysis.CSharp.UseImplicitObjectCreation { @@ -44,7 +46,6 @@ private void AnalyzeSyntax(SyntaxNodeAnalysisContext context) if (syntaxTree.Options.LanguageVersion() < LanguageVersion.CSharp9) return; - var optionSet = options.GetAnalyzerOptionSet(syntaxTree, cancellationToken); var styleOption = options.GetOption(CSharpCodeStyleOptions.ImplicitObjectCreationWhenTypeIsApparent, syntaxTree, cancellationToken); if (!styleOption.Value) { @@ -73,11 +74,15 @@ objectCreation.Parent.Parent.Parent is VariableDeclarationSyntax variableDeclara typeNode = variableDeclaration.Type; var helper = CSharpUseImplicitTypeHelper.Instance; - if (helper.ShouldAnalyzeVariableDeclaration(variableDeclaration, cancellationToken) && - helper.AnalyzeTypeName(typeNode, semanticModel, optionSet, cancellationToken).IsStylePreferred) + if (helper.ShouldAnalyzeVariableDeclaration(variableDeclaration, cancellationToken)) { - // this is a case where the user would prefer 'var'. don't offer to use an implicit object here. - return; + var simplifierOptions = context.Options.GetCSharpSimplifierOptions(syntaxTree); + + if (helper.AnalyzeTypeName(typeNode, semanticModel, simplifierOptions, cancellationToken).IsStylePreferred) + { + // this is a case where the user would prefer 'var'. don't offer to use an implicit object here. + return; + } } } else if (objectCreation.Parent.IsKind(SyntaxKind.ArrowExpressionClause)) diff --git a/src/Analyzers/CSharp/Analyzers/UseImplicitOrExplicitType/CSharpTypeStyleDiagnosticAnalyzerBase.cs b/src/Analyzers/CSharp/Analyzers/UseImplicitOrExplicitType/CSharpTypeStyleDiagnosticAnalyzerBase.cs index 26a0f557e3371..fb2439791a12f 100644 --- a/src/Analyzers/CSharp/Analyzers/UseImplicitOrExplicitType/CSharpTypeStyleDiagnosticAnalyzerBase.cs +++ b/src/Analyzers/CSharp/Analyzers/UseImplicitOrExplicitType/CSharpTypeStyleDiagnosticAnalyzerBase.cs @@ -6,6 +6,7 @@ using Microsoft.CodeAnalysis.CodeStyle; using Microsoft.CodeAnalysis.CSharp.CodeStyle; using Microsoft.CodeAnalysis.CSharp.Extensions; +using Microsoft.CodeAnalysis.CSharp.Simplification; using Microsoft.CodeAnalysis.CSharp.Utilities; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Options; @@ -52,10 +53,8 @@ protected override void InitializeWorker(AnalysisContext context) private void HandleVariableDeclaration(SyntaxNodeAnalysisContext context) { var declarationStatement = context.Node; - var options = context.Options; var syntaxTree = context.Node.SyntaxTree; var cancellationToken = context.CancellationToken; - var optionSet = options.GetAnalyzerOptionSet(syntaxTree, cancellationToken); var semanticModel = context.SemanticModel; var declaredType = Helper.FindAnalyzableType(declarationStatement, semanticModel, cancellationToken); @@ -64,8 +63,10 @@ private void HandleVariableDeclaration(SyntaxNodeAnalysisContext context) return; } + var simplifierOptions = context.Options.GetCSharpSimplifierOptions(syntaxTree); + var typeStyle = Helper.AnalyzeTypeName( - declaredType, semanticModel, optionSet, cancellationToken); + declaredType, semanticModel, simplifierOptions, cancellationToken); if (!typeStyle.IsStylePreferred || !typeStyle.CanConvert()) { return; diff --git a/src/Analyzers/CSharp/CodeFixes/MisplacedUsingDirectives/MisplacedUsingDirectivesCodeFixProvider.cs b/src/Analyzers/CSharp/CodeFixes/MisplacedUsingDirectives/MisplacedUsingDirectivesCodeFixProvider.cs index 540a1a2521913..eade815ae34f3 100644 --- a/src/Analyzers/CSharp/CodeFixes/MisplacedUsingDirectives/MisplacedUsingDirectivesCodeFixProvider.cs +++ b/src/Analyzers/CSharp/CodeFixes/MisplacedUsingDirectives/MisplacedUsingDirectivesCodeFixProvider.cs @@ -16,6 +16,7 @@ using Microsoft.CodeAnalysis.CodeStyle; using Microsoft.CodeAnalysis.CSharp.CodeStyle; using Microsoft.CodeAnalysis.CSharp.Extensions; +using Microsoft.CodeAnalysis.CSharp.Simplification; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Formatting; @@ -65,14 +66,17 @@ public override async Task RegisterCodeFixesAsync(CodeFixContext context) #if CODE_STYLE var options = document.Project.AnalyzerOptions.GetAnalyzerOptionSet(syntaxRoot.SyntaxTree, cancellationToken); + var simplifierOptions = CSharpSimplifierOptions.Create(options, fallbackOptions: null); #else var options = await document.GetOptionsAsync(cancellationToken).ConfigureAwait(false); + var simplifierOptions = await SimplifierOptions.FromDocumentAsync(document, fallbackOptions: context.Options(document.Project.LanguageServices).SimplifierOptions, cancellationToken).ConfigureAwait(false); #endif + var codeStyleOption = options.GetOption(CSharpCodeStyleOptions.PreferredUsingDirectivePlacement); // Read the preferred placement option and verify if it can be applied to this code file. // There are cases where we will not be able to fix the diagnostic and the user will need to resolve // it manually. - var (placement, preferPreservation) = DeterminePlacement(compilationUnit, options); + var (placement, preferPreservation) = DeterminePlacement(compilationUnit, codeStyleOption); if (preferPreservation) return; @@ -81,24 +85,22 @@ public override async Task RegisterCodeFixesAsync(CodeFixContext context) context.RegisterCodeFix( CodeAction.Create( CSharpAnalyzersResources.Move_misplaced_using_directives, - token => GetTransformedDocumentAsync(document, compilationUnit, GetAllUsingDirectives(compilationUnit), placement, token), + token => GetTransformedDocumentAsync(document, compilationUnit, GetAllUsingDirectives(compilationUnit), placement, simplifierOptions, token), nameof(CSharpAnalyzersResources.Move_misplaced_using_directives)), diagnostic); } } - internal static async Task TransformDocumentIfRequiredAsync(Document document, CancellationToken cancellationToken) + internal static async Task TransformDocumentIfRequiredAsync( + Document document, + SimplifierOptions simplifierOptions, + CodeStyleOption2 importPlacementStyleOption, + CancellationToken cancellationToken) { var syntaxRoot = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); var compilationUnit = (CompilationUnitSyntax)syntaxRoot; -#if CODE_STYLE - var options = document.Project.AnalyzerOptions.GetAnalyzerOptionSet(syntaxRoot.SyntaxTree, cancellationToken); -#else - var options = await document.GetOptionsAsync(cancellationToken).ConfigureAwait(false); -#endif - - var (placement, preferPreservation) = DeterminePlacement(compilationUnit, options); + var (placement, preferPreservation) = DeterminePlacement(compilationUnit, importPlacementStyleOption); if (preferPreservation) { return document; @@ -112,7 +114,7 @@ internal static async Task TransformDocumentIfRequiredAsync(Document d return document; } - return await GetTransformedDocumentAsync(document, compilationUnit, allUsingDirectives, placement, cancellationToken).ConfigureAwait(false); + return await GetTransformedDocumentAsync(document, compilationUnit, allUsingDirectives, placement, simplifierOptions, cancellationToken).ConfigureAwait(false); } private static ImmutableList GetAllUsingDirectives(CompilationUnitSyntax compilationUnit) @@ -127,6 +129,7 @@ private static async Task GetTransformedDocumentAsync( CompilationUnitSyntax compilationUnit, IEnumerable allUsingDirectives, AddImportPlacement placement, + SimplifierOptions simplifierOptions, CancellationToken cancellationToken) { var bannerService = document.GetRequiredLanguageService(); @@ -149,8 +152,13 @@ private static async Task GetTransformedDocumentAsync( var newDocument = document.WithSyntaxRoot(newCompilationUnitWithHeader); // Simplify usings now that they have been moved and are in the proper context. - var options = await document.GetOptionsAsync(cancellationToken).ConfigureAwait(false); - return await Simplifier.ReduceAsync(newDocument, Simplifier.Annotation, options, cancellationToken).ConfigureAwait(false); +#if CODE_STYLE +#pragma warning disable RS0030 // Do not used banned APIs + return await Simplifier.ReduceAsync(newDocument, Simplifier.Annotation, optionSet: null, cancellationToken).ConfigureAwait(false); +#pragma warning restore +#else + return await Simplifier.ReduceAsync(newDocument, Simplifier.Annotation, simplifierOptions, cancellationToken).ConfigureAwait(false); +#endif } private static async Task ExpandUsingDirectivesAsync(Document document, CompilationUnitSyntax containerNode, IEnumerable allUsingDirectives, CancellationToken cancellationToken) @@ -360,12 +368,10 @@ private static TSyntaxNode EnsureLeadingBlankLineBeforeFirstMember( return node.ReplaceNode(firstMember, newFirstMember); } - private static (AddImportPlacement placement, bool preferPreservation) DeterminePlacement(CompilationUnitSyntax compilationUnit, OptionSet options) + private static (AddImportPlacement placement, bool preferPreservation) DeterminePlacement(CompilationUnitSyntax compilationUnit, CodeStyleOption2 styleOption) { - var codeStyleOption = options.GetOption(CSharpCodeStyleOptions.PreferredUsingDirectivePlacement); - - var placement = codeStyleOption.Value; - var preferPreservation = codeStyleOption.Notification == NotificationOption2.None; + var placement = styleOption.Value; + var preferPreservation = styleOption.Notification == NotificationOption2.None; if (preferPreservation || placement == AddImportPlacement.OutsideNamespace) return (placement, preferPreservation); diff --git a/src/Analyzers/Core/Analyzers/Helpers/AnalyzerOptionsExtensions.cs b/src/Analyzers/Core/Analyzers/Helpers/AnalyzerOptionsExtensions.cs index 7e76442dbfdfc..c81c069ede0ee 100644 --- a/src/Analyzers/Core/Analyzers/Helpers/AnalyzerOptionsExtensions.cs +++ b/src/Analyzers/Core/Analyzers/Helpers/AnalyzerOptionsExtensions.cs @@ -4,12 +4,8 @@ using System.Runtime.Serialization; using System.Diagnostics.CodeAnalysis; -using System.IO; -using System.Reflection; -using System.Threading; -using System.Threading.Tasks; using Microsoft.CodeAnalysis.Options; -using Roslyn.Utilities; +using Microsoft.CodeAnalysis.Simplification; #if CODE_STYLE using TOption = Microsoft.CodeAnalysis.Options.IOption2; @@ -27,7 +23,8 @@ internal readonly record struct IdeAnalyzerOptions( [property: DataMember(Order = 3)] bool ReportInvalidPlaceholdersInStringDotFormatCalls = true, [property: DataMember(Order = 4)] bool ReportInvalidRegexPatterns = true, [property: DataMember(Order = 5)] bool ReportInvalidJsonPatterns = true, - [property: DataMember(Order = 6)] bool DetectAndOfferEditorFeaturesForProbableJsonStrings = true) + [property: DataMember(Order = 6)] bool DetectAndOfferEditorFeaturesForProbableJsonStrings = true, + [property: DataMember(Order = 7)] SimplifierOptions? SimplifierOptions = null) { public IdeAnalyzerOptions() : this(CrashOnAnalyzerException: false) diff --git a/src/Analyzers/Core/Analyzers/QualifyMemberAccess/AbstractQualifyMemberAccessDiagnosticAnalyzer.cs b/src/Analyzers/Core/Analyzers/QualifyMemberAccess/AbstractQualifyMemberAccessDiagnosticAnalyzer.cs index 5274b582473cd..307649bb6f946 100644 --- a/src/Analyzers/Core/Analyzers/QualifyMemberAccess/AbstractQualifyMemberAccessDiagnosticAnalyzer.cs +++ b/src/Analyzers/Core/Analyzers/QualifyMemberAccess/AbstractQualifyMemberAccessDiagnosticAnalyzer.cs @@ -7,6 +7,7 @@ using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Operations; using Microsoft.CodeAnalysis.Options; +using Microsoft.CodeAnalysis.Simplification; using Roslyn.Utilities; #if CODE_STYLE @@ -18,11 +19,13 @@ namespace Microsoft.CodeAnalysis.QualifyMemberAccess internal abstract class AbstractQualifyMemberAccessDiagnosticAnalyzer< TLanguageKindEnum, TExpressionSyntax, - TSimpleNameSyntax> + TSimpleNameSyntax, + TSimplifierOptions> : AbstractBuiltInCodeStyleDiagnosticAnalyzer where TLanguageKindEnum : struct where TExpressionSyntax : SyntaxNode where TSimpleNameSyntax : TExpressionSyntax + where TSimplifierOptions : SimplifierOptions { protected AbstractQualifyMemberAccessDiagnosticAnalyzer() : base(IDEDiagnosticIds.AddQualificationDiagnosticId, @@ -62,6 +65,7 @@ protected override void InitializeWorker(AnalysisContext context) => context.RegisterOperationAction(AnalyzeOperation, OperationKind.FieldReference, OperationKind.PropertyReference, OperationKind.MethodReference, OperationKind.Invocation); protected abstract Location GetLocation(IOperation operation); + protected abstract TSimplifierOptions GetSimplifierOptions(AnalyzerOptions options, SyntaxTree syntaxTree); public override DiagnosticAnalyzerCategory GetAnalyzerCategory() => DiagnosticAnalyzerCategory.SemanticSpanAnalysis; @@ -117,8 +121,15 @@ private void AnalyzeOperation(OperationAnalysisContext context, IOperation opera if (instanceOperation.Syntax is not TSimpleNameSyntax simpleName) return; - var applicableOption = QualifyMembersHelpers.GetApplicableOptionFromSymbolKind(operation); - var optionValue = context.GetOption(applicableOption, context.Operation.Syntax.Language); + var symbolKind = operation switch + { + IMemberReferenceOperation memberReferenceOperation => memberReferenceOperation.Member.Kind, + IInvocationOperation invocationOperation => invocationOperation.TargetMethod.Kind, + _ => throw ExceptionUtilities.UnexpectedValue(operation), + }; + + var simplifierOptions = GetSimplifierOptions(context.Options, context.Operation.Syntax.SyntaxTree); + var optionValue = simplifierOptions.QualifyMemberAccess(symbolKind); var shouldOptionBePresent = optionValue.Value; var severity = optionValue.Notification.Severity; @@ -153,25 +164,4 @@ static bool IsStaticMemberOrIsLocalFunctionHelper(ISymbol symbol) } } } - - internal static class QualifyMembersHelpers - { - public static PerLanguageOption2> GetApplicableOptionFromSymbolKind(SymbolKind symbolKind) - => symbolKind switch - { - SymbolKind.Field => CodeStyleOptions2.QualifyFieldAccess, - SymbolKind.Property => CodeStyleOptions2.QualifyPropertyAccess, - SymbolKind.Method => CodeStyleOptions2.QualifyMethodAccess, - SymbolKind.Event => CodeStyleOptions2.QualifyEventAccess, - _ => throw ExceptionUtilities.UnexpectedValue(symbolKind), - }; - - internal static PerLanguageOption2> GetApplicableOptionFromSymbolKind(IOperation operation) - => operation switch - { - IMemberReferenceOperation memberReferenceOperation => GetApplicableOptionFromSymbolKind(memberReferenceOperation.Member.Kind), - IInvocationOperation invocationOperation => GetApplicableOptionFromSymbolKind(invocationOperation.TargetMethod.Kind), - _ => throw ExceptionUtilities.UnexpectedValue(operation), - }; - } } diff --git a/src/Analyzers/Core/CodeFixes/MatchFolderAndNamespace/AbstractChangeNamespaceToMatchFolderCodeFixProvider.CustomFixAllProvider.cs b/src/Analyzers/Core/CodeFixes/MatchFolderAndNamespace/AbstractChangeNamespaceToMatchFolderCodeFixProvider.CustomFixAllProvider.cs index b7b8c464dcb15..f635a0ad40383 100644 --- a/src/Analyzers/Core/CodeFixes/MatchFolderAndNamespace/AbstractChangeNamespaceToMatchFolderCodeFixProvider.CustomFixAllProvider.cs +++ b/src/Analyzers/Core/CodeFixes/MatchFolderAndNamespace/AbstractChangeNamespaceToMatchFolderCodeFixProvider.CustomFixAllProvider.cs @@ -46,6 +46,11 @@ private class CustomFixAllProvider : FixAllProvider fixAllContext.Project.Solution, diagnostics, fixAllContext.GetProgressTracker(), +#if CODE_STYLE + options: _ => default, +#else + fixAllContext.State.CodeActionOptionsProvider, +#endif cancellationToken), title); @@ -67,6 +72,7 @@ private static async Task FixAllByDocumentAsync( Solution solution, ImmutableArray diagnostics, IProgressTracker progressTracker, + CodeActionOptionsProvider options, CancellationToken cancellationToken) { // Use documentId instead of tree here because the @@ -89,7 +95,7 @@ private static async Task FixAllByDocumentAsync( var document = newSolution.GetRequiredDocument(documentId); using var _ = progressTracker.ItemCompletedScope(document.Name); - newSolution = await FixAllInDocumentAsync(document, diagnosticsInTree, cancellationToken).ConfigureAwait(false); + newSolution = await FixAllInDocumentAsync(document, diagnosticsInTree, options, cancellationToken).ConfigureAwait(false); } return newSolution; diff --git a/src/Analyzers/Core/CodeFixes/MatchFolderAndNamespace/AbstractChangeNamespaceToMatchFolderCodeFixProvider.cs b/src/Analyzers/Core/CodeFixes/MatchFolderAndNamespace/AbstractChangeNamespaceToMatchFolderCodeFixProvider.cs index 408f4c464f7ef..1155e31fa0f53 100644 --- a/src/Analyzers/Core/CodeFixes/MatchFolderAndNamespace/AbstractChangeNamespaceToMatchFolderCodeFixProvider.cs +++ b/src/Analyzers/Core/CodeFixes/MatchFolderAndNamespace/AbstractChangeNamespaceToMatchFolderCodeFixProvider.cs @@ -8,12 +8,16 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; +using Microsoft.CodeAnalysis.AddImport; using Microsoft.CodeAnalysis.Analyzers.MatchFolderAndNamespace; +using Microsoft.CodeAnalysis.ChangeNamespace; using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.Rename; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.Utilities; +using Microsoft.CodeAnalysis.Simplification; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CodeFixes.MatchFolderAndNamespace @@ -29,7 +33,13 @@ public override Task RegisterCodeFixesAsync(CodeFixContext context) context.RegisterCodeFix( CodeAction.Create( AnalyzersResources.Change_namespace_to_match_folder_structure, - cancellationToken => FixAllInDocumentAsync(context.Document, context.Diagnostics, cancellationToken), + cancellationToken => FixAllInDocumentAsync(context.Document, context.Diagnostics, +#if CODE_STYLE + options: _ => default, +#else + context.Options, +#endif + cancellationToken), nameof(AnalyzersResources.Change_namespace_to_match_folder_structure)), context.Diagnostics); } @@ -37,7 +47,7 @@ public override Task RegisterCodeFixesAsync(CodeFixContext context) return Task.CompletedTask; } - private static async Task FixAllInDocumentAsync(Document document, ImmutableArray diagnostics, CancellationToken cancellationToken) + private static async Task FixAllInDocumentAsync(Document document, ImmutableArray diagnostics, CodeActionOptionsProvider options, CancellationToken cancellationToken) { // All the target namespaces should be the same for a given document Debug.Assert(diagnostics.Select(diagnostic => diagnostic.Properties[MatchFolderAndNamespaceConstants.TargetNamespace]).Distinct().Count() == 1); @@ -54,6 +64,9 @@ private static async Task FixAllInDocumentAsync(Document document, Imm var renameActionSet = await Renamer.RenameDocumentAsync( documentWithInvalidFolders, new DocumentRenameOptions(), +#if !CODE_STYLE + ChangeNamespaceOptions.CreateProvider(options), +#endif documentWithInvalidFolders.Name, newDocumentFolders: targetFolders, cancellationToken: cancellationToken).ConfigureAwait(false); diff --git a/src/Analyzers/VisualBasic/Analyzers/QualifyMemberAccess/VisualBasicQualifyMemberAccessDiagnosticAnalyzer.vb b/src/Analyzers/VisualBasic/Analyzers/QualifyMemberAccess/VisualBasicQualifyMemberAccessDiagnosticAnalyzer.vb index 2ee70fa172f2f..46aaf5e54f4c9 100644 --- a/src/Analyzers/VisualBasic/Analyzers/QualifyMemberAccess/VisualBasicQualifyMemberAccessDiagnosticAnalyzer.vb +++ b/src/Analyzers/VisualBasic/Analyzers/QualifyMemberAccess/VisualBasicQualifyMemberAccessDiagnosticAnalyzer.vb @@ -5,16 +5,21 @@ Imports Microsoft.CodeAnalysis.Diagnostics Imports Microsoft.CodeAnalysis.QualifyMemberAccess Imports Microsoft.CodeAnalysis.VisualBasic.Syntax +Imports Microsoft.CodeAnalysis.VisualBasic.Simplification Namespace Microsoft.CodeAnalysis.VisualBasic.QualifyMemberAccess Friend NotInheritable Class VisualBasicQualifyMemberAccessDiagnosticAnalyzer - Inherits AbstractQualifyMemberAccessDiagnosticAnalyzer(Of SyntaxKind, ExpressionSyntax, SimpleNameSyntax) + Inherits AbstractQualifyMemberAccessDiagnosticAnalyzer(Of SyntaxKind, ExpressionSyntax, SimpleNameSyntax, VisualBasicSimplifierOptions) Protected Overrides Function GetLanguageName() As String Return LanguageNames.VisualBasic End Function + Protected Overrides Function GetSimplifierOptions(options As AnalyzerOptions, syntaxTree As SyntaxTree) As VisualBasicSimplifierOptions + Return options.GetVisualBasicSimplifierOptions(syntaxTree) + End Function + Protected Overrides Function IsAlreadyQualifiedMemberAccess(node As ExpressionSyntax) As Boolean Return node.IsKind(SyntaxKind.MeExpression) End Function diff --git a/src/Analyzers/VisualBasic/Analyzers/Simplification/VisualBasicSimplifierOptionsFactory.vb b/src/Analyzers/VisualBasic/Analyzers/Simplification/VisualBasicSimplifierOptionsFactory.vb new file mode 100644 index 0000000000000..2b402e2a29155 --- /dev/null +++ b/src/Analyzers/VisualBasic/Analyzers/Simplification/VisualBasicSimplifierOptionsFactory.vb @@ -0,0 +1,19 @@ +' 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. + +Imports System.Runtime.CompilerServices +Imports Microsoft.CodeAnalysis.Diagnostics + +Namespace Microsoft.CodeAnalysis.VisualBasic.Simplification + Friend Module VisualBasicSimplifierOptionsFactory + + Public Function GetVisualBasicSimplifierOptions(options As AnalyzerOptions, syntaxTree As SyntaxTree) As VisualBasicSimplifierOptions + Dim configOptions = options.AnalyzerConfigOptionsProvider.GetOptions(syntaxTree) + Dim ideOptions = options.GetIdeOptions() + + Return VisualBasicSimplifierOptions.Create(configOptions, DirectCast(ideOptions.SimplifierOptions, VisualBasicSimplifierOptions)) + End Function + End Module +End Namespace + diff --git a/src/Analyzers/VisualBasic/Analyzers/VisualBasicAnalyzers.projitems b/src/Analyzers/VisualBasic/Analyzers/VisualBasicAnalyzers.projitems index 6665cce389e70..72e888f4bef43 100644 --- a/src/Analyzers/VisualBasic/Analyzers/VisualBasicAnalyzers.projitems +++ b/src/Analyzers/VisualBasic/Analyzers/VisualBasicAnalyzers.projitems @@ -36,6 +36,7 @@ + diff --git a/src/EditorFeatures/CSharp/EncapsulateField/EncapsulateFieldCommandHandler.cs b/src/EditorFeatures/CSharp/EncapsulateField/EncapsulateFieldCommandHandler.cs index 74af10b1f1e32..547aae4494c4c 100644 --- a/src/EditorFeatures/CSharp/EncapsulateField/EncapsulateFieldCommandHandler.cs +++ b/src/EditorFeatures/CSharp/EncapsulateField/EncapsulateFieldCommandHandler.cs @@ -7,6 +7,7 @@ using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.EncapsulateField; using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Shared.TestHooks; using Microsoft.VisualStudio.Commanding; using Microsoft.VisualStudio.Text.Operations; @@ -25,8 +26,9 @@ internal class EncapsulateFieldCommandHandler : AbstractEncapsulateFieldCommandH public EncapsulateFieldCommandHandler( IThreadingContext threadingContext, ITextBufferUndoManagerProvider undoManager, + IGlobalOptionService globalOptions, IAsynchronousOperationListenerProvider listenerProvider) - : base(threadingContext, undoManager, listenerProvider) + : base(threadingContext, undoManager, globalOptions, listenerProvider) { } } diff --git a/src/EditorFeatures/CSharp/EventHookup/EventHookupCommandHandler_TabKeyCommand.cs b/src/EditorFeatures/CSharp/EventHookup/EventHookupCommandHandler_TabKeyCommand.cs index 89b9c9a95ef9e..6c66369c81fb8 100644 --- a/src/EditorFeatures/CSharp/EventHookup/EventHookupCommandHandler_TabKeyCommand.cs +++ b/src/EditorFeatures/CSharp/EventHookup/EventHookupCommandHandler_TabKeyCommand.cs @@ -168,8 +168,9 @@ private Solution CreateSolutionWithEventHandler( } var formattingOptions = SyntaxFormattingOptions.FromDocumentAsync(document, cancellationToken).WaitAndGetResult(cancellationToken); + var simplifierOptions = document.GetSimplifierOptionsAsync(_globalOptions, cancellationToken).WaitAndGetResult(cancellationToken); - var simplifiedDocument = Simplifier.ReduceAsync(documentWithNameAndAnnotationsAdded.WithSyntaxRoot(updatedRoot), Simplifier.Annotation, cancellationToken: cancellationToken).WaitAndGetResult(cancellationToken); + var simplifiedDocument = Simplifier.ReduceAsync(documentWithNameAndAnnotationsAdded.WithSyntaxRoot(updatedRoot), Simplifier.Annotation, simplifierOptions, cancellationToken).WaitAndGetResult(cancellationToken); var formattedDocument = Formatter.FormatAsync(simplifiedDocument, Formatter.Annotation, formattingOptions, cancellationToken).WaitAndGetResult(cancellationToken); var newRoot = formattedDocument.GetSyntaxRootSynchronously(cancellationToken); diff --git a/src/EditorFeatures/CSharp/Simplification/CSharpSimplifierOptionsStorage.cs b/src/EditorFeatures/CSharp/Simplification/CSharpSimplifierOptionsStorage.cs new file mode 100644 index 0000000000000..1029a436c209b --- /dev/null +++ b/src/EditorFeatures/CSharp/Simplification/CSharpSimplifierOptionsStorage.cs @@ -0,0 +1,43 @@ +// 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; +using System.Composition; +using Microsoft.CodeAnalysis.CodeStyle; +using Microsoft.CodeAnalysis.CSharp.CodeStyle; +using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.CodeAnalysis.Options; +using Microsoft.CodeAnalysis.Simplification; + +namespace Microsoft.CodeAnalysis.CSharp.Simplification; + +internal static class CSharpSimplifierOptionsStorage +{ + [ExportLanguageService(typeof(ISimplifierOptionsStorage), LanguageNames.CSharp), Shared] + private sealed class Service : ISimplifierOptionsStorage + { + [ImportingConstructor] + [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] + public Service() + { + } + + public SimplifierOptions GetOptions(IGlobalOptionService globalOptions) + => GetCSharpSimplifierOptions(globalOptions); + } + + public static CSharpSimplifierOptions GetCSharpSimplifierOptions(this IGlobalOptionService globalOptions) + => new( + qualifyFieldAccess: globalOptions.GetOption(CodeStyleOptions2.QualifyFieldAccess, LanguageNames.CSharp), + qualifyPropertyAccess: globalOptions.GetOption(CodeStyleOptions2.QualifyPropertyAccess, LanguageNames.CSharp), + qualifyMethodAccess: globalOptions.GetOption(CodeStyleOptions2.QualifyMethodAccess, LanguageNames.CSharp), + qualifyEventAccess: globalOptions.GetOption(CodeStyleOptions2.QualifyEventAccess, LanguageNames.CSharp), + preferPredefinedTypeKeywordInMemberAccess: globalOptions.GetOption(CodeStyleOptions2.PreferIntrinsicPredefinedTypeKeywordInMemberAccess, LanguageNames.CSharp), + preferPredefinedTypeKeywordInDeclaration: globalOptions.GetOption(CodeStyleOptions2.PreferIntrinsicPredefinedTypeKeywordInDeclaration, LanguageNames.CSharp), + varForBuiltInTypes: globalOptions.GetOption(CSharpCodeStyleOptions.VarForBuiltInTypes), + varWhenTypeIsApparent: globalOptions.GetOption(CSharpCodeStyleOptions.VarWhenTypeIsApparent), + varElsewhere: globalOptions.GetOption(CSharpCodeStyleOptions.VarElsewhere), + preferSimpleDefaultExpression: globalOptions.GetOption(CSharpCodeStyleOptions.PreferSimpleDefaultExpression), + preferBraces: globalOptions.GetOption(CSharpCodeStyleOptions.PreferBraces)); +} diff --git a/src/EditorFeatures/CSharpTest/MoveToNamespace/MoveToNamespaceTests.cs b/src/EditorFeatures/CSharpTest/MoveToNamespace/MoveToNamespaceTests.cs index 01c56d4628746..b06ed35872de8 100644 --- a/src/EditorFeatures/CSharpTest/MoveToNamespace/MoveToNamespaceTests.cs +++ b/src/EditorFeatures/CSharpTest/MoveToNamespace/MoveToNamespaceTests.cs @@ -8,6 +8,7 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; +using Microsoft.CodeAnalysis.ChangeNamespace; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Editor.UnitTests.Diagnostics; using Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces; @@ -1174,6 +1175,7 @@ void Method() { } var actions = await testState.MoveToNamespaceService.GetCodeActionsAsync( testState.InvocationDocument, testState.TestInvocationDocument.SelectedSpans.Single(), + language => ChangeNamespaceOptions.GetDefault(testState.InvocationDocument.Project.LanguageServices), CancellationToken.None); Assert.Empty(actions); diff --git a/src/EditorFeatures/Core.Cocoa/Snippets/AbstractSnippetExpansionClient.cs b/src/EditorFeatures/Core.Cocoa/Snippets/AbstractSnippetExpansionClient.cs index 705445b4258ec..512420104affc 100644 --- a/src/EditorFeatures/Core.Cocoa/Snippets/AbstractSnippetExpansionClient.cs +++ b/src/EditorFeatures/Core.Cocoa/Snippets/AbstractSnippetExpansionClient.cs @@ -12,6 +12,7 @@ using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.Internal.Log; +using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; using Microsoft.CodeAnalysis.Text.Shared.Extensions; @@ -30,18 +31,21 @@ internal abstract class AbstractSnippetExpansionClient : IExpansionClient protected readonly ITextView TextView; protected readonly ITextBuffer SubjectBuffer; + public readonly IGlobalOptionService GlobalOptions; + protected bool _indentCaretOnCommit; protected int _indentDepth; protected bool _earlyEndExpansionHappened; public IExpansionSession? ExpansionSession { get; private set; } - public AbstractSnippetExpansionClient(IContentType languageServiceGuid, ITextView textView, ITextBuffer subjectBuffer, IExpansionServiceProvider expansionServiceProvider) + public AbstractSnippetExpansionClient(IContentType languageServiceGuid, ITextView textView, ITextBuffer subjectBuffer, IExpansionServiceProvider expansionServiceProvider, IGlobalOptionService globalOptions) { - this.LanguageServiceGuid = languageServiceGuid; - this.TextView = textView; - this.SubjectBuffer = subjectBuffer; - this.ExpansionServiceProvider = expansionServiceProvider; + LanguageServiceGuid = languageServiceGuid; + TextView = textView; + SubjectBuffer = subjectBuffer; + ExpansionServiceProvider = expansionServiceProvider; + GlobalOptions = globalOptions; } public abstract IExpansionFunction? GetExpansionFunction(XElement xmlFunctionNode, string fieldName); diff --git a/src/EditorFeatures/Core.Cocoa/Snippets/CSharpSnippets/SnippetCommandHandler.cs b/src/EditorFeatures/Core.Cocoa/Snippets/CSharpSnippets/SnippetCommandHandler.cs index 5cc96ccbcfb70..eee35719dac32 100644 --- a/src/EditorFeatures/Core.Cocoa/Snippets/CSharpSnippets/SnippetCommandHandler.cs +++ b/src/EditorFeatures/Core.Cocoa/Snippets/CSharpSnippets/SnippetCommandHandler.cs @@ -84,7 +84,7 @@ protected override AbstractSnippetExpansionClient GetSnippetExpansionClient(ITex { if (!textView.Properties.TryGetProperty(typeof(AbstractSnippetExpansionClient), out AbstractSnippetExpansionClient expansionClient)) { - expansionClient = new SnippetExpansionClient(subjectBuffer.ContentType, textView, subjectBuffer, ExpansionServiceProvider); + expansionClient = new SnippetExpansionClient(subjectBuffer.ContentType, textView, subjectBuffer, ExpansionServiceProvider, GlobalOptions); textView.Properties.AddProperty(typeof(AbstractSnippetExpansionClient), expansionClient); } diff --git a/src/EditorFeatures/Core.Cocoa/Snippets/CSharpSnippets/SnippetExpansionClient.cs b/src/EditorFeatures/Core.Cocoa/Snippets/CSharpSnippets/SnippetExpansionClient.cs index 5254107f15e7c..6243391dd4f7c 100644 --- a/src/EditorFeatures/Core.Cocoa/Snippets/CSharpSnippets/SnippetExpansionClient.cs +++ b/src/EditorFeatures/Core.Cocoa/Snippets/CSharpSnippets/SnippetExpansionClient.cs @@ -5,6 +5,7 @@ using System; using System.Xml.Linq; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; +using Microsoft.CodeAnalysis.Options; using Microsoft.VisualStudio.LanguageServices.CSharp.Snippets.SnippetFunctions; using Microsoft.VisualStudio.LanguageServices.Implementation.Snippets; using Microsoft.VisualStudio.Text; @@ -17,8 +18,8 @@ namespace Microsoft.VisualStudio.LanguageServices.CSharp.Snippets { internal sealed partial class SnippetExpansionClient : AbstractSnippetExpansionClient { - public SnippetExpansionClient(IContentType languageServiceGuid, ITextView textView, ITextBuffer subjectBuffer, IExpansionServiceProvider expansionServiceProvider) - : base(languageServiceGuid, textView, subjectBuffer, expansionServiceProvider) + public SnippetExpansionClient(IContentType languageServiceGuid, ITextView textView, ITextBuffer subjectBuffer, IExpansionServiceProvider expansionServiceProvider, IGlobalOptionService globalOptions) + : base(languageServiceGuid, textView, subjectBuffer, expansionServiceProvider, globalOptions) { } diff --git a/src/EditorFeatures/Core.Cocoa/Snippets/CSharpSnippets/SnippetFunctions/SnippetFunctionGenerateSwitchCases.cs b/src/EditorFeatures/Core.Cocoa/Snippets/CSharpSnippets/SnippetFunctions/SnippetFunctionGenerateSwitchCases.cs index c1344fe4e68af..d085206abfcd8 100644 --- a/src/EditorFeatures/Core.Cocoa/Snippets/CSharpSnippets/SnippetFunctions/SnippetFunctionGenerateSwitchCases.cs +++ b/src/EditorFeatures/Core.Cocoa/Snippets/CSharpSnippets/SnippetFunctions/SnippetFunctionGenerateSwitchCases.cs @@ -96,7 +96,8 @@ protected override bool TryGetSimplifiedTypeNameInCaseContext(Document document, var updatedRoot = syntaxRoot.ReplaceNode(nodeToReplace, nodeToReplace.WithAdditionalAnnotations(typeAnnotation, Simplifier.Annotation)); var documentWithAnnotations = documentWithCaseAdded.WithSyntaxRoot(updatedRoot); - var simplifiedDocument = Simplifier.ReduceAsync(documentWithAnnotations, cancellationToken: cancellationToken).Result; + var simplifierOptions = document.GetSimplifierOptionsAsync(_snippetExpansionClient.GlobalOptions, cancellationToken).WaitAndGetResult(cancellationToken); + var simplifiedDocument = Simplifier.ReduceAsync(documentWithAnnotations, simplifierOptions, cancellationToken).WaitAndGetResult(cancellationToken); simplifiedTypeName = simplifiedDocument.GetRequiredSyntaxRootSynchronously(cancellationToken).GetAnnotatedNodesAndTokens(typeAnnotation).Single().ToString(); return true; } diff --git a/src/EditorFeatures/Core.Cocoa/Snippets/CSharpSnippets/SnippetFunctions/SnippetFunctionSimpleTypeName.cs b/src/EditorFeatures/Core.Cocoa/Snippets/CSharpSnippets/SnippetFunctions/SnippetFunctionSimpleTypeName.cs index bfa6bf753cd0e..460cbf48be81b 100644 --- a/src/EditorFeatures/Core.Cocoa/Snippets/CSharpSnippets/SnippetFunctions/SnippetFunctionSimpleTypeName.cs +++ b/src/EditorFeatures/Core.Cocoa/Snippets/CSharpSnippets/SnippetFunctions/SnippetFunctionSimpleTypeName.cs @@ -37,7 +37,8 @@ protected override bool TryGetSimplifiedTypeName(Document documentWithFullyQuali var updatedRoot = syntaxRoot.ReplaceNode(nodeToReplace, nodeToReplace.WithAdditionalAnnotations(typeAnnotation, Simplifier.Annotation)); var documentWithAnnotations = documentWithFullyQualifiedTypeName.WithSyntaxRoot(updatedRoot); - var simplifiedDocument = Simplifier.ReduceAsync(documentWithAnnotations, cancellationToken: cancellationToken).WaitAndGetResult(cancellationToken); + var simplifierOptions = documentWithAnnotations.GetSimplifierOptionsAsync(_snippetExpansionClient.GlobalOptions, cancellationToken).WaitAndGetResult(cancellationToken); + var simplifiedDocument = Simplifier.ReduceAsync(documentWithAnnotations, simplifierOptions, cancellationToken).WaitAndGetResult(cancellationToken); simplifiedTypeName = simplifiedDocument.GetRequiredSyntaxRootSynchronously(cancellationToken).GetAnnotatedNodesAndTokens(typeAnnotation).Single().ToString(); return true; } diff --git a/src/EditorFeatures/Core.Wpf/Peek/DefinitionPeekableItem.cs b/src/EditorFeatures/Core.Wpf/Peek/DefinitionPeekableItem.cs index 4b398e7df05c7..f3d7a685ac961 100644 --- a/src/EditorFeatures/Core.Wpf/Peek/DefinitionPeekableItem.cs +++ b/src/EditorFeatures/Core.Wpf/Peek/DefinitionPeekableItem.cs @@ -77,7 +77,7 @@ public void FindResults(string relationshipName, IPeekResultCollection resultCol if (!sourceLocations.Any()) { // It's a symbol from metadata, so we want to go produce it from metadata - var options = _peekableItem._globalOptions.GetMetadataAsSourceOptions(); + var options = _peekableItem._globalOptions.GetMetadataAsSourceOptions(project.LanguageServices); var declarationFile = _peekableItem._metadataAsSourceFileService.GetGeneratedFileAsync(project, symbol, signaturesOnly: true, options, cancellationToken).WaitAndGetResult_CanCallOnBackground(cancellationToken); var peekDisplayInfo = new PeekResultDisplayInfo(declarationFile.DocumentTitle, declarationFile.DocumentTitle, declarationFile.DocumentTitle, declarationFile.DocumentTitle); var identifierSpan = declarationFile.IdentifierLocation.GetLineSpan().Span; diff --git a/src/EditorFeatures/Core/AddImports/AbstractAddImportsPasteCommandHandler.cs b/src/EditorFeatures/Core/AddImports/AbstractAddImportsPasteCommandHandler.cs index 115762c6da533..0ac259ae9afb6 100644 --- a/src/EditorFeatures/Core/AddImports/AbstractAddImportsPasteCommandHandler.cs +++ b/src/EditorFeatures/Core/AddImports/AbstractAddImportsPasteCommandHandler.cs @@ -4,6 +4,7 @@ using System; using Microsoft.CodeAnalysis.AddMissingImports; +using Microsoft.CodeAnalysis.CodeCleanup; using Microsoft.CodeAnalysis.Completion; using Microsoft.CodeAnalysis.Editor.Shared.Extensions; using Microsoft.CodeAnalysis.Editor.Shared.Options; @@ -125,11 +126,11 @@ private void ExecuteCommandWorker( #pragma warning disable VSTHRD102 // Implement internal logic asynchronously var updatedDocument = _threadingContext.JoinableTaskFactory.Run(async () => { - var placement = await AddImportPlacementOptions.FromDocumentAsync(document, cancellationToken).ConfigureAwait(false); + var cleanupOptions = await CodeCleanupOptions.FromDocumentAsync(document, fallbackOptions: null, cancellationToken).ConfigureAwait(false); var options = new AddMissingImportsOptions( - HideAdvancedMembers: _globalOptions.GetOption(CompletionOptionsStorage.HideAdvancedMembers, document.Project.Language), - placement); + CleanupOptions: cleanupOptions, + HideAdvancedMembers: _globalOptions.GetOption(CompletionOptionsStorage.HideAdvancedMembers, document.Project.Language)); return await addMissingImportsService.AddMissingImportsAsync(document, textSpan, options, cancellationToken).ConfigureAwait(false); }); diff --git a/src/EditorFeatures/Core/CodeActions/CodeActionOptionsStorage.cs b/src/EditorFeatures/Core/CodeActions/CodeActionOptionsStorage.cs index 3c453445d267d..7060d90303be5 100644 --- a/src/EditorFeatures/Core/CodeActions/CodeActionOptionsStorage.cs +++ b/src/EditorFeatures/Core/CodeActions/CodeActionOptionsStorage.cs @@ -4,39 +4,43 @@ using System.Collections.Immutable; using Microsoft.CodeAnalysis.Completion; +using Microsoft.CodeAnalysis.ExtractMethod; +using Microsoft.CodeAnalysis.Formatting; +using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.ImplementType; using Microsoft.CodeAnalysis.Options; +using Microsoft.CodeAnalysis.Simplification; using Microsoft.CodeAnalysis.SymbolSearch; -using Microsoft.CodeAnalysis.ExtractMethod; namespace Microsoft.CodeAnalysis.CodeActions { internal static class CodeActionOptionsStorage { - internal static CodeActionOptions GetCodeActionOptions(this IGlobalOptionService globalOptions, string language) - => GetCodeActionOptions(globalOptions, language, isBlocking: false); + internal static CodeActionOptions GetCodeActionOptions(this IGlobalOptionService globalOptions, HostLanguageServices languageServices) + => GetCodeActionOptions(globalOptions, languageServices, isBlocking: false); - internal static CodeActionOptions GetBlockingCodeActionOptions(this IGlobalOptionService globalOptions, string language) - => GetCodeActionOptions(globalOptions, language, isBlocking: true); + internal static CodeActionOptions GetBlockingCodeActionOptions(this IGlobalOptionService globalOptions, HostLanguageServices languageServices) + => GetCodeActionOptions(globalOptions, languageServices, isBlocking: true); - private static CodeActionOptions GetCodeActionOptions(this IGlobalOptionService globalOptions, string language, bool isBlocking) + private static CodeActionOptions GetCodeActionOptions(this IGlobalOptionService globalOptions, HostLanguageServices languageServices, bool isBlocking) => new( - SearchOptions: globalOptions.GetSymbolSearchOptions(language), - ImplementTypeOptions: globalOptions.GetImplementTypeOptions(language), - ExtractMethodOptions: globalOptions.GetExtractMethodOptions(language), - HideAdvancedMembers: globalOptions.GetOption(CompletionOptionsStorage.HideAdvancedMembers, language), + SearchOptions: globalOptions.GetSymbolSearchOptions(languageServices.Language), + ImplementTypeOptions: globalOptions.GetImplementTypeOptions(languageServices.Language), + ExtractMethodOptions: globalOptions.GetExtractMethodOptions(languageServices.Language), + SimplifierOptions: globalOptions.GetSimplifierOptions(languageServices), + HideAdvancedMembers: globalOptions.GetOption(CompletionOptionsStorage.HideAdvancedMembers, languageServices.Language), IsBlocking: isBlocking); internal static CodeActionOptionsProvider GetCodeActionOptionsProvider(this IGlobalOptionService globalOptions) { var cache = ImmutableDictionary.Empty; - return language => ImmutableInterlocked.GetOrAdd(ref cache, language, (language, options) => GetCodeActionOptions(options, language), globalOptions); + return languageService => ImmutableInterlocked.GetOrAdd(ref cache, languageService.Language, (_, options) => GetCodeActionOptions(options, languageService), globalOptions); } internal static CodeActionOptionsProvider GetBlockingCodeActionOptionsProvider(this IGlobalOptionService globalOptions) { var cache = ImmutableDictionary.Empty; - return language => ImmutableInterlocked.GetOrAdd(ref cache, language, (language, options) => GetBlockingCodeActionOptions(options, language), globalOptions); + return languageService => ImmutableInterlocked.GetOrAdd(ref cache, languageService.Language, (language, options) => GetBlockingCodeActionOptions(options, languageService), globalOptions); } } } diff --git a/src/EditorFeatures/Core/CodeDefinitionWindow/DefinitionContextTracker.cs b/src/EditorFeatures/Core/CodeDefinitionWindow/DefinitionContextTracker.cs index 02e8b5918d848..d5861917efa69 100644 --- a/src/EditorFeatures/Core/CodeDefinitionWindow/DefinitionContextTracker.cs +++ b/src/EditorFeatures/Core/CodeDefinitionWindow/DefinitionContextTracker.cs @@ -210,7 +210,7 @@ internal async Task> GetContextFrom } else if (_metadataAsSourceFileService.IsNavigableMetadataSymbol(symbol)) { - var options = _globalOptions.GetMetadataAsSourceOptions(); + var options = _globalOptions.GetMetadataAsSourceOptions(document.Project.LanguageServices); var declarationFile = await _metadataAsSourceFileService.GetGeneratedFileAsync(document.Project, symbol, signaturesOnly: false, options, cancellationToken).ConfigureAwait(false); var identifierSpan = declarationFile.IdentifierLocation.GetLineSpan().Span; return ImmutableArray.Create(new CodeDefinitionWindowLocation(symbol.ToDisplayString(), declarationFile.FilePath, identifierSpan.Start)); diff --git a/src/EditorFeatures/Core/EncapsulateField/AbstractEncapsulateFieldCommandHandler.cs b/src/EditorFeatures/Core/EncapsulateField/AbstractEncapsulateFieldCommandHandler.cs index 68847172ebd8b..12a9eba7e599f 100644 --- a/src/EditorFeatures/Core/EncapsulateField/AbstractEncapsulateFieldCommandHandler.cs +++ b/src/EditorFeatures/Core/EncapsulateField/AbstractEncapsulateFieldCommandHandler.cs @@ -9,8 +9,10 @@ using Microsoft.CodeAnalysis.Editor.Shared.Extensions; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.Notification; +using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.TestHooks; +using Microsoft.CodeAnalysis.Simplification; using Microsoft.VisualStudio.Commanding; using Microsoft.VisualStudio.Text.Editor.Commanding.Commands; using Microsoft.VisualStudio.Text.Operations; @@ -23,6 +25,7 @@ internal abstract class AbstractEncapsulateFieldCommandHandler : ICommandHandler { private readonly IThreadingContext _threadingContext; private readonly ITextBufferUndoManagerProvider _undoManager; + private readonly IGlobalOptionService _globalOptions; private readonly IAsynchronousOperationListener _listener; public string DisplayName => EditorFeaturesResources.Encapsulate_Field; @@ -30,10 +33,12 @@ internal abstract class AbstractEncapsulateFieldCommandHandler : ICommandHandler public AbstractEncapsulateFieldCommandHandler( IThreadingContext threadingContext, ITextBufferUndoManagerProvider undoManager, + IGlobalOptionService globalOptions, IAsynchronousOperationListenerProvider listenerProvider) { _threadingContext = threadingContext; _undoManager = undoManager; + _globalOptions = globalOptions; _listener = listenerProvider.GetListener(FeatureAttribute.EncapsulateField); } @@ -65,7 +70,13 @@ private bool Execute(EncapsulateFieldCommandArgs args, IUIThreadOperationScope w var service = document.GetLanguageService(); - var result = service.EncapsulateFieldsInSpanAsync(document, spans.First().Span.ToTextSpan(), true, cancellationToken).WaitAndGetResult(cancellationToken); + // The formatting and simplification options are only applied within the given document (and all linked documents). + // We can therefore fetch all necessary options for the language now rather then lazily, + // which would be needed if we had to apply them to documents of different languages. + var fallbackOptions = new EncapsulateFieldOptions( + SimplifierOptions: _globalOptions.GetSimplifierOptions(document.Project.LanguageServices)); + + var result = service.EncapsulateFieldsInSpanAsync(document, spans.First().Span.ToTextSpan(), fallbackOptions, useDefaultBehavior: true, cancellationToken).WaitAndGetResult(cancellationToken); // We are about to show a modal UI dialog so we should take over the command execution // wait context. That means the command system won't attempt to show its own wait dialog diff --git a/src/EditorFeatures/Core/LanguageServer/Handlers/References/FindUsagesLSPContext.cs b/src/EditorFeatures/Core/LanguageServer/Handlers/References/FindUsagesLSPContext.cs index 64787cfc4819c..90912055ea1b1 100644 --- a/src/EditorFeatures/Core/LanguageServer/Handlers/References/FindUsagesLSPContext.cs +++ b/src/EditorFeatures/Core/LanguageServer/Handlers/References/FindUsagesLSPContext.cs @@ -244,7 +244,7 @@ public override async ValueTask OnReferenceFoundAsync(SourceReferenceItem refere return null; } - var options = _globalOptions.GetMetadataAsSourceOptions(); + var options = _globalOptions.GetMetadataAsSourceOptions(_document.Project.LanguageServices); var declarationFile = await _metadataAsSourceFileService.GetGeneratedFileAsync( _document.Project, symbol, signaturesOnly: true, options, cancellationToken).ConfigureAwait(false); diff --git a/src/EditorFeatures/DiagnosticsTestUtilities/CodeActions/AbstractCodeActionOrUserDiagnosticTest.cs b/src/EditorFeatures/DiagnosticsTestUtilities/CodeActions/AbstractCodeActionOrUserDiagnosticTest.cs index 31d9a9bdefae0..4cff315e31f8d 100644 --- a/src/EditorFeatures/DiagnosticsTestUtilities/CodeActions/AbstractCodeActionOrUserDiagnosticTest.cs +++ b/src/EditorFeatures/DiagnosticsTestUtilities/CodeActions/AbstractCodeActionOrUserDiagnosticTest.cs @@ -196,7 +196,6 @@ protected TestWorkspace CreateWorkspaceFromOptions(string workspaceMarkupOrCode, #endif // we need to set global options since the tests are going thru incremental diagnostic analyzer that reads them from there: workspace.GlobalOptions.SetIdeAnalyzerOptions(GetLanguage(), parameters.ideAnalyzerOptions); - return workspace; } diff --git a/src/EditorFeatures/DiagnosticsTestUtilities/MoveToNamespace/AbstractMoveToNamespaceTests.cs b/src/EditorFeatures/DiagnosticsTestUtilities/MoveToNamespace/AbstractMoveToNamespaceTests.cs index eefb13e9583c9..509a5b87a1122 100644 --- a/src/EditorFeatures/DiagnosticsTestUtilities/MoveToNamespace/AbstractMoveToNamespaceTests.cs +++ b/src/EditorFeatures/DiagnosticsTestUtilities/MoveToNamespace/AbstractMoveToNamespaceTests.cs @@ -9,6 +9,7 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; +using Microsoft.CodeAnalysis.ChangeNamespace; using Microsoft.CodeAnalysis.CodeRefactorings; using Microsoft.CodeAnalysis.Editor.UnitTests.CodeActions; using Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces; @@ -47,6 +48,7 @@ public async Task TestMoveToNamespaceAsync( var actions = await testState.MoveToNamespaceService.GetCodeActionsAsync( testState.InvocationDocument, testState.TestInvocationDocument.SelectedSpans.Single(), + language => ChangeNamespaceOptions.GetDefault(workspace.Services.GetLanguageServices(GetLanguage())), CancellationToken.None); var operationTasks = actions diff --git a/src/EditorFeatures/Test/CodeGeneration/AbstractCodeGenerationTests.cs b/src/EditorFeatures/Test/CodeGeneration/AbstractCodeGenerationTests.cs index 45ff92a6ef52f..096f9d9102285 100644 --- a/src/EditorFeatures/Test/CodeGeneration/AbstractCodeGenerationTests.cs +++ b/src/EditorFeatures/Test/CodeGeneration/AbstractCodeGenerationTests.cs @@ -4,6 +4,7 @@ using System; using System.Linq; +using System.Threading; using Microsoft.CodeAnalysis.CodeGeneration; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Editing; @@ -38,7 +39,8 @@ private static SyntaxNode Simplify( var annotatedDocument = document.WithSyntaxRoot( root.WithAdditionalAnnotations(Simplifier.Annotation)); - var simplifiedDocument = Simplifier.ReduceAsync(annotatedDocument).Result; + var options = document.Project.LanguageServices.GetRequiredService().DefaultOptions; + var simplifiedDocument = Simplifier.ReduceAsync(annotatedDocument, options, CancellationToken.None).Result; var rootNode = simplifiedDocument.GetRequiredSyntaxRootAsync(default).AsTask().Result; diff --git a/src/EditorFeatures/Test/CodeGeneration/CodeGenerationTests.cs b/src/EditorFeatures/Test/CodeGeneration/CodeGenerationTests.cs index 35174142febdc..97219f300c705 100644 --- a/src/EditorFeatures/Test/CodeGeneration/CodeGenerationTests.cs +++ b/src/EditorFeatures/Test/CodeGeneration/CodeGenerationTests.cs @@ -13,6 +13,7 @@ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CodeGeneration; using Microsoft.CodeAnalysis.CSharp.Formatting; +using Microsoft.CodeAnalysis.CSharp.Simplification; using Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces; using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.Options; @@ -22,6 +23,7 @@ using Microsoft.CodeAnalysis.Test.Utilities; using Microsoft.CodeAnalysis.Text; using Microsoft.CodeAnalysis.VisualBasic.Formatting; +using Microsoft.CodeAnalysis.VisualBasic.Simplification; using Roslyn.Test.Utilities; using Roslyn.Utilities; using Xunit; @@ -885,8 +887,9 @@ public void Dispose() this.Document = this.Result; var formattingOptions = IsVisualBasic ? (SyntaxFormattingOptions)VisualBasicSyntaxFormattingOptions.Default : CSharpSyntaxFormattingOptions.Default; + var simplifierOptions = IsVisualBasic ? (SimplifierOptions)VisualBasicSimplifierOptions.Default : CSharpSimplifierOptions.Default; - var simplified = Simplifier.ReduceAsync(this.Document, Simplifier.Annotation).Result; + var simplified = Simplifier.ReduceAsync(this.Document, Simplifier.Annotation, simplifierOptions, CancellationToken.None).Result; var actual = Formatter.FormatAsync(simplified, Formatter.Annotation, formattingOptions, CancellationToken.None).Result.GetSyntaxRootAsync().Result.ToFullString(); Assert.Equal(_expected, actual); diff --git a/src/EditorFeatures/Test2/Expansion/AbstractExpansionTest.vb b/src/EditorFeatures/Test2/Expansion/AbstractExpansionTest.vb index 9ff69b2523c3d..58d14b0f784d7 100644 --- a/src/EditorFeatures/Test2/Expansion/AbstractExpansionTest.vb +++ b/src/EditorFeatures/Test2/Expansion/AbstractExpansionTest.vb @@ -27,6 +27,9 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.Expansion Dim root = Await document.GetSyntaxRootAsync() + Dim formattingOptions = Await SyntaxFormattingOptions.FromDocumentAsync(document, CancellationToken.None) + Dim simplifyOptions = Await SimplifierOptions.FromDocumentAsync(document, fallbackOptions:=Nothing, CancellationToken.None) + If (hostDocument.AnnotatedSpans.ContainsKey("Expand")) Then For Each span In hostDocument.AnnotatedSpans("Expand") Dim node = GetExpressionSyntaxWithSameSpan(root.FindToken(span.Start).Parent, span.End) @@ -37,13 +40,11 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.Expansion Dim node = GetExpressionSyntaxWithSameSpan(root.FindToken(span.Start).Parent, span.End) root = root.ReplaceNode(node, Await Simplifier.ExpandAsync(node, document, expandInsideNode:=Nothing, expandParameter:=expandParameter)) document = document.WithSyntaxRoot(root) - document = Await Simplifier.ReduceAsync(document, Simplifier.Annotation) + document = Await Simplifier.ReduceAsync(document, Simplifier.Annotation, simplifyOptions, CancellationToken.None) root = Await document.GetSyntaxRootAsync() Next End If - Dim formattingOptions = Await SyntaxFormattingOptions.FromDocumentAsync(document, CancellationToken.None) - document = document.WithSyntaxRoot(root) document = Await Formatter.FormatAsync(document, FormattingOptions, CancellationToken.None) diff --git a/src/EditorFeatures/Test2/NavigationBar/TestHelpers.vb b/src/EditorFeatures/Test2/NavigationBar/TestHelpers.vb index fc199dd1b1667..5de020bb74c8b 100644 --- a/src/EditorFeatures/Test2/NavigationBar/TestHelpers.vb +++ b/src/EditorFeatures/Test2/NavigationBar/TestHelpers.vb @@ -96,7 +96,7 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.NavigationBar Dim contextLocation = (Await document.GetSyntaxTreeAsync()).GetLocation(New TextSpan(0, 0)) Dim generateCodeItem = DirectCast(rightItem, WrappedNavigationBarItem).UnderlyingItem - Dim newDocument = Await VisualBasicEditorNavigationBarItemService.GetGeneratedDocumentAsync(document, generateCodeItem, CancellationToken.None) + Dim newDocument = Await VisualBasicEditorNavigationBarItemService.GetGeneratedDocumentAsync(document, generateCodeItem, workspace.GlobalOptions, CancellationToken.None) Dim actual = (Await newDocument.GetSyntaxRootAsync()).ToFullString().TrimEnd() Dim expected = expectedText.NormalizedValue.TrimEnd() diff --git a/src/EditorFeatures/Test2/Simplification/AbstractSimplificationTests.vb b/src/EditorFeatures/Test2/Simplification/AbstractSimplificationTests.vb index 4a23a6a4834a2..6e604bb4e1624 100644 --- a/src/EditorFeatures/Test2/Simplification/AbstractSimplificationTests.vb +++ b/src/EditorFeatures/Test2/Simplification/AbstractSimplificationTests.vb @@ -114,12 +114,14 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.Simplification document = document.WithSyntaxRoot(root) +#Disable Warning RS0030 ' Do Not used banned APIs Dim simplifiedDocument As Document If Not explicitSpansToSimplifyWithin.IsDefaultOrEmpty Then simplifiedDocument = Await Simplifier.ReduceAsync(document, explicitSpansToSimplifyWithin, optionSet) Else simplifiedDocument = Await Simplifier.ReduceAsync(document, Simplifier.Annotation, optionSet) End If +#Enable Warning RS0030 Return simplifiedDocument End Function diff --git a/src/EditorFeatures/Test2/Simplification/ParameterSimplificationTests.vb b/src/EditorFeatures/Test2/Simplification/ParameterSimplificationTests.vb index 45bfae7c85aef..0c6aafb34c9e8 100644 --- a/src/EditorFeatures/Test2/Simplification/ParameterSimplificationTests.vb +++ b/src/EditorFeatures/Test2/Simplification/ParameterSimplificationTests.vb @@ -2,6 +2,8 @@ ' The .NET Foundation licenses this file to you under the MIT license. ' See the LICENSE file in the project root for more information. +Imports System.Threading +Imports Microsoft.CodeAnalysis.CSharp.Simplification Imports Microsoft.CodeAnalysis.Simplification Imports Microsoft.CodeAnalysis.Text @@ -23,7 +25,7 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.Simplification Dim annotatedDocument = document.WithSyntaxRoot( (Await document.GetSyntaxRootAsync()).WithAdditionalAnnotations(Simplifier.Annotation)) - Dim simplifiedDocument = Await Simplifier.ReduceAsync(annotatedDocument) + Dim simplifiedDocument = Await Simplifier.ReduceAsync(annotatedDocument, CSharpSimplifierOptions.Default, CancellationToken.None) Assert.Equal(expected, (Await simplifiedDocument.GetTextAsync()).ToString()) End Using diff --git a/src/EditorFeatures/Test2/Simplification/SimplifierAPITests.vb b/src/EditorFeatures/Test2/Simplification/SimplifierAPITests.vb deleted file mode 100644 index 7ec0fc594a4b4..0000000000000 --- a/src/EditorFeatures/Test2/Simplification/SimplifierAPITests.vb +++ /dev/null @@ -1,154 +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. - -Imports Microsoft.CodeAnalysis.CSharp -Imports Microsoft.CodeAnalysis.Simplification -Imports Microsoft.CodeAnalysis.Text - -Namespace Microsoft.CodeAnalysis.Editor.UnitTests.Simplification - - Public Class SimplifierAPITests - - - Public Async Function TestExpandAsync() As Task - Await Assert.ThrowsAsync(Of ArgumentNullException)("node", - Function() - Return Simplifier.ExpandAsync(Of SyntaxNode)(Nothing, Nothing) - End Function) - End Function - - - Public Async Function TestExpandAsync2() As Task - Dim node = GetSyntaxNode() - Await Assert.ThrowsAsync(Of ArgumentNullException)("document", - Function() As Task - Return Simplifier.ExpandAsync(node, Nothing) - End Function) - End Function - - - Public Sub TestExpand() - Assert.Throws(Of ArgumentNullException)("node", - Sub() - Simplifier.Expand(Of SyntaxNode)(Nothing, Nothing, Nothing) - End Sub) - End Sub - - - Public Sub TestExpand2() - Dim node = GetSyntaxNode() - Assert.Throws(Of ArgumentNullException)("semanticModel", - Sub() - Simplifier.Expand(node, Nothing, Nothing) - End Sub) - End Sub - - - Public Sub TestExpand3() - Dim node = GetSyntaxNode() - Dim semanticModel = GetSemanticModel() - Assert.Throws(Of ArgumentNullException)("workspace", - Sub() - Simplifier.Expand(node, semanticModel, Nothing) - End Sub) - End Sub - - - Public Async Function TestTokenExpandAsync() As Task - Await Assert.ThrowsAsync(Of ArgumentNullException)("document", - Function() - Return Simplifier.ExpandAsync(Nothing, Nothing) - End Function) - End Function - - - Public Sub TestTokenExpand() - Assert.Throws(Of ArgumentNullException)("semanticModel", - Sub() - Dim expandedNode = Simplifier.Expand(Nothing, Nothing, Nothing) - End Sub) - End Sub - - - Public Sub TestTokenExpand2() - Dim semanticModel = GetSemanticModel() - Assert.Throws(Of ArgumentNullException)("workspace", - Sub() - Dim expandedNode = Simplifier.Expand(Nothing, semanticModel, Nothing) - End Sub) - End Sub - - - Public Async Function TestReduceAsync() As Task - Await Assert.ThrowsAsync(Of ArgumentNullException)("document", - Function() - Return Simplifier.ReduceAsync(Nothing) - End Function) - End Function - - - Public Async Function TestReduceAsync2() As Task - Dim syntaxAnnotation As SyntaxAnnotation = Nothing - Await Assert.ThrowsAsync(Of ArgumentNullException)("document", - Function() - Return Simplifier.ReduceAsync(Nothing, syntaxAnnotation) - End Function) - End Function - - - Public Async Function TestReduceAsync3() As Task - Dim syntaxAnnotation As SyntaxAnnotation = Nothing - Dim document = GetDocument() - Await Assert.ThrowsAsync(Of ArgumentNullException)("annotation", - Function() - Return Simplifier.ReduceAsync(document, syntaxAnnotation) - End Function) - End Function - - - Public Async Function TestReduceAsync4() As Task - Dim textSpan As TextSpan = Nothing - Await Assert.ThrowsAsync(Of ArgumentNullException)("document", - Function() - Return Simplifier.ReduceAsync(Nothing, textSpan) - End Function) - End Function - - - Public Async Function TestReduceAsync5() As Task - Dim spans As IEnumerable(Of TextSpan) = Nothing - Await Assert.ThrowsAsync(Of ArgumentNullException)("document", - Function() - Return Simplifier.ReduceAsync(Nothing, spans) - End Function) - End Function - - - Public Async Function TestReduceAsync6() As Task - Dim document = GetDocument() - Dim spans As IEnumerable(Of TextSpan) = Nothing - Await Assert.ThrowsAsync(Of ArgumentNullException)("spans", - Function() As Task - Return Simplifier.ReduceAsync(document, spans) - End Function) - End Function - - Private Shared Function GetDocument() As Document - Dim workspace = New AdhocWorkspace() - - Dim solution = workspace.CreateSolution(SolutionId.CreateNewId()) - Dim project = workspace.AddProject("CSharpTest", LanguageNames.CSharp) - - Return workspace.AddDocument(project.Id, "CSharpFile.cs", SourceText.From("class C { }")) - End Function - - Private Shared Function GetSemanticModel() As SemanticModel - Return GetDocument().GetSemanticModelAsync().Result - End Function - - Private Shared Function GetSyntaxNode() As SyntaxNode - Return SyntaxFactory.IdentifierName(SyntaxFactory.Identifier("Test")) - End Function - End Class -End Namespace diff --git a/src/EditorFeatures/TestUtilities/Formatting/AbstractNewDocumentFormattingServiceTests.cs b/src/EditorFeatures/TestUtilities/Formatting/AbstractNewDocumentFormattingServiceTests.cs index 432ae717e94cc..a4603c33d98cf 100644 --- a/src/EditorFeatures/TestUtilities/Formatting/AbstractNewDocumentFormattingServiceTests.cs +++ b/src/EditorFeatures/TestUtilities/Formatting/AbstractNewDocumentFormattingServiceTests.cs @@ -5,6 +5,7 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; +using Microsoft.CodeAnalysis.CodeCleanup; using Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces; using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.Options; @@ -66,8 +67,8 @@ private async Task TestCoreAsync(string testCode, string expected, (OptionKey var document = workspace.CurrentSolution.Projects.First().Documents.First(); var formattingService = document.GetRequiredLanguageService(); - var formattingOptions = await SyntaxFormattingOptions.FromDocumentAsync(document, CancellationToken.None).ConfigureAwait(false); - var formattedDocument = await formattingService.FormatNewDocumentAsync(document, hintDocument: null, formattingOptions, CancellationToken.None); + var cleanupOptions = await CodeCleanupOptions.FromDocumentAsync(document, fallbackOptions: null, CancellationToken.None).ConfigureAwait(false); + var formattedDocument = await formattingService.FormatNewDocumentAsync(document, hintDocument: null, cleanupOptions, CancellationToken.None); var actual = await formattedDocument.GetTextAsync(); AssertEx.EqualOrDiff(expected, actual.ToString()); diff --git a/src/EditorFeatures/VisualBasic/EncapsulateField/EncapsulateFieldCommandHandler.vb b/src/EditorFeatures/VisualBasic/EncapsulateField/EncapsulateFieldCommandHandler.vb index 3deca66036fa7..692cfdb2df231 100644 --- a/src/EditorFeatures/VisualBasic/EncapsulateField/EncapsulateFieldCommandHandler.vb +++ b/src/EditorFeatures/VisualBasic/EncapsulateField/EncapsulateFieldCommandHandler.vb @@ -11,6 +11,7 @@ Imports Microsoft.CodeAnalysis.Shared.TestHooks Imports Microsoft.VisualStudio.Commanding Imports Microsoft.VisualStudio.Text.Operations Imports Microsoft.VisualStudio.Utilities +Imports Microsoft.CodeAnalysis.Options Namespace Microsoft.CodeAnalysis.VisualBasic.EncapsulateField @@ -24,8 +25,9 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.EncapsulateField Public Sub New(threadingContext As IThreadingContext, undoManager As ITextBufferUndoManagerProvider, + globalOptions As IGlobalOptionService, listenerProvider As IAsynchronousOperationListenerProvider) - MyBase.New(threadingContext, undoManager, listenerProvider) + MyBase.New(threadingContext, undoManager, globalOptions, listenerProvider) End Sub End Class End Namespace diff --git a/src/EditorFeatures/VisualBasic/LineCommit/CommitFormatter.vb b/src/EditorFeatures/VisualBasic/LineCommit/CommitFormatter.vb index f5889434f3474..0d77f26a96de0 100644 --- a/src/EditorFeatures/VisualBasic/LineCommit/CommitFormatter.vb +++ b/src/EditorFeatures/VisualBasic/LineCommit/CommitFormatter.vb @@ -5,6 +5,7 @@ Imports System.Collections.Immutable Imports System.ComponentModel.Composition Imports System.Threading +Imports Microsoft.CodeAnalysis.AddImport Imports Microsoft.CodeAnalysis.CodeCleanup Imports Microsoft.CodeAnalysis.CodeCleanup.Providers Imports Microsoft.CodeAnalysis.Formatting @@ -13,6 +14,7 @@ Imports Microsoft.CodeAnalysis.Host.Mef Imports Microsoft.CodeAnalysis.Indentation Imports Microsoft.CodeAnalysis.Internal.Log Imports Microsoft.CodeAnalysis.Options +Imports Microsoft.CodeAnalysis.Simplification Imports Microsoft.CodeAnalysis.Text Imports Microsoft.VisualStudio.Text Imports Microsoft.VisualStudio.Text.Editor @@ -88,13 +90,16 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.LineCommit Concat(commitFormattingCleanup) Dim cleanupService = document.GetRequiredLanguageService(Of ICodeCleanerService) + Dim simplifierOptions = document.GetSimplifierOptionsAsync(_globalOptions, cancellationToken).WaitAndGetResult(cancellationToken) + Dim addImportOptions = AddImportPlacementOptions.FromDocumentAsync(document, cancellationToken).WaitAndGetResult(cancellationToken) + Dim cleanupOptions = New CodeCleanupOptions(formattingOptions, simplifierOptions, addImportOptions) Dim finalDocument As Document If useSemantics OrElse isExplicitFormat Then finalDocument = cleanupService.CleanupAsync( document, ImmutableArray.Create(textSpanToFormat), - formattingOptions, + cleanupOptions, codeCleanups, cancellationToken).WaitAndGetResult(cancellationToken) Else diff --git a/src/EditorFeatures/VisualBasic/NavigationBar/VisualBasicEditorNavigationBarItemService.vb b/src/EditorFeatures/VisualBasic/NavigationBar/VisualBasicEditorNavigationBarItemService.vb index 370bf1681bc55..29d1e8bb7edf6 100644 --- a/src/EditorFeatures/VisualBasic/NavigationBar/VisualBasicEditorNavigationBarItemService.vb +++ b/src/EditorFeatures/VisualBasic/NavigationBar/VisualBasicEditorNavigationBarItemService.vb @@ -9,6 +9,7 @@ Imports Microsoft.CodeAnalysis.Editor.Shared.Utilities Imports Microsoft.CodeAnalysis.Editor.VisualBasic.Utilities Imports Microsoft.CodeAnalysis.Host.Mef Imports Microsoft.CodeAnalysis.NavigationBar.RoslynNavigationBarItem +Imports Microsoft.CodeAnalysis.Options Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Imports Microsoft.VisualStudio.Text Imports Microsoft.VisualStudio.Text.Editor @@ -23,16 +24,19 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.NavigationBar Private ReadOnly _editorOperationsFactoryService As IEditorOperationsFactoryService Private ReadOnly _textUndoHistoryRegistry As ITextUndoHistoryRegistry + Private ReadOnly _globalOptions As IGlobalOptionService Public Sub New( threadingContext As IThreadingContext, editorOperationsFactoryService As IEditorOperationsFactoryService, - textUndoHistoryRegistry As ITextUndoHistoryRegistry) + textUndoHistoryRegistry As ITextUndoHistoryRegistry, + globalOptions As IGlobalOptionService) MyBase.New(threadingContext) _editorOperationsFactoryService = editorOperationsFactoryService _textUndoHistoryRegistry = textUndoHistoryRegistry + _globalOptions = globalOptions End Sub Friend Overrides Async Function GetNavigationLocationAsync( diff --git a/src/EditorFeatures/VisualBasic/NavigationBar/VisualBasicEditorNavigationBarItemService_CodeGeneration.vb b/src/EditorFeatures/VisualBasic/NavigationBar/VisualBasicEditorNavigationBarItemService_CodeGeneration.vb index 15e8944e24f20..41300ee881aba 100644 --- a/src/EditorFeatures/VisualBasic/NavigationBar/VisualBasicEditorNavigationBarItemService_CodeGeneration.vb +++ b/src/EditorFeatures/VisualBasic/NavigationBar/VisualBasicEditorNavigationBarItemService_CodeGeneration.vb @@ -13,6 +13,7 @@ Imports Microsoft.CodeAnalysis.Formatting Imports Microsoft.CodeAnalysis.Formatting.Rules Imports Microsoft.CodeAnalysis.NavigationBar Imports Microsoft.CodeAnalysis.NavigationBar.RoslynNavigationBarItem +Imports Microsoft.CodeAnalysis.Options Imports Microsoft.CodeAnalysis.PooledObjects Imports Microsoft.CodeAnalysis.Simplification Imports Microsoft.CodeAnalysis.Text @@ -24,7 +25,7 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.NavigationBar Private Async Function GenerateCodeForItemAsync(document As Document, generateCodeItem As AbstractGenerateCodeItem, textView As ITextView, cancellationToken As CancellationToken) As Task ' We'll compute everything up front before we go mutate state Dim text = Await document.GetTextAsync(cancellationToken).ConfigureAwait(False) - Dim newDocument = Await GetGeneratedDocumentAsync(document, generateCodeItem, cancellationToken).ConfigureAwait(False) + Dim newDocument = Await GetGeneratedDocumentAsync(document, generateCodeItem, _globalOptions, cancellationToken).ConfigureAwait(False) Dim generatedTree = Await newDocument.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(False) Dim generatedNode = generatedTree.GetAnnotatedNodes(GeneratedSymbolAnnotation).Single().FirstAncestorOrSelf(Of MethodBlockBaseSyntax) @@ -48,7 +49,7 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.NavigationBar End Using End Function - Public Shared Async Function GetGeneratedDocumentAsync(document As Document, generateCodeItem As RoslynNavigationBarItem, cancellationToken As CancellationToken) As Task(Of Document) + Public Shared Async Function GetGeneratedDocumentAsync(document As Document, generateCodeItem As RoslynNavigationBarItem, globalOptions As IGlobalOptionService, cancellationToken As CancellationToken) As Task(Of Document) Dim syntaxTree = Await document.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(False) Dim contextLocation = syntaxTree.GetLocation(New TextSpan(0, 0)) @@ -59,19 +60,20 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.NavigationBar Return document End If - newDocument = Await Simplifier.ReduceAsync(newDocument, Simplifier.Annotation, Nothing, cancellationToken).ConfigureAwait(False) + Dim simplifierOptions = Await newDocument.GetSimplifierOptionsAsync(globalOptions, cancellationToken).ConfigureAwait(False) + Dim formattingOptions = Await SyntaxFormattingOptions.FromDocumentAsync(newDocument, cancellationToken).ConfigureAwait(False) + + newDocument = Await Simplifier.ReduceAsync(newDocument, Simplifier.Annotation, simplifierOptions, cancellationToken).ConfigureAwait(False) Dim formatterRules = Formatter.GetDefaultFormattingRules(newDocument) If ShouldApplyLineAdjustmentFormattingRule(generateCodeItem) Then formatterRules = ImmutableArray.Create(Of AbstractFormattingRule)(LineAdjustmentFormattingRule.Instance).AddRange(formatterRules) End If - Dim documentOptions = Await document.GetOptionsAsync(cancellationToken).ConfigureAwait(False) - Return Await Formatter.FormatAsync( newDocument, Formatter.Annotation, - options:=documentOptions, + options:=formattingOptions, cancellationToken:=cancellationToken, rules:=formatterRules).ConfigureAwait(False) End Function diff --git a/src/EditorFeatures/VisualBasic/Simplification/VisualBasicSimplifierOptionsStorage.vb b/src/EditorFeatures/VisualBasic/Simplification/VisualBasicSimplifierOptionsStorage.vb new file mode 100644 index 0000000000000..6351689884e39 --- /dev/null +++ b/src/EditorFeatures/VisualBasic/Simplification/VisualBasicSimplifierOptionsStorage.vb @@ -0,0 +1,40 @@ +' 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. + +Imports System.Composition +Imports System.Runtime.CompilerServices +Imports Microsoft.CodeAnalysis.CodeStyle +Imports Microsoft.CodeAnalysis.Host.Mef +Imports Microsoft.CodeAnalysis.Options +Imports Microsoft.CodeAnalysis.Simplification + +Namespace Microsoft.CodeAnalysis.VisualBasic.Simplification + Friend Module VisualBasicSimplifierOptionsStorage + + + Private NotInheritable Class Service + Implements ISimplifierOptionsStorage + + + + Public Sub New() + End Sub + + Public Function GetOptions(globalOptions As IGlobalOptionService) As SimplifierOptions Implements ISimplifierOptionsStorage.GetOptions + Return GetVisualBasicSimplifierOptions(globalOptions) + End Function + End Class + + + Public Function GetVisualBasicSimplifierOptions(globalOptions As IGlobalOptionService) As VisualBasicSimplifierOptions + Return New VisualBasicSimplifierOptions( + qualifyFieldAccess:=globalOptions.GetOption(CodeStyleOptions2.QualifyFieldAccess, LanguageNames.VisualBasic), + qualifyPropertyAccess:=globalOptions.GetOption(CodeStyleOptions2.QualifyPropertyAccess, LanguageNames.VisualBasic), + qualifyMethodAccess:=globalOptions.GetOption(CodeStyleOptions2.QualifyMethodAccess, LanguageNames.VisualBasic), + qualifyEventAccess:=globalOptions.GetOption(CodeStyleOptions2.QualifyEventAccess, LanguageNames.VisualBasic), + preferPredefinedTypeKeywordInMemberAccess:=globalOptions.GetOption(CodeStyleOptions2.PreferIntrinsicPredefinedTypeKeywordInMemberAccess, LanguageNames.VisualBasic), + preferPredefinedTypeKeywordInDeclaration:=globalOptions.GetOption(CodeStyleOptions2.PreferIntrinsicPredefinedTypeKeywordInDeclaration, LanguageNames.VisualBasic)) + End Function + End Module +End Namespace diff --git a/src/EditorFeatures/VisualBasic/Utilities/CommandHandlers/AbstractImplementAbstractClassOrInterfaceCommandHandler.vb b/src/EditorFeatures/VisualBasic/Utilities/CommandHandlers/AbstractImplementAbstractClassOrInterfaceCommandHandler.vb index d2978febaf77b..d756e35ee6f72 100644 --- a/src/EditorFeatures/VisualBasic/Utilities/CommandHandlers/AbstractImplementAbstractClassOrInterfaceCommandHandler.vb +++ b/src/EditorFeatures/VisualBasic/Utilities/CommandHandlers/AbstractImplementAbstractClassOrInterfaceCommandHandler.vb @@ -171,8 +171,9 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.Utilities.CommandHandlers End If Dim formattingOptions = SyntaxFormattingOptions.FromDocumentAsync(newDocument, cancellationToken).WaitAndGetResult(cancellationToken) + Dim simplifierOptions = newDocument.GetSimplifierOptionsAsync(_globalOptions, cancellationToken).WaitAndGetResult(cancellationToken) - newDocument = Simplifier.ReduceAsync(newDocument, Simplifier.Annotation, Nothing, cancellationToken).WaitAndGetResult(cancellationToken) + newDocument = Simplifier.ReduceAsync(newDocument, Simplifier.Annotation, simplifierOptions, cancellationToken).WaitAndGetResult(cancellationToken) newDocument = Formatter.FormatAsync(newDocument, Formatter.Annotation, formattingOptions, cancellationToken).WaitAndGetResult(cancellationToken) newDocument.Project.Solution.Workspace.ApplyDocumentChanges(newDocument, cancellationToken) diff --git a/src/EditorFeatures/VisualBasicTest/CaseCorrecting/CaseCorrectionServiceTests.vb b/src/EditorFeatures/VisualBasicTest/CaseCorrecting/CaseCorrectionServiceTests.vb index 3ef31c1fa05ec..c9c2de0f14ce7 100644 --- a/src/EditorFeatures/VisualBasicTest/CaseCorrecting/CaseCorrectionServiceTests.vb +++ b/src/EditorFeatures/VisualBasicTest/CaseCorrecting/CaseCorrectionServiceTests.vb @@ -4,13 +4,11 @@ Imports System.Collections.Immutable Imports System.Threading -Imports System.Xml.Linq Imports Microsoft.CodeAnalysis Imports Microsoft.CodeAnalysis.CodeCleanup Imports Microsoft.CodeAnalysis.CodeCleanup.Providers Imports Microsoft.CodeAnalysis.Editor.UnitTests.Extensions Imports Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces -Imports Microsoft.CodeAnalysis.Formatting Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.CaseCorrecting <[UseExportProvider]> @@ -34,7 +32,8 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.CaseCorrecting Dim buffer = hostDocument.GetTextBuffer() Dim document = workspace.CurrentSolution.GetDocument(hostDocument.Id) Dim span = (Await document.GetSyntaxRootAsync()).FullSpan - Dim options = Await SyntaxFormattingOptions.FromDocumentAsync(document, CancellationToken.None) + + Dim options = Await CodeCleanupOptions.FromDocumentAsync(document, fallbackOptions:=Nothing, CancellationToken.None) Dim service = document.GetLanguageService(Of ICodeCleanerService) Dim newDocument = Await service.CleanupAsync( diff --git a/src/EditorFeatures/VisualBasicTest/EncapsulateField/EncapsulateFieldCommandHandlerTests.vb b/src/EditorFeatures/VisualBasicTest/EncapsulateField/EncapsulateFieldCommandHandlerTests.vb index 30ea8abb4dfaf..25d5a68b0f56b 100644 --- a/src/EditorFeatures/VisualBasicTest/EncapsulateField/EncapsulateFieldCommandHandlerTests.vb +++ b/src/EditorFeatures/VisualBasicTest/EncapsulateField/EncapsulateFieldCommandHandlerTests.vb @@ -6,6 +6,7 @@ Imports Microsoft.CodeAnalysis.Editor.Shared.Utilities Imports Microsoft.CodeAnalysis.Editor.UnitTests Imports Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces Imports Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests +Imports Microsoft.CodeAnalysis.Options Imports Microsoft.CodeAnalysis.Shared.TestHooks Imports Microsoft.CodeAnalysis.VisualBasic.EncapsulateField Imports Microsoft.VisualStudio.Text.Editor.Commanding.Commands @@ -154,6 +155,7 @@ End Class Dim handler = New EncapsulateFieldCommandHandler( workspace.GetService(Of IThreadingContext), workspace.GetService(Of ITextBufferUndoManagerProvider), + workspace.GlobalOptions, workspace.GetService(Of IAsynchronousOperationListenerProvider)()) Dim state = handler.GetCommandState(New EncapsulateFieldCommandArgs(textView, textView.TextBuffer)) diff --git a/src/EditorFeatures/VisualBasicTest/EncapsulateField/EncapsulateFieldTestState.vb b/src/EditorFeatures/VisualBasicTest/EncapsulateField/EncapsulateFieldTestState.vb index c5f187fa03b38..386325aca98d5 100644 --- a/src/EditorFeatures/VisualBasicTest/EncapsulateField/EncapsulateFieldTestState.vb +++ b/src/EditorFeatures/VisualBasicTest/EncapsulateField/EncapsulateFieldTestState.vb @@ -35,6 +35,7 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.EncapsulateField Dim commandHandler = New EncapsulateFieldCommandHandler( Workspace.ExportProvider.GetExportedValue(Of IThreadingContext)(), Workspace.GetService(Of ITextBufferUndoManagerProvider)(), + Workspace.GlobalOptions, Workspace.ExportProvider.GetExportedValue(Of IAsynchronousOperationListenerProvider)) commandHandler.ExecuteCommand(args, TestCommandExecutionContext.Create()) End Sub diff --git a/src/EditorFeatures/VisualBasicTest/Wrapping/AbstractParameterWrappingTests.vb b/src/EditorFeatures/VisualBasicTest/Wrapping/AbstractParameterWrappingTests.vb index 356f108c1dc35..73cebdd9aaa55 100644 --- a/src/EditorFeatures/VisualBasicTest/Wrapping/AbstractParameterWrappingTests.vb +++ b/src/EditorFeatures/VisualBasicTest/Wrapping/AbstractParameterWrappingTests.vb @@ -6,9 +6,6 @@ Imports System.Collections.Immutable Imports Microsoft.CodeAnalysis.CodeActions Imports Microsoft.CodeAnalysis.Editor.UnitTests.CodeActions Imports Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.CodeRefactorings -Imports Microsoft.CodeAnalysis.ExtractMethod -Imports Microsoft.CodeAnalysis.ImplementType -Imports Microsoft.CodeAnalysis.SymbolSearch Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.Wrapping Public MustInherit Class AbstractWrappingTests @@ -19,11 +16,7 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.Wrapping End Function Private Protected Shared Function GetIndentionColumn(column As Integer) As CodeActionOptions - Return New CodeActionOptions( - SymbolSearchOptions.Default, - ImplementTypeOptions.Default, - ExtractMethodOptions.Default, - WrappingColumn:=column) + Return New CodeActionOptions(WrappingColumn:=column) End Function Protected Function TestAllWrappingCasesAsync( diff --git a/src/Features/CSharp/Portable/CodeRefactorings/UseExplicitOrImplicitType/AbstractUseTypeCodeRefactoringProvider.cs b/src/Features/CSharp/Portable/CodeRefactorings/UseExplicitOrImplicitType/AbstractUseTypeCodeRefactoringProvider.cs index 24be9b03fd663..dcc989931b350 100644 --- a/src/Features/CSharp/Portable/CodeRefactorings/UseExplicitOrImplicitType/AbstractUseTypeCodeRefactoringProvider.cs +++ b/src/Features/CSharp/Portable/CodeRefactorings/UseExplicitOrImplicitType/AbstractUseTypeCodeRefactoringProvider.cs @@ -11,12 +11,14 @@ using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeRefactorings; using Microsoft.CodeAnalysis.CSharp.Extensions; +using Microsoft.CodeAnalysis.CSharp.Simplification; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.CSharp.Utilities; using Microsoft.CodeAnalysis.Editing; using Microsoft.CodeAnalysis.LanguageServices; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Shared.Extensions; +using Microsoft.CodeAnalysis.Simplification; namespace Microsoft.CodeAnalysis.CSharp.CodeRefactorings.UseType { @@ -25,7 +27,7 @@ internal abstract class AbstractUseTypeCodeRefactoringProvider : CodeRefactoring protected abstract string Title { get; } protected abstract Task HandleDeclarationAsync(Document document, SyntaxEditor editor, TypeSyntax type, CancellationToken cancellationToken); protected abstract TypeSyntax FindAnalyzableType(SyntaxNode node, SemanticModel semanticModel, CancellationToken cancellationToken); - protected abstract TypeStyleResult AnalyzeTypeName(TypeSyntax typeName, SemanticModel semanticModel, OptionSet optionSet, CancellationToken cancellationToken); + protected abstract TypeStyleResult AnalyzeTypeName(TypeSyntax typeName, SemanticModel semanticModel, CSharpSimplifierOptions options, CancellationToken cancellationToken); public override async Task ComputeRefactoringsAsync(CodeRefactoringContext context) { @@ -50,8 +52,9 @@ public override async Task ComputeRefactoringsAsync(CodeRefactoringContext conte return; } - var optionSet = await document.GetOptionsAsync(cancellationToken).ConfigureAwait(false); - var typeStyle = AnalyzeTypeName(declaredType, semanticModel, optionSet, cancellationToken); + var configOptions = await document.GetAnalyzerConfigOptionsAsync(cancellationToken).ConfigureAwait(false); + var simplifierOptions = CSharpSimplifierOptions.Create(configOptions, (CSharpSimplifierOptions)context.Options(document.Project.LanguageServices).SimplifierOptions); + var typeStyle = AnalyzeTypeName(declaredType, semanticModel, simplifierOptions, cancellationToken); if (typeStyle.IsStylePreferred && typeStyle.Severity != ReportDiagnostic.Suppress) { // the analyzer would handle this. So we do not. diff --git a/src/Features/CSharp/Portable/CodeRefactorings/UseExplicitOrImplicitType/UseExplicitTypeCodeRefactoringProvider.cs b/src/Features/CSharp/Portable/CodeRefactorings/UseExplicitOrImplicitType/UseExplicitTypeCodeRefactoringProvider.cs index af6445056d210..f093ba1f6af8f 100644 --- a/src/Features/CSharp/Portable/CodeRefactorings/UseExplicitOrImplicitType/UseExplicitTypeCodeRefactoringProvider.cs +++ b/src/Features/CSharp/Portable/CodeRefactorings/UseExplicitOrImplicitType/UseExplicitTypeCodeRefactoringProvider.cs @@ -10,6 +10,7 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeRefactorings; using Microsoft.CodeAnalysis.CSharp.CodeRefactorings.UseType; +using Microsoft.CodeAnalysis.CSharp.Simplification; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.CSharp.TypeStyle; using Microsoft.CodeAnalysis.CSharp.Utilities; @@ -33,8 +34,8 @@ protected override string Title protected override TypeSyntax FindAnalyzableType(SyntaxNode node, SemanticModel semanticModel, CancellationToken cancellationToken) => CSharpUseExplicitTypeHelper.Instance.FindAnalyzableType(node, semanticModel, cancellationToken); - protected override TypeStyleResult AnalyzeTypeName(TypeSyntax typeName, SemanticModel semanticModel, OptionSet optionSet, CancellationToken cancellationToken) - => CSharpUseExplicitTypeHelper.Instance.AnalyzeTypeName(typeName, semanticModel, optionSet, cancellationToken); + protected override TypeStyleResult AnalyzeTypeName(TypeSyntax typeName, SemanticModel semanticModel, CSharpSimplifierOptions options, CancellationToken cancellationToken) + => CSharpUseExplicitTypeHelper.Instance.AnalyzeTypeName(typeName, semanticModel, options, cancellationToken); protected override Task HandleDeclarationAsync(Document document, SyntaxEditor editor, TypeSyntax node, CancellationToken cancellationToken) => UseExplicitTypeCodeFixProvider.HandleDeclarationAsync(document, editor, node, cancellationToken); diff --git a/src/Features/CSharp/Portable/CodeRefactorings/UseExplicitOrImplicitType/UseImplicitTypeCodeRefactoringProvider.cs b/src/Features/CSharp/Portable/CodeRefactorings/UseExplicitOrImplicitType/UseImplicitTypeCodeRefactoringProvider.cs index dc35f8912897d..17f922876f708 100644 --- a/src/Features/CSharp/Portable/CodeRefactorings/UseExplicitOrImplicitType/UseImplicitTypeCodeRefactoringProvider.cs +++ b/src/Features/CSharp/Portable/CodeRefactorings/UseExplicitOrImplicitType/UseImplicitTypeCodeRefactoringProvider.cs @@ -10,11 +10,11 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeRefactorings; using Microsoft.CodeAnalysis.CSharp.CodeRefactorings.UseType; +using Microsoft.CodeAnalysis.CSharp.Simplification; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.CSharp.TypeStyle; using Microsoft.CodeAnalysis.CSharp.Utilities; using Microsoft.CodeAnalysis.Editing; -using Microsoft.CodeAnalysis.Options; namespace Microsoft.CodeAnalysis.CSharp.CodeRefactorings.UseImplicitType { @@ -33,8 +33,8 @@ protected override string Title protected override TypeSyntax FindAnalyzableType(SyntaxNode node, SemanticModel semanticModel, CancellationToken cancellationToken) => CSharpUseImplicitTypeHelper.Instance.FindAnalyzableType(node, semanticModel, cancellationToken); - protected override TypeStyleResult AnalyzeTypeName(TypeSyntax typeName, SemanticModel semanticModel, OptionSet optionSet, CancellationToken cancellationToken) - => CSharpUseImplicitTypeHelper.Instance.AnalyzeTypeName(typeName, semanticModel, optionSet, cancellationToken); + protected override TypeStyleResult AnalyzeTypeName(TypeSyntax typeName, SemanticModel semanticModel, CSharpSimplifierOptions options, CancellationToken cancellationToken) + => CSharpUseImplicitTypeHelper.Instance.AnalyzeTypeName(typeName, semanticModel, options, cancellationToken); protected override Task HandleDeclarationAsync(Document document, SyntaxEditor editor, TypeSyntax type, CancellationToken cancellationToken) { diff --git a/src/Features/CSharp/Portable/Diagnostics/Analyzers/CSharpSimplifyTypeNamesDiagnosticAnalyzer.cs b/src/Features/CSharp/Portable/Diagnostics/Analyzers/CSharpSimplifyTypeNamesDiagnosticAnalyzer.cs index d625cd68869d3..275d9240590c1 100644 --- a/src/Features/CSharp/Portable/Diagnostics/Analyzers/CSharpSimplifyTypeNamesDiagnosticAnalyzer.cs +++ b/src/Features/CSharp/Portable/Diagnostics/Analyzers/CSharpSimplifyTypeNamesDiagnosticAnalyzer.cs @@ -6,11 +6,13 @@ using System.Threading; using Microsoft.CodeAnalysis.CodeStyle; using Microsoft.CodeAnalysis.CSharp.Extensions; +using Microsoft.CodeAnalysis.CSharp.Simplification; using Microsoft.CodeAnalysis.CSharp.Simplification.Simplifiers; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Shared.Collections; +using Microsoft.CodeAnalysis.Simplification; using Microsoft.CodeAnalysis.SimplifyTypeNames; using Microsoft.CodeAnalysis.Text; @@ -18,7 +20,7 @@ namespace Microsoft.CodeAnalysis.CSharp.Diagnostics.SimplifyTypeNames { [DiagnosticAnalyzer(LanguageNames.CSharp)] internal sealed class CSharpSimplifyTypeNamesDiagnosticAnalyzer - : SimplifyTypeNamesDiagnosticAnalyzerBase + : SimplifyTypeNamesDiagnosticAnalyzerBase { private static readonly ImmutableArray s_kindsOfInterest = ImmutableArray.Create( @@ -51,8 +53,8 @@ protected override ImmutableArray AnalyzeCodeBlock(CodeBlockAnalysis var cancellationToken = context.CancellationToken; var syntaxTree = semanticModel.SyntaxTree; - var optionSet = context.Options.GetAnalyzerOptionSet(syntaxTree, cancellationToken); - var simplifier = new TypeSyntaxSimplifierWalker(this, semanticModel, optionSet, ignoredSpans: null, cancellationToken); + var options = context.Options.GetCSharpSimplifierOptions(syntaxTree); + var simplifier = new TypeSyntaxSimplifierWalker(this, semanticModel, options, ignoredSpans: null, cancellationToken); simplifier.Visit(context.CodeBlock); return simplifier.Diagnostics; } @@ -63,10 +65,10 @@ protected override ImmutableArray AnalyzeSemanticModel(SemanticModel var cancellationToken = context.CancellationToken; var syntaxTree = semanticModel.SyntaxTree; - var optionSet = context.Options.GetAnalyzerOptionSet(syntaxTree, cancellationToken); + var simplifierOptions = context.Options.GetCSharpSimplifierOptions(syntaxTree); var root = syntaxTree.GetRoot(cancellationToken); - var simplifier = new TypeSyntaxSimplifierWalker(this, semanticModel, optionSet, ignoredSpans: codeBlockIntervalTree, cancellationToken); + var simplifier = new TypeSyntaxSimplifierWalker(this, semanticModel, simplifierOptions, ignoredSpans: codeBlockIntervalTree, cancellationToken); simplifier.Visit(root); return simplifier.Diagnostics; } @@ -75,7 +77,7 @@ internal override bool IsCandidate(SyntaxNode node) => node != null && s_kindsOfInterest.Contains(node.Kind()); internal override bool CanSimplifyTypeNameExpression( - SemanticModel model, SyntaxNode node, OptionSet optionSet, + SemanticModel model, SyntaxNode node, CSharpSimplifierOptions options, out TextSpan issueSpan, out string diagnosticId, out bool inDeclaration, CancellationToken cancellationToken) { @@ -98,14 +100,14 @@ internal override bool CanSimplifyTypeNameExpression( SyntaxNode replacementSyntax; if (node.IsKind(SyntaxKind.QualifiedCref, out QualifiedCrefSyntax? crefSyntax)) { - if (!QualifiedCrefSimplifier.Instance.TrySimplify(crefSyntax, model, optionSet, out var replacement, out issueSpan, cancellationToken)) + if (!QualifiedCrefSimplifier.Instance.TrySimplify(crefSyntax, model, options, out var replacement, out issueSpan, cancellationToken)) return false; replacementSyntax = replacement; } else { - if (!ExpressionSimplifier.Instance.TrySimplify((ExpressionSyntax)node, model, optionSet, out var replacement, out issueSpan, cancellationToken)) + if (!ExpressionSimplifier.Instance.TrySimplify((ExpressionSyntax)node, model, options, out var replacement, out issueSpan, cancellationToken)) return false; replacementSyntax = replacement; diff --git a/src/Features/CSharp/Portable/Diagnostics/Analyzers/TypeSyntaxSimplifierWalker.cs b/src/Features/CSharp/Portable/Diagnostics/Analyzers/TypeSyntaxSimplifierWalker.cs index bb4ee748b1cac..f0eb6e638b222 100644 --- a/src/Features/CSharp/Portable/Diagnostics/Analyzers/TypeSyntaxSimplifierWalker.cs +++ b/src/Features/CSharp/Portable/Diagnostics/Analyzers/TypeSyntaxSimplifierWalker.cs @@ -6,6 +6,7 @@ using System.Collections.Immutable; using System.Threading; using Microsoft.CodeAnalysis.CSharp.Extensions; +using Microsoft.CodeAnalysis.CSharp.Simplification; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Shared.Collections; @@ -42,7 +43,7 @@ internal class TypeSyntaxSimplifierWalker : CSharpSyntaxWalker private readonly CSharpSimplifyTypeNamesDiagnosticAnalyzer _analyzer; private readonly SemanticModel _semanticModel; - private readonly OptionSet _optionSet; + private readonly CSharpSimplifierOptions _options; private readonly SimpleIntervalTree? _ignoredSpans; private readonly CancellationToken _cancellationToken; @@ -71,12 +72,12 @@ public ImmutableArray.Builder DiagnosticsBuilder } } - public TypeSyntaxSimplifierWalker(CSharpSimplifyTypeNamesDiagnosticAnalyzer analyzer, SemanticModel semanticModel, OptionSet optionSet, SimpleIntervalTree? ignoredSpans, CancellationToken cancellationToken) + public TypeSyntaxSimplifierWalker(CSharpSimplifyTypeNamesDiagnosticAnalyzer analyzer, SemanticModel semanticModel, CSharpSimplifierOptions options, SimpleIntervalTree? ignoredSpans, CancellationToken cancellationToken) : base(SyntaxWalkerDepth.StructuredTrivia) { _analyzer = analyzer; _semanticModel = semanticModel; - _optionSet = optionSet; + _options = options; _ignoredSpans = ignoredSpans; _cancellationToken = cancellationToken; @@ -276,7 +277,7 @@ public override void VisitQualifiedCref(QualifiedCrefSyntax node) /// private bool TrySimplify(SyntaxNode node) { - if (!_analyzer.TrySimplify(_semanticModel, node, out var diagnostic, _optionSet, _cancellationToken)) + if (!_analyzer.TrySimplify(_semanticModel, node, out var diagnostic, _options, _cancellationToken)) return false; DiagnosticsBuilder.Add(diagnostic); diff --git a/src/Features/CSharp/Portable/Formatting/CSharpAccessibilityModifiersNewDocumentFormattingProvider.cs b/src/Features/CSharp/Portable/Formatting/CSharpAccessibilityModifiersNewDocumentFormattingProvider.cs index ba53dbbc9a20f..2c6ac1de5ab38 100644 --- a/src/Features/CSharp/Portable/Formatting/CSharpAccessibilityModifiersNewDocumentFormattingProvider.cs +++ b/src/Features/CSharp/Portable/Formatting/CSharpAccessibilityModifiersNewDocumentFormattingProvider.cs @@ -8,6 +8,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.AddAccessibilityModifiers; +using Microsoft.CodeAnalysis.CodeCleanup; using Microsoft.CodeAnalysis.CodeStyle; using Microsoft.CodeAnalysis.CSharp.LanguageServices; using Microsoft.CodeAnalysis.Editing; @@ -26,7 +27,7 @@ public CSharpAccessibilityModifiersNewDocumentFormattingProvider() { } - public async Task FormatNewDocumentAsync(Document document, Document? hintDocument, SyntaxFormattingOptions options, CancellationToken cancellationToken) + public async Task FormatNewDocumentAsync(Document document, Document? hintDocument, CodeCleanupOptions options, CancellationToken cancellationToken) { var documentOptions = await document.GetOptionsAsync(cancellationToken).ConfigureAwait(false); var accessibilityPreferences = documentOptions.GetOption(CodeStyleOptions2.RequireAccessibilityModifiers, document.Project.Language); diff --git a/src/Features/CSharp/Portable/Formatting/CSharpNamespaceDeclarationNewDocumentFormattingProvider.cs b/src/Features/CSharp/Portable/Formatting/CSharpNamespaceDeclarationNewDocumentFormattingProvider.cs index 050e3b16ed36a..428db28a1c04a 100644 --- a/src/Features/CSharp/Portable/Formatting/CSharpNamespaceDeclarationNewDocumentFormattingProvider.cs +++ b/src/Features/CSharp/Portable/Formatting/CSharpNamespaceDeclarationNewDocumentFormattingProvider.cs @@ -8,6 +8,7 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; +using Microsoft.CodeAnalysis.CodeCleanup; using Microsoft.CodeAnalysis.CSharp.ConvertNamespace; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Formatting; @@ -27,7 +28,7 @@ public CSharpNamespaceDeclarationNewDocumentFormattingProvider() { } - public async Task FormatNewDocumentAsync(Document document, Document? hintDocument, SyntaxFormattingOptions options, CancellationToken cancellationToken) + public async Task FormatNewDocumentAsync(Document document, Document? hintDocument, CodeCleanupOptions options, CancellationToken cancellationToken) { var optionSet = await document.GetOptionsAsync(cancellationToken).ConfigureAwait(false); var root = (CompilationUnitSyntax)await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); @@ -36,7 +37,7 @@ public async Task FormatNewDocumentAsync(Document document, Document? if (namespaces.Count != 1) return document; - return await ConvertNamespaceTransform.ConvertAsync(document, namespaces[0], options, cancellationToken).ConfigureAwait(false); + return await ConvertNamespaceTransform.ConvertAsync(document, namespaces[0], options.FormattingOptions, cancellationToken).ConfigureAwait(false); } private static IEnumerable GetNamespacesToReplace(Document document, CompilationUnitSyntax root, DocumentOptionSet optionSet) diff --git a/src/Features/CSharp/Portable/Formatting/CSharpOrganizeUsingsNewDocumentFormattingProvider.cs b/src/Features/CSharp/Portable/Formatting/CSharpOrganizeUsingsNewDocumentFormattingProvider.cs index ed370a01dd77a..4bfbf176acb6c 100644 --- a/src/Features/CSharp/Portable/Formatting/CSharpOrganizeUsingsNewDocumentFormattingProvider.cs +++ b/src/Features/CSharp/Portable/Formatting/CSharpOrganizeUsingsNewDocumentFormattingProvider.cs @@ -6,9 +6,14 @@ using System.Composition; using System.Threading; using System.Threading.Tasks; +using Microsoft.CodeAnalysis.CodeCleanup; +using Microsoft.CodeAnalysis.CSharp.CodeStyle; using Microsoft.CodeAnalysis.CSharp.MisplacedUsingDirectives; using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.CodeAnalysis.OrganizeImports; +using Microsoft.CodeAnalysis.Shared.Extensions; +using Microsoft.CodeAnalysis.Simplification; namespace Microsoft.CodeAnalysis.CSharp.Formatting { @@ -21,10 +26,17 @@ public CSharpOrganizeUsingsNewDocumentFormattingProvider() { } - public async Task FormatNewDocumentAsync(Document document, Document? hintDocument, SyntaxFormattingOptions options, CancellationToken cancellationToken) + public async Task FormatNewDocumentAsync(Document document, Document? hintDocument, CodeCleanupOptions options, CancellationToken cancellationToken) { - var organizedDocument = await Formatter.OrganizeImportsAsync(document, cancellationToken).ConfigureAwait(false); - return await MisplacedUsingDirectivesCodeFixProvider.TransformDocumentIfRequiredAsync(organizedDocument, cancellationToken).ConfigureAwait(false); + var organizeImportsService = document.GetRequiredLanguageService(); + + var organizeOptions = await OrganizeImportsOptions.FromDocumentAsync(document, cancellationToken).ConfigureAwait(false); + var documentOptions = await document.GetOptionsAsync(cancellationToken).ConfigureAwait(false); + var codeStyleOption = documentOptions.GetOption(CSharpCodeStyleOptions.PreferredUsingDirectivePlacement); + + var organizedDocument = await organizeImportsService.OrganizeImportsAsync(document, organizeOptions, cancellationToken).ConfigureAwait(false); + + return await MisplacedUsingDirectivesCodeFixProvider.TransformDocumentIfRequiredAsync(organizedDocument, options.SimplifierOptions, codeStyleOption, cancellationToken).ConfigureAwait(false); } } } diff --git a/src/Features/CSharp/Portable/Formatting/CSharpUseProgramMainNewDocumentFormattingProvider.cs b/src/Features/CSharp/Portable/Formatting/CSharpUseProgramMainNewDocumentFormattingProvider.cs index a7cec74575b69..128f258cc56f6 100644 --- a/src/Features/CSharp/Portable/Formatting/CSharpUseProgramMainNewDocumentFormattingProvider.cs +++ b/src/Features/CSharp/Portable/Formatting/CSharpUseProgramMainNewDocumentFormattingProvider.cs @@ -8,6 +8,7 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis.CSharp.CodeStyle; using Microsoft.CodeAnalysis.CSharp.ConvertProgram; +using Microsoft.CodeAnalysis.CodeCleanup; using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.Host.Mef; @@ -22,13 +23,13 @@ public CSharpUseProgramMainNewDocumentFormattingProvider() { } - public async Task FormatNewDocumentAsync(Document document, Document? hintDocument, SyntaxFormattingOptions formattingOptions, CancellationToken cancellationToken) + public async Task FormatNewDocumentAsync(Document document, Document? hintDocument, CodeCleanupOptions options, CancellationToken cancellationToken) { - var options = await document.GetOptionsAsync(cancellationToken).ConfigureAwait(false); + var documentOptions = await document.GetOptionsAsync(cancellationToken).ConfigureAwait(false); // if the user prefers Program.Main style instead, then attempt to convert a template with // top-level-statements to that form. - var option = options.GetOption(CSharpCodeStyleOptions.PreferTopLevelStatements); + var option = documentOptions.GetOption(CSharpCodeStyleOptions.PreferTopLevelStatements); if (option.Value) return document; diff --git a/src/Features/CSharp/Portable/ImplementInterface/CSharpImplementInterfaceCodeFixProvider.cs b/src/Features/CSharp/Portable/ImplementInterface/CSharpImplementInterfaceCodeFixProvider.cs index 676af4f7ba025..1362d6a7fe76f 100644 --- a/src/Features/CSharp/Portable/ImplementInterface/CSharpImplementInterfaceCodeFixProvider.cs +++ b/src/Features/CSharp/Portable/ImplementInterface/CSharpImplementInterfaceCodeFixProvider.cs @@ -54,7 +54,7 @@ public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) var actions = token.Parent.GetAncestorsOrThis() .Where(_interfaceName) - .Select(n => service.GetCodeActions(document, context.Options(document.Project.Language).ImplementTypeOptions, model, n, cancellationToken)) + .Select(n => service.GetCodeActions(document, context.Options(document.Project.LanguageServices).ImplementTypeOptions, model, n, cancellationToken)) .FirstOrDefault(a => !a.IsEmpty); if (actions.IsDefaultOrEmpty) diff --git a/src/Features/CSharp/Portable/SimplifyThisOrMe/CSharpSimplifyThisOrMeDiagnosticAnalyzer.cs b/src/Features/CSharp/Portable/SimplifyThisOrMe/CSharpSimplifyThisOrMeDiagnosticAnalyzer.cs index f572364f624b5..61355bddd70fc 100644 --- a/src/Features/CSharp/Portable/SimplifyThisOrMe/CSharpSimplifyThisOrMeDiagnosticAnalyzer.cs +++ b/src/Features/CSharp/Portable/SimplifyThisOrMe/CSharpSimplifyThisOrMeDiagnosticAnalyzer.cs @@ -4,11 +4,12 @@ using System.Threading; using Microsoft.CodeAnalysis.CSharp.LanguageServices; +using Microsoft.CodeAnalysis.CSharp.Simplification; using Microsoft.CodeAnalysis.CSharp.Simplification.Simplifiers; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.LanguageServices; -using Microsoft.CodeAnalysis.Options; +using Microsoft.CodeAnalysis.Simplification; using Microsoft.CodeAnalysis.SimplifyThisOrMe; using Microsoft.CodeAnalysis.Text; @@ -20,16 +21,20 @@ internal sealed class CSharpSimplifyThisOrMeDiagnosticAnalyzer SyntaxKind, ExpressionSyntax, ThisExpressionSyntax, - MemberAccessExpressionSyntax> + MemberAccessExpressionSyntax, + CSharpSimplifierOptions> { protected override ISyntaxFacts GetSyntaxFacts() => CSharpSyntaxFacts.Instance; + protected override CSharpSimplifierOptions GetSimplifierOptions(AnalyzerOptions options, SyntaxTree syntaxTree) + => options.GetCSharpSimplifierOptions(syntaxTree); + protected override bool CanSimplifyTypeNameExpression( - SemanticModel model, MemberAccessExpressionSyntax node, OptionSet optionSet, + SemanticModel model, MemberAccessExpressionSyntax node, CSharpSimplifierOptions options, out TextSpan issueSpan, CancellationToken cancellationToken) { - return ExpressionSimplifier.Instance.TrySimplify(node, model, optionSet, out _, out issueSpan, cancellationToken); + return ExpressionSimplifier.Instance.TrySimplify(node, model, options, out _, out issueSpan, cancellationToken); } } } diff --git a/src/Features/CSharp/Portable/SimplifyTypeNames/SimplifyTypeNamesCodeFixProvider.cs b/src/Features/CSharp/Portable/SimplifyTypeNames/SimplifyTypeNamesCodeFixProvider.cs index 0742e1a32f5e3..5a68a42614dbb 100644 --- a/src/Features/CSharp/Portable/SimplifyTypeNames/SimplifyTypeNamesCodeFixProvider.cs +++ b/src/Features/CSharp/Portable/SimplifyTypeNames/SimplifyTypeNamesCodeFixProvider.cs @@ -8,6 +8,7 @@ using System.Diagnostics.CodeAnalysis; using Microsoft.CodeAnalysis.CodeFixes; using Microsoft.CodeAnalysis.CSharp.Diagnostics.SimplifyTypeNames; +using Microsoft.CodeAnalysis.CSharp.Simplification; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Formatting; @@ -19,7 +20,7 @@ namespace Microsoft.CodeAnalysis.CSharp.SimplifyTypeNames { [ExportCodeFixProvider(LanguageNames.CSharp, Name = PredefinedCodeFixProviderNames.SimplifyNames), Shared] [ExtensionOrder(After = PredefinedCodeFixProviderNames.RemoveUnnecessaryCast)] - internal partial class SimplifyTypeNamesCodeFixProvider : AbstractSimplifyTypeNamesCodeFixProvider + internal partial class SimplifyTypeNamesCodeFixProvider : AbstractSimplifyTypeNamesCodeFixProvider { [ImportingConstructor] [SuppressMessage("RoslynDiagnosticsReliability", "RS0033:Importing constructor should be [Obsolete]", Justification = "Used in test code: https://github.com/dotnet/roslyn/issues/42814")] diff --git a/src/Features/Core/Portable/AddFileBanner/AbstractAddFileBannerNewDocumentFormattingProvider.cs b/src/Features/Core/Portable/AddFileBanner/AbstractAddFileBannerNewDocumentFormattingProvider.cs index 0e723e3457129..ef1f1a6f61d04 100644 --- a/src/Features/Core/Portable/AddFileBanner/AbstractAddFileBannerNewDocumentFormattingProvider.cs +++ b/src/Features/Core/Portable/AddFileBanner/AbstractAddFileBannerNewDocumentFormattingProvider.cs @@ -4,6 +4,7 @@ using System.Threading; using System.Threading.Tasks; +using Microsoft.CodeAnalysis.CodeCleanup; using Microsoft.CodeAnalysis.CodeStyle; using Microsoft.CodeAnalysis.Editing; using Microsoft.CodeAnalysis.FileHeaders; @@ -19,7 +20,7 @@ internal abstract class AbstractAddFileBannerNewDocumentFormattingProvider : INe protected abstract SyntaxGeneratorInternal SyntaxGeneratorInternal { get; } protected abstract AbstractFileHeaderHelper FileHeaderHelper { get; } - public async Task FormatNewDocumentAsync(Document document, Document? hintDocument, SyntaxFormattingOptions options, CancellationToken cancellationToken) + public async Task FormatNewDocumentAsync(Document document, Document? hintDocument, CodeCleanupOptions options, CancellationToken cancellationToken) { var rootToFormat = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); var documentOptions = await document.GetOptionsAsync(cancellationToken).ConfigureAwait(false); @@ -28,7 +29,7 @@ public async Task FormatNewDocumentAsync(Document document, Document? var fileHeaderTemplate = documentOptions.GetOption(CodeStyleOptions2.FileHeaderTemplate); if (!string.IsNullOrEmpty(fileHeaderTemplate)) { - var newLineTrivia = SyntaxGeneratorInternal.EndOfLine(options.NewLine); + var newLineTrivia = SyntaxGeneratorInternal.EndOfLine(options.FormattingOptions.NewLine); var rootWithFileHeader = await AbstractFileHeaderCodeFixProvider.GetTransformedSyntaxRootAsync( SyntaxGenerator.SyntaxFacts, FileHeaderHelper, diff --git a/src/Features/Core/Portable/AddImport/AbstractAddImportCodeFixProvider.cs b/src/Features/Core/Portable/AddImport/AbstractAddImportCodeFixProvider.cs index 2d12603c7e556..2f687a4e61786 100644 --- a/src/Features/Core/Portable/AddImport/AbstractAddImportCodeFixProvider.cs +++ b/src/Features/Core/Portable/AddImport/AbstractAddImportCodeFixProvider.cs @@ -4,6 +4,7 @@ using System.Collections.Immutable; using System.Threading.Tasks; +using Microsoft.CodeAnalysis.CodeCleanup; using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeFixes; using Microsoft.CodeAnalysis.Packaging; @@ -55,7 +56,7 @@ public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) var addImportService = document.GetRequiredLanguageService(); var services = document.Project.Solution.Workspace.Services; - var searchOptions = context.Options(document.Project.Language).SearchOptions; + var searchOptions = context.Options(document.Project.LanguageServices).SearchOptions; var symbolSearchService = _symbolSearchService ?? services.GetRequiredService(); @@ -71,12 +72,12 @@ public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) searchOptions = searchOptions with { SearchNuGetPackages = false }; } - var placement = await AddImportPlacementOptions.FromDocumentAsync(document, cancellationToken).ConfigureAwait(false); + var cleanupOptions = await CodeCleanupOptions.FromDocumentAsync(document, fallbackOptions: null, cancellationToken).ConfigureAwait(false); var addImportOptions = new AddImportOptions( searchOptions, - context.Options(document.Project.Language).HideAdvancedMembers, - placement); + cleanupOptions, + context.Options(document.Project.LanguageServices).HideAdvancedMembers); var fixesForDiagnostic = await addImportService.GetFixesForDiagnosticsAsync( document, span, diagnostics, MaxResults, symbolSearchService, addImportOptions, packageSources, cancellationToken).ConfigureAwait(false); diff --git a/src/Features/Core/Portable/AddImport/AbstractAddImportFeatureService.cs b/src/Features/Core/Portable/AddImport/AbstractAddImportFeatureService.cs index a6cb300bb006c..49bf94ea79a47 100644 --- a/src/Features/Core/Portable/AddImport/AbstractAddImportFeatureService.cs +++ b/src/Features/Core/Portable/AddImport/AbstractAddImportFeatureService.cs @@ -23,6 +23,7 @@ using Microsoft.CodeAnalysis.Text; using Roslyn.Utilities; using Microsoft.CodeAnalysis.CodeGeneration; +using Microsoft.CodeAnalysis.CodeCleanup; namespace Microsoft.CodeAnalysis.AddImport { @@ -94,7 +95,7 @@ private async Task> GetFixesInCurrentProcessAsy { if (!cancellationToken.IsCancellationRequested) { - if (CanAddImport(node, options.Placement.AllowInHiddenRegions, cancellationToken)) + if (CanAddImport(node, options.CleanupOptions.AddImportOptions.AllowInHiddenRegions, cancellationToken)) { var semanticModel = await document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false); var allSymbolReferences = await FindResultsAsync( @@ -106,7 +107,7 @@ private async Task> GetFixesInCurrentProcessAsy { cancellationToken.ThrowIfCancellationRequested(); - var fixData = await reference.TryGetFixDataAsync(document, node, options.Placement, cancellationToken).ConfigureAwait(false); + var fixData = await reference.TryGetFixDataAsync(document, node, options.CleanupOptions, cancellationToken).ConfigureAwait(false); result.AddIfNotNull(fixData); } } diff --git a/src/Features/Core/Portable/AddImport/IAddImportFeatureService.cs b/src/Features/Core/Portable/AddImport/IAddImportFeatureService.cs index 453c8a89cd5c8..2f856e4edc061 100644 --- a/src/Features/Core/Portable/AddImport/IAddImportFeatureService.cs +++ b/src/Features/Core/Portable/AddImport/IAddImportFeatureService.cs @@ -7,6 +7,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeActions; +using Microsoft.CodeAnalysis.CodeCleanup; using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.Packaging; using Microsoft.CodeAnalysis.SymbolSearch; @@ -17,8 +18,8 @@ namespace Microsoft.CodeAnalysis.AddImport [DataContract] internal readonly record struct AddImportOptions( [property: DataMember(Order = 0)] SymbolSearchOptions SearchOptions, - [property: DataMember(Order = 1)] bool HideAdvancedMembers, - [property: DataMember(Order = 2)] AddImportPlacementOptions Placement); + [property: DataMember(Order = 1)] CodeCleanupOptions CleanupOptions, + [property: DataMember(Order = 2)] bool HideAdvancedMembers); internal interface IAddImportFeatureService : ILanguageService { diff --git a/src/Features/Core/Portable/AddImport/References/AssemblyReference.cs b/src/Features/Core/Portable/AddImport/References/AssemblyReference.cs index 680218405a222..4e5fecb1a9af9 100644 --- a/src/Features/Core/Portable/AddImport/References/AssemblyReference.cs +++ b/src/Features/Core/Portable/AddImport/References/AssemblyReference.cs @@ -6,6 +6,7 @@ using System.Threading; using System.Threading.Tasks; +using Microsoft.CodeAnalysis.CodeCleanup; using Microsoft.CodeAnalysis.CodeGeneration; using Microsoft.CodeAnalysis.SymbolSearch; using Roslyn.Utilities; @@ -28,7 +29,7 @@ public AssemblyReference( } public override async Task TryGetFixDataAsync( - Document document, SyntaxNode node, AddImportPlacementOptions options, CancellationToken cancellationToken) + Document document, SyntaxNode node, CodeCleanupOptions options, CancellationToken cancellationToken) { var textChanges = await GetTextChangesAsync(document, node, options, cancellationToken).ConfigureAwait(false); diff --git a/src/Features/Core/Portable/AddImport/References/MetadataSymbolReference.cs b/src/Features/Core/Portable/AddImport/References/MetadataSymbolReference.cs index 1671105787b8a..bace3e619a3e3 100644 --- a/src/Features/Core/Portable/AddImport/References/MetadataSymbolReference.cs +++ b/src/Features/Core/Portable/AddImport/References/MetadataSymbolReference.cs @@ -9,6 +9,7 @@ using System.IO; using System.Threading; using Microsoft.CodeAnalysis.CodeActions; +using Microsoft.CodeAnalysis.CodeCleanup; using Microsoft.CodeAnalysis.CodeGeneration; using Microsoft.CodeAnalysis.Tags; using Microsoft.CodeAnalysis.Text; @@ -41,7 +42,7 @@ public MetadataSymbolReference( protected override bool ShouldAddWithExistingImport(Document document) => true; protected override (string description, bool hasExistingImport) GetDescription( - Document document, AddImportPlacementOptions options, SyntaxNode node, + Document document, CodeCleanupOptions options, SyntaxNode node, SemanticModel semanticModel, CancellationToken cancellationToken) { var (description, hasExistingImport) = base.GetDescription(document, options, node, semanticModel, cancellationToken); diff --git a/src/Features/Core/Portable/AddImport/References/PackageReference.cs b/src/Features/Core/Portable/AddImport/References/PackageReference.cs index 0168a9f3d3830..e790aa14aa0ef 100644 --- a/src/Features/Core/Portable/AddImport/References/PackageReference.cs +++ b/src/Features/Core/Portable/AddImport/References/PackageReference.cs @@ -6,6 +6,7 @@ using System.Threading; using System.Threading.Tasks; +using Microsoft.CodeAnalysis.CodeCleanup; using Microsoft.CodeAnalysis.CodeGeneration; using Roslyn.Utilities; @@ -33,7 +34,7 @@ public PackageReference( } public override async Task TryGetFixDataAsync( - Document document, SyntaxNode node, AddImportPlacementOptions options, CancellationToken cancellationToken) + Document document, SyntaxNode node, CodeCleanupOptions options, CancellationToken cancellationToken) { var textChanges = await GetTextChangesAsync( document, node, options, cancellationToken).ConfigureAwait(false); diff --git a/src/Features/Core/Portable/AddImport/References/ProjectSymbolReference.cs b/src/Features/Core/Portable/AddImport/References/ProjectSymbolReference.cs index 3f85b7457f2f8..aed38f3db4a81 100644 --- a/src/Features/Core/Portable/AddImport/References/ProjectSymbolReference.cs +++ b/src/Features/Core/Portable/AddImport/References/ProjectSymbolReference.cs @@ -7,6 +7,7 @@ using System.Collections.Immutable; using System.Threading; using Microsoft.CodeAnalysis.CodeActions; +using Microsoft.CodeAnalysis.CodeCleanup; using Microsoft.CodeAnalysis.CodeGeneration; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Tags; @@ -87,7 +88,7 @@ protected override AddImportFixData GetFixData( } protected override (string description, bool hasExistingImport) GetDescription( - Document document, AddImportPlacementOptions options, SyntaxNode node, + Document document, CodeCleanupOptions options, SyntaxNode node, SemanticModel semanticModel, CancellationToken cancellationToken) { var (description, hasExistingImport) = base.GetDescription(document, options, node, semanticModel, cancellationToken); diff --git a/src/Features/Core/Portable/AddImport/References/Reference.cs b/src/Features/Core/Portable/AddImport/References/Reference.cs index 98dbb57fa3853..a9080a50f67e6 100644 --- a/src/Features/Core/Portable/AddImport/References/Reference.cs +++ b/src/Features/Core/Portable/AddImport/References/Reference.cs @@ -10,7 +10,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeActions; -using Microsoft.CodeAnalysis.CodeGeneration; +using Microsoft.CodeAnalysis.CodeCleanup; using Microsoft.CodeAnalysis.Editing; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; @@ -102,10 +102,10 @@ public override int GetHashCode() } public abstract Task TryGetFixDataAsync( - Document document, SyntaxNode node, AddImportPlacementOptions options, CancellationToken cancellationToken); + Document document, SyntaxNode node, CodeCleanupOptions options, CancellationToken cancellationToken); protected async Task> GetTextChangesAsync( - Document document, SyntaxNode node, AddImportPlacementOptions options, CancellationToken cancellationToken) + Document document, SyntaxNode node, CodeCleanupOptions options, CancellationToken cancellationToken) { var originalDocument = document; @@ -113,10 +113,10 @@ protected async Task> GetTextChangesAsync( node, document, cancellationToken).ConfigureAwait(false); var newDocument = await provider.AddImportAsync( - node, SearchResult.NameParts, document, options, cancellationToken).ConfigureAwait(false); + node, SearchResult.NameParts, document, options.AddImportOptions, cancellationToken).ConfigureAwait(false); var cleanedDocument = await CodeAction.CleanupDocumentAsync( - newDocument, cancellationToken).ConfigureAwait(false); + newDocument, options, cancellationToken).ConfigureAwait(false); var textChanges = await cleanedDocument.GetTextChangesAsync( originalDocument, cancellationToken).ConfigureAwait(false); diff --git a/src/Features/Core/Portable/AddImport/References/SymbolReference.cs b/src/Features/Core/Portable/AddImport/References/SymbolReference.cs index 45f8cf54a43f6..2b8eb2c7f361e 100644 --- a/src/Features/Core/Portable/AddImport/References/SymbolReference.cs +++ b/src/Features/Core/Portable/AddImport/References/SymbolReference.cs @@ -9,6 +9,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeActions; +using Microsoft.CodeAnalysis.CodeCleanup; using Microsoft.CodeAnalysis.CodeGeneration; using Microsoft.CodeAnalysis.Tags; using Microsoft.CodeAnalysis.Text; @@ -52,7 +53,7 @@ public override int GetHashCode() private async Task> GetTextChangesAsync( Document document, SyntaxNode contextNode, - AddImportPlacementOptions options, bool hasExistingImport, + CodeCleanupOptions options, bool hasExistingImport, CancellationToken cancellationToken) { // Defer to the language to add the actual import/using. @@ -66,10 +67,10 @@ private async Task> GetTextChangesAsync( var updatedDocument = await provider.AddImportAsync( newContextNode, SymbolResult.Symbol, newDocument, - options, cancellationToken).ConfigureAwait(false); + options.AddImportOptions, cancellationToken).ConfigureAwait(false); var cleanedDocument = await CodeAction.CleanupDocumentAsync( - updatedDocument, cancellationToken).ConfigureAwait(false); + updatedDocument, options, cancellationToken).ConfigureAwait(false); var textChanges = await cleanedDocument.GetTextChangesAsync( document, cancellationToken).ConfigureAwait(false); @@ -79,7 +80,7 @@ private async Task> GetTextChangesAsync( public sealed override async Task TryGetFixDataAsync( Document document, SyntaxNode node, - AddImportPlacementOptions options, CancellationToken cancellationToken) + CodeCleanupOptions options, CancellationToken cancellationToken) { var semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); var (description, hasExistingImport) = GetDescription(document, options, node, semanticModel, cancellationToken); @@ -127,11 +128,11 @@ protected abstract AddImportFixData GetFixData( protected abstract CodeActionPriority GetPriority(Document document); protected virtual (string description, bool hasExistingImport) GetDescription( - Document document, AddImportPlacementOptions options, SyntaxNode node, + Document document, CodeCleanupOptions options, SyntaxNode node, SemanticModel semanticModel, CancellationToken cancellationToken) { return provider.GetDescription( - document, options, SymbolResult.Symbol, semanticModel, node, cancellationToken); + document, options.AddImportOptions, SymbolResult.Symbol, semanticModel, node, cancellationToken); } } } diff --git a/src/Features/Core/Portable/AddPackage/AbstractAddPackageCodeFixProvider.cs b/src/Features/Core/Portable/AddPackage/AbstractAddPackageCodeFixProvider.cs index 94c8901b70553..9e543e09569ad 100644 --- a/src/Features/Core/Portable/AddPackage/AbstractAddPackageCodeFixProvider.cs +++ b/src/Features/Core/Portable/AddPackage/AbstractAddPackageCodeFixProvider.cs @@ -52,7 +52,7 @@ protected async Task> GetAddPackagesCodeActionsAsync( var codeActions = ArrayBuilder.GetInstance(); if (symbolSearchService != null && installerService != null && - context.Options(document.Project.Language).SearchOptions.SearchNuGetPackages && + context.Options(document.Project.LanguageServices).SearchOptions.SearchNuGetPackages && installerService.IsEnabled(document.Project.Id)) { var packageSources = PackageSourceHelper.GetPackageSources(installerService.TryGetPackageSources()); diff --git a/src/Features/Core/Portable/ChangeSignature/AbstractChangeSignatureService.cs b/src/Features/Core/Portable/ChangeSignature/AbstractChangeSignatureService.cs index 48915313eab50..7f0bab1059332 100644 --- a/src/Features/Core/Portable/ChangeSignature/AbstractChangeSignatureService.cs +++ b/src/Features/Core/Portable/ChangeSignature/AbstractChangeSignatureService.cs @@ -12,7 +12,7 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.AddImport; -using Microsoft.CodeAnalysis.Completion; +using Microsoft.CodeAnalysis.CodeCleanup; using Microsoft.CodeAnalysis.Editing; using Microsoft.CodeAnalysis.FindSymbols; using Microsoft.CodeAnalysis.FindSymbols.Finders; @@ -416,12 +416,11 @@ private static async Task> FindChangeSignatureR foreach (var docId in nodesToUpdate.Keys) { var updatedDoc = currentSolution.GetRequiredDocument(docId).WithSyntaxRoot(updatedRoots[docId]); - var addImportOptions = await AddImportPlacementOptions.FromDocumentAsync(updatedDoc, cancellationToken).ConfigureAwait(false); - var formattingOptions = await SyntaxFormattingOptions.FromDocumentAsync(updatedDoc, cancellationToken).ConfigureAwait(false); + var cleanupOptions = await CodeCleanupOptions.FromDocumentAsync(updatedDoc, fallbackOptions: null, cancellationToken).ConfigureAwait(false); - var docWithImports = await ImportAdder.AddImportsFromSymbolAnnotationAsync(updatedDoc, addImportOptions, cancellationToken).ConfigureAwait(false); - var reducedDoc = await Simplifier.ReduceAsync(docWithImports, Simplifier.Annotation, cancellationToken: cancellationToken).ConfigureAwait(false); - var formattedDoc = await Formatter.FormatAsync(reducedDoc, SyntaxAnnotation.ElasticAnnotation, formattingOptions, cancellationToken).ConfigureAwait(false); + var docWithImports = await ImportAdder.AddImportsFromSymbolAnnotationAsync(updatedDoc, cleanupOptions.AddImportOptions, cancellationToken).ConfigureAwait(false); + var reducedDoc = await Simplifier.ReduceAsync(docWithImports, Simplifier.Annotation, cleanupOptions.SimplifierOptions, cancellationToken: cancellationToken).ConfigureAwait(false); + var formattedDoc = await Formatter.FormatAsync(reducedDoc, SyntaxAnnotation.ElasticAnnotation, cleanupOptions.FormattingOptions, cancellationToken).ConfigureAwait(false); currentSolution = currentSolution.WithDocumentSyntaxRoot(docId, (await formattedDoc.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false))!); } diff --git a/src/Features/Core/Portable/CodeFixes/Suppression/AbstractSuppressionCodeFixProvider.GlobalSuppressMessageFixAllCodeAction.cs b/src/Features/Core/Portable/CodeFixes/Suppression/AbstractSuppressionCodeFixProvider.GlobalSuppressMessageFixAllCodeAction.cs index 407042a49b2dd..f3373836744dd 100644 --- a/src/Features/Core/Portable/CodeFixes/Suppression/AbstractSuppressionCodeFixProvider.GlobalSuppressMessageFixAllCodeAction.cs +++ b/src/Features/Core/Portable/CodeFixes/Suppression/AbstractSuppressionCodeFixProvider.GlobalSuppressMessageFixAllCodeAction.cs @@ -17,6 +17,7 @@ using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Formatting; using Roslyn.Utilities; +using Microsoft.CodeAnalysis.CodeCleanup; namespace Microsoft.CodeAnalysis.CodeFixes.Suppression { @@ -124,7 +125,7 @@ protected override async Task GetChangedSuppressionDocumentAsync(Cance var services = suppressionsDoc.Project.Solution.Workspace.Services; var suppressionsRoot = await suppressionsDoc.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); var addImportsService = suppressionsDoc.GetRequiredLanguageService(); - var options = await SyntaxFormattingOptions.FromDocumentAsync(suppressionsDoc, cancellationToken).ConfigureAwait(false); + var cleanupOptions = await CodeCleanupOptions.FromDocumentAsync(suppressionsDoc, fallbackOptions: null, cancellationToken).ConfigureAwait(false); foreach (var (targetSymbol, diagnostics) in _diagnosticsBySymbol) { @@ -133,12 +134,12 @@ protected override async Task GetChangedSuppressionDocumentAsync(Cance Contract.ThrowIfFalse(!diagnostic.IsSuppressed); suppressionsRoot = Fixer.AddGlobalSuppressMessageAttribute( suppressionsRoot, targetSymbol, _suppressMessageAttribute, diagnostic, - services, options, addImportsService, cancellationToken); + services, cleanupOptions.FormattingOptions, addImportsService, cancellationToken); } } var result = suppressionsDoc.WithSyntaxRoot(suppressionsRoot); - var final = await CleanupDocumentAsync(result, cancellationToken).ConfigureAwait(false); + var final = await CleanupDocumentAsync(result, cleanupOptions, cancellationToken).ConfigureAwait(false); return final; } diff --git a/src/Features/Core/Portable/CodeRefactorings/AddMissingImports/AbstractAddMissingImportsFeatureService.cs b/src/Features/Core/Portable/CodeRefactorings/AddMissingImports/AbstractAddMissingImportsFeatureService.cs index 5c6001c3ddea6..17da6c72cc9d7 100644 --- a/src/Features/Core/Portable/CodeRefactorings/AddMissingImports/AbstractAddMissingImportsFeatureService.cs +++ b/src/Features/Core/Portable/CodeRefactorings/AddMissingImports/AbstractAddMissingImportsFeatureService.cs @@ -62,8 +62,8 @@ public async Task AnalyzeAsync(Document documen var addImportOptions = new AddImportOptions( SearchOptions: new(SearchReferenceAssemblies: true, SearchNuGetPackages: false), - HideAdvancedMembers: options.HideAdvancedMembers, - Placement: options.Placement); + CleanupOptions: options.CleanupOptions, + HideAdvancedMembers: options.HideAdvancedMembers); var unambiguousFixes = await addImportFeatureService.GetUniqueFixesAsync( document, textSpan, FixableDiagnosticIds, symbolSearchService, diff --git a/src/Features/Core/Portable/CodeRefactorings/AddMissingImports/AbstractAddMissingImportsRefactoringProvider.cs b/src/Features/Core/Portable/CodeRefactorings/AddMissingImports/AbstractAddMissingImportsRefactoringProvider.cs index df26d9b289e2b..a798c3084bbc8 100644 --- a/src/Features/Core/Portable/CodeRefactorings/AddMissingImports/AbstractAddMissingImportsRefactoringProvider.cs +++ b/src/Features/Core/Portable/CodeRefactorings/AddMissingImports/AbstractAddMissingImportsRefactoringProvider.cs @@ -7,14 +7,10 @@ using System; using System.Threading; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.AddImport; -using Microsoft.CodeAnalysis.CodeGeneration; +using Microsoft.CodeAnalysis.CodeCleanup; using Microsoft.CodeAnalysis.CodeRefactorings; -using Microsoft.CodeAnalysis.Completion; using Microsoft.CodeAnalysis.PasteTracking; using Microsoft.CodeAnalysis.Shared.Extensions; -using Microsoft.CodeAnalysis.Text; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.AddMissingImports { @@ -39,8 +35,10 @@ public override async Task ComputeRefactoringsAsync(CodeRefactoringContext conte // Check pasted text span for missing imports var addMissingImportsService = document.GetLanguageService(); - var placement = await AddImportPlacementOptions.FromDocumentAsync(document, cancellationToken).ConfigureAwait(false); - var options = new AddMissingImportsOptions(context.Options(document.Project.Language).HideAdvancedMembers, placement); + var cleanupOptions = await CodeCleanupOptions.FromDocumentAsync(document, fallbackOptions: null, cancellationToken).ConfigureAwait(false); + var options = new AddMissingImportsOptions( + cleanupOptions, + context.Options(document.Project.LanguageServices).HideAdvancedMembers); var analysis = await addMissingImportsService.AnalyzeAsync(document, textSpan, options, cancellationToken).ConfigureAwait(false); if (!analysis.CanAddMissingImports) diff --git a/src/Features/Core/Portable/CodeRefactorings/AddMissingImports/IAddMissingImportsFeatureService.cs b/src/Features/Core/Portable/CodeRefactorings/AddMissingImports/IAddMissingImportsFeatureService.cs index 7cb68cf7d3cd9..aa84f876128a4 100644 --- a/src/Features/Core/Portable/CodeRefactorings/AddMissingImports/IAddMissingImportsFeatureService.cs +++ b/src/Features/Core/Portable/CodeRefactorings/AddMissingImports/IAddMissingImportsFeatureService.cs @@ -5,8 +5,7 @@ using System.Runtime.Serialization; using System.Threading; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.AddImport; -using Microsoft.CodeAnalysis.CodeGeneration; +using Microsoft.CodeAnalysis.CodeCleanup; using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.Text; @@ -14,8 +13,8 @@ namespace Microsoft.CodeAnalysis.AddMissingImports { [DataContract] internal readonly record struct AddMissingImportsOptions( - [property: DataMember(Order = 0)] bool HideAdvancedMembers, - [property: DataMember(Order = 1)] AddImportPlacementOptions Placement); + [property: DataMember(Order = 0)] CodeCleanupOptions CleanupOptions, + [property: DataMember(Order = 1)] bool HideAdvancedMembers); internal interface IAddMissingImportsFeatureService : ILanguageService { diff --git a/src/Features/Core/Portable/CodeRefactorings/ExtractMethod/AbstractExtractMethodCodeRefactoringProvider.cs b/src/Features/Core/Portable/CodeRefactorings/ExtractMethod/AbstractExtractMethodCodeRefactoringProvider.cs index aae685a87be61..51aded52f3354 100644 --- a/src/Features/Core/Portable/CodeRefactorings/ExtractMethod/AbstractExtractMethodCodeRefactoringProvider.cs +++ b/src/Features/Core/Portable/CodeRefactorings/ExtractMethod/AbstractExtractMethodCodeRefactoringProvider.cs @@ -56,7 +56,7 @@ public override async Task ComputeRefactoringsAsync(CodeRefactoringContext conte return; } - var options = context.Options(document.Project.Language).ExtractMethodOptions; + var options = context.Options(document.Project.LanguageServices).ExtractMethodOptions; var actions = await GetCodeActionsAsync(document, textSpan, options, cancellationToken).ConfigureAwait(false); context.RegisterRefactorings(actions); } diff --git a/src/Features/Core/Portable/CodeRefactorings/SyncNamespace/AbstractChangeNamespaceService.cs b/src/Features/Core/Portable/CodeRefactorings/SyncNamespace/AbstractChangeNamespaceService.cs index 8e2fa98735110..1997d385a21f7 100644 --- a/src/Features/Core/Portable/CodeRefactorings/SyncNamespace/AbstractChangeNamespaceService.cs +++ b/src/Features/Core/Portable/CodeRefactorings/SyncNamespace/AbstractChangeNamespaceService.cs @@ -34,9 +34,9 @@ internal abstract class AbstractChangeNamespaceService : IChangeNamespaceService { public abstract Task CanChangeNamespaceAsync(Document document, SyntaxNode container, CancellationToken cancellationToken); - public abstract Task ChangeNamespaceAsync(Document document, SyntaxNode container, string targetNamespace, CancellationToken cancellationToken); + public abstract Task ChangeNamespaceAsync(Document document, SyntaxNode container, string targetNamespace, ChangeNamespaceOptionsProvider options, CancellationToken cancellationToken); - public abstract Task TryChangeTopLevelNamespacesAsync(Document document, string targetNamespace, CancellationToken cancellationToken); + public abstract Task TryChangeTopLevelNamespacesAsync(Document document, string targetNamespace, ChangeNamespaceOptionsProvider options, CancellationToken cancellationToken); /// /// Try to get a new node to replace given node, which is a reference to a top-level type declared inside the @@ -110,6 +110,7 @@ public override async Task CanChangeNamespaceAsync(Document document, Synt public override async Task TryChangeTopLevelNamespacesAsync( Document document, string targetNamespace, + ChangeNamespaceOptionsProvider options, CancellationToken cancellationToken) { var syntaxFacts = document.GetRequiredLanguageService(); @@ -151,7 +152,7 @@ public override async Task CanChangeNamespaceAsync(Document document, Synt Debug.Assert(namespaces.Length == originalNamespaceDeclarations.Length); var namespaceToRename = namespaces[i]; - solution = await ChangeNamespaceAsync(document, namespaceToRename, targetNamespace, cancellationToken).ConfigureAwait(false); + solution = await ChangeNamespaceAsync(document, namespaceToRename, targetNamespace, options, cancellationToken).ConfigureAwait(false); document = solution.GetRequiredDocument(document.Id); } @@ -172,6 +173,7 @@ public override async Task ChangeNamespaceAsync( Document document, SyntaxNode container, string targetNamespace, + ChangeNamespaceOptionsProvider options, CancellationToken cancellationToken) { // Make sure given namespace name is valid, "" means global namespace. @@ -220,7 +222,7 @@ public override async Task ChangeNamespaceAsync( foreach (var documentId in documentIds) { var (newSolution, refDocumentIds) = - await ChangeNamespaceInSingleDocumentAsync(solutionAfterNamespaceChange, documentId, declaredNamespace, targetNamespace, cancellationToken) + await ChangeNamespaceInSingleDocumentAsync(solutionAfterNamespaceChange, documentId, declaredNamespace, targetNamespace, options, cancellationToken) .ConfigureAwait(false); solutionAfterNamespaceChange = newSolution; referenceDocuments.AddRange(refDocumentIds); @@ -426,6 +428,7 @@ private static SyntaxNode CreateImport(SyntaxGenerator syntaxGenerator, string n DocumentId id, string oldNamespace, string newNamespace, + ChangeNamespaceOptionsProvider options, CancellationToken cancellationToken) { var document = solution.GetRequiredDocument(id); @@ -462,7 +465,7 @@ private static SyntaxNode CreateImport(SyntaxGenerator syntaxGenerator, string n } } - var documentWithNewNamespace = await FixDeclarationDocumentAsync(document, refLocationsInCurrentDocument, oldNamespace, newNamespace, cancellationToken) + var documentWithNewNamespace = await FixDeclarationDocumentAsync(document, refLocationsInCurrentDocument, oldNamespace, newNamespace, options, cancellationToken) .ConfigureAwait(false); var solutionWithChangedNamespace = documentWithNewNamespace.Project.Solution; @@ -474,6 +477,7 @@ private static SyntaxNode CreateImport(SyntaxGenerator syntaxGenerator, string n solutionWithChangedNamespace.GetRequiredDocument(refInOneDocument.Key), refInOneDocument, newNamespace, + options, cancellationToken))).ConfigureAwait(false); var solutionWithFixedReferences = await MergeDocumentChangesAsync(solutionWithChangedNamespace, fixedDocuments, cancellationToken).ConfigureAwait(false); @@ -558,6 +562,7 @@ private async Task FixDeclarationDocumentAsync( IReadOnlyList refLocations, string oldNamespace, string newNamespace, + ChangeNamespaceOptionsProvider options, CancellationToken cancellationToken) { Debug.Assert(newNamespace != null); @@ -606,15 +611,14 @@ private async Task FixDeclarationDocumentAsync( // references to the type inside it's new namespace var namesToImport = GetAllNamespaceImportsForDeclaringDocument(oldNamespace, newNamespace); - var optionSet = await document.GetOptionsAsync(cancellationToken).ConfigureAwait(false); - var addImportsOptions = await AddImportPlacementOptions.FromDocumentAsync(document, cancellationToken).ConfigureAwait(false); + var documentOptions = await ChangeNamespaceOptions.FromDocumentAsync(document, options(document.Project.LanguageServices), cancellationToken).ConfigureAwait(false); var documentWithAddedImports = await AddImportsInContainersAsync( document, addImportService, containersToAddImports, namesToImport, - addImportsOptions, + documentOptions.AddImportOptions, cancellationToken).ConfigureAwait(false); var root = await documentWithAddedImports.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); @@ -624,18 +628,18 @@ private async Task FixDeclarationDocumentAsync( // Need to invoke formatter explicitly since we are doing the diff merge ourselves. var services = documentWithAddedImports.Project.Solution.Workspace.Services; - var formattingOptions = SyntaxFormattingOptions.Create(optionSet, services, root.Language); - root = Formatter.Format(root, Formatter.Annotation, services, formattingOptions, cancellationToken); + root = Formatter.Format(root, Formatter.Annotation, services, documentOptions.FormattingOptions, cancellationToken); root = root.WithAdditionalAnnotations(Simplifier.Annotation); var formattedDocument = documentWithAddedImports.WithSyntaxRoot(root); - return await Simplifier.ReduceAsync(formattedDocument, optionSet, cancellationToken).ConfigureAwait(false); + return await Simplifier.ReduceAsync(formattedDocument, documentOptions.SimplifierOptions, cancellationToken).ConfigureAwait(false); } private static async Task FixReferencingDocumentAsync( Document document, IEnumerable refLocations, string newNamespace, + ChangeNamespaceOptionsProvider options, CancellationToken cancellationToken) { // 1. Fully qualify all simple references (i.e. not via an alias) with new namespace. @@ -651,23 +655,21 @@ private static async Task FixReferencingDocumentAsync( await FixReferencesAsync(document, changeNamespaceService, addImportService, refLocations, newNamespaceParts, cancellationToken) .ConfigureAwait(false); - var formattingOptions = await SyntaxFormattingOptions.FromDocumentAsync(document, cancellationToken).ConfigureAwait(false); - var addImportsOptions = await AddImportPlacementOptions.FromDocumentAsync(document, cancellationToken).ConfigureAwait(false); + var documentOptions = await ChangeNamespaceOptions.FromDocumentAsync(document, options(document.Project.LanguageServices), cancellationToken).ConfigureAwait(false); var documentWithAdditionalImports = await AddImportsInContainersAsync( documentWithRefFixed, addImportService, containers, ImmutableArray.Create(newNamespace), - addImportsOptions, + documentOptions.AddImportOptions, cancellationToken).ConfigureAwait(false); // Need to invoke formatter explicitly since we are doing the diff merge ourselves. - var formattedDocument = await Formatter.FormatAsync(documentWithAdditionalImports, Formatter.Annotation, formattingOptions, cancellationToken) + var formattedDocument = await Formatter.FormatAsync(documentWithAdditionalImports, Formatter.Annotation, documentOptions.FormattingOptions, cancellationToken) .ConfigureAwait(false); - var optionSet = await document.GetOptionsAsync(cancellationToken).ConfigureAwait(false); - return await Simplifier.ReduceAsync(formattedDocument, optionSet, cancellationToken).ConfigureAwait(false); + return await Simplifier.ReduceAsync(formattedDocument, documentOptions.SimplifierOptions, cancellationToken).ConfigureAwait(false); } /// diff --git a/src/Features/Core/Portable/CodeRefactorings/SyncNamespace/AbstractSyncNamespaceCodeRefactoringProvider.cs b/src/Features/Core/Portable/CodeRefactorings/SyncNamespace/AbstractSyncNamespaceCodeRefactoringProvider.cs index 95d0fb8d24e5e..678198a141e9c 100644 --- a/src/Features/Core/Portable/CodeRefactorings/SyncNamespace/AbstractSyncNamespaceCodeRefactoringProvider.cs +++ b/src/Features/Core/Portable/CodeRefactorings/SyncNamespace/AbstractSyncNamespaceCodeRefactoringProvider.cs @@ -73,7 +73,7 @@ public override async Task ComputeRefactoringsAsync(CodeRefactoringContext conte state.TargetNamespace.Length == 0 ? FeaturesResources.Change_to_global_namespace : string.Format(FeaturesResources.Change_namespace_to_0, state.TargetNamespace), - token => service.ChangeNamespaceAsync(document, state.Container, state.TargetNamespace, token)); + token => service.ChangeNamespaceAsync(document, state.Container, state.TargetNamespace, ChangeNamespaceOptions.CreateProvider(context.Options), token)); context.RegisterRefactoring(solutionChangeAction, textSpan); } diff --git a/src/Features/Core/Portable/Completion/Providers/AbstractMemberInsertingCompletionProvider.cs b/src/Features/Core/Portable/Completion/Providers/AbstractMemberInsertingCompletionProvider.cs index 8e4c0d35092ae..fb0a718f0f008 100644 --- a/src/Features/Core/Portable/Completion/Providers/AbstractMemberInsertingCompletionProvider.cs +++ b/src/Features/Core/Portable/Completion/Providers/AbstractMemberInsertingCompletionProvider.cs @@ -6,6 +6,7 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; +using Microsoft.CodeAnalysis.CodeCleanup; using Microsoft.CodeAnalysis.CodeGeneration; using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.LanguageServices; @@ -85,9 +86,9 @@ private async Task DetermineNewDocumentAsync(Document document, Comple return document; } - var memberContainingDocumentFormattingOptions = await SyntaxFormattingOptions.FromDocumentAsync(document, cancellationToken).ConfigureAwait(false); - var insertionRoot = await GetTreeWithAddedSyntaxNodeRemovedAsync(memberContainingDocument, memberContainingDocumentFormattingOptions, cancellationToken).ConfigureAwait(false); - var insertionText = await GenerateInsertionTextAsync(memberContainingDocument, memberContainingDocumentFormattingOptions, cancellationToken).ConfigureAwait(false); + var memberContainingDocumentCleanupOptions = await CodeCleanupOptions.FromDocumentAsync(document, fallbackOptions: null, cancellationToken).ConfigureAwait(false); + var insertionRoot = await GetTreeWithAddedSyntaxNodeRemovedAsync(memberContainingDocument, memberContainingDocumentCleanupOptions, cancellationToken).ConfigureAwait(false); + var insertionText = await GenerateInsertionTextAsync(memberContainingDocument, memberContainingDocumentCleanupOptions, cancellationToken).ConfigureAwait(false); var destinationSpan = ComputeDestinationSpan(insertionRoot); @@ -179,21 +180,21 @@ private TextSpan ComputeDestinationSpan(SyntaxNode insertionRoot) } private async Task GenerateInsertionTextAsync( - Document memberContainingDocument, SyntaxFormattingOptions formattingOptions, CancellationToken cancellationToken) + Document memberContainingDocument, CodeCleanupOptions cleanupOptions, CancellationToken cancellationToken) { - memberContainingDocument = await Simplifier.ReduceAsync(memberContainingDocument, Simplifier.Annotation, optionSet: null, cancellationToken).ConfigureAwait(false); - memberContainingDocument = await Formatter.FormatAsync(memberContainingDocument, Formatter.Annotation, formattingOptions, cancellationToken).ConfigureAwait(false); + memberContainingDocument = await Simplifier.ReduceAsync(memberContainingDocument, Simplifier.Annotation, cleanupOptions.SimplifierOptions, cancellationToken).ConfigureAwait(false); + memberContainingDocument = await Formatter.FormatAsync(memberContainingDocument, Formatter.Annotation, cleanupOptions.FormattingOptions, cancellationToken).ConfigureAwait(false); var root = await memberContainingDocument.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); return root.GetAnnotatedNodes(_annotation).Single().ToString().Trim(); } private async Task GetTreeWithAddedSyntaxNodeRemovedAsync( - Document document, SyntaxFormattingOptions formattingOptions, CancellationToken cancellationToken) + Document document, CodeCleanupOptions cleanupOptions, CancellationToken cancellationToken) { // Added imports are annotated for simplification too. Therefore, we simplify the document // before removing added member node to preserve those imports in the document. - document = await Simplifier.ReduceAsync(document, Simplifier.Annotation, optionSet: null, cancellationToken).ConfigureAwait(false); + document = await Simplifier.ReduceAsync(document, Simplifier.Annotation, cleanupOptions.SimplifierOptions, cancellationToken).ConfigureAwait(false); var root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); var members = root.GetAnnotatedNodes(_annotation).AsImmutable(); @@ -203,7 +204,7 @@ private async Task GetTreeWithAddedSyntaxNodeRemovedAsync( var dismemberedDocument = document.WithSyntaxRoot(root); - dismemberedDocument = await Formatter.FormatAsync(dismemberedDocument, Formatter.Annotation, formattingOptions, cancellationToken).ConfigureAwait(false); + dismemberedDocument = await Formatter.FormatAsync(dismemberedDocument, Formatter.Annotation, cleanupOptions.FormattingOptions, cancellationToken).ConfigureAwait(false); return await dismemberedDocument.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); } diff --git a/src/Features/Core/Portable/EncapsulateField/AbstractEncapsulateFieldService.cs b/src/Features/Core/Portable/EncapsulateField/AbstractEncapsulateFieldService.cs index f7f7226721e08..5006dfb1f79df 100644 --- a/src/Features/Core/Portable/EncapsulateField/AbstractEncapsulateFieldService.cs +++ b/src/Features/Core/Portable/EncapsulateField/AbstractEncapsulateFieldService.cs @@ -32,7 +32,7 @@ internal abstract partial class AbstractEncapsulateFieldService : ILanguageServi protected abstract Task RewriteFieldNameAndAccessibilityAsync(string originalFieldName, bool makePrivate, Document document, SyntaxAnnotation declarationAnnotation, CancellationToken cancellationToken); protected abstract Task> GetFieldsAsync(Document document, TextSpan span, CancellationToken cancellationToken); - public async Task EncapsulateFieldsInSpanAsync(Document document, TextSpan span, bool useDefaultBehavior, CancellationToken cancellationToken) + public async Task EncapsulateFieldsInSpanAsync(Document document, TextSpan span, EncapsulateFieldOptions fallbackOptions, bool useDefaultBehavior, CancellationToken cancellationToken) { var fields = await GetFieldsAsync(document, span, cancellationToken).ConfigureAwait(false); if (fields.IsDefaultOrEmpty) @@ -42,10 +42,10 @@ public async Task EncapsulateFieldsInSpanAsync(Document return new EncapsulateFieldResult( firstField.ToDisplayString(), firstField.GetGlyph(), - c => EncapsulateFieldsAsync(document, fields, useDefaultBehavior, c)); + c => EncapsulateFieldsAsync(document, fields, fallbackOptions, useDefaultBehavior, c)); } - public async Task> GetEncapsulateFieldCodeActionsAsync(Document document, TextSpan span, CancellationToken cancellationToken) + public async Task> GetEncapsulateFieldCodeActionsAsync(Document document, TextSpan span, EncapsulateFieldOptions fallbackOptions, CancellationToken cancellationToken) { var fields = await GetFieldsAsync(document, span, cancellationToken).ConfigureAwait(false); if (fields.IsDefaultOrEmpty) @@ -54,7 +54,7 @@ public async Task> GetEncapsulateFieldCodeActionsAsyn if (fields.Length == 1) { // there is only one field - return EncapsulateOneField(document, fields[0]); + return EncapsulateOneField(document, fields[0], fallbackOptions); } // there are multiple fields. @@ -64,38 +64,39 @@ public async Task> GetEncapsulateFieldCodeActionsAsyn { // if there is no selection, get action for each field + all of them. foreach (var field in fields) - builder.AddRange(EncapsulateOneField(document, field)); + builder.AddRange(EncapsulateOneField(document, field, fallbackOptions)); } - builder.AddRange(EncapsulateAllFields(document, fields)); + builder.AddRange(EncapsulateAllFields(document, fields, fallbackOptions)); return builder.ToImmutable(); } - private ImmutableArray EncapsulateAllFields(Document document, ImmutableArray fields) + private ImmutableArray EncapsulateAllFields(Document document, ImmutableArray fields, EncapsulateFieldOptions fallbackOptions) { return ImmutableArray.Create( new MyCodeAction( FeaturesResources.Encapsulate_fields_and_use_property, - c => EncapsulateFieldsAsync(document, fields, updateReferences: true, c)), + c => EncapsulateFieldsAsync(document, fields, fallbackOptions, updateReferences: true, c)), new MyCodeAction( FeaturesResources.Encapsulate_fields_but_still_use_field, - c => EncapsulateFieldsAsync(document, fields, updateReferences: false, c))); + c => EncapsulateFieldsAsync(document, fields, fallbackOptions, updateReferences: false, c))); } - private ImmutableArray EncapsulateOneField(Document document, IFieldSymbol field) + private ImmutableArray EncapsulateOneField(Document document, IFieldSymbol field, EncapsulateFieldOptions fallbackOptions) { var fields = ImmutableArray.Create(field); return ImmutableArray.Create( new MyCodeAction( string.Format(FeaturesResources.Encapsulate_field_colon_0_and_use_property, field.Name), - c => EncapsulateFieldsAsync(document, fields, updateReferences: true, c)), + c => EncapsulateFieldsAsync(document, fields, fallbackOptions, updateReferences: true, c)), new MyCodeAction( string.Format(FeaturesResources.Encapsulate_field_colon_0_but_still_use_field, field.Name), - c => EncapsulateFieldsAsync(document, fields, updateReferences: false, c))); + c => EncapsulateFieldsAsync(document, fields, fallbackOptions, updateReferences: false, c))); } public async Task EncapsulateFieldsAsync( Document document, ImmutableArray fields, + EncapsulateFieldOptions fallbackOptions, bool updateReferences, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); @@ -110,7 +111,7 @@ public async Task EncapsulateFieldsAsync( var result = await client.TryInvokeAsync)>>( solution, - (service, solutionInfo, cancellationToken) => service.EncapsulateFieldsAsync(solutionInfo, document.Id, fieldSymbolKeys, updateReferences, cancellationToken), + (service, solutionInfo, cancellationToken) => service.EncapsulateFieldsAsync(solutionInfo, document.Id, fieldSymbolKeys, fallbackOptions, updateReferences, cancellationToken), cancellationToken).ConfigureAwait(false); if (!result.HasValue) @@ -124,10 +125,10 @@ public async Task EncapsulateFieldsAsync( } return await EncapsulateFieldsInCurrentProcessAsync( - document, fields, updateReferences, cancellationToken).ConfigureAwait(false); + document, fields, fallbackOptions, updateReferences, cancellationToken).ConfigureAwait(false); } - private async Task EncapsulateFieldsInCurrentProcessAsync(Document document, ImmutableArray fields, bool updateReferences, CancellationToken cancellationToken) + private async Task EncapsulateFieldsInCurrentProcessAsync(Document document, ImmutableArray fields, EncapsulateFieldOptions fallbackOptions, bool updateReferences, CancellationToken cancellationToken) { Contract.ThrowIfTrue(fields.Length == 0); @@ -143,7 +144,7 @@ private async Task EncapsulateFieldsInCurrentProcessAsync(Document doc if (field.GetSymbolKey(cancellationToken).Resolve(compilation, cancellationToken: cancellationToken).Symbol is not IFieldSymbol currentField) continue; - var nextSolution = await EncapsulateFieldAsync(document, currentField, updateReferences, cancellationToken).ConfigureAwait(false); + var nextSolution = await EncapsulateFieldAsync(document, currentField, updateReferences, fallbackOptions, cancellationToken).ConfigureAwait(false); if (nextSolution == null) continue; @@ -154,8 +155,11 @@ private async Task EncapsulateFieldsInCurrentProcessAsync(Document doc } private async Task EncapsulateFieldAsync( - Document document, IFieldSymbol field, - bool updateReferences, CancellationToken cancellationToken) + Document document, + IFieldSymbol field, + bool updateReferences, + EncapsulateFieldOptions fallbackOptions, + CancellationToken cancellationToken) { var originalField = field; var (finalFieldName, generatedPropertyName) = GenerateFieldAndPropertyNames(field); @@ -202,6 +206,7 @@ private async Task EncapsulateFieldAsync( var rewrittenFieldDeclaration = await RewriteFieldNameAndAccessibilityAsync(finalFieldName, markFieldPrivate, document, declarationAnnotation, cancellationToken).ConfigureAwait(false); var formattingOptions = await SyntaxFormattingOptions.FromDocumentAsync(document, cancellationToken).ConfigureAwait(false); + document = await Formatter.FormatAsync(document.WithSyntaxRoot(rewrittenFieldDeclaration), Formatter.Annotation, formattingOptions, cancellationToken).ConfigureAwait(false); solution = document.Project.Solution; @@ -231,8 +236,10 @@ private async Task EncapsulateFieldAsync( new SyntaxAnnotation(), document); + var simplifierOptions = await SimplifierOptions.FromDocumentAsync(document, fallbackOptions.SimplifierOptions, cancellationToken).ConfigureAwait(false); + var solutionWithProperty = await AddPropertyAsync( - document, document.Project.Solution, field, generatedProperty, formattingOptions, cancellationToken).ConfigureAwait(false); + document, document.Project.Solution, field, generatedProperty, formattingOptions, simplifierOptions, cancellationToken).ConfigureAwait(false); return solutionWithProperty; } @@ -318,7 +325,14 @@ private ISet GetConstructorLocations(INamedTypeSymbol containingType) internal abstract IEnumerable GetConstructorNodes(INamedTypeSymbol containingType); - protected static async Task AddPropertyAsync(Document document, Solution destinationSolution, IFieldSymbol field, IPropertySymbol property, SyntaxFormattingOptions formattingOptions, CancellationToken cancellationToken) + protected static async Task AddPropertyAsync( + Document document, + Solution destinationSolution, + IFieldSymbol field, + IPropertySymbol property, + SyntaxFormattingOptions formattingOptions, + SimplifierOptions simplifierOptions, + CancellationToken cancellationToken) { var codeGenerationService = document.GetLanguageService(); @@ -332,7 +346,7 @@ protected static async Task AddPropertyAsync(Document document, Soluti destinationSolution, destination, property, context, cancellationToken).ConfigureAwait(false); updatedDocument = await Formatter.FormatAsync(updatedDocument, Formatter.Annotation, formattingOptions, cancellationToken).ConfigureAwait(false); - updatedDocument = await Simplifier.ReduceAsync(updatedDocument, cancellationToken: cancellationToken).ConfigureAwait(false); + updatedDocument = await Simplifier.ReduceAsync(updatedDocument, simplifierOptions, cancellationToken).ConfigureAwait(false); return updatedDocument.Project.Solution; } diff --git a/src/Features/Core/Portable/EncapsulateField/EncapsulateFieldOptions.cs b/src/Features/Core/Portable/EncapsulateField/EncapsulateFieldOptions.cs new file mode 100644 index 0000000000000..29070875bebbd --- /dev/null +++ b/src/Features/Core/Portable/EncapsulateField/EncapsulateFieldOptions.cs @@ -0,0 +1,12 @@ +// 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.Runtime.Serialization; +using Microsoft.CodeAnalysis.Simplification; + +namespace Microsoft.CodeAnalysis.EncapsulateField; + +[DataContract] +internal readonly record struct EncapsulateFieldOptions( + [property: DataMember(Order = 0)] SimplifierOptions SimplifierOptions); diff --git a/src/Features/Core/Portable/EncapsulateField/EncapsulateFieldRefactoringProvider.cs b/src/Features/Core/Portable/EncapsulateField/EncapsulateFieldRefactoringProvider.cs index f936e59e6db14..606142d8928d1 100644 --- a/src/Features/Core/Portable/EncapsulateField/EncapsulateFieldRefactoringProvider.cs +++ b/src/Features/Core/Portable/EncapsulateField/EncapsulateFieldRefactoringProvider.cs @@ -26,7 +26,11 @@ public sealed override async Task ComputeRefactoringsAsync(CodeRefactoringContex { var (document, textSpan, cancellationToken) = context; var service = document.GetLanguageService(); - var actions = await service.GetEncapsulateFieldCodeActionsAsync(document, textSpan, cancellationToken).ConfigureAwait(false); + + var fallbackOptions = new EncapsulateFieldOptions( + SimplifierOptions: context.Options(document.Project.LanguageServices).SimplifierOptions); + + var actions = await service.GetEncapsulateFieldCodeActionsAsync(document, textSpan, fallbackOptions, cancellationToken).ConfigureAwait(false); context.RegisterRefactorings(actions); } } diff --git a/src/Features/Core/Portable/EncapsulateField/IRemoteEncapsulateFieldService.cs b/src/Features/Core/Portable/EncapsulateField/IRemoteEncapsulateFieldService.cs index ac5bbb3dbf8a0..aafe8d671de79 100644 --- a/src/Features/Core/Portable/EncapsulateField/IRemoteEncapsulateFieldService.cs +++ b/src/Features/Core/Portable/EncapsulateField/IRemoteEncapsulateFieldService.cs @@ -18,6 +18,7 @@ internal interface IRemoteEncapsulateFieldService PinnedSolutionInfo solutionInfo, DocumentId documentId, ImmutableArray fieldSymbolKeys, + EncapsulateFieldOptions fallbackOptions, bool updateReferences, CancellationToken cancellationToken); } diff --git a/src/Features/Core/Portable/ExtractInterface/AbstractExtractInterfaceService.cs b/src/Features/Core/Portable/ExtractInterface/AbstractExtractInterfaceService.cs index 0ea7726d5142a..9e3b7d1021387 100644 --- a/src/Features/Core/Portable/ExtractInterface/AbstractExtractInterfaceService.cs +++ b/src/Features/Core/Portable/ExtractInterface/AbstractExtractInterfaceService.cs @@ -289,6 +289,7 @@ private static async Task GetFormattedSolutionAsync(Solution unformatt var document = formattedSolution.GetDocument(documentId); var formattingOptions = await SyntaxFormattingOptions.FromDocumentAsync(document, cancellationToken).ConfigureAwait(false); + var simplifierOptions = await SimplifierOptions.FromDocumentAsync(document, fallbackOptions: null, cancellationToken).ConfigureAwait(false); var formattedDocument = await Formatter.FormatAsync( document, @@ -299,7 +300,8 @@ private static async Task GetFormattedSolutionAsync(Solution unformatt var simplifiedDocument = await Simplifier.ReduceAsync( formattedDocument, Simplifier.Annotation, - cancellationToken: cancellationToken).ConfigureAwait(false); + simplifierOptions, + cancellationToken).ConfigureAwait(false); formattedSolution = simplifiedDocument.Project.Solution; } diff --git a/src/Features/Core/Portable/ExtractMethod/ExtractMethodResult.cs b/src/Features/Core/Portable/ExtractMethod/ExtractMethodResult.cs index b47327e345306..bc220976d354e 100644 --- a/src/Features/Core/Portable/ExtractMethod/ExtractMethodResult.cs +++ b/src/Features/Core/Portable/ExtractMethod/ExtractMethodResult.cs @@ -8,6 +8,7 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; +using Microsoft.CodeAnalysis.CodeCleanup; using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.Formatting.Rules; using Microsoft.CodeAnalysis.Shared.Extensions; @@ -90,15 +91,16 @@ internal ExtractMethodResult( var root = await DocumentWithoutFinalFormatting.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); root = root.ReplaceToken(InvocationNameToken, InvocationNameToken.WithAdditionalAnnotations(annotation)); + var cleanupOptions = await CodeCleanupOptions.FromDocumentAsync(DocumentWithoutFinalFormatting, fallbackOptions: null, cancellationToken).ConfigureAwait(false); + var annotatedDocument = DocumentWithoutFinalFormatting.WithSyntaxRoot(root); - var simplifiedDocument = await Simplifier.ReduceAsync(annotatedDocument, Simplifier.Annotation, optionSet: null, cancellationToken).ConfigureAwait(false); + var simplifiedDocument = await Simplifier.ReduceAsync(annotatedDocument, Simplifier.Annotation, cleanupOptions.SimplifierOptions, cancellationToken).ConfigureAwait(false); var simplifiedRoot = await simplifiedDocument.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); - var options = await SyntaxFormattingOptions.FromDocumentAsync(DocumentWithoutFinalFormatting, cancellationToken).ConfigureAwait(false); var services = DocumentWithoutFinalFormatting.Project.Solution.Workspace.Services; var formattedDocument = simplifiedDocument.WithSyntaxRoot( - Formatter.Format(simplifiedRoot, Formatter.Annotation, services, options, FormattingRules, cancellationToken)); + Formatter.Format(simplifiedRoot, Formatter.Annotation, services, cleanupOptions.FormattingOptions, FormattingRules, cancellationToken)); var formattedRoot = await formattedDocument.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); return (formattedDocument, formattedRoot.GetAnnotatedTokens(annotation).Single()); diff --git a/src/Features/Core/Portable/Formatting/AbstractNewDocumentFormattingService.cs b/src/Features/Core/Portable/Formatting/AbstractNewDocumentFormattingService.cs index e7f59e6c693dc..15d06e7a3ce98 100644 --- a/src/Features/Core/Portable/Formatting/AbstractNewDocumentFormattingService.cs +++ b/src/Features/Core/Portable/Formatting/AbstractNewDocumentFormattingService.cs @@ -8,6 +8,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeActions; +using Microsoft.CodeAnalysis.CodeCleanup; using Microsoft.CodeAnalysis.ErrorReporting; using Microsoft.CodeAnalysis.Host.Mef; using Roslyn.Utilities; @@ -32,7 +33,7 @@ private IEnumerable GetProviders() return _providerValues; } - public async Task FormatNewDocumentAsync(Document document, Document? hintDocument, SyntaxFormattingOptions options, CancellationToken cancellationToken) + public async Task FormatNewDocumentAsync(Document document, Document? hintDocument, CodeCleanupOptions options, CancellationToken cancellationToken) { foreach (var provider in GetProviders()) { @@ -52,7 +53,7 @@ public async Task FormatNewDocumentAsync(Document document, Document? // before we call the next provider, otherwise they might not see things as they are meant to be. // Because formatting providers often re-use code fix logic, they are often written assuming this will // happen. - document = await CodeAction.CleanupDocumentAsync(document, cancellationToken).ConfigureAwait(false); + document = await CodeAction.CleanupDocumentAsync(document, options, cancellationToken).ConfigureAwait(false); } catch (Exception ex) when (FatalError.ReportAndCatchUnlessCanceled(ex, cancellationToken, ErrorSeverity.General)) { diff --git a/src/Features/Core/Portable/Formatting/INewDocumentFormattingProvider.cs b/src/Features/Core/Portable/Formatting/INewDocumentFormattingProvider.cs index 3012091569619..1612691204b45 100644 --- a/src/Features/Core/Portable/Formatting/INewDocumentFormattingProvider.cs +++ b/src/Features/Core/Portable/Formatting/INewDocumentFormattingProvider.cs @@ -4,12 +4,13 @@ using System.Threading; using System.Threading.Tasks; +using Microsoft.CodeAnalysis.CodeCleanup; namespace Microsoft.CodeAnalysis.Formatting { internal interface INewDocumentFormattingProvider { - /// - Task FormatNewDocumentAsync(Document document, Document? hintDocument, SyntaxFormattingOptions options, CancellationToken cancellationToken); + /// + Task FormatNewDocumentAsync(Document document, Document? hintDocument, CodeCleanupOptions options, CancellationToken cancellationToken); } } diff --git a/src/Features/Core/Portable/Formatting/INewDocumentFormattingService.cs b/src/Features/Core/Portable/Formatting/INewDocumentFormattingService.cs index 74b3452f825f7..80e6f58a7fdc5 100644 --- a/src/Features/Core/Portable/Formatting/INewDocumentFormattingService.cs +++ b/src/Features/Core/Portable/Formatting/INewDocumentFormattingService.cs @@ -4,6 +4,7 @@ using System.Threading; using System.Threading.Tasks; +using Microsoft.CodeAnalysis.CodeCleanup; using Microsoft.CodeAnalysis.Host; namespace Microsoft.CodeAnalysis.Formatting @@ -16,6 +17,6 @@ internal interface INewDocumentFormattingService : ILanguageService /// The document to format. /// An optional additional document that can be used to inform the formatting operation. /// A cancellation token. - Task FormatNewDocumentAsync(Document document, Document? hintDocument, SyntaxFormattingOptions options, CancellationToken cancellationToken); + Task FormatNewDocumentAsync(Document document, Document? hintDocument, CodeCleanupOptions options, CancellationToken cancellationToken); } } diff --git a/src/Features/Core/Portable/FullyQualify/AbstractFullyQualifyCodeFixProvider.cs b/src/Features/Core/Portable/FullyQualify/AbstractFullyQualifyCodeFixProvider.cs index 6b7f4a4bb3cf6..0d9a624da1027 100644 --- a/src/Features/Core/Portable/FullyQualify/AbstractFullyQualifyCodeFixProvider.cs +++ b/src/Features/Core/Portable/FullyQualify/AbstractFullyQualifyCodeFixProvider.cs @@ -63,7 +63,7 @@ public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) return; } - var hideAdvancedMembers = context.Options(document.Project.Language).HideAdvancedMembers; + var hideAdvancedMembers = context.Options(document.Project.LanguageServices).HideAdvancedMembers; var semanticModel = await document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false); var matchingTypes = await GetMatchingTypesAsync(document, semanticModel, node, hideAdvancedMembers, cancellationToken).ConfigureAwait(false); diff --git a/src/Features/Core/Portable/GenerateType/AbstractGenerateTypeService.Editor.cs b/src/Features/Core/Portable/GenerateType/AbstractGenerateTypeService.Editor.cs index 4daf9502e6281..42db6a142687a 100644 --- a/src/Features/Core/Portable/GenerateType/AbstractGenerateTypeService.Editor.cs +++ b/src/Features/Core/Portable/GenerateType/AbstractGenerateTypeService.Editor.cs @@ -13,6 +13,7 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CodeActions; +using Microsoft.CodeAnalysis.CodeCleanup; using Microsoft.CodeAnalysis.CodeGeneration; using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.LanguageServices; @@ -312,8 +313,8 @@ private async Task> GetGenerateInNewFileOperati var formattingService = newDocument.GetLanguageService(); if (formattingService is not null) { - var formattingOptions = await SyntaxFormattingOptions.FromDocumentAsync(_semanticDocument.Document, _cancellationToken).ConfigureAwait(false); - codeGenResult = await formattingService.FormatNewDocumentAsync(codeGenResult, _semanticDocument.Document, formattingOptions, _cancellationToken).ConfigureAwait(false); + var cleanupOptions = await CodeCleanupOptions.FromDocumentAsync(_semanticDocument.Document, fallbackOptions: null, _cancellationToken).ConfigureAwait(false); + codeGenResult = await formattingService.FormatNewDocumentAsync(codeGenResult, _semanticDocument.Document, cleanupOptions, _cancellationToken).ConfigureAwait(false); } } diff --git a/src/Features/Core/Portable/ImplementAbstractClass/AbstractImplementAbstractClassCodeFixProvider.cs b/src/Features/Core/Portable/ImplementAbstractClass/AbstractImplementAbstractClassCodeFixProvider.cs index b15c4fd3d2640..47e275514e026 100644 --- a/src/Features/Core/Portable/ImplementAbstractClass/AbstractImplementAbstractClassCodeFixProvider.cs +++ b/src/Features/Core/Portable/ImplementAbstractClass/AbstractImplementAbstractClassCodeFixProvider.cs @@ -42,7 +42,7 @@ public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) return; var data = await ImplementAbstractClassData.TryGetDataAsync( - document, classNode, GetClassIdentifier(classNode), context.Options(document.Project.Language).ImplementTypeOptions, cancellationToken).ConfigureAwait(false); + document, classNode, GetClassIdentifier(classNode), context.Options(document.Project.LanguageServices).ImplementTypeOptions, cancellationToken).ConfigureAwait(false); if (data == null) return; diff --git a/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceVariableService.AbstractIntroduceVariableCodeAction.cs b/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceVariableService.AbstractIntroduceVariableCodeAction.cs index 4d16d6b2d0f7f..38eb1732c5e5d 100644 --- a/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceVariableService.AbstractIntroduceVariableCodeAction.cs +++ b/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceVariableService.AbstractIntroduceVariableCodeAction.cs @@ -49,7 +49,8 @@ internal AbstractIntroduceVariableCodeAction( protected override async Task GetChangedDocumentAsync(CancellationToken cancellationToken) { var changedDocument = await GetChangedDocumentCoreAsync(cancellationToken).ConfigureAwait(false); - return await Simplifier.ReduceAsync(changedDocument, cancellationToken: cancellationToken).ConfigureAwait(false); + var simplifierOptions = await SimplifierOptions.FromDocumentAsync(changedDocument, fallbackOptions: null, cancellationToken).ConfigureAwait(false); + return await Simplifier.ReduceAsync(changedDocument, simplifierOptions, cancellationToken).ConfigureAwait(false); } private async Task GetChangedDocumentCoreAsync(CancellationToken cancellationToken) diff --git a/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceVariableService.IntroduceVariableAllOccurrenceCodeAction.cs b/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceVariableService.IntroduceVariableAllOccurrenceCodeAction.cs index b48273827f380..f3a6e31eafc5f 100644 --- a/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceVariableService.IntroduceVariableAllOccurrenceCodeAction.cs +++ b/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceVariableService.IntroduceVariableAllOccurrenceCodeAction.cs @@ -31,7 +31,9 @@ internal IntroduceVariableAllOccurrenceCodeAction( protected override async Task PostProcessChangesAsync(Document document, CancellationToken cancellationToken) { var formattingOptions = await SyntaxFormattingOptions.FromDocumentAsync(document, cancellationToken).ConfigureAwait(false); - document = await Simplifier.ReduceAsync(document, Simplifier.Annotation, cancellationToken: cancellationToken).ConfigureAwait(false); + var simplifierOptions = await SimplifierOptions.FromDocumentAsync(document, fallbackOptions: null, cancellationToken).ConfigureAwait(false); + + document = await Simplifier.ReduceAsync(document, Simplifier.Annotation, simplifierOptions, cancellationToken).ConfigureAwait(false); document = await Formatter.FormatAsync(document, Formatter.Annotation, formattingOptions, cancellationToken).ConfigureAwait(false); document = await CaseCorrector.CaseCorrectAsync(document, CaseCorrector.Annotation, cancellationToken).ConfigureAwait(false); return document; diff --git a/src/Features/Core/Portable/MetadataAsSource/AbstractMetadataAsSourceService.cs b/src/Features/Core/Portable/MetadataAsSource/AbstractMetadataAsSourceService.cs index 2f8aea25577e4..19f2619684215 100644 --- a/src/Features/Core/Portable/MetadataAsSource/AbstractMetadataAsSourceService.cs +++ b/src/Features/Core/Portable/MetadataAsSource/AbstractMetadataAsSourceService.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System; using System.Collections.Generic; using System.Collections.Immutable; @@ -24,15 +22,22 @@ namespace Microsoft.CodeAnalysis.MetadataAsSource { internal abstract partial class AbstractMetadataAsSourceService : IMetadataAsSourceService { - public async Task AddSourceToAsync(Document document, Compilation symbolCompilation, ISymbol symbol, SyntaxFormattingOptions formattingOptions, CancellationToken cancellationToken) + public async Task AddSourceToAsync( + Document document, + Compilation symbolCompilation, + ISymbol symbol, + SyntaxFormattingOptions formattingOptions, + SimplifierOptions simplifierOptions, + CancellationToken cancellationToken) { if (document == null) { throw new ArgumentNullException(nameof(document)); } - var newSemanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); - var rootNamespace = newSemanticModel.GetEnclosingNamespace(0, cancellationToken); + var newSemanticModel = await document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false); + var rootNamespace = newSemanticModel.GetEnclosingNamespace(position: 0, cancellationToken); + Contract.ThrowIfNull(rootNamespace); var context = new CodeGenerationContext( contextLocation: newSemanticModel.SyntaxTree.GetLocation(new TextSpan()), @@ -51,11 +56,11 @@ public async Task AddSourceToAsync(Document document, Compilation symb document = await AddNullableRegionsAsync(document, cancellationToken).ConfigureAwait(false); - var docCommentFormattingService = document.GetLanguageService(); + var docCommentFormattingService = document.GetRequiredLanguageService(); var docWithDocComments = await ConvertDocCommentsToRegularCommentsAsync(document, docCommentFormattingService, cancellationToken).ConfigureAwait(false); var docWithAssemblyInfo = await AddAssemblyInfoRegionAsync(docWithDocComments, symbolCompilation, symbol.GetOriginalUnreducedDefinition(), cancellationToken).ConfigureAwait(false); - var node = await docWithAssemblyInfo.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); + var node = await docWithAssemblyInfo.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); var formattedDoc = await Formatter.FormatAsync( docWithAssemblyInfo, @@ -65,7 +70,7 @@ public async Task AddSourceToAsync(Document document, Compilation symb cancellationToken).ConfigureAwait(false); var reducers = GetReducers(); - return await Simplifier.ReduceAsync(formattedDoc, reducers, null, cancellationToken).ConfigureAwait(false); + return await Simplifier.ReduceAsync(formattedDoc, reducers, simplifierOptions, cancellationToken).ConfigureAwait(false); } protected abstract Task AddNullableRegionsAsync(Document document, CancellationToken cancellationToken); @@ -99,7 +104,7 @@ private static INamespaceOrTypeSymbol CreateCodeGenerationSymbol(Document docume var topLevelNamespaceSymbol = symbol.ContainingNamespace; var topLevelNamedType = MetadataAsSourceHelpers.GetTopLevelContainingNamedType(symbol); - var canImplementImplicitly = document.GetLanguageService().SupportsImplicitInterfaceImplementation; + var canImplementImplicitly = document.GetRequiredLanguageService().SupportsImplicitInterfaceImplementation; var docCommentFormattingService = document.GetLanguageService(); INamespaceOrTypeSymbol wrappedType = new WrappedNamedTypeSymbol(topLevelNamedType, canImplementImplicitly, docCommentFormattingService); diff --git a/src/Features/Core/Portable/MetadataAsSource/DecompilationMetadataAsSourceFileProvider.cs b/src/Features/Core/Portable/MetadataAsSource/DecompilationMetadataAsSourceFileProvider.cs index 1387299960d96..79b25b8767313 100644 --- a/src/Features/Core/Portable/MetadataAsSource/DecompilationMetadataAsSourceFileProvider.cs +++ b/src/Features/Core/Portable/MetadataAsSource/DecompilationMetadataAsSourceFileProvider.cs @@ -16,6 +16,7 @@ using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Shared.Extensions; +using Microsoft.CodeAnalysis.Simplification; using Microsoft.CodeAnalysis.Text; using Roslyn.Utilities; @@ -79,6 +80,7 @@ public DecompilationMetadataAsSourceFileProvider() .GetRequiredDocument(temporaryProjectInfoAndDocumentId.Item2); var formattingOptions = await SyntaxFormattingOptions.FromDocumentAsync(temporaryDocument, cancellationToken).ConfigureAwait(false); + var simplifierOptions = await SimplifierOptions.FromDocumentAsync(temporaryDocument, options.SimplifierOptions, cancellationToken).ConfigureAwait(false); if (useDecompiler) { @@ -107,7 +109,7 @@ public DecompilationMetadataAsSourceFileProvider() if (!useDecompiler) { var sourceFromMetadataService = temporaryDocument.Project.LanguageServices.GetRequiredService(); - temporaryDocument = await sourceFromMetadataService.AddSourceToAsync(temporaryDocument, compilation, symbol, formattingOptions, cancellationToken).ConfigureAwait(false); + temporaryDocument = await sourceFromMetadataService.AddSourceToAsync(temporaryDocument, compilation, symbol, formattingOptions, simplifierOptions, cancellationToken).ConfigureAwait(false); } // We have the content, so write it out to disk diff --git a/src/Features/Core/Portable/MetadataAsSource/IMetadataAsSourceService.cs b/src/Features/Core/Portable/MetadataAsSource/IMetadataAsSourceService.cs index 7a032a04a219b..f8689f463c795 100644 --- a/src/Features/Core/Portable/MetadataAsSource/IMetadataAsSourceService.cs +++ b/src/Features/Core/Portable/MetadataAsSource/IMetadataAsSourceService.cs @@ -8,6 +8,7 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.Host; +using Microsoft.CodeAnalysis.Simplification; namespace Microsoft.CodeAnalysis.MetadataAsSource { @@ -23,6 +24,6 @@ internal interface IMetadataAsSourceService : ILanguageService /// The symbol to generate source for /// To cancel document operations /// The updated document - Task AddSourceToAsync(Document document, Compilation symbolCompilation, ISymbol symbol, SyntaxFormattingOptions formattingOptions, CancellationToken cancellationToken = default); + Task AddSourceToAsync(Document document, Compilation symbolCompilation, ISymbol symbol, SyntaxFormattingOptions formattingOptions, SimplifierOptions simplifierOptions, CancellationToken cancellationToken = default); } } diff --git a/src/Features/Core/Portable/MetadataAsSource/MetadataAsSourceOptions.cs b/src/Features/Core/Portable/MetadataAsSource/MetadataAsSourceOptions.cs index 2443af58b00c5..9b2f4313f6b15 100644 --- a/src/Features/Core/Portable/MetadataAsSource/MetadataAsSourceOptions.cs +++ b/src/Features/Core/Portable/MetadataAsSource/MetadataAsSourceOptions.cs @@ -2,6 +2,8 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using Microsoft.CodeAnalysis.Simplification; + namespace Microsoft.CodeAnalysis.MetadataAsSource { /// @@ -12,13 +14,14 @@ namespace Microsoft.CodeAnalysis.MetadataAsSource /// Whether navigation should try to use the default Microsoft and /// Nuget symbol servers regardless of debugger settings internal readonly record struct MetadataAsSourceOptions( + SimplifierOptions? SimplifierOptions = null, bool NavigateToDecompiledSources = true, bool AlwaysUseDefaultSymbolServers = true) { public static readonly MetadataAsSourceOptions Default = new(); public MetadataAsSourceOptions() - : this(NavigateToDecompiledSources: true) + : this(SimplifierOptions: null) { } } diff --git a/src/Features/Core/Portable/MoveToNamespace/AbstractMoveToNamespaceCodeAction.MoveItemsToNamespaceCodeAction.cs b/src/Features/Core/Portable/MoveToNamespace/AbstractMoveToNamespaceCodeAction.MoveItemsToNamespaceCodeAction.cs index a052948c87713..eef94890a6c15 100644 --- a/src/Features/Core/Portable/MoveToNamespace/AbstractMoveToNamespaceCodeAction.MoveItemsToNamespaceCodeAction.cs +++ b/src/Features/Core/Portable/MoveToNamespace/AbstractMoveToNamespaceCodeAction.MoveItemsToNamespaceCodeAction.cs @@ -2,6 +2,8 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using Microsoft.CodeAnalysis.ChangeNamespace; + namespace Microsoft.CodeAnalysis.MoveToNamespace { internal abstract partial class AbstractMoveToNamespaceCodeAction @@ -10,8 +12,8 @@ private class MoveItemsToNamespaceCodeAction : AbstractMoveToNamespaceCodeAction { public override string Title => FeaturesResources.Move_contents_to_namespace; - public MoveItemsToNamespaceCodeAction(IMoveToNamespaceService changeNamespaceService, MoveToNamespaceAnalysisResult analysisResult) - : base(changeNamespaceService, analysisResult) + public MoveItemsToNamespaceCodeAction(IMoveToNamespaceService changeNamespaceService, MoveToNamespaceAnalysisResult analysisResult, ChangeNamespaceOptionsProvider changeNamespaceOptions) + : base(changeNamespaceService, analysisResult, changeNamespaceOptions) { } } diff --git a/src/Features/Core/Portable/MoveToNamespace/AbstractMoveToNamespaceCodeAction.MoveTypeToNamespaceCodeAction.cs b/src/Features/Core/Portable/MoveToNamespace/AbstractMoveToNamespaceCodeAction.MoveTypeToNamespaceCodeAction.cs index 0c403a550a6cd..090fb8b058346 100644 --- a/src/Features/Core/Portable/MoveToNamespace/AbstractMoveToNamespaceCodeAction.MoveTypeToNamespaceCodeAction.cs +++ b/src/Features/Core/Portable/MoveToNamespace/AbstractMoveToNamespaceCodeAction.MoveTypeToNamespaceCodeAction.cs @@ -2,6 +2,8 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using Microsoft.CodeAnalysis.ChangeNamespace; + namespace Microsoft.CodeAnalysis.MoveToNamespace { internal abstract partial class AbstractMoveToNamespaceCodeAction @@ -10,8 +12,8 @@ private class MoveTypeToNamespaceCodeAction : AbstractMoveToNamespaceCodeAction { public override string Title => FeaturesResources.Move_to_namespace; - public MoveTypeToNamespaceCodeAction(IMoveToNamespaceService changeNamespaceService, MoveToNamespaceAnalysisResult analysisResult) - : base(changeNamespaceService, analysisResult) + public MoveTypeToNamespaceCodeAction(IMoveToNamespaceService changeNamespaceService, MoveToNamespaceAnalysisResult analysisResult, ChangeNamespaceOptionsProvider changeNamespaceOptions) + : base(changeNamespaceService, analysisResult, changeNamespaceOptions) { } } diff --git a/src/Features/Core/Portable/MoveToNamespace/AbstractMoveToNamespaceCodeAction.cs b/src/Features/Core/Portable/MoveToNamespace/AbstractMoveToNamespaceCodeAction.cs index 00534fe23c5bc..253db52b650e8 100644 --- a/src/Features/Core/Portable/MoveToNamespace/AbstractMoveToNamespaceCodeAction.cs +++ b/src/Features/Core/Portable/MoveToNamespace/AbstractMoveToNamespaceCodeAction.cs @@ -7,6 +7,7 @@ using System.Diagnostics; using System.Threading; using System.Threading.Tasks; +using Microsoft.CodeAnalysis.ChangeNamespace; using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeActions.WorkspaceServices; using Roslyn.Utilities; @@ -17,11 +18,13 @@ internal abstract partial class AbstractMoveToNamespaceCodeAction : CodeActionWi { private readonly IMoveToNamespaceService _moveToNamespaceService; private readonly MoveToNamespaceAnalysisResult _moveToNamespaceAnalysisResult; + private readonly ChangeNamespaceOptionsProvider _changeNamespaceOptions; - public AbstractMoveToNamespaceCodeAction(IMoveToNamespaceService moveToNamespaceService, MoveToNamespaceAnalysisResult analysisResult) + public AbstractMoveToNamespaceCodeAction(IMoveToNamespaceService moveToNamespaceService, MoveToNamespaceAnalysisResult analysisResult, ChangeNamespaceOptionsProvider changeNamespaceOptions) { _moveToNamespaceService = moveToNamespaceService; _moveToNamespaceAnalysisResult = analysisResult; + _changeNamespaceOptions = changeNamespaceOptions; } public override object GetOptions(CancellationToken cancellationToken) @@ -42,6 +45,7 @@ protected override async Task> ComputeOperation var moveToNamespaceResult = await _moveToNamespaceService.MoveToNamespaceAsync( _moveToNamespaceAnalysisResult, moveToNamespaceOptions.Namespace, + _changeNamespaceOptions, cancellationToken).ConfigureAwait(false); if (moveToNamespaceResult.Succeeded) @@ -81,11 +85,11 @@ private static ImmutableArray CreateRenameOperations(MoveTo return operations.ToImmutable(); } - public static AbstractMoveToNamespaceCodeAction Generate(IMoveToNamespaceService changeNamespaceService, MoveToNamespaceAnalysisResult analysisResult) + public static AbstractMoveToNamespaceCodeAction Generate(IMoveToNamespaceService changeNamespaceService, MoveToNamespaceAnalysisResult analysisResult, ChangeNamespaceOptionsProvider changeNamespaceOptions) => analysisResult.Container switch { - MoveToNamespaceAnalysisResult.ContainerType.NamedType => new MoveTypeToNamespaceCodeAction(changeNamespaceService, analysisResult), - MoveToNamespaceAnalysisResult.ContainerType.Namespace => new MoveItemsToNamespaceCodeAction(changeNamespaceService, analysisResult), + MoveToNamespaceAnalysisResult.ContainerType.NamedType => new MoveTypeToNamespaceCodeAction(changeNamespaceService, analysisResult, changeNamespaceOptions), + MoveToNamespaceAnalysisResult.ContainerType.Namespace => new MoveItemsToNamespaceCodeAction(changeNamespaceService, analysisResult, changeNamespaceOptions), _ => throw ExceptionUtilities.UnexpectedValue(analysisResult.Container) }; } diff --git a/src/Features/Core/Portable/MoveToNamespace/AbstractMoveToNamespaceService.cs b/src/Features/Core/Portable/MoveToNamespace/AbstractMoveToNamespaceService.cs index 11e92a4f545f9..c315c056424df 100644 --- a/src/Features/Core/Portable/MoveToNamespace/AbstractMoveToNamespaceService.cs +++ b/src/Features/Core/Portable/MoveToNamespace/AbstractMoveToNamespaceService.cs @@ -24,9 +24,9 @@ namespace Microsoft.CodeAnalysis.MoveToNamespace { internal interface IMoveToNamespaceService : ILanguageService { - Task> GetCodeActionsAsync(Document document, TextSpan span, CancellationToken cancellationToken); + Task> GetCodeActionsAsync(Document document, TextSpan span, ChangeNamespaceOptionsProvider options, CancellationToken cancellationToken); Task AnalyzeTypeAtPositionAsync(Document document, int position, CancellationToken cancellationToken); - Task MoveToNamespaceAsync(MoveToNamespaceAnalysisResult analysisResult, string targetNamespace, CancellationToken cancellationToken); + Task MoveToNamespaceAsync(MoveToNamespaceAnalysisResult analysisResult, string targetNamespace, ChangeNamespaceOptionsProvider options, CancellationToken cancellationToken); MoveToNamespaceOptionsResult GetChangeNamespaceOptions(Document document, string defaultNamespace, ImmutableArray namespaces); IMoveToNamespaceOptionsService OptionsService { get; } } @@ -49,6 +49,7 @@ protected AbstractMoveToNamespaceService(IMoveToNamespaceOptionsService moveToNa public async Task> GetCodeActionsAsync( Document document, TextSpan span, + ChangeNamespaceOptionsProvider changeNamespaceOptions, CancellationToken cancellationToken) { // Code actions cannot be completed without the options needed @@ -59,7 +60,7 @@ public async Task> GetCodeActi if (typeAnalysisResult.CanPerform) { - return ImmutableArray.Create(AbstractMoveToNamespaceCodeAction.Generate(this, typeAnalysisResult)); + return ImmutableArray.Create(AbstractMoveToNamespaceCodeAction.Generate(this, typeAnalysisResult, changeNamespaceOptions)); } } @@ -166,6 +167,7 @@ private static bool ContainsMultipleTypesInSpine(SyntaxNode node) public Task MoveToNamespaceAsync( MoveToNamespaceAnalysisResult analysisResult, string targetNamespace, + ChangeNamespaceOptionsProvider options, CancellationToken cancellationToken) { if (!analysisResult.CanPerform) @@ -175,8 +177,8 @@ public Task MoveToNamespaceAsync( return analysisResult.Container switch { - MoveToNamespaceAnalysisResult.ContainerType.Namespace => MoveItemsInNamespaceAsync(analysisResult.Document, analysisResult.SyntaxNode, targetNamespace, cancellationToken), - MoveToNamespaceAnalysisResult.ContainerType.NamedType => MoveTypeToNamespaceAsync(analysisResult.Document, analysisResult.SyntaxNode, targetNamespace, cancellationToken), + MoveToNamespaceAnalysisResult.ContainerType.Namespace => MoveItemsInNamespaceAsync(analysisResult.Document, analysisResult.SyntaxNode, targetNamespace, options, cancellationToken), + MoveToNamespaceAnalysisResult.ContainerType.NamedType => MoveTypeToNamespaceAsync(analysisResult.Document, analysisResult.SyntaxNode, targetNamespace, options, cancellationToken), _ => throw new InvalidOperationException(), }; } @@ -208,6 +210,7 @@ private static async Task MoveItemsInNamespaceAsync( Document document, SyntaxNode container, string targetNamespace, + ChangeNamespaceOptionsProvider options, CancellationToken cancellationToken) { var memberSymbols = await GetMemberSymbolsAsync(document, container, cancellationToken).ConfigureAwait(false); @@ -226,6 +229,7 @@ private static async Task MoveItemsInNamespaceAsync( document, container, targetNamespace, + options, cancellationToken).ConfigureAwait(false); return new MoveToNamespaceResult(originalSolution, changedSolution, document.Id, newNameOriginalSymbolMapping); @@ -235,6 +239,7 @@ private static async Task MoveTypeToNamespaceAsync( Document document, SyntaxNode container, string targetNamespace, + ChangeNamespaceOptionsProvider options, CancellationToken cancellationToken) { var moveTypeService = document.GetLanguageService(); @@ -272,6 +277,7 @@ private static async Task MoveTypeToNamespaceAsync( mergedDocument, syntaxNode, targetNamespace, + options, cancellationToken).ConfigureAwait(false); } diff --git a/src/Features/Core/Portable/MoveToNamespace/MoveToNamespaceCodeActionProvider.cs b/src/Features/Core/Portable/MoveToNamespace/MoveToNamespaceCodeActionProvider.cs index ad1bcf4f48095..9c0f902d9dfac 100644 --- a/src/Features/Core/Portable/MoveToNamespace/MoveToNamespaceCodeActionProvider.cs +++ b/src/Features/Core/Portable/MoveToNamespace/MoveToNamespaceCodeActionProvider.cs @@ -7,6 +7,7 @@ using System.Composition; using System.Diagnostics.CodeAnalysis; using System.Threading.Tasks; +using Microsoft.CodeAnalysis.ChangeNamespace; using Microsoft.CodeAnalysis.CodeRefactorings; using Microsoft.CodeAnalysis.Shared.Extensions; @@ -27,7 +28,7 @@ public override async Task ComputeRefactoringsAsync(CodeRefactoringContext conte { var (document, textSpan, cancellationToken) = context; var moveToNamespaceService = document.GetLanguageService(); - var actions = await moveToNamespaceService.GetCodeActionsAsync(document, textSpan, cancellationToken).ConfigureAwait(false); + var actions = await moveToNamespaceService.GetCodeActionsAsync(document, textSpan, ChangeNamespaceOptions.CreateProvider(context.Options), cancellationToken).ConfigureAwait(false); context.RegisterRefactorings(actions); } } diff --git a/src/Features/Core/Portable/Shared/Utilities/ExtractTypeHelpers.cs b/src/Features/Core/Portable/Shared/Utilities/ExtractTypeHelpers.cs index 1a1ef00e6a0ac..ed6501cd2ea4c 100644 --- a/src/Features/Core/Portable/Shared/Utilities/ExtractTypeHelpers.cs +++ b/src/Features/Core/Portable/Shared/Utilities/ExtractTypeHelpers.cs @@ -10,6 +10,7 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; +using Microsoft.CodeAnalysis.CodeCleanup; using Microsoft.CodeAnalysis.CodeGeneration; using Microsoft.CodeAnalysis.Editing; using Microsoft.CodeAnalysis.Formatting; @@ -87,12 +88,12 @@ internal static class ExtractTypeHelpers context, cancellationToken).ConfigureAwait(false); - var newTypeFormattingOptions = await SyntaxFormattingOptions.FromDocumentAsync(newTypeDocument, cancellationToken).ConfigureAwait(false); + var newCleanupOptions = await CodeCleanupOptions.FromDocumentAsync(newTypeDocument, fallbackOptions: null, cancellationToken).ConfigureAwait(false); var formattingService = newTypeDocument.GetLanguageService(); if (formattingService is not null) { - newTypeDocument = await formattingService.FormatNewDocumentAsync(newTypeDocument, hintDocument, newTypeFormattingOptions, cancellationToken).ConfigureAwait(false); + newTypeDocument = await formattingService.FormatNewDocumentAsync(newTypeDocument, hintDocument, newCleanupOptions, cancellationToken).ConfigureAwait(false); } var syntaxRoot = await newTypeDocument.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); @@ -105,8 +106,8 @@ internal static class ExtractTypeHelpers newTypeDocument = newTypeDocument.WithSyntaxRoot(annotatedRoot); - var simplified = await Simplifier.ReduceAsync(newTypeDocument, cancellationToken: cancellationToken).ConfigureAwait(false); - var formattedDocument = await Formatter.FormatAsync(simplified, newTypeFormattingOptions, cancellationToken).ConfigureAwait(false); + var simplified = await Simplifier.ReduceAsync(newTypeDocument, newCleanupOptions.SimplifierOptions, cancellationToken).ConfigureAwait(false); + var formattedDocument = await Formatter.FormatAsync(simplified, newCleanupOptions.FormattingOptions, cancellationToken).ConfigureAwait(false); return (formattedDocument, typeAnnotation); } diff --git a/src/Features/Core/Portable/SimplifyThisOrMe/AbstractSimplifyThisOrMeDiagnosticAnalyzer.cs b/src/Features/Core/Portable/SimplifyThisOrMe/AbstractSimplifyThisOrMeDiagnosticAnalyzer.cs index 737e5dfc062d8..74d29d3be55fd 100644 --- a/src/Features/Core/Portable/SimplifyThisOrMe/AbstractSimplifyThisOrMeDiagnosticAnalyzer.cs +++ b/src/Features/Core/Portable/SimplifyThisOrMe/AbstractSimplifyThisOrMeDiagnosticAnalyzer.cs @@ -10,6 +10,7 @@ using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.QualifyMemberAccess; using Microsoft.CodeAnalysis.Shared.Extensions; +using Microsoft.CodeAnalysis.Simplification; using Microsoft.CodeAnalysis.Text; namespace Microsoft.CodeAnalysis.SimplifyThisOrMe @@ -18,12 +19,14 @@ internal abstract class AbstractSimplifyThisOrMeDiagnosticAnalyzer< TLanguageKindEnum, TExpressionSyntax, TThisExpressionSyntax, - TMemberAccessExpressionSyntax> : + TMemberAccessExpressionSyntax, + TSimplifierOptions> : AbstractBuiltInCodeStyleDiagnosticAnalyzer where TLanguageKindEnum : struct where TExpressionSyntax : SyntaxNode where TThisExpressionSyntax : TExpressionSyntax where TMemberAccessExpressionSyntax : TExpressionSyntax + where TSimplifierOptions : SimplifierOptions { private readonly ImmutableArray _kindsOfInterest; @@ -43,7 +46,7 @@ protected AbstractSimplifyThisOrMeDiagnosticAnalyzer() protected abstract ISyntaxFacts GetSyntaxFacts(); protected abstract bool CanSimplifyTypeNameExpression( - SemanticModel model, TMemberAccessExpressionSyntax memberAccess, OptionSet optionSet, out TextSpan issueSpan, CancellationToken cancellationToken); + SemanticModel model, TMemberAccessExpressionSyntax memberAccess, TSimplifierOptions options, out TextSpan issueSpan, CancellationToken cancellationToken); public override DiagnosticAnalyzerCategory GetAnalyzerCategory() => DiagnosticAnalyzerCategory.SemanticSpanAnalysis; @@ -51,6 +54,8 @@ public override DiagnosticAnalyzerCategory GetAnalyzerCategory() protected override void InitializeWorker(AnalysisContext context) => context.RegisterSyntaxNodeAction(AnalyzeNode, _kindsOfInterest); + protected abstract TSimplifierOptions GetSimplifierOptions(AnalyzerOptions options, SyntaxTree syntaxTree); + private void AnalyzeNode(SyntaxNodeAnalysisContext context) { var cancellationToken = context.CancellationToken; @@ -61,13 +66,13 @@ private void AnalyzeNode(SyntaxNodeAnalysisContext context) return; } - var analyzerOptions = context.Options; var syntaxTree = node.SyntaxTree; - var optionSet = analyzerOptions.GetAnalyzerOptionSet(syntaxTree, cancellationToken); + + var simplifierOptions = GetSimplifierOptions(context.Options, syntaxTree); var model = context.SemanticModel; if (!CanSimplifyTypeNameExpression( - model, expr, optionSet, out var issueSpan, cancellationToken)) + model, expr, simplifierOptions, out var issueSpan, cancellationToken)) { return; } @@ -83,8 +88,7 @@ private void AnalyzeNode(SyntaxNodeAnalysisContext context) return; } - var applicableOption = QualifyMembersHelpers.GetApplicableOptionFromSymbolKind(symbolInfo.Symbol.Kind); - var optionValue = optionSet.GetOption(applicableOption, model.Language); + var optionValue = simplifierOptions.QualifyMemberAccess(symbolInfo.Symbol.Kind); if (optionValue == null) { return; diff --git a/src/Features/Core/Portable/SimplifyTypeNames/AbstractSimplifyTypeNamesCodeFixProvider.cs b/src/Features/Core/Portable/SimplifyTypeNames/AbstractSimplifyTypeNamesCodeFixProvider.cs index d8f7c5d6900d8..c4048f8c26339 100644 --- a/src/Features/Core/Portable/SimplifyTypeNames/AbstractSimplifyTypeNamesCodeFixProvider.cs +++ b/src/Features/Core/Portable/SimplifyTypeNames/AbstractSimplifyTypeNamesCodeFixProvider.cs @@ -13,20 +13,21 @@ using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Editing; using Microsoft.CodeAnalysis.LanguageServices; -using Microsoft.CodeAnalysis.Options; +using Microsoft.CodeAnalysis.Simplification; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; namespace Microsoft.CodeAnalysis.SimplifyTypeNames { - internal abstract partial class AbstractSimplifyTypeNamesCodeFixProvider + internal abstract partial class AbstractSimplifyTypeNamesCodeFixProvider : SyntaxEditorBasedCodeFixProvider where TSyntaxKind : struct + where TSimplifierOptions : SimplifierOptions { - private readonly SimplifyTypeNamesDiagnosticAnalyzerBase _analyzer; + private readonly SimplifyTypeNamesDiagnosticAnalyzerBase _analyzer; protected AbstractSimplifyTypeNamesCodeFixProvider( - SimplifyTypeNamesDiagnosticAnalyzerBase analyzer) + SimplifyTypeNamesDiagnosticAnalyzerBase analyzer) { _analyzer = analyzer; } @@ -42,7 +43,7 @@ protected AbstractSimplifyTypeNamesCodeFixProvider( private (SyntaxNode, string diagnosticId) GetNodeToSimplify( SyntaxNode root, SemanticModel model, TextSpan span, - OptionSet optionSet, CancellationToken cancellationToken) + TSimplifierOptions options, CancellationToken cancellationToken) { var token = root.FindToken(span.Start, findInsideTrivia: true); if (!token.Span.IntersectsWith(span)) @@ -54,7 +55,7 @@ protected AbstractSimplifyTypeNamesCodeFixProvider( string topmostDiagnosticId = null; foreach (var node in token.GetAncestors()) { - if (node.Span.IntersectsWith(span) && CanSimplifyTypeNameExpression(model, node, optionSet, span, out var diagnosticId, cancellationToken)) + if (node.Span.IntersectsWith(span) && CanSimplifyTypeNameExpression(model, node, options, span, out var diagnosticId, cancellationToken)) { // keep overwriting the best simplifiable node as long as we keep finding them. topmostSimplifiableNode = node; @@ -79,10 +80,10 @@ public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); var model = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); - var documentOptions = await document.GetOptionsAsync(cancellationToken).ConfigureAwait(false); + var options = (TSimplifierOptions)await SimplifierOptions.FromDocumentAsync(document, context.Options(document.Project.LanguageServices).SimplifierOptions, cancellationToken).ConfigureAwait(false); var (node, diagnosticId) = GetNodeToSimplify( - root, model, span, documentOptions, cancellationToken); + root, model, span, options, cancellationToken); if (node == null) return; @@ -101,13 +102,13 @@ protected override async Task FixAllAsync( { var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); var model = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); - var documentOptions = await document.GetOptionsAsync(cancellationToken).ConfigureAwait(false); + var simplifierOptions = (TSimplifierOptions)await SimplifierOptions.FromDocumentAsync(document, options(document.Project.LanguageServices).SimplifierOptions, cancellationToken).ConfigureAwait(false); foreach (var diagnostic in diagnostics) { var (node, _) = GetNodeToSimplify( root, model, diagnostic.Location.SourceSpan, - documentOptions, cancellationToken); + simplifierOptions, cancellationToken); if (node == null) return; @@ -118,12 +119,12 @@ protected override async Task FixAllAsync( } } - private bool CanSimplifyTypeNameExpression(SemanticModel model, SyntaxNode node, OptionSet optionSet, TextSpan span, out string diagnosticId, CancellationToken cancellationToken) + private bool CanSimplifyTypeNameExpression(SemanticModel model, SyntaxNode node, TSimplifierOptions options, TextSpan span, out string diagnosticId, CancellationToken cancellationToken) { diagnosticId = null; if (!_analyzer.IsCandidate(node) || !_analyzer.CanSimplifyTypeNameExpression( - model, node, optionSet, out var issueSpan, out diagnosticId, out _, cancellationToken)) + model, node, options, out var issueSpan, out diagnosticId, out _, cancellationToken)) { return false; } diff --git a/src/Features/Core/Portable/SimplifyTypeNames/SimplifyTypeNamesDiagnosticAnalyzerBase.cs b/src/Features/Core/Portable/SimplifyTypeNames/SimplifyTypeNamesDiagnosticAnalyzerBase.cs index 31c955c328795..fe6393072ae8d 100644 --- a/src/Features/Core/Portable/SimplifyTypeNames/SimplifyTypeNamesDiagnosticAnalyzerBase.cs +++ b/src/Features/Core/Portable/SimplifyTypeNames/SimplifyTypeNamesDiagnosticAnalyzerBase.cs @@ -15,6 +15,7 @@ using Microsoft.CodeAnalysis.CodeStyle; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Options; +using Microsoft.CodeAnalysis.Simplification; using Microsoft.CodeAnalysis.Shared.Collections; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; @@ -27,7 +28,10 @@ namespace Microsoft.CodeAnalysis.SimplifyTypeNames { - internal abstract class SimplifyTypeNamesDiagnosticAnalyzerBase : DiagnosticAnalyzer, IBuiltInAnalyzer where TLanguageKindEnum : struct + internal abstract class SimplifyTypeNamesDiagnosticAnalyzerBase + : DiagnosticAnalyzer, IBuiltInAnalyzer + where TLanguageKindEnum : struct + where TSimplifierOptions : SimplifierOptions { #if LOG private static string _logFile = @"c:\temp\simplifytypenames.txt"; @@ -68,7 +72,7 @@ internal abstract class SimplifyTypeNamesDiagnosticAnalyzerBase> option; DiagnosticDescriptor descriptor; ReportDiagnostic severity; switch (diagnosticId) @@ -163,12 +166,11 @@ internal static Diagnostic CreateDiagnostic(SemanticModel model, OptionSet optio break; case IDEDiagnosticIds.PreferBuiltInOrFrameworkTypeDiagnosticId: - option = inDeclaration - ? CodeStyleOptions2.PreferIntrinsicPredefinedTypeKeywordInDeclaration - : CodeStyleOptions2.PreferIntrinsicPredefinedTypeKeywordInMemberAccess; - descriptor = s_descriptorPreferBuiltinOrFrameworkType; + var optionValue = inDeclaration + ? options.PreferPredefinedTypeKeywordInDeclaration + : options.PreferPredefinedTypeKeywordInMemberAccess; - var optionValue = optionSet.GetOption(option, model.Language)!; + descriptor = s_descriptorPreferBuiltinOrFrameworkType; severity = optionValue.Notification.Severity; break; default: @@ -210,7 +212,7 @@ public DiagnosticAnalyzerCategory GetAnalyzerCategory() private class AnalyzerImpl { - private readonly SimplifyTypeNamesDiagnosticAnalyzerBase _analyzer; + private readonly SimplifyTypeNamesDiagnosticAnalyzerBase _analyzer; /// /// Tracks the analysis state of syntax trees in a compilation. Each syntax tree has the properties: @@ -237,7 +239,7 @@ private class AnalyzerImpl private readonly ConcurrentDictionary completed, SimpleIntervalTree? intervalTree)> _codeBlockIntervals = new(); - public AnalyzerImpl(SimplifyTypeNamesDiagnosticAnalyzerBase analyzer) + public AnalyzerImpl(SimplifyTypeNamesDiagnosticAnalyzerBase analyzer) => _analyzer = analyzer; public void AnalyzeCodeBlock(CodeBlockAnalysisContext context) diff --git a/src/Features/Core/Portable/Snippets/SnippetFunctionService.cs b/src/Features/Core/Portable/Snippets/SnippetFunctionService.cs index 4aa7f180eb464..c2b59bfcd6899 100644 --- a/src/Features/Core/Portable/Snippets/SnippetFunctionService.cs +++ b/src/Features/Core/Portable/Snippets/SnippetFunctionService.cs @@ -35,7 +35,7 @@ internal abstract class SnippetFunctionService : ILanguageService /// For a specified snippet field, replace it with the fully qualified name then simplify in the context of the document /// in order to retrieve the simplified type name. /// - public static async Task GetSimplifiedTypeNameAsync(Document document, TextSpan fieldSpan, string fullyQualifiedTypeName, CancellationToken cancellationToken) + public static async Task GetSimplifiedTypeNameAsync(Document document, TextSpan fieldSpan, string fullyQualifiedTypeName, SimplifierOptions simplifierOptions, CancellationToken cancellationToken) { // Insert the function parameter (fully qualified type name) into the document. var updatedTextSpan = new TextSpan(fieldSpan.Start, fullyQualifiedTypeName.Length); @@ -45,7 +45,7 @@ internal abstract class SnippetFunctionService : ILanguageService var documentWithFullyQualifiedTypeName = document.WithText(text.WithChanges(textChange)); // Simplify - var simplifiedTypeName = await GetSimplifiedTypeNameAtSpanAsync(documentWithFullyQualifiedTypeName, updatedTextSpan, cancellationToken).ConfigureAwait(false); + var simplifiedTypeName = await GetSimplifiedTypeNameAtSpanAsync(documentWithFullyQualifiedTypeName, updatedTextSpan, simplifierOptions, cancellationToken).ConfigureAwait(false); return simplifiedTypeName; } @@ -53,7 +53,7 @@ internal abstract class SnippetFunctionService : ILanguageService /// For a document with the default switch snippet inserted, generate the expanded set of cases based on the value /// of the field currently inserted into the switch statement. /// - public async Task GetSwitchExpansionAsync(Document document, TextSpan caseGenerationLocation, TextSpan switchExpressionLocation, CancellationToken cancellationToken) + public async Task GetSwitchExpansionAsync(Document document, TextSpan caseGenerationLocation, TextSpan switchExpressionLocation, SimplifierOptions simplifierOptions, CancellationToken cancellationToken) { var typeSymbol = await GetEnumSymbolAsync(document, switchExpressionLocation, cancellationToken).ConfigureAwait(false); if (typeSymbol?.TypeKind != TypeKind.Enum) @@ -69,7 +69,7 @@ internal abstract class SnippetFunctionService : ILanguageService // Find and use the most simplified legal version of the enum type name in this context var fullyQualifiedEnumName = typeSymbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat); - var simplifiedTypeName = await GetSimplifiedEnumNameAsync(document, fullyQualifiedEnumName, enumFields.First().Name, caseGenerationLocation, cancellationToken).ConfigureAwait(false); + var simplifiedTypeName = await GetSimplifiedEnumNameAsync(document, fullyQualifiedEnumName, enumFields.First().Name, caseGenerationLocation, simplifierOptions, cancellationToken).ConfigureAwait(false); if (simplifiedTypeName == null) { return null; @@ -126,17 +126,18 @@ public static bool TryGetSnippetFunctionInfo( string fullyQualifiedTypeName, string firstEnumMemberName, TextSpan caseGenerationLocation, + SimplifierOptions simplifierOptions, CancellationToken cancellationToken) { // Insert switch with enum case into the document. var (documentWithFullyQualified, fullyQualifiedTypeLocation) = await GetDocumentWithEnumCaseAsync(document, fullyQualifiedTypeName, firstEnumMemberName, caseGenerationLocation, cancellationToken).ConfigureAwait(false); // Simplify enum case. - var simplifiedEnum = await GetSimplifiedTypeNameAtSpanAsync(documentWithFullyQualified, fullyQualifiedTypeLocation, cancellationToken).ConfigureAwait(false); + var simplifiedEnum = await GetSimplifiedTypeNameAtSpanAsync(documentWithFullyQualified, fullyQualifiedTypeLocation, simplifierOptions, cancellationToken).ConfigureAwait(false); return simplifiedEnum; } - private static async Task GetSimplifiedTypeNameAtSpanAsync(Document documentWithFullyQualifiedTypeName, TextSpan fullyQualifiedTypeSpan, CancellationToken cancellationToken) + private static async Task GetSimplifiedTypeNameAtSpanAsync(Document documentWithFullyQualifiedTypeName, TextSpan fullyQualifiedTypeSpan, SimplifierOptions simplifierOptions, CancellationToken cancellationToken) { // Simplify var typeAnnotation = new SyntaxAnnotation(); @@ -151,7 +152,7 @@ public static bool TryGetSnippetFunctionInfo( var updatedRoot = syntaxRoot.ReplaceNode(nodeToReplace, nodeToReplace.WithAdditionalAnnotations(typeAnnotation, Simplifier.Annotation)); var documentWithAnnotations = documentWithFullyQualifiedTypeName.WithSyntaxRoot(updatedRoot); - var simplifiedDocument = await Simplifier.ReduceAsync(documentWithAnnotations, cancellationToken: cancellationToken).ConfigureAwait(false); + var simplifiedDocument = await Simplifier.ReduceAsync(documentWithAnnotations, simplifierOptions, cancellationToken).ConfigureAwait(false); var simplifiedRoot = await simplifiedDocument.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); var simplifiedTypeName = simplifiedRoot.GetAnnotatedNodesAndTokens(typeAnnotation).Single().ToString(); return simplifiedTypeName; diff --git a/src/Features/Core/Portable/SpellCheck/AbstractSpellCheckCodeFixProvider.cs b/src/Features/Core/Portable/SpellCheck/AbstractSpellCheckCodeFixProvider.cs index d2752c63438fc..fb8cf487ab84c 100644 --- a/src/Features/Core/Portable/SpellCheck/AbstractSpellCheckCodeFixProvider.cs +++ b/src/Features/Core/Portable/SpellCheck/AbstractSpellCheckCodeFixProvider.cs @@ -118,7 +118,7 @@ private async Task CreateSpellCheckCodeIssueAsync( // - We believe spell-check should only compare what you have typed to what symbol would be offered here. var options = CompletionOptions.Default with { - HideAdvancedMembers = context.Options(document.Project.Language).HideAdvancedMembers, + HideAdvancedMembers = context.Options(document.Project.LanguageServices).HideAdvancedMembers, SnippetsBehavior = SnippetsRule.NeverInclude, ShowItemsFromUnimportedNamespaces = false, TargetTypedCompletionFilter = false, diff --git a/src/Features/Core/Portable/Wrapping/AbstractWrappingCodeRefactoringProvider.cs b/src/Features/Core/Portable/Wrapping/AbstractWrappingCodeRefactoringProvider.cs index f0e74dbfd704b..d54d2493c0e7c 100644 --- a/src/Features/Core/Portable/Wrapping/AbstractWrappingCodeRefactoringProvider.cs +++ b/src/Features/Core/Portable/Wrapping/AbstractWrappingCodeRefactoringProvider.cs @@ -45,7 +45,7 @@ public override async Task ComputeRefactoringsAsync(CodeRefactoringContext conte var token = root.FindToken(position); var configOptions = await document.GetAnalyzerConfigOptionsAsync(cancellationToken).ConfigureAwait(false); - var options = GetWrappingOptions(configOptions, context.Options(document.Project.Language)); + var options = GetWrappingOptions(configOptions, context.Options(document.Project.LanguageServices)); foreach (var node in token.GetRequiredParent().AncestorsAndSelf()) { diff --git a/src/Features/LanguageServer/Protocol/Features/Diagnostics/DefaultDiagnosticAnalyzerService.cs b/src/Features/LanguageServer/Protocol/Features/Diagnostics/DefaultDiagnosticAnalyzerService.cs index 5544664855183..a4ad7569e739b 100644 --- a/src/Features/LanguageServer/Protocol/Features/Diagnostics/DefaultDiagnosticAnalyzerService.cs +++ b/src/Features/LanguageServer/Protocol/Features/Diagnostics/DefaultDiagnosticAnalyzerService.cs @@ -162,7 +162,7 @@ private async Task> GetDiagnosticsAsync( if (analyzers.IsEmpty) return ImmutableArray.Empty; - var ideOptions = _service._globalOptions.GetIdeAnalyzerOptions(project.Language); + var ideOptions = _service._globalOptions.GetIdeAnalyzerOptions(project); var compilationWithAnalyzers = await DocumentAnalysisExecutor.CreateCompilationWithAnalyzersAsync( project, ideOptions, analyzers, includeSuppressedDiagnostics: false, cancellationToken).ConfigureAwait(false); diff --git a/src/Features/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.CompilationManager.cs b/src/Features/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.CompilationManager.cs index d8aadbc4882b4..7c343d558a941 100644 --- a/src/Features/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.CompilationManager.cs +++ b/src/Features/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.CompilationManager.cs @@ -24,7 +24,7 @@ internal partial class DiagnosticIncrementalAnalyzer return null; } - var ideOptions = AnalyzerService.GlobalOptions.GetIdeAnalyzerOptions(project.Language); + var ideOptions = AnalyzerService.GlobalOptions.GetIdeAnalyzerOptions(project); if (_projectCompilationsWithAnalyzers.TryGetValue(project, out var compilationWithAnalyzers) && ((WorkspaceAnalyzerOptions)compilationWithAnalyzers!.AnalysisOptions.Options!).IdeOptions == ideOptions) diff --git a/src/Features/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer_GetDiagnostics.cs b/src/Features/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer_GetDiagnostics.cs index cd7f50098eb14..9fa626514040f 100644 --- a/src/Features/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer_GetDiagnostics.cs +++ b/src/Features/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer_GetDiagnostics.cs @@ -260,7 +260,7 @@ protected override async Task AppendDiagnosticsAsync(Project project, IEnumerabl // get analyzers that are not suppressed. var stateSets = StateManager.GetOrCreateStateSets(project).Where(s => ShouldIncludeStateSet(project, s)).ToImmutableArrayOrEmpty(); - var ideOptions = Owner.AnalyzerService.GlobalOptions.GetIdeAnalyzerOptions(project.Language); + var ideOptions = Owner.AnalyzerService.GlobalOptions.GetIdeAnalyzerOptions(project); // unlike the suppressed (disabled) analyzer, we will include hidden diagnostic only analyzers here. var compilation = await CreateCompilationWithAnalyzersAsync(project, ideOptions, stateSets, IncludeSuppressedDiagnostics, cancellationToken).ConfigureAwait(false); diff --git a/src/Features/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer_GetDiagnosticsForSpan.cs b/src/Features/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer_GetDiagnosticsForSpan.cs index 99f77ca564dad..dff2ea6da5a2f 100644 --- a/src/Features/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer_GetDiagnosticsForSpan.cs +++ b/src/Features/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer_GetDiagnosticsForSpan.cs @@ -88,7 +88,7 @@ public static async Task CreateAsync( var stateSets = owner._stateManager .GetOrCreateStateSets(document.Project).Where(s => DocumentAnalysisExecutor.IsAnalyzerEnabledForProject(s.Analyzer, document.Project, owner.GlobalOptions)); - var ideOptions = owner.AnalyzerService.GlobalOptions.GetIdeAnalyzerOptions(document.Project.Language); + var ideOptions = owner.AnalyzerService.GlobalOptions.GetIdeAnalyzerOptions(document.Project); var compilationWithAnalyzers = await GetOrCreateCompilationWithAnalyzersAsync(document.Project, ideOptions, stateSets, includeSuppressedDiagnostics, cancellationToken).ConfigureAwait(false); diff --git a/src/Features/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer_IncrementalAnalyzer.cs b/src/Features/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer_IncrementalAnalyzer.cs index 3d62cdbd54389..73b8f5c895116 100644 --- a/src/Features/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer_IncrementalAnalyzer.cs +++ b/src/Features/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer_IncrementalAnalyzer.cs @@ -146,7 +146,7 @@ private async Task AnalyzeProjectAsync(Project project, bool forceAnalyzerRun, C .Where(a => DocumentAnalysisExecutor.IsAnalyzerEnabledForProject(a, project, GlobalOptions) && !a.IsOpenFileOnly(options)); // get driver only with active analyzers. - var ideOptions = AnalyzerService.GlobalOptions.GetIdeAnalyzerOptions(project.Language); + var ideOptions = AnalyzerService.GlobalOptions.GetIdeAnalyzerOptions(project); var compilationWithAnalyzers = await DocumentAnalysisExecutor.CreateCompilationWithAnalyzersAsync(project, ideOptions, activeAnalyzers, includeSuppressedDiagnostics: true, cancellationToken).ConfigureAwait(false); diff --git a/src/Features/Core/Portable/Options/AutoFormattingOptionsStorage.cs b/src/Features/LanguageServer/Protocol/Features/Options/AutoFormattingOptionsStorage.cs similarity index 98% rename from src/Features/Core/Portable/Options/AutoFormattingOptionsStorage.cs rename to src/Features/LanguageServer/Protocol/Features/Options/AutoFormattingOptionsStorage.cs index 3626ea10265a7..92bf0bd3401c6 100644 --- a/src/Features/Core/Portable/Options/AutoFormattingOptionsStorage.cs +++ b/src/Features/LanguageServer/Protocol/Features/Options/AutoFormattingOptionsStorage.cs @@ -6,8 +6,6 @@ namespace Microsoft.CodeAnalysis.Formatting; -// TODO: move to LSP layer - internal static class AutoFormattingOptionsStorage { public static AutoFormattingOptions GetAutoFormattingOptions(this IGlobalOptionService globalOptions, string language) diff --git a/src/Features/LanguageServer/Protocol/Features/Options/BlockStructureOptionsStorage.cs b/src/Features/LanguageServer/Protocol/Features/Options/BlockStructureOptionsStorage.cs index ab630ee962014..0dd1f2832a658 100644 --- a/src/Features/LanguageServer/Protocol/Features/Options/BlockStructureOptionsStorage.cs +++ b/src/Features/LanguageServer/Protocol/Features/Options/BlockStructureOptionsStorage.cs @@ -4,57 +4,56 @@ using Microsoft.CodeAnalysis.Options; -namespace Microsoft.CodeAnalysis.Structure +namespace Microsoft.CodeAnalysis.Structure; + +internal static class BlockStructureOptionsStorage { - internal static class BlockStructureOptionsStorage - { - public static BlockStructureOptions GetBlockStructureOptions(this IGlobalOptionService globalOptions, Project project) - => GetBlockStructureOptions(globalOptions, project.Language, isMetadataAsSource: project.Solution.Workspace.Kind == WorkspaceKind.MetadataAsSource); - - public static BlockStructureOptions GetBlockStructureOptions(this IGlobalOptionService globalOptions, string language, bool isMetadataAsSource) - => new( - ShowBlockStructureGuidesForCommentsAndPreprocessorRegions: globalOptions.GetOption(ShowBlockStructureGuidesForCommentsAndPreprocessorRegions, language), - ShowBlockStructureGuidesForDeclarationLevelConstructs: globalOptions.GetOption(ShowBlockStructureGuidesForDeclarationLevelConstructs, language), - ShowBlockStructureGuidesForCodeLevelConstructs: globalOptions.GetOption(ShowBlockStructureGuidesForCodeLevelConstructs, language), - ShowOutliningForCommentsAndPreprocessorRegions: globalOptions.GetOption(ShowOutliningForCommentsAndPreprocessorRegions, language), - ShowOutliningForDeclarationLevelConstructs: globalOptions.GetOption(ShowOutliningForDeclarationLevelConstructs, language), - ShowOutliningForCodeLevelConstructs: globalOptions.GetOption(ShowOutliningForCodeLevelConstructs, language), - CollapseRegionsWhenCollapsingToDefinitions: globalOptions.GetOption(CollapseRegionsWhenCollapsingToDefinitions, language), - MaximumBannerLength: globalOptions.GetOption(MaximumBannerLength, language), - IsMetadataAsSource: isMetadataAsSource); - - private const string FeatureName = "BlockStructureOptions"; - - public static readonly PerLanguageOption2 ShowBlockStructureGuidesForCommentsAndPreprocessorRegions = new( - FeatureName, "ShowBlockStructureGuidesForCommentsAndPreprocessorRegions", BlockStructureOptions.Default.ShowBlockStructureGuidesForCommentsAndPreprocessorRegions, - storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.ShowBlockStructureGuidesForCommentsAndPreprocessorRegions")); - - public static readonly PerLanguageOption2 ShowBlockStructureGuidesForDeclarationLevelConstructs = new( - FeatureName, "ShowBlockStructureGuidesForDeclarationLevelConstructs", BlockStructureOptions.Default.ShowBlockStructureGuidesForDeclarationLevelConstructs, - storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.ShowBlockStructureGuidesForDeclarationLevelConstructs")); - - public static readonly PerLanguageOption2 ShowBlockStructureGuidesForCodeLevelConstructs = new( - FeatureName, "ShowBlockStructureGuidesForCodeLevelConstructs", BlockStructureOptions.Default.ShowBlockStructureGuidesForCodeLevelConstructs, - storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.ShowBlockStructureGuidesForCodeLevelConstructs")); - - public static readonly PerLanguageOption2 ShowOutliningForCommentsAndPreprocessorRegions = new( - FeatureName, "ShowOutliningForCommentsAndPreprocessorRegions", BlockStructureOptions.Default.ShowOutliningForCommentsAndPreprocessorRegions, - storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.ShowOutliningForCommentsAndPreprocessorRegions")); - - public static readonly PerLanguageOption2 ShowOutliningForDeclarationLevelConstructs = new( - FeatureName, "ShowOutliningForDeclarationLevelConstructs", BlockStructureOptions.Default.ShowOutliningForDeclarationLevelConstructs, - storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.ShowOutliningForDeclarationLevelConstructs")); - - public static readonly PerLanguageOption2 ShowOutliningForCodeLevelConstructs = new( - FeatureName, "ShowOutliningForCodeLevelConstructs", BlockStructureOptions.Default.ShowOutliningForCodeLevelConstructs, - storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.ShowOutliningForCodeLevelConstructs")); - - public static readonly PerLanguageOption2 CollapseRegionsWhenCollapsingToDefinitions = new( - FeatureName, "CollapseRegionsWhenCollapsingToDefinitions", BlockStructureOptions.Default.CollapseRegionsWhenCollapsingToDefinitions, - storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.CollapseRegionsWhenCollapsingToDefinitions")); - - public static readonly PerLanguageOption2 MaximumBannerLength = new( - FeatureName, "MaximumBannerLength", BlockStructureOptions.Default.MaximumBannerLength, - storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.MaximumBannerLength")); - } + public static BlockStructureOptions GetBlockStructureOptions(this IGlobalOptionService globalOptions, Project project) + => GetBlockStructureOptions(globalOptions, project.Language, isMetadataAsSource: project.Solution.Workspace.Kind == WorkspaceKind.MetadataAsSource); + + public static BlockStructureOptions GetBlockStructureOptions(this IGlobalOptionService globalOptions, string language, bool isMetadataAsSource) + => new( + ShowBlockStructureGuidesForCommentsAndPreprocessorRegions: globalOptions.GetOption(ShowBlockStructureGuidesForCommentsAndPreprocessorRegions, language), + ShowBlockStructureGuidesForDeclarationLevelConstructs: globalOptions.GetOption(ShowBlockStructureGuidesForDeclarationLevelConstructs, language), + ShowBlockStructureGuidesForCodeLevelConstructs: globalOptions.GetOption(ShowBlockStructureGuidesForCodeLevelConstructs, language), + ShowOutliningForCommentsAndPreprocessorRegions: globalOptions.GetOption(ShowOutliningForCommentsAndPreprocessorRegions, language), + ShowOutliningForDeclarationLevelConstructs: globalOptions.GetOption(ShowOutliningForDeclarationLevelConstructs, language), + ShowOutliningForCodeLevelConstructs: globalOptions.GetOption(ShowOutliningForCodeLevelConstructs, language), + CollapseRegionsWhenCollapsingToDefinitions: globalOptions.GetOption(CollapseRegionsWhenCollapsingToDefinitions, language), + MaximumBannerLength: globalOptions.GetOption(MaximumBannerLength, language), + IsMetadataAsSource: isMetadataAsSource); + + private const string FeatureName = "BlockStructureOptions"; + + public static readonly PerLanguageOption2 ShowBlockStructureGuidesForCommentsAndPreprocessorRegions = new( + FeatureName, "ShowBlockStructureGuidesForCommentsAndPreprocessorRegions", BlockStructureOptions.Default.ShowBlockStructureGuidesForCommentsAndPreprocessorRegions, + storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.ShowBlockStructureGuidesForCommentsAndPreprocessorRegions")); + + public static readonly PerLanguageOption2 ShowBlockStructureGuidesForDeclarationLevelConstructs = new( + FeatureName, "ShowBlockStructureGuidesForDeclarationLevelConstructs", BlockStructureOptions.Default.ShowBlockStructureGuidesForDeclarationLevelConstructs, + storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.ShowBlockStructureGuidesForDeclarationLevelConstructs")); + + public static readonly PerLanguageOption2 ShowBlockStructureGuidesForCodeLevelConstructs = new( + FeatureName, "ShowBlockStructureGuidesForCodeLevelConstructs", BlockStructureOptions.Default.ShowBlockStructureGuidesForCodeLevelConstructs, + storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.ShowBlockStructureGuidesForCodeLevelConstructs")); + + public static readonly PerLanguageOption2 ShowOutliningForCommentsAndPreprocessorRegions = new( + FeatureName, "ShowOutliningForCommentsAndPreprocessorRegions", BlockStructureOptions.Default.ShowOutliningForCommentsAndPreprocessorRegions, + storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.ShowOutliningForCommentsAndPreprocessorRegions")); + + public static readonly PerLanguageOption2 ShowOutliningForDeclarationLevelConstructs = new( + FeatureName, "ShowOutliningForDeclarationLevelConstructs", BlockStructureOptions.Default.ShowOutliningForDeclarationLevelConstructs, + storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.ShowOutliningForDeclarationLevelConstructs")); + + public static readonly PerLanguageOption2 ShowOutliningForCodeLevelConstructs = new( + FeatureName, "ShowOutliningForCodeLevelConstructs", BlockStructureOptions.Default.ShowOutliningForCodeLevelConstructs, + storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.ShowOutliningForCodeLevelConstructs")); + + public static readonly PerLanguageOption2 CollapseRegionsWhenCollapsingToDefinitions = new( + FeatureName, "CollapseRegionsWhenCollapsingToDefinitions", BlockStructureOptions.Default.CollapseRegionsWhenCollapsingToDefinitions, + storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.CollapseRegionsWhenCollapsingToDefinitions")); + + public static readonly PerLanguageOption2 MaximumBannerLength = new( + FeatureName, "MaximumBannerLength", BlockStructureOptions.Default.MaximumBannerLength, + storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.MaximumBannerLength")); } diff --git a/src/Features/LanguageServer/Protocol/Features/Options/ClassificationOptionsStorage.cs b/src/Features/LanguageServer/Protocol/Features/Options/ClassificationOptionsStorage.cs index f9e96a8b39750..15a80efaa3155 100644 --- a/src/Features/LanguageServer/Protocol/Features/Options/ClassificationOptionsStorage.cs +++ b/src/Features/LanguageServer/Protocol/Features/Options/ClassificationOptionsStorage.cs @@ -4,26 +4,25 @@ using Microsoft.CodeAnalysis.Options; -namespace Microsoft.CodeAnalysis.Classification +namespace Microsoft.CodeAnalysis.Classification; + +internal static class ClassificationOptionsStorage { - internal static class ClassificationOptionsStorage - { - public static ClassificationOptions GetClassificationOptions(this IGlobalOptionService globalOptions, string language) - => new( - ClassifyReassignedVariables: globalOptions.GetOption(ClassifyReassignedVariables, language), - ColorizeRegexPatterns: globalOptions.GetOption(ColorizeRegexPatterns, language), - ColorizeJsonPatterns: globalOptions.GetOption(ColorizeJsonPatterns, language)); + public static ClassificationOptions GetClassificationOptions(this IGlobalOptionService globalOptions, string language) + => new( + ClassifyReassignedVariables: globalOptions.GetOption(ClassifyReassignedVariables, language), + ColorizeRegexPatterns: globalOptions.GetOption(ColorizeRegexPatterns, language), + ColorizeJsonPatterns: globalOptions.GetOption(ColorizeJsonPatterns, language)); - public static PerLanguageOption2 ClassifyReassignedVariables = - new("ClassificationOptions", "ClassifyReassignedVariables", ClassificationOptions.Default.ClassifyReassignedVariables, - storageLocation: new RoamingProfileStorageLocation($"TextEditor.%LANGUAGE%.Specific.ClassificationOptions.ClassifyReassignedVariables")); + public static PerLanguageOption2 ClassifyReassignedVariables = + new("ClassificationOptions", "ClassifyReassignedVariables", ClassificationOptions.Default.ClassifyReassignedVariables, + storageLocation: new RoamingProfileStorageLocation($"TextEditor.%LANGUAGE%.Specific.ClassificationOptions.ClassifyReassignedVariables")); - public static PerLanguageOption2 ColorizeRegexPatterns = - new("RegularExpressionsOptions", "ColorizeRegexPatterns", ClassificationOptions.Default.ColorizeRegexPatterns, - storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.ColorizeRegexPatterns")); + public static PerLanguageOption2 ColorizeRegexPatterns = + new("RegularExpressionsOptions", "ColorizeRegexPatterns", ClassificationOptions.Default.ColorizeRegexPatterns, + storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.ColorizeRegexPatterns")); - public static PerLanguageOption2 ColorizeJsonPatterns = - new("JsonFeatureOptions", "ColorizeJsonPatterns", ClassificationOptions.Default.ColorizeJsonPatterns, - storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.ColorizeJsonPatterns")); - } + public static PerLanguageOption2 ColorizeJsonPatterns = + new("JsonFeatureOptions", "ColorizeJsonPatterns", ClassificationOptions.Default.ColorizeJsonPatterns, + storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.ColorizeJsonPatterns")); } diff --git a/src/Features/LanguageServer/Protocol/Features/Options/CompletionOptionsStorage.cs b/src/Features/LanguageServer/Protocol/Features/Options/CompletionOptionsStorage.cs index b08d6555cd385..90e9c1145c703 100644 --- a/src/Features/LanguageServer/Protocol/Features/Options/CompletionOptionsStorage.cs +++ b/src/Features/LanguageServer/Protocol/Features/Options/CompletionOptionsStorage.cs @@ -4,101 +4,100 @@ using Microsoft.CodeAnalysis.Options; -namespace Microsoft.CodeAnalysis.Completion +namespace Microsoft.CodeAnalysis.Completion; + +internal static class CompletionOptionsStorage { - internal static class CompletionOptionsStorage - { - public static CompletionOptions GetCompletionOptions(this IGlobalOptionService options, string language) - => new( - TriggerOnTyping: options.GetOption(TriggerOnTyping, language), - TriggerOnTypingLetters: options.GetOption(TriggerOnTypingLetters, language), - TriggerOnDeletion: options.GetOption(TriggerOnDeletion, language), - TriggerInArgumentLists: options.GetOption(TriggerInArgumentLists, language), - EnterKeyBehavior: options.GetOption(EnterKeyBehavior, language), - SnippetsBehavior: options.GetOption(SnippetsBehavior, language), - HideAdvancedMembers: options.GetOption(HideAdvancedMembers, language), - ShowNameSuggestions: options.GetOption(ShowNameSuggestions, language), - ShowItemsFromUnimportedNamespaces: options.GetOption(ShowItemsFromUnimportedNamespaces, language), - UnnamedSymbolCompletionDisabled: options.GetOption(UnnamedSymbolCompletionDisabledFeatureFlag), - TargetTypedCompletionFilter: options.GetOption(TargetTypedCompletionFilterFeatureFlag), - TypeImportCompletion: options.GetOption(TypeImportCompletionFeatureFlag), - ProvideDateAndTimeCompletions: options.GetOption(ProvideDateAndTimeCompletions, language), - ProvideRegexCompletions: options.GetOption(ProvideRegexCompletions, language), - ForceExpandedCompletionIndexCreation: options.GetOption(ForceExpandedCompletionIndexCreation), - UpdateImportCompletionCacheInBackground: options.GetOption(UpdateImportCompletionCacheInBackground)); - - // feature flags - - public static readonly Option2 TypeImportCompletionFeatureFlag = new(nameof(CompletionOptions), nameof(TypeImportCompletionFeatureFlag), - CompletionOptions.Default.TypeImportCompletion, - new FeatureFlagStorageLocation("Roslyn.TypeImportCompletion")); - - public static readonly Option2 TargetTypedCompletionFilterFeatureFlag = new(nameof(CompletionOptions), nameof(TargetTypedCompletionFilterFeatureFlag), - CompletionOptions.Default.TargetTypedCompletionFilter, - new FeatureFlagStorageLocation("Roslyn.TargetTypedCompletionFilter")); - - public static readonly Option2 UnnamedSymbolCompletionDisabledFeatureFlag = new(nameof(CompletionOptions), nameof(UnnamedSymbolCompletionDisabledFeatureFlag), - CompletionOptions.Default.UnnamedSymbolCompletionDisabled, - new FeatureFlagStorageLocation("Roslyn.UnnamedSymbolCompletionDisabled")); - - // This is serialized by the Visual Studio-specific LanguageSettingsPersister - public static readonly PerLanguageOption2 HideAdvancedMembers = new(nameof(CompletionOptions), nameof(HideAdvancedMembers), CompletionOptions.Default.HideAdvancedMembers); - - // This is serialized by the Visual Studio-specific LanguageSettingsPersister - public static readonly PerLanguageOption2 TriggerOnTyping = new(nameof(CompletionOptions), nameof(TriggerOnTyping), CompletionOptions.Default.TriggerOnTyping); - - public static readonly PerLanguageOption2 TriggerOnTypingLetters = new(nameof(CompletionOptions), nameof(TriggerOnTypingLetters), CompletionOptions.Default.TriggerOnTypingLetters, - storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.TriggerOnTypingLetters")); - - public static readonly PerLanguageOption2 TriggerOnDeletion = new(nameof(CompletionOptions), nameof(TriggerOnDeletion), CompletionOptions.Default.TriggerOnDeletion, - storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.TriggerOnDeletion")); - - public static readonly PerLanguageOption2 EnterKeyBehavior = - new(nameof(CompletionOptions), nameof(EnterKeyBehavior), CompletionOptions.Default.EnterKeyBehavior, - storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.EnterKeyBehavior")); - - public static readonly PerLanguageOption2 SnippetsBehavior = - new(nameof(CompletionOptions), nameof(SnippetsBehavior), CompletionOptions.Default.SnippetsBehavior, - storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.SnippetsBehavior")); - - public static readonly PerLanguageOption2 ShowNameSuggestions = - new(nameof(CompletionOptions), nameof(ShowNameSuggestions), CompletionOptions.Default.ShowNameSuggestions, - storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.ShowNameSuggestions")); - - //Dev16 options - - // Use tri-value so the default state can be used to turn on the feature with experimentation service. - public static readonly PerLanguageOption2 ShowItemsFromUnimportedNamespaces = - new(nameof(CompletionOptions), nameof(ShowItemsFromUnimportedNamespaces), CompletionOptions.Default.ShowItemsFromUnimportedNamespaces, - storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.ShowItemsFromUnimportedNamespaces")); - - public static readonly PerLanguageOption2 TriggerInArgumentLists = - new(nameof(CompletionOptions), nameof(TriggerInArgumentLists), CompletionOptions.Default.TriggerInArgumentLists, - storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.TriggerInArgumentLists")); - - // Test-only option - public static readonly Option2 ForceExpandedCompletionIndexCreation - = new(nameof(CompletionOptions), nameof(ForceExpandedCompletionIndexCreation), defaultValue: false); - - // Set to true to update import completion cache in background if the provider isn't supposed to be triggered in the context. - // (cache will alsways be refreshed when provider is triggered) - public static readonly Option2 UpdateImportCompletionCacheInBackground - = new(nameof(CompletionOptions), nameof(UpdateImportCompletionCacheInBackground), defaultValue: false); - - // Embedded languages: - - public static PerLanguageOption2 ProvideRegexCompletions = - new( - "RegularExpressionsOptions", - nameof(ProvideRegexCompletions), - CompletionOptions.Default.ProvideRegexCompletions, - storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.ProvideRegexCompletions")); - - public static readonly PerLanguageOption2 ProvideDateAndTimeCompletions = - new( - "DateAndTime", - nameof(ProvideDateAndTimeCompletions), - CompletionOptions.Default.ProvideDateAndTimeCompletions, - storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.ProvideDateAndTimeCompletions")); - } + public static CompletionOptions GetCompletionOptions(this IGlobalOptionService options, string language) + => new( + TriggerOnTyping: options.GetOption(TriggerOnTyping, language), + TriggerOnTypingLetters: options.GetOption(TriggerOnTypingLetters, language), + TriggerOnDeletion: options.GetOption(TriggerOnDeletion, language), + TriggerInArgumentLists: options.GetOption(TriggerInArgumentLists, language), + EnterKeyBehavior: options.GetOption(EnterKeyBehavior, language), + SnippetsBehavior: options.GetOption(SnippetsBehavior, language), + HideAdvancedMembers: options.GetOption(HideAdvancedMembers, language), + ShowNameSuggestions: options.GetOption(ShowNameSuggestions, language), + ShowItemsFromUnimportedNamespaces: options.GetOption(ShowItemsFromUnimportedNamespaces, language), + UnnamedSymbolCompletionDisabled: options.GetOption(UnnamedSymbolCompletionDisabledFeatureFlag), + TargetTypedCompletionFilter: options.GetOption(TargetTypedCompletionFilterFeatureFlag), + TypeImportCompletion: options.GetOption(TypeImportCompletionFeatureFlag), + ProvideDateAndTimeCompletions: options.GetOption(ProvideDateAndTimeCompletions, language), + ProvideRegexCompletions: options.GetOption(ProvideRegexCompletions, language), + ForceExpandedCompletionIndexCreation: options.GetOption(ForceExpandedCompletionIndexCreation), + UpdateImportCompletionCacheInBackground: options.GetOption(UpdateImportCompletionCacheInBackground)); + + // feature flags + + public static readonly Option2 TypeImportCompletionFeatureFlag = new(nameof(CompletionOptions), nameof(TypeImportCompletionFeatureFlag), + CompletionOptions.Default.TypeImportCompletion, + new FeatureFlagStorageLocation("Roslyn.TypeImportCompletion")); + + public static readonly Option2 TargetTypedCompletionFilterFeatureFlag = new(nameof(CompletionOptions), nameof(TargetTypedCompletionFilterFeatureFlag), + CompletionOptions.Default.TargetTypedCompletionFilter, + new FeatureFlagStorageLocation("Roslyn.TargetTypedCompletionFilter")); + + public static readonly Option2 UnnamedSymbolCompletionDisabledFeatureFlag = new(nameof(CompletionOptions), nameof(UnnamedSymbolCompletionDisabledFeatureFlag), + CompletionOptions.Default.UnnamedSymbolCompletionDisabled, + new FeatureFlagStorageLocation("Roslyn.UnnamedSymbolCompletionDisabled")); + + // This is serialized by the Visual Studio-specific LanguageSettingsPersister + public static readonly PerLanguageOption2 HideAdvancedMembers = new(nameof(CompletionOptions), nameof(HideAdvancedMembers), CompletionOptions.Default.HideAdvancedMembers); + + // This is serialized by the Visual Studio-specific LanguageSettingsPersister + public static readonly PerLanguageOption2 TriggerOnTyping = new(nameof(CompletionOptions), nameof(TriggerOnTyping), CompletionOptions.Default.TriggerOnTyping); + + public static readonly PerLanguageOption2 TriggerOnTypingLetters = new(nameof(CompletionOptions), nameof(TriggerOnTypingLetters), CompletionOptions.Default.TriggerOnTypingLetters, + storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.TriggerOnTypingLetters")); + + public static readonly PerLanguageOption2 TriggerOnDeletion = new(nameof(CompletionOptions), nameof(TriggerOnDeletion), CompletionOptions.Default.TriggerOnDeletion, + storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.TriggerOnDeletion")); + + public static readonly PerLanguageOption2 EnterKeyBehavior = + new(nameof(CompletionOptions), nameof(EnterKeyBehavior), CompletionOptions.Default.EnterKeyBehavior, + storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.EnterKeyBehavior")); + + public static readonly PerLanguageOption2 SnippetsBehavior = + new(nameof(CompletionOptions), nameof(SnippetsBehavior), CompletionOptions.Default.SnippetsBehavior, + storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.SnippetsBehavior")); + + public static readonly PerLanguageOption2 ShowNameSuggestions = + new(nameof(CompletionOptions), nameof(ShowNameSuggestions), CompletionOptions.Default.ShowNameSuggestions, + storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.ShowNameSuggestions")); + + //Dev16 options + + // Use tri-value so the default state can be used to turn on the feature with experimentation service. + public static readonly PerLanguageOption2 ShowItemsFromUnimportedNamespaces = + new(nameof(CompletionOptions), nameof(ShowItemsFromUnimportedNamespaces), CompletionOptions.Default.ShowItemsFromUnimportedNamespaces, + storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.ShowItemsFromUnimportedNamespaces")); + + public static readonly PerLanguageOption2 TriggerInArgumentLists = + new(nameof(CompletionOptions), nameof(TriggerInArgumentLists), CompletionOptions.Default.TriggerInArgumentLists, + storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.TriggerInArgumentLists")); + + // Test-only option + public static readonly Option2 ForceExpandedCompletionIndexCreation + = new(nameof(CompletionOptions), nameof(ForceExpandedCompletionIndexCreation), defaultValue: false); + + // Set to true to update import completion cache in background if the provider isn't supposed to be triggered in the context. + // (cache will alsways be refreshed when provider is triggered) + public static readonly Option2 UpdateImportCompletionCacheInBackground + = new(nameof(CompletionOptions), nameof(UpdateImportCompletionCacheInBackground), defaultValue: false); + + // Embedded languages: + + public static PerLanguageOption2 ProvideRegexCompletions = + new( + "RegularExpressionsOptions", + nameof(ProvideRegexCompletions), + CompletionOptions.Default.ProvideRegexCompletions, + storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.ProvideRegexCompletions")); + + public static readonly PerLanguageOption2 ProvideDateAndTimeCompletions = + new( + "DateAndTime", + nameof(ProvideDateAndTimeCompletions), + CompletionOptions.Default.ProvideDateAndTimeCompletions, + storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.ProvideDateAndTimeCompletions")); } diff --git a/src/Features/Core/Portable/Options/DocumentationCommentOptionsStorage.cs b/src/Features/LanguageServer/Protocol/Features/Options/DocumentationCommentOptionsStorage.cs similarity index 98% rename from src/Features/Core/Portable/Options/DocumentationCommentOptionsStorage.cs rename to src/Features/LanguageServer/Protocol/Features/Options/DocumentationCommentOptionsStorage.cs index 249bb5c4c3a24..d8018e8553bfd 100644 --- a/src/Features/Core/Portable/Options/DocumentationCommentOptionsStorage.cs +++ b/src/Features/LanguageServer/Protocol/Features/Options/DocumentationCommentOptionsStorage.cs @@ -7,8 +7,6 @@ namespace Microsoft.CodeAnalysis.DocumentationComments; -// TODO: move to LSP layer - internal static class DocumentationCommentOptionsStorage { public static DocumentationCommentOptions GetDocumentationCommentOptions(this IGlobalOptionService globalOptions, DocumentOptionSet documentOptions) diff --git a/src/Features/Core/Portable/Options/ExtractMethodOptionsStorage.cs b/src/Features/LanguageServer/Protocol/Features/Options/ExtractMethodOptionsStorage.cs similarity index 97% rename from src/Features/Core/Portable/Options/ExtractMethodOptionsStorage.cs rename to src/Features/LanguageServer/Protocol/Features/Options/ExtractMethodOptionsStorage.cs index 727319e2b558a..fa7f762a27208 100644 --- a/src/Features/Core/Portable/Options/ExtractMethodOptionsStorage.cs +++ b/src/Features/LanguageServer/Protocol/Features/Options/ExtractMethodOptionsStorage.cs @@ -6,7 +6,6 @@ namespace Microsoft.CodeAnalysis.ExtractMethod; -// TODO: move to LSP layer internal static class ExtractMethodOptionsStorage { public static ExtractMethodOptions GetExtractMethodOptions(this IGlobalOptionService globalOptions, string language) diff --git a/src/Features/Core/Portable/Options/HighlightingOptionsStorage.cs b/src/Features/LanguageServer/Protocol/Features/Options/HighlightingOptionsStorage.cs similarity index 98% rename from src/Features/Core/Portable/Options/HighlightingOptionsStorage.cs rename to src/Features/LanguageServer/Protocol/Features/Options/HighlightingOptionsStorage.cs index f73b7cf3db134..0b348595eba77 100644 --- a/src/Features/Core/Portable/Options/HighlightingOptionsStorage.cs +++ b/src/Features/LanguageServer/Protocol/Features/Options/HighlightingOptionsStorage.cs @@ -6,7 +6,6 @@ namespace Microsoft.CodeAnalysis.DocumentHighlighting; -// TODO: move to LSP layer internal static class HighlightingOptionsStorage { public static HighlightingOptions GetHighlightingOptions(this IGlobalOptionService globalOptions, string language) diff --git a/src/Features/Core/Portable/Options/IdeAnalyzerOptionsStorage.cs b/src/Features/LanguageServer/Protocol/Features/Options/IdeAnalyzerOptionsStorage.cs similarity index 88% rename from src/Features/Core/Portable/Options/IdeAnalyzerOptionsStorage.cs rename to src/Features/LanguageServer/Protocol/Features/Options/IdeAnalyzerOptionsStorage.cs index a9c50a709eaf4..3dac3a7484fba 100644 --- a/src/Features/Core/Portable/Options/IdeAnalyzerOptionsStorage.cs +++ b/src/Features/LanguageServer/Protocol/Features/Options/IdeAnalyzerOptionsStorage.cs @@ -3,21 +3,30 @@ // See the LICENSE file in the project root for more information. using Microsoft.CodeAnalysis.Options; +using Microsoft.CodeAnalysis.Simplification; +using Microsoft.CodeAnalysis.Host; namespace Microsoft.CodeAnalysis.Diagnostics; -// TODO: move to LSP layer internal static class IdeAnalyzerOptionsStorage { - public static IdeAnalyzerOptions GetIdeAnalyzerOptions(this IGlobalOptionService globalOptions, string language) - => new( + public static IdeAnalyzerOptions GetIdeAnalyzerOptions(this IGlobalOptionService globalOptions, Project project) + => GetIdeAnalyzerOptions(globalOptions, project.Solution.Workspace.Services, project.Language); + + public static IdeAnalyzerOptions GetIdeAnalyzerOptions(this IGlobalOptionService globalOptions, HostWorkspaceServices services, string language) + { + var provider = services.GetLanguageService(language); + + return new( CrashOnAnalyzerException: globalOptions.GetOption(CrashOnAnalyzerException), FadeOutUnusedImports: globalOptions.GetOption(FadeOutUnusedImports, language), FadeOutUnreachableCode: globalOptions.GetOption(FadeOutUnreachableCode, language), ReportInvalidPlaceholdersInStringDotFormatCalls: globalOptions.GetOption(ReportInvalidPlaceholdersInStringDotFormatCalls, language), ReportInvalidRegexPatterns: globalOptions.GetOption(ReportInvalidRegexPatterns, language), ReportInvalidJsonPatterns: globalOptions.GetOption(ReportInvalidJsonPatterns, language), - DetectAndOfferEditorFeaturesForProbableJsonStrings: globalOptions.GetOption(DetectAndOfferEditorFeaturesForProbableJsonStrings, language)); + DetectAndOfferEditorFeaturesForProbableJsonStrings: globalOptions.GetOption(DetectAndOfferEditorFeaturesForProbableJsonStrings, language), + SimplifierOptions: provider?.GetOptions(globalOptions)); + } // for testing only internal static void SetIdeAnalyzerOptions(this IGlobalOptionService globalOptions, string language, IdeAnalyzerOptions options) diff --git a/src/Features/Core/Portable/Options/IndentationOptionsStorage.cs b/src/Features/LanguageServer/Protocol/Features/Options/IndentationOptionsStorage.cs similarity index 97% rename from src/Features/Core/Portable/Options/IndentationOptionsStorage.cs rename to src/Features/LanguageServer/Protocol/Features/Options/IndentationOptionsStorage.cs index f120ebc5de9b2..0d69f6b4d20af 100644 --- a/src/Features/Core/Portable/Options/IndentationOptionsStorage.cs +++ b/src/Features/LanguageServer/Protocol/Features/Options/IndentationOptionsStorage.cs @@ -11,7 +11,6 @@ namespace Microsoft.CodeAnalysis.Indentation; internal static class IndentationOptionsStorage { - // TODO: move to LSP layer public static async Task GetIndentationOptionsAsync(this IGlobalOptionService globalOptions, Document document, CancellationToken cancellationToken) { var formattingOptions = await SyntaxFormattingOptions.FromDocumentAsync(document, cancellationToken).ConfigureAwait(false); diff --git a/src/Features/LanguageServer/Protocol/Features/Options/InternalDiagnosticsOptions.cs b/src/Features/LanguageServer/Protocol/Features/Options/InternalDiagnosticsOptions.cs index cb6f0bf50c15c..2be5ca07a6cf4 100644 --- a/src/Features/LanguageServer/Protocol/Features/Options/InternalDiagnosticsOptions.cs +++ b/src/Features/LanguageServer/Protocol/Features/Options/InternalDiagnosticsOptions.cs @@ -4,11 +4,10 @@ using Microsoft.CodeAnalysis.Options; -namespace Microsoft.CodeAnalysis.Diagnostics +namespace Microsoft.CodeAnalysis.Diagnostics; + +internal static class InternalDiagnosticsOptions { - internal static class InternalDiagnosticsOptions - { - public static readonly Option2 NormalDiagnosticMode = new("InternalDiagnosticsOptions", "NormalDiagnosticMode", defaultValue: DiagnosticMode.Default, - storageLocation: new LocalUserProfileStorageLocation(@"Roslyn\Internal\Diagnostics\NormalDiagnosticMode")); - } + public static readonly Option2 NormalDiagnosticMode = new("InternalDiagnosticsOptions", "NormalDiagnosticMode", defaultValue: DiagnosticMode.Default, + storageLocation: new LocalUserProfileStorageLocation(@"Roslyn\Internal\Diagnostics\NormalDiagnosticMode")); } diff --git a/src/Features/LanguageServer/Protocol/Features/Options/MetadataAsSourceOptionsStorage.cs b/src/Features/LanguageServer/Protocol/Features/Options/MetadataAsSourceOptionsStorage.cs index ee8e7e24bcb0c..c35d03e2b8613 100644 --- a/src/Features/LanguageServer/Protocol/Features/Options/MetadataAsSourceOptionsStorage.cs +++ b/src/Features/LanguageServer/Protocol/Features/Options/MetadataAsSourceOptionsStorage.cs @@ -2,28 +2,25 @@ // 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; -using System.Collections.Immutable; -using System.Composition; -using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.Options; -using Microsoft.CodeAnalysis.Options.Providers; +using Microsoft.CodeAnalysis.Simplification; -namespace Microsoft.CodeAnalysis.MetadataAsSource +namespace Microsoft.CodeAnalysis.MetadataAsSource; + +internal static class MetadataAsSourceOptionsStorage { - internal static class MetadataAsSourceOptionsStorage - { - public static MetadataAsSourceOptions GetMetadataAsSourceOptions(this IGlobalOptionService globalOptions) - => new( - NavigateToDecompiledSources: globalOptions.GetOption(NavigateToDecompiledSources), - AlwaysUseDefaultSymbolServers: globalOptions.GetOption(AlwaysUseDefaultSymbolServers)); + public static MetadataAsSourceOptions GetMetadataAsSourceOptions(this IGlobalOptionService globalOptions, HostLanguageServices languageServices) + => new( + SimplifierOptions: globalOptions.GetSimplifierOptions(languageServices), + NavigateToDecompiledSources: globalOptions.GetOption(NavigateToDecompiledSources), + AlwaysUseDefaultSymbolServers: globalOptions.GetOption(AlwaysUseDefaultSymbolServers)); - public static Option2 NavigateToDecompiledSources = - new("FeatureOnOffOptions", "NavigateToDecompiledSources", defaultValue: true, - storageLocation: new RoamingProfileStorageLocation($"TextEditor.NavigateToDecompiledSources")); + public static Option2 NavigateToDecompiledSources = + new("FeatureOnOffOptions", "NavigateToDecompiledSources", defaultValue: true, + storageLocation: new RoamingProfileStorageLocation($"TextEditor.NavigateToDecompiledSources")); - public static Option2 AlwaysUseDefaultSymbolServers = - new("FeatureOnOffOptions", "AlwaysUseDefaultSymbolServers", defaultValue: true, - storageLocation: new RoamingProfileStorageLocation($"TextEditor.AlwaysUseDefaultSymbolServers")); - } + public static Option2 AlwaysUseDefaultSymbolServers = + new("FeatureOnOffOptions", "AlwaysUseDefaultSymbolServers", defaultValue: true, + storageLocation: new RoamingProfileStorageLocation($"TextEditor.AlwaysUseDefaultSymbolServers")); } diff --git a/src/Features/LanguageServer/Protocol/Features/Options/SignatureHelpOptionsStorage.cs b/src/Features/LanguageServer/Protocol/Features/Options/SignatureHelpOptionsStorage.cs index 82c287f298695..7cf5d259cae15 100644 --- a/src/Features/LanguageServer/Protocol/Features/Options/SignatureHelpOptionsStorage.cs +++ b/src/Features/LanguageServer/Protocol/Features/Options/SignatureHelpOptionsStorage.cs @@ -5,12 +5,11 @@ using Microsoft.CodeAnalysis.Completion; using Microsoft.CodeAnalysis.Options; -namespace Microsoft.CodeAnalysis.SignatureHelp +namespace Microsoft.CodeAnalysis.SignatureHelp; + +internal static class SignatureHelpOptionsStorage { - internal static class SignatureHelpOptionsStorage - { - public static SignatureHelpOptions GetSignatureHelpOptions(this IGlobalOptionService globalOptions, string language) - => new( - HideAdvancedMembers: globalOptions.GetOption(CompletionOptionsStorage.HideAdvancedMembers, language)); - } + public static SignatureHelpOptions GetSignatureHelpOptions(this IGlobalOptionService globalOptions, string language) + => new( + HideAdvancedMembers: globalOptions.GetOption(CompletionOptionsStorage.HideAdvancedMembers, language)); } diff --git a/src/Features/LanguageServer/Protocol/Features/Options/SimplifierOptionsStorage.cs b/src/Features/LanguageServer/Protocol/Features/Options/SimplifierOptionsStorage.cs new file mode 100644 index 0000000000000..7fab81e6ef776 --- /dev/null +++ b/src/Features/LanguageServer/Protocol/Features/Options/SimplifierOptionsStorage.cs @@ -0,0 +1,24 @@ +// 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; +using Microsoft.CodeAnalysis.Options; + +namespace Microsoft.CodeAnalysis.Simplification; + +internal interface ISimplifierOptionsStorage : ILanguageService +{ + SimplifierOptions GetOptions(IGlobalOptionService globalOptions); +} + +internal static class SimplifierOptionsStorage +{ + public static Task GetSimplifierOptionsAsync(this Document document, IGlobalOptionService globalOptions, CancellationToken cancellationToken) + => SimplifierOptions.FromDocumentAsync(document, globalOptions.GetSimplifierOptions(document.Project.LanguageServices), cancellationToken); + + public static SimplifierOptions? GetSimplifierOptions(this IGlobalOptionService globalOptions, HostLanguageServices languageServices) + => languageServices.GetService()?.GetOptions(globalOptions); +} diff --git a/src/Features/LanguageServer/Protocol/Features/Options/SolutionCrawlerOptionsStorage.cs b/src/Features/LanguageServer/Protocol/Features/Options/SolutionCrawlerOptionsStorage.cs index d79dc94922507..d10ce27861020 100644 --- a/src/Features/LanguageServer/Protocol/Features/Options/SolutionCrawlerOptionsStorage.cs +++ b/src/Features/LanguageServer/Protocol/Features/Options/SolutionCrawlerOptionsStorage.cs @@ -5,48 +5,47 @@ using System; using Microsoft.CodeAnalysis.Options; -namespace Microsoft.CodeAnalysis.SolutionCrawler +namespace Microsoft.CodeAnalysis.SolutionCrawler; + +internal static class SolutionCrawlerOptionsStorage { - internal static class SolutionCrawlerOptionsStorage + /// + /// Option to turn configure background analysis scope for the current user. + /// + public static readonly PerLanguageOption2 BackgroundAnalysisScopeOption = new( + "SolutionCrawlerOptionsStorage", "BackgroundAnalysisScopeOption", defaultValue: BackgroundAnalysisScope.Default, + storageLocation: new RoamingProfileStorageLocation($"TextEditor.%LANGUAGE%.Specific.BackgroundAnalysisScopeOption")); + + /// + /// Option to turn configure background analysis scope for the current solution. + /// + public static readonly Option2 SolutionBackgroundAnalysisScopeOption = new( + "SolutionCrawlerOptionsStorage", "SolutionBackgroundAnalysisScopeOption", defaultValue: null); + + public static readonly PerLanguageOption2 RemoveDocumentDiagnosticsOnDocumentClose = new( + "ServiceFeatureOnOffOptions", "RemoveDocumentDiagnosticsOnDocumentClose", defaultValue: false, + storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.RemoveDocumentDiagnosticsOnDocumentClose")); + + /// + /// Enables forced scope when low VM is detected to improve performance. + /// + public static bool LowMemoryForcedMinimalBackgroundAnalysis = false; + + /// + /// Gets the effective background analysis scope for the current solution. + /// + /// Gets the solution-specific analysis scope set through + /// , or the default analysis scope if no solution-specific + /// scope is set. + /// + public static BackgroundAnalysisScope GetBackgroundAnalysisScope(this IGlobalOptionService globalOptions, string language) { - /// - /// Option to turn configure background analysis scope for the current user. - /// - public static readonly PerLanguageOption2 BackgroundAnalysisScopeOption = new( - "SolutionCrawlerOptionsStorage", "BackgroundAnalysisScopeOption", defaultValue: BackgroundAnalysisScope.Default, - storageLocation: new RoamingProfileStorageLocation($"TextEditor.%LANGUAGE%.Specific.BackgroundAnalysisScopeOption")); - - /// - /// Option to turn configure background analysis scope for the current solution. - /// - public static readonly Option2 SolutionBackgroundAnalysisScopeOption = new( - "SolutionCrawlerOptionsStorage", "SolutionBackgroundAnalysisScopeOption", defaultValue: null); - - public static readonly PerLanguageOption2 RemoveDocumentDiagnosticsOnDocumentClose = new( - "ServiceFeatureOnOffOptions", "RemoveDocumentDiagnosticsOnDocumentClose", defaultValue: false, - storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.RemoveDocumentDiagnosticsOnDocumentClose")); - - /// - /// Enables forced scope when low VM is detected to improve performance. - /// - public static bool LowMemoryForcedMinimalBackgroundAnalysis = false; - - /// - /// Gets the effective background analysis scope for the current solution. - /// - /// Gets the solution-specific analysis scope set through - /// , or the default analysis scope if no solution-specific - /// scope is set. - /// - public static BackgroundAnalysisScope GetBackgroundAnalysisScope(this IGlobalOptionService globalOptions, string language) + if (LowMemoryForcedMinimalBackgroundAnalysis) { - if (LowMemoryForcedMinimalBackgroundAnalysis) - { - return BackgroundAnalysisScope.Minimal; - } - - return globalOptions.GetOption(SolutionBackgroundAnalysisScopeOption) ?? - globalOptions.GetOption(BackgroundAnalysisScopeOption, language); + return BackgroundAnalysisScope.Minimal; } + + return globalOptions.GetOption(SolutionBackgroundAnalysisScopeOption) ?? + globalOptions.GetOption(BackgroundAnalysisScopeOption, language); } } diff --git a/src/Features/LanguageServer/Protocol/Features/Options/WorkspaceConfigurationOptionsStorage.cs b/src/Features/LanguageServer/Protocol/Features/Options/WorkspaceConfigurationOptionsStorage.cs index f16587510fa34..6fbe5cb5f57de 100644 --- a/src/Features/LanguageServer/Protocol/Features/Options/WorkspaceConfigurationOptionsStorage.cs +++ b/src/Features/LanguageServer/Protocol/Features/Options/WorkspaceConfigurationOptionsStorage.cs @@ -5,47 +5,46 @@ using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Storage; -namespace Microsoft.CodeAnalysis.Host +namespace Microsoft.CodeAnalysis.Host; + +internal static class WorkspaceConfigurationOptionsStorage { - internal static class WorkspaceConfigurationOptionsStorage - { - public static WorkspaceConfigurationOptions GetWorkspaceConfigurationOptions(this IGlobalOptionService globalOptions) - => new( - CacheStorage: globalOptions.GetOption(CloudCacheFeatureFlag) ? StorageDatabase.CloudCache : globalOptions.GetOption(Database), - DisableProjectCacheService: globalOptions.GetOption(DisableProjectCacheService), - DisableRecoverableTrees: globalOptions.GetOption(DisableRecoverableTrees), - EnableOpeningSourceGeneratedFiles: globalOptions.GetOption(EnableOpeningSourceGeneratedFilesInWorkspace) ?? - globalOptions.GetOption(EnableOpeningSourceGeneratedFilesInWorkspaceFeatureFlag)); - - public static readonly Option2 Database = new( - "FeatureManager/Storage", nameof(Database), WorkspaceConfigurationOptions.Default.CacheStorage, - new LocalUserProfileStorageLocation(@"Roslyn\Internal\OnOff\Features\Database")); - - public static readonly Option2 CloudCacheFeatureFlag = new( - "FeatureManager/Storage", "CloudCacheFeatureFlag", WorkspaceConfigurationOptions.Default.CacheStorage == StorageDatabase.CloudCache, - new FeatureFlagStorageLocation("Roslyn.CloudCache3")); - - /// - /// Disables if the workspace creates recoverable trees when from its s. - /// - public static readonly Option2 DisableRecoverableTrees = new( - "WorkspaceConfigurationOptions", "DisableRecoverableTrees", WorkspaceConfigurationOptions.Default.DisableRecoverableTrees, - new FeatureFlagStorageLocation("Roslyn.DisableRecoverableTrees")); - - public static readonly Option2 DisableProjectCacheService = new( - "WorkspaceConfigurationOptions", nameof(DisableProjectCacheService), WorkspaceConfigurationOptions.Default.DisableProjectCacheService, - new FeatureFlagStorageLocation("Roslyn.DisableProjectCacheService")); - - /// - /// This option allows the user to enable this. We are putting this behind a feature flag for now since we could have extensions - /// surprised by this and we want some time to work through those issues. - /// - public static readonly Option2 EnableOpeningSourceGeneratedFilesInWorkspace = new( - "WorkspaceConfigurationOptions", "EnableOpeningSourceGeneratedFilesInWorkspace", defaultValue: null, - new RoamingProfileStorageLocation("TextEditor.Roslyn.Specific.EnableOpeningSourceGeneratedFilesInWorkspaceExperiment")); - - public static readonly Option2 EnableOpeningSourceGeneratedFilesInWorkspaceFeatureFlag = new( - "WorkspaceConfigurationOptions", "EnableOpeningSourceGeneratedFilesInWorkspaceFeatureFlag", WorkspaceConfigurationOptions.Default.EnableOpeningSourceGeneratedFiles, - new FeatureFlagStorageLocation("Roslyn.SourceGeneratorsEnableOpeningInWorkspace")); - } + public static WorkspaceConfigurationOptions GetWorkspaceConfigurationOptions(this IGlobalOptionService globalOptions) + => new( + CacheStorage: globalOptions.GetOption(CloudCacheFeatureFlag) ? StorageDatabase.CloudCache : globalOptions.GetOption(Database), + DisableProjectCacheService: globalOptions.GetOption(DisableProjectCacheService), + DisableRecoverableTrees: globalOptions.GetOption(DisableRecoverableTrees), + EnableOpeningSourceGeneratedFiles: globalOptions.GetOption(EnableOpeningSourceGeneratedFilesInWorkspace) ?? + globalOptions.GetOption(EnableOpeningSourceGeneratedFilesInWorkspaceFeatureFlag)); + + public static readonly Option2 Database = new( + "FeatureManager/Storage", nameof(Database), WorkspaceConfigurationOptions.Default.CacheStorage, + new LocalUserProfileStorageLocation(@"Roslyn\Internal\OnOff\Features\Database")); + + public static readonly Option2 CloudCacheFeatureFlag = new( + "FeatureManager/Storage", "CloudCacheFeatureFlag", WorkspaceConfigurationOptions.Default.CacheStorage == StorageDatabase.CloudCache, + new FeatureFlagStorageLocation("Roslyn.CloudCache3")); + + /// + /// Disables if the workspace creates recoverable trees when from its s. + /// + public static readonly Option2 DisableRecoverableTrees = new( + "WorkspaceConfigurationOptions", "DisableRecoverableTrees", WorkspaceConfigurationOptions.Default.DisableRecoverableTrees, + new FeatureFlagStorageLocation("Roslyn.DisableRecoverableTrees")); + + public static readonly Option2 DisableProjectCacheService = new( + "WorkspaceConfigurationOptions", nameof(DisableProjectCacheService), WorkspaceConfigurationOptions.Default.DisableProjectCacheService, + new FeatureFlagStorageLocation("Roslyn.DisableProjectCacheService")); + + /// + /// This option allows the user to enable this. We are putting this behind a feature flag for now since we could have extensions + /// surprised by this and we want some time to work through those issues. + /// + public static readonly Option2 EnableOpeningSourceGeneratedFilesInWorkspace = new( + "WorkspaceConfigurationOptions", "EnableOpeningSourceGeneratedFilesInWorkspace", defaultValue: null, + new RoamingProfileStorageLocation("TextEditor.Roslyn.Specific.EnableOpeningSourceGeneratedFilesInWorkspaceExperiment")); + + public static readonly Option2 EnableOpeningSourceGeneratedFilesInWorkspaceFeatureFlag = new( + "WorkspaceConfigurationOptions", "EnableOpeningSourceGeneratedFilesInWorkspaceFeatureFlag", WorkspaceConfigurationOptions.Default.EnableOpeningSourceGeneratedFiles, + new FeatureFlagStorageLocation("Roslyn.SourceGeneratorsEnableOpeningInWorkspace")); } diff --git a/src/Features/LanguageServer/Protocol/Features/Options/WorkspaceConfigurationService.cs b/src/Features/LanguageServer/Protocol/Features/Options/WorkspaceConfigurationService.cs index 9def0f584375c..e42b269ae1d35 100644 --- a/src/Features/LanguageServer/Protocol/Features/Options/WorkspaceConfigurationService.cs +++ b/src/Features/LanguageServer/Protocol/Features/Options/WorkspaceConfigurationService.cs @@ -8,25 +8,24 @@ using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Options; -namespace Microsoft.CodeAnalysis.Host +namespace Microsoft.CodeAnalysis.Host; + +[ExportWorkspaceService(typeof(IWorkspaceConfigurationService)), Shared] +internal sealed class WorkspaceConfigurationService : IWorkspaceConfigurationService { - [ExportWorkspaceService(typeof(IWorkspaceConfigurationService)), Shared] - internal sealed class WorkspaceConfigurationService : IWorkspaceConfigurationService - { - private readonly IGlobalOptionService _globalOptions; - private WorkspaceConfigurationOptions? _lazyOptions; + private readonly IGlobalOptionService _globalOptions; + private WorkspaceConfigurationOptions? _lazyOptions; - [ImportingConstructor] - [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - public WorkspaceConfigurationService(IGlobalOptionService globalOptions) - { - _globalOptions = globalOptions; - } + [ImportingConstructor] + [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] + public WorkspaceConfigurationService(IGlobalOptionService globalOptions) + { + _globalOptions = globalOptions; + } - public WorkspaceConfigurationOptions Options - => _lazyOptions ??= _globalOptions.GetWorkspaceConfigurationOptions(); + public WorkspaceConfigurationOptions Options + => _lazyOptions ??= _globalOptions.GetWorkspaceConfigurationOptions(); - internal void Clear() - => _lazyOptions = null; - } + internal void Clear() + => _lazyOptions = null; } diff --git a/src/Features/LanguageServer/Protocol/Handler/Definitions/AbstractGoToDefinitionHandler.cs b/src/Features/LanguageServer/Protocol/Handler/Definitions/AbstractGoToDefinitionHandler.cs index 7b655a7fdc579..27109a471f4a8 100644 --- a/src/Features/LanguageServer/Protocol/Handler/Definitions/AbstractGoToDefinitionHandler.cs +++ b/src/Features/LanguageServer/Protocol/Handler/Definitions/AbstractGoToDefinitionHandler.cs @@ -67,7 +67,7 @@ public AbstractGoToDefinitionHandler(IMetadataAsSourceFileService metadataAsSour { if (!typeOnly || symbol is ITypeSymbol) { - var options = _globalOptions.GetMetadataAsSourceOptions(); + var options = _globalOptions.GetMetadataAsSourceOptions(document.Project.LanguageServices); var declarationFile = await _metadataAsSourceFileService.GetGeneratedFileAsync(document.Project, symbol, signaturesOnly: false, options, cancellationToken).ConfigureAwait(false); var linePosSpan = declarationFile.IdentifierLocation.GetLineSpan().Span; diff --git a/src/Features/LanguageServer/Protocol/Handler/InlineCompletions/InlineCompletionsHandler.cs b/src/Features/LanguageServer/Protocol/Handler/InlineCompletions/InlineCompletionsHandler.cs index 99540d07f0711..4846eb433a7aa 100644 --- a/src/Features/LanguageServer/Protocol/Handler/InlineCompletions/InlineCompletionsHandler.cs +++ b/src/Features/LanguageServer/Protocol/Handler/InlineCompletions/InlineCompletionsHandler.cs @@ -17,6 +17,7 @@ using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Collections; using Microsoft.CodeAnalysis.Shared.Extensions; +using Microsoft.CodeAnalysis.Simplification; using Microsoft.CodeAnalysis.Snippets; using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.LanguageServer.Protocol; @@ -99,8 +100,9 @@ public InlineCompletionsHandler(XmlSnippetParser xmlSnippetParser) // Use the formatting options specified by the client to format the snippet. var formattingOptions = await ProtocolConversions.GetFormattingOptionsAsync(request.Options, context.Document, cancellationToken).ConfigureAwait(false); + var simplifierOptions = await SimplifierOptions.FromDocumentAsync(context.Document, fallbackOptions: null, cancellationToken).ConfigureAwait(false); - var formattedLspSnippet = await GetFormattedLspSnippetAsync(parsedSnippet, wordOnLeft.Value, context.Document, sourceText, formattingOptions, cancellationToken).ConfigureAwait(false); + var formattedLspSnippet = await GetFormattedLspSnippetAsync(parsedSnippet, wordOnLeft.Value, context.Document, sourceText, formattingOptions, simplifierOptions, cancellationToken).ConfigureAwait(false); return new VSInternalInlineCompletionList { @@ -122,11 +124,18 @@ public InlineCompletionsHandler(XmlSnippetParser xmlSnippetParser) /// /// Note that the operations in this method are sensitive to the context in the document and so must be calculated on each request. /// - private static async Task GetFormattedLspSnippetAsync(ParsedXmlSnippet parsedSnippet, TextSpan snippetShortcut, Document originalDocument, SourceText originalSourceText, SyntaxFormattingOptions options, CancellationToken cancellationToken) + private static async Task GetFormattedLspSnippetAsync( + ParsedXmlSnippet parsedSnippet, + TextSpan snippetShortcut, + Document originalDocument, + SourceText originalSourceText, + SyntaxFormattingOptions formattingOptions, + SimplifierOptions simplifierOptions, + CancellationToken cancellationToken) { // Calculate the snippet text with defaults + snippet function results. var (snippetFullText, fields, caretSpan) = await GetReplacedSnippetTextAsync( - originalDocument, originalSourceText, snippetShortcut, parsedSnippet, cancellationToken).ConfigureAwait(false); + originalDocument, originalSourceText, snippetShortcut, parsedSnippet, simplifierOptions, cancellationToken).ConfigureAwait(false); // Create a document with the default snippet text that we can use to format the snippet. var textChange = new TextChange(snippetShortcut, snippetFullText); @@ -136,7 +145,7 @@ private static async Task GetFormattedLspSnippetAsync(ParsedXmlSnippet p var root = await originalDocument.WithText(documentWithSnippetText).GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); var spanToFormat = TextSpan.FromBounds(textChange.Span.Start, snippetEndPosition); - var formattingChanges = Formatter.GetFormattedTextChanges(root, spanToFormat, originalDocument.Project.Solution.Workspace.Services, options, cancellationToken: cancellationToken) + var formattingChanges = Formatter.GetFormattedTextChanges(root, spanToFormat, originalDocument.Project.Solution.Workspace.Services, formattingOptions, cancellationToken: cancellationToken) ?.ToImmutableArray() ?? ImmutableArray.Empty; var formattedText = documentWithSnippetText.WithChanges(formattingChanges); @@ -200,6 +209,7 @@ static TextSpan GetTextSpanInContextOfSnippet(int positionInFullText, int snippe SourceText originalSourceText, TextSpan snippetSpan, ParsedXmlSnippet parsedSnippet, + SimplifierOptions simplifierOptions, CancellationToken cancellationToken) { var documentWithDefaultSnippet = originalDocument.WithText( @@ -228,7 +238,7 @@ static TextSpan GetTextSpanInContextOfSnippet(int positionInFullText, int snippe // To avoid a bunch of document changes and re-parsing, we always calculate the snippet function result // against the document with the default snippet text applied to it instead of with each incremental function result. // So we need to remember the index into the original document. - part = await functionPart.WithSnippetFunctionResultAsync(documentWithDefaultSnippet, new TextSpan(locationInDefaultSnippet, part.DefaultText.Length), cancellationToken).ConfigureAwait(false); + part = await functionPart.WithSnippetFunctionResultAsync(documentWithDefaultSnippet, new TextSpan(locationInDefaultSnippet, part.DefaultText.Length), simplifierOptions, cancellationToken).ConfigureAwait(false); } // Only store spans for editable fields or the cursor location, we don't need to get back to anything else. diff --git a/src/Features/LanguageServer/Protocol/Handler/InlineCompletions/XmlSnippetParser.ParsedXmlSnippet.cs b/src/Features/LanguageServer/Protocol/Handler/InlineCompletions/XmlSnippetParser.ParsedXmlSnippet.cs index 925d86259707b..d6ae271ecb170 100644 --- a/src/Features/LanguageServer/Protocol/Handler/InlineCompletions/XmlSnippetParser.ParsedXmlSnippet.cs +++ b/src/Features/LanguageServer/Protocol/Handler/InlineCompletions/XmlSnippetParser.ParsedXmlSnippet.cs @@ -7,6 +7,7 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; +using Microsoft.CodeAnalysis.Simplification; using Microsoft.CodeAnalysis.Text; namespace Microsoft.CodeAnalysis.LanguageServer.Handler.InlineCompletions; @@ -40,7 +41,7 @@ internal record SnippetFieldPart(string FieldName, string DefaultText, int? Edit internal record SnippetFunctionPart(string FieldName, string DefaultText, int? EditIndex, string FunctionName, string? FunctionParam) : SnippetFieldPart(FieldName, DefaultText, EditIndex) { - public async Task WithSnippetFunctionResultAsync(Document documentWithSnippet, TextSpan fieldSpan, CancellationToken cancellationToken) + public async Task WithSnippetFunctionResultAsync(Document documentWithSnippet, TextSpan fieldSpan, SimplifierOptions simplifierOptions, CancellationToken cancellationToken) { var snippetFunctionService = documentWithSnippet.Project.GetRequiredLanguageService(); switch (FunctionName) @@ -51,7 +52,7 @@ public async Task WithSnippetFunctionResultAsync(Document d return this; } - var simplifiedTypeName = await SnippetFunctionService.GetSimplifiedTypeNameAsync(documentWithSnippet, fieldSpan, FunctionParam, cancellationToken).ConfigureAwait(false); + var simplifiedTypeName = await SnippetFunctionService.GetSimplifiedTypeNameAsync(documentWithSnippet, fieldSpan, FunctionParam, simplifierOptions, cancellationToken).ConfigureAwait(false); if (simplifiedTypeName == null) { return this; diff --git a/src/Features/LanguageServer/Protocol/Microsoft.CodeAnalysis.LanguageServer.Protocol.csproj b/src/Features/LanguageServer/Protocol/Microsoft.CodeAnalysis.LanguageServer.Protocol.csproj index 3de6b96acd04d..e99ebd1d3c9a3 100644 --- a/src/Features/LanguageServer/Protocol/Microsoft.CodeAnalysis.LanguageServer.Protocol.csproj +++ b/src/Features/LanguageServer/Protocol/Microsoft.CodeAnalysis.LanguageServer.Protocol.csproj @@ -53,9 +53,10 @@ - + + diff --git a/src/Features/VisualBasic/Portable/Diagnostics/Analyzers/TypeSyntaxSimplifierWalker.vb b/src/Features/VisualBasic/Portable/Diagnostics/Analyzers/TypeSyntaxSimplifierWalker.vb index b0a6a512fc8f6..06ce76fa0ecee 100644 --- a/src/Features/VisualBasic/Portable/Diagnostics/Analyzers/TypeSyntaxSimplifierWalker.vb +++ b/src/Features/VisualBasic/Portable/Diagnostics/Analyzers/TypeSyntaxSimplifierWalker.vb @@ -7,6 +7,7 @@ Imports System.Threading Imports Microsoft.CodeAnalysis.Options Imports Microsoft.CodeAnalysis.Shared.Collections Imports Microsoft.CodeAnalysis.Text +Imports Microsoft.CodeAnalysis.VisualBasic.Simplification Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Namespace Microsoft.CodeAnalysis.VisualBasic.CodeFixes.SimplifyTypeNames @@ -36,7 +37,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeFixes.SimplifyTypeNames Private ReadOnly _analyzer As VisualBasicSimplifyTypeNamesDiagnosticAnalyzer Private ReadOnly _semanticModel As SemanticModel - Private ReadOnly _optionSet As OptionSet + Private ReadOnly _options As VisualBasicSimplifierOptions Private ReadOnly _ignoredSpans As SimpleIntervalTree(Of TextSpan, TextSpanIntervalIntrospector) Private ReadOnly _cancellationToken As CancellationToken @@ -66,12 +67,12 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeFixes.SimplifyTypeNames End Get End Property - Public Sub New(analyzer As VisualBasicSimplifyTypeNamesDiagnosticAnalyzer, semanticModel As SemanticModel, optionSet As OptionSet, ignoredSpans As SimpleIntervalTree(Of TextSpan, TextSpanIntervalIntrospector), cancellationToken As CancellationToken) + Public Sub New(analyzer As VisualBasicSimplifyTypeNamesDiagnosticAnalyzer, semanticModel As SemanticModel, options As VisualBasicSimplifierOptions, ignoredSpans As SimpleIntervalTree(Of TextSpan, TextSpanIntervalIntrospector), cancellationToken As CancellationToken) MyBase.New(SyntaxWalkerDepth.StructuredTrivia) _analyzer = analyzer _semanticModel = semanticModel - _optionSet = optionSet + _options = options _ignoredSpans = ignoredSpans _cancellationToken = cancellationToken @@ -184,7 +185,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeFixes.SimplifyTypeNames Private Function TrySimplify(node As SyntaxNode) As Boolean Dim diagnostic As Diagnostic = Nothing - If Not _analyzer.TrySimplify(_semanticModel, node, diagnostic, _optionSet, _cancellationToken) Then + If Not _analyzer.TrySimplify(_semanticModel, node, diagnostic, _options, _cancellationToken) Then Return False End If diff --git a/src/Features/VisualBasic/Portable/Diagnostics/Analyzers/VisualBasicSimplifyTypeNamesDiagnosticAnalyzer.vb b/src/Features/VisualBasic/Portable/Diagnostics/Analyzers/VisualBasicSimplifyTypeNamesDiagnosticAnalyzer.vb index 8579b85422ad7..2456c2287bdb3 100644 --- a/src/Features/VisualBasic/Portable/Diagnostics/Analyzers/VisualBasicSimplifyTypeNamesDiagnosticAnalyzer.vb +++ b/src/Features/VisualBasic/Portable/Diagnostics/Analyzers/VisualBasicSimplifyTypeNamesDiagnosticAnalyzer.vb @@ -10,6 +10,7 @@ Imports Microsoft.CodeAnalysis.Options Imports Microsoft.CodeAnalysis.Shared.Collections Imports Microsoft.CodeAnalysis.SimplifyTypeNames Imports Microsoft.CodeAnalysis.Text +Imports Microsoft.CodeAnalysis.VisualBasic.Simplification Imports Microsoft.CodeAnalysis.VisualBasic.Simplification.Simplifiers Imports Microsoft.CodeAnalysis.VisualBasic.Syntax @@ -17,7 +18,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeFixes.SimplifyTypeNames Friend NotInheritable Class VisualBasicSimplifyTypeNamesDiagnosticAnalyzer - Inherits SimplifyTypeNamesDiagnosticAnalyzerBase(Of SyntaxKind) + Inherits SimplifyTypeNamesDiagnosticAnalyzerBase(Of SyntaxKind, VisualBasicSimplifierOptions) Private Shared ReadOnly s_kindsOfInterest As ImmutableArray(Of SyntaxKind) = ImmutableArray.Create( SyntaxKind.QualifiedName, @@ -38,10 +39,9 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeFixes.SimplifyTypeNames Dim semanticModel = context.SemanticModel Dim cancellationToken = context.CancellationToken - Dim syntaxTree = semanticModel.SyntaxTree - Dim optionSet = context.Options.GetAnalyzerOptionSet(syntaxTree, cancellationToken) + Dim simplifierOptions = context.Options.GetVisualBasicSimplifierOptions(semanticModel.SyntaxTree) - Dim simplifier As New TypeSyntaxSimplifierWalker(Me, semanticModel, optionSet, ignoredSpans:=Nothing, cancellationToken) + Dim simplifier As New TypeSyntaxSimplifierWalker(Me, semanticModel, simplifierOptions, ignoredSpans:=Nothing, cancellationToken) simplifier.Visit(context.CodeBlock) Return simplifier.Diagnostics End Function @@ -51,10 +51,11 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeFixes.SimplifyTypeNames Dim cancellationToken = context.CancellationToken Dim syntaxTree = semanticModel.SyntaxTree - Dim optionSet = context.Options.GetAnalyzerOptionSet(syntaxTree, cancellationToken) + Dim configOptions = context.Options.AnalyzerConfigOptionsProvider.GetOptions(syntaxTree) + Dim simplifierOptions = context.Options.GetVisualBasicSimplifierOptions(semanticModel.SyntaxTree) Dim root = syntaxTree.GetRoot(cancellationToken) - Dim simplifier As New TypeSyntaxSimplifierWalker(Me, semanticModel, optionSet, ignoredSpans:=codeBlockIntervalTree, cancellationToken) + Dim simplifier As New TypeSyntaxSimplifierWalker(Me, semanticModel, simplifierOptions, ignoredSpans:=codeBlockIntervalTree, cancellationToken) simplifier.Visit(root) Return simplifier.Diagnostics End Function @@ -68,7 +69,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeFixes.SimplifyTypeNames End Function Friend Overrides Function CanSimplifyTypeNameExpression( - model As SemanticModel, node As SyntaxNode, optionSet As OptionSet, + model As SemanticModel, node As SyntaxNode, options As VisualBasicSimplifierOptions, ByRef issueSpan As TextSpan, ByRef diagnosticId As String, ByRef inDeclaration As Boolean, cancellationToken As CancellationToken) As Boolean issueSpan = Nothing @@ -87,7 +88,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeFixes.SimplifyTypeNames End If Dim replacementSyntax As ExpressionSyntax = Nothing - If Not ExpressionSimplifier.Instance.TrySimplify(expression, model, optionSet, replacementSyntax, issueSpan, cancellationToken) Then + If Not ExpressionSimplifier.Instance.TrySimplify(expression, model, options, replacementSyntax, issueSpan, cancellationToken) Then Return False End If diff --git a/src/Features/VisualBasic/Portable/Formatting/VisualBasicOrganizeUsingsNewDocumentFormattingProvider.vb b/src/Features/VisualBasic/Portable/Formatting/VisualBasicOrganizeUsingsNewDocumentFormattingProvider.vb index 7199cf45bd65a..51b0f473ae6cd 100644 --- a/src/Features/VisualBasic/Portable/Formatting/VisualBasicOrganizeUsingsNewDocumentFormattingProvider.vb +++ b/src/Features/VisualBasic/Portable/Formatting/VisualBasicOrganizeUsingsNewDocumentFormattingProvider.vb @@ -4,6 +4,7 @@ Imports System.Composition Imports System.Threading +Imports Microsoft.CodeAnalysis.CodeCleanup Imports Microsoft.CodeAnalysis.Formatting Imports Microsoft.CodeAnalysis.Host.Mef @@ -17,7 +18,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Formatting Public Sub New() End Sub - Public Function FormatNewDocumentAsync(document As Document, hintDocument As Document, options As SyntaxFormattingOptions, cancellationToken As CancellationToken) As Task(Of Document) Implements INewDocumentFormattingProvider.FormatNewDocumentAsync + Public Function FormatNewDocumentAsync(document As Document, hintDocument As Document, options As CodeCleanupOptions, cancellationToken As CancellationToken) As Task(Of Document) Implements INewDocumentFormattingProvider.FormatNewDocumentAsync Return Formatter.OrganizeImportsAsync(document, cancellationToken) End Function End Class diff --git a/src/Features/VisualBasic/Portable/ImplementInterface/VisualBasicImplementInterfaceCodeFixProvider.vb b/src/Features/VisualBasic/Portable/ImplementInterface/VisualBasicImplementInterfaceCodeFixProvider.vb index 41e153d3a8c24..2103001078cf6 100644 --- a/src/Features/VisualBasic/Portable/ImplementInterface/VisualBasicImplementInterfaceCodeFixProvider.vb +++ b/src/Features/VisualBasic/Portable/ImplementInterface/VisualBasicImplementInterfaceCodeFixProvider.vb @@ -61,7 +61,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ImplementInterface Dim service = document.GetLanguageService(Of IImplementInterfaceService)() Dim actions = service.GetCodeActions( document, - context.Options(document.Project.Language).ImplementTypeOptions, + context.Options(document.Project.LanguageServices).ImplementTypeOptions, Await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(False), typeNode, cancellationToken) diff --git a/src/Features/VisualBasic/Portable/SimplifyThisOrMe/VisualBasicSimplifyThisOrMeDiagnosticAnalyzer.vb b/src/Features/VisualBasic/Portable/SimplifyThisOrMe/VisualBasicSimplifyThisOrMeDiagnosticAnalyzer.vb index 315c9020ae6b1..bd7e94245a4a0 100644 --- a/src/Features/VisualBasic/Portable/SimplifyThisOrMe/VisualBasicSimplifyThisOrMeDiagnosticAnalyzer.vb +++ b/src/Features/VisualBasic/Portable/SimplifyThisOrMe/VisualBasicSimplifyThisOrMeDiagnosticAnalyzer.vb @@ -10,6 +10,7 @@ Imports Microsoft.CodeAnalysis.SimplifyThisOrMe Imports Microsoft.CodeAnalysis.Text Imports Microsoft.CodeAnalysis.VisualBasic.LanguageServices Imports Microsoft.CodeAnalysis.VisualBasic.Simplification.Simplifiers +Imports Microsoft.CodeAnalysis.VisualBasic.Simplification Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Namespace Microsoft.CodeAnalysis.VisualBasic.SimplifyThisOrMe @@ -19,19 +20,24 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.SimplifyThisOrMe SyntaxKind, ExpressionSyntax, MeExpressionSyntax, - MemberAccessExpressionSyntax) + MemberAccessExpressionSyntax, + VisualBasicSimplifierOptions) Protected Overrides Function GetSyntaxFacts() As ISyntaxFacts Return VisualBasicSyntaxFacts.Instance End Function + Protected Overrides Function GetSimplifierOptions(options As AnalyzerOptions, syntaxTree As SyntaxTree) As VisualBasicSimplifierOptions + Return options.GetVisualBasicSimplifierOptions(syntaxTree) + End Function + Protected Overrides Function CanSimplifyTypeNameExpression( model As SemanticModel, memberAccess As MemberAccessExpressionSyntax, - optionSet As OptionSet, ByRef issueSpan As TextSpan, + options As VisualBasicSimplifierOptions, ByRef issueSpan As TextSpan, cancellationToken As CancellationToken) As Boolean Dim replacementSyntax As ExpressionSyntax = Nothing - Return ExpressionSimplifier.Instance.TrySimplify(memberAccess, model, optionSet, replacementSyntax, issueSpan, cancellationToken) + Return ExpressionSimplifier.Instance.TrySimplify(memberAccess, model, options, replacementSyntax, issueSpan, cancellationToken) End Function End Class End Namespace diff --git a/src/Features/VisualBasic/Portable/SimplifyTypeNames/SimplifyTypeNamesCodeFixProvider.vb b/src/Features/VisualBasic/Portable/SimplifyTypeNames/SimplifyTypeNamesCodeFixProvider.vb index 5752a5acc11d8..d28d543d2b490 100644 --- a/src/Features/VisualBasic/Portable/SimplifyTypeNames/SimplifyTypeNamesCodeFixProvider.vb +++ b/src/Features/VisualBasic/Portable/SimplifyTypeNames/SimplifyTypeNamesCodeFixProvider.vb @@ -8,6 +8,7 @@ Imports Microsoft.CodeAnalysis.CodeFixes Imports Microsoft.CodeAnalysis.Diagnostics Imports Microsoft.CodeAnalysis.Simplification Imports Microsoft.CodeAnalysis.SimplifyTypeNames +Imports Microsoft.CodeAnalysis.VisualBasic.Simplification Imports Microsoft.CodeAnalysis.VisualBasic.CodeFixes.SimplifyTypeNames Namespace Microsoft.CodeAnalysis.VisualBasic.SimplifyTypeNames @@ -15,7 +16,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.SimplifyTypeNames Partial Friend Class SimplifyTypeNamesCodeFixProvider - Inherits AbstractSimplifyTypeNamesCodeFixProvider(Of SyntaxKind) + Inherits AbstractSimplifyTypeNamesCodeFixProvider(Of SyntaxKind, VisualBasicSimplifierOptions) diff --git a/src/Tools/ExternalAccess/OmniSharp.CSharp/Formatting/OmniSharpSyntaxFormattingOptionsFactory.cs b/src/Tools/ExternalAccess/OmniSharp.CSharp/Formatting/OmniSharpSyntaxFormattingOptionsFactory.cs index 66ecf8cdd0fcf..1fa3106504b86 100644 --- a/src/Tools/ExternalAccess/OmniSharp.CSharp/Formatting/OmniSharpSyntaxFormattingOptionsFactory.cs +++ b/src/Tools/ExternalAccess/OmniSharp.CSharp/Formatting/OmniSharpSyntaxFormattingOptionsFactory.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using Microsoft.CodeAnalysis.CSharp.Formatting; +using Microsoft.CodeAnalysis.CSharp.Simplification; using Microsoft.CodeAnalysis.ExternalAccess.OmniSharp.Formatting; using Microsoft.CodeAnalysis.Formatting; @@ -76,61 +77,62 @@ public static OmniSharpSyntaxFormattingOptionsWrapper Create( bool newLineForMembersInObjectInit, bool newLineForMembersInAnonymousTypes, bool newLineForClausesInQuery) - => new(new CSharpSyntaxFormattingOptions( - new LineFormattingOptions( - UseTabs: useTabs, - TabSize: tabSize, - IndentationSize: indentationSize, - NewLine: newLine), - separateImportDirectiveGroups: separateImportDirectiveGroups, - spacing: - (spacingAfterMethodDeclarationName ? SpacePlacement.AfterMethodDeclarationName : 0) | - (spaceBetweenEmptyMethodDeclarationParentheses ? SpacePlacement.BetweenEmptyMethodDeclarationParentheses : 0) | - (spaceWithinMethodDeclarationParenthesis ? SpacePlacement.WithinMethodDeclarationParenthesis : 0) | - (spaceAfterMethodCallName ? SpacePlacement.AfterMethodCallName : 0) | - (spaceBetweenEmptyMethodCallParentheses ? SpacePlacement.BetweenEmptyMethodCallParentheses : 0) | - (spaceWithinMethodCallParentheses ? SpacePlacement.WithinMethodCallParentheses : 0) | - (spaceAfterControlFlowStatementKeyword ? SpacePlacement.AfterControlFlowStatementKeyword : 0) | - (spaceWithinExpressionParentheses ? SpacePlacement.WithinExpressionParentheses : 0) | - (spaceWithinCastParentheses ? SpacePlacement.WithinCastParentheses : 0) | - (spaceBeforeSemicolonsInForStatement ? SpacePlacement.BeforeSemicolonsInForStatement : 0) | - (spaceAfterSemicolonsInForStatement ? SpacePlacement.AfterSemicolonsInForStatement : 0) | - (spaceWithinOtherParentheses ? SpacePlacement.WithinOtherParentheses : 0) | - (spaceAfterCast ? SpacePlacement.AfterCast : 0) | - (spaceBeforeOpenSquareBracket ? SpacePlacement.BeforeOpenSquareBracket : 0) | - (spaceBetweenEmptySquareBrackets ? SpacePlacement.BetweenEmptySquareBrackets : 0) | - (spaceWithinSquareBrackets ? SpacePlacement.WithinSquareBrackets : 0) | - (spaceAfterColonInBaseTypeDeclaration ? SpacePlacement.AfterColonInBaseTypeDeclaration : 0) | - (spaceBeforeColonInBaseTypeDeclaration ? SpacePlacement.BeforeColonInBaseTypeDeclaration : 0) | - (spaceAfterComma ? SpacePlacement.AfterComma : 0) | - (spaceBeforeComma ? SpacePlacement.BeforeComma : 0) | - (spaceAfterDot ? SpacePlacement.AfterDot : 0) | - (spaceBeforeDot ? SpacePlacement.BeforeDot : 0), - spacingAroundBinaryOperator: (BinaryOperatorSpacingOptions)spacingAroundBinaryOperator, - newLines: - (newLineForMembersInObjectInit ? NewLinePlacement.BeforeMembersInObjectInitializers : 0) | - (newLineForMembersInAnonymousTypes ? NewLinePlacement.BeforeMembersInAnonymousTypes : 0) | - (newLineForElse ? NewLinePlacement.BeforeElse : 0) | - (newLineForCatch ? NewLinePlacement.BeforeCatch : 0) | - (newLineForFinally ? NewLinePlacement.BeforeFinally : 0) | - (newLinesForBracesInTypes ? NewLinePlacement.BeforeOpenBraceInTypes : 0) | - (newLinesForBracesInAnonymousTypes ? NewLinePlacement.BeforeOpenBraceInAnonymousTypes : 0) | - (newLinesForBracesInObjectCollectionArrayInitializers ? NewLinePlacement.BeforeOpenBraceInObjectCollectionArrayInitializers : 0) | - (newLinesForBracesInProperties ? NewLinePlacement.BeforeOpenBraceInProperties : 0) | - (newLinesForBracesInMethods ? NewLinePlacement.BeforeOpenBraceInMethods : 0) | - (newLinesForBracesInAccessors ? NewLinePlacement.BeforeOpenBraceInAccessors : 0) | - (newLinesForBracesInAnonymousMethods ? NewLinePlacement.BeforeOpenBraceInAnonymousMethods : 0) | - (newLinesForBracesInLambdaExpressionBody ? NewLinePlacement.BeforeOpenBraceInLambdaExpressionBody : 0) | - (newLinesForBracesInControlBlocks ? NewLinePlacement.BeforeOpenBraceInControlBlocks : 0) | - (newLineForClausesInQuery ? NewLinePlacement.BetweenQueryExpressionClauses : 0), - labelPositioning: (LabelPositionOptions)labelPositioning, - indentation: - (indentBraces ? IndentationPlacement.Braces : 0) | - (indentBlock ? IndentationPlacement.BlockContents : 0) | - (indentSwitchCaseSection ? IndentationPlacement.SwitchCaseContents : 0) | - (indentSwitchCaseSectionWhenBlock ? IndentationPlacement.SwitchCaseContentsWhenBlock : 0) | - (indentSwitchSection ? IndentationPlacement.SwitchSection : 0), - wrappingKeepStatementsOnSingleLine: wrappingKeepStatementsOnSingleLine, - wrappingPreserveSingleLine: wrappingPreserveSingleLine)); + => new(formattingOptions: new CSharpSyntaxFormattingOptions( + new LineFormattingOptions( + UseTabs: useTabs, + TabSize: tabSize, + IndentationSize: indentationSize, + NewLine: newLine), + separateImportDirectiveGroups: separateImportDirectiveGroups, + spacing: + (spacingAfterMethodDeclarationName ? SpacePlacement.AfterMethodDeclarationName : 0) | + (spaceBetweenEmptyMethodDeclarationParentheses ? SpacePlacement.BetweenEmptyMethodDeclarationParentheses : 0) | + (spaceWithinMethodDeclarationParenthesis ? SpacePlacement.WithinMethodDeclarationParenthesis : 0) | + (spaceAfterMethodCallName ? SpacePlacement.AfterMethodCallName : 0) | + (spaceBetweenEmptyMethodCallParentheses ? SpacePlacement.BetweenEmptyMethodCallParentheses : 0) | + (spaceWithinMethodCallParentheses ? SpacePlacement.WithinMethodCallParentheses : 0) | + (spaceAfterControlFlowStatementKeyword ? SpacePlacement.AfterControlFlowStatementKeyword : 0) | + (spaceWithinExpressionParentheses ? SpacePlacement.WithinExpressionParentheses : 0) | + (spaceWithinCastParentheses ? SpacePlacement.WithinCastParentheses : 0) | + (spaceBeforeSemicolonsInForStatement ? SpacePlacement.BeforeSemicolonsInForStatement : 0) | + (spaceAfterSemicolonsInForStatement ? SpacePlacement.AfterSemicolonsInForStatement : 0) | + (spaceWithinOtherParentheses ? SpacePlacement.WithinOtherParentheses : 0) | + (spaceAfterCast ? SpacePlacement.AfterCast : 0) | + (spaceBeforeOpenSquareBracket ? SpacePlacement.BeforeOpenSquareBracket : 0) | + (spaceBetweenEmptySquareBrackets ? SpacePlacement.BetweenEmptySquareBrackets : 0) | + (spaceWithinSquareBrackets ? SpacePlacement.WithinSquareBrackets : 0) | + (spaceAfterColonInBaseTypeDeclaration ? SpacePlacement.AfterColonInBaseTypeDeclaration : 0) | + (spaceBeforeColonInBaseTypeDeclaration ? SpacePlacement.BeforeColonInBaseTypeDeclaration : 0) | + (spaceAfterComma ? SpacePlacement.AfterComma : 0) | + (spaceBeforeComma ? SpacePlacement.BeforeComma : 0) | + (spaceAfterDot ? SpacePlacement.AfterDot : 0) | + (spaceBeforeDot ? SpacePlacement.BeforeDot : 0), + spacingAroundBinaryOperator: (BinaryOperatorSpacingOptions)spacingAroundBinaryOperator, + newLines: + (newLineForMembersInObjectInit ? NewLinePlacement.BeforeMembersInObjectInitializers : 0) | + (newLineForMembersInAnonymousTypes ? NewLinePlacement.BeforeMembersInAnonymousTypes : 0) | + (newLineForElse ? NewLinePlacement.BeforeElse : 0) | + (newLineForCatch ? NewLinePlacement.BeforeCatch : 0) | + (newLineForFinally ? NewLinePlacement.BeforeFinally : 0) | + (newLinesForBracesInTypes ? NewLinePlacement.BeforeOpenBraceInTypes : 0) | + (newLinesForBracesInAnonymousTypes ? NewLinePlacement.BeforeOpenBraceInAnonymousTypes : 0) | + (newLinesForBracesInObjectCollectionArrayInitializers ? NewLinePlacement.BeforeOpenBraceInObjectCollectionArrayInitializers : 0) | + (newLinesForBracesInProperties ? NewLinePlacement.BeforeOpenBraceInProperties : 0) | + (newLinesForBracesInMethods ? NewLinePlacement.BeforeOpenBraceInMethods : 0) | + (newLinesForBracesInAccessors ? NewLinePlacement.BeforeOpenBraceInAccessors : 0) | + (newLinesForBracesInAnonymousMethods ? NewLinePlacement.BeforeOpenBraceInAnonymousMethods : 0) | + (newLinesForBracesInLambdaExpressionBody ? NewLinePlacement.BeforeOpenBraceInLambdaExpressionBody : 0) | + (newLinesForBracesInControlBlocks ? NewLinePlacement.BeforeOpenBraceInControlBlocks : 0) | + (newLineForClausesInQuery ? NewLinePlacement.BetweenQueryExpressionClauses : 0), + labelPositioning: (LabelPositionOptions)labelPositioning, + indentation: + (indentBraces ? IndentationPlacement.Braces : 0) | + (indentBlock ? IndentationPlacement.BlockContents : 0) | + (indentSwitchCaseSection ? IndentationPlacement.SwitchCaseContents : 0) | + (indentSwitchCaseSectionWhenBlock ? IndentationPlacement.SwitchCaseContentsWhenBlock : 0) | + (indentSwitchSection ? IndentationPlacement.SwitchSection : 0), + wrappingKeepStatementsOnSingleLine: wrappingKeepStatementsOnSingleLine, + wrappingPreserveSingleLine: wrappingPreserveSingleLine), + simplifierOptions: CSharpSimplifierOptions.Default); } } diff --git a/src/Tools/ExternalAccess/OmniSharp/CodeActions/OmniSharpCodeActionOptions.cs b/src/Tools/ExternalAccess/OmniSharp/CodeActions/OmniSharpCodeActionOptions.cs index c60ad8943d52b..a7181ba1a4a51 100644 --- a/src/Tools/ExternalAccess/OmniSharp/CodeActions/OmniSharpCodeActionOptions.cs +++ b/src/Tools/ExternalAccess/OmniSharp/CodeActions/OmniSharpCodeActionOptions.cs @@ -13,10 +13,8 @@ internal readonly record struct OmniSharpCodeActionOptions( OmniSharpImplementTypeOptions ImplementTypeOptions) { internal CodeActionOptions GetCodeActionOptions() - => new( - SymbolSearchOptions.Default, - new ImplementTypeOptions( - InsertionBehavior: (ImplementTypeInsertionBehavior)ImplementTypeOptions.InsertionBehavior, - PropertyGenerationBehavior: (ImplementTypePropertyGenerationBehavior)ImplementTypeOptions.PropertyGenerationBehavior)); + => new(ImplementTypeOptions: new( + InsertionBehavior: (ImplementTypeInsertionBehavior)ImplementTypeOptions.InsertionBehavior, + PropertyGenerationBehavior: (ImplementTypePropertyGenerationBehavior)ImplementTypeOptions.PropertyGenerationBehavior)); } } diff --git a/src/Tools/ExternalAccess/OmniSharp/CodeActions/OmniSharpCodeFixContextFactory.cs b/src/Tools/ExternalAccess/OmniSharp/CodeActions/OmniSharpCodeFixContextFactory.cs index 65dc921a7f9f3..8e3e5dbf477db 100644 --- a/src/Tools/ExternalAccess/OmniSharp/CodeActions/OmniSharpCodeFixContextFactory.cs +++ b/src/Tools/ExternalAccess/OmniSharp/CodeActions/OmniSharpCodeFixContextFactory.cs @@ -54,7 +54,7 @@ public static FixAllContext CreateFixAllContext( codeActionEquivalenceKey, diagnosticIds, fixAllDiagnosticProvider, - language => optionsProvider(language).GetCodeActionOptions()), + languageServices => optionsProvider(languageServices.Language).GetCodeActionOptions()), new ProgressTracker(), cancellationToken); } } diff --git a/src/Tools/ExternalAccess/OmniSharp/Formatting/OmniSharpFormatter.cs b/src/Tools/ExternalAccess/OmniSharp/Formatting/OmniSharpFormatter.cs index cadbac84be4ea..08017496c278e 100644 --- a/src/Tools/ExternalAccess/OmniSharp/Formatting/OmniSharpFormatter.cs +++ b/src/Tools/ExternalAccess/OmniSharp/Formatting/OmniSharpFormatter.cs @@ -15,7 +15,7 @@ namespace Microsoft.CodeAnalysis.ExternalAccess.OmniSharp.Formatting internal static class OmniSharpFormatter { public static Task FormatAsync(Document document, IEnumerable? spans, OmniSharpSyntaxFormattingOptionsWrapper options, CancellationToken cancellationToken) - => Formatter.FormatAsync(document, spans, options.UnderlyingObject, rules: null, cancellationToken); + => Formatter.FormatAsync(document, spans, options.FormattingOptions, rules: null, cancellationToken); public static async Task OrganizeImportsAsync(Document document, OmniSharpOrganizeImportsOptionsWrapper options, CancellationToken cancellationToken) { diff --git a/src/Tools/ExternalAccess/OmniSharp/Formatting/OmniSharpSyntaxFormattingOptionsWrapper.cs b/src/Tools/ExternalAccess/OmniSharp/Formatting/OmniSharpSyntaxFormattingOptionsWrapper.cs index 5ff2ccf0b9e0f..bf6039b17e0d1 100644 --- a/src/Tools/ExternalAccess/OmniSharp/Formatting/OmniSharpSyntaxFormattingOptionsWrapper.cs +++ b/src/Tools/ExternalAccess/OmniSharp/Formatting/OmniSharpSyntaxFormattingOptionsWrapper.cs @@ -5,20 +5,27 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Formatting; +using Microsoft.CodeAnalysis.Simplification; namespace Microsoft.CodeAnalysis.ExternalAccess.OmniSharp.Formatting { internal readonly record struct OmniSharpSyntaxFormattingOptionsWrapper { - internal readonly SyntaxFormattingOptions UnderlyingObject; + internal readonly SyntaxFormattingOptions FormattingOptions; + internal readonly SimplifierOptions SimplifierOptions; - internal OmniSharpSyntaxFormattingOptionsWrapper(SyntaxFormattingOptions underlyingObject) - => UnderlyingObject = underlyingObject; + internal OmniSharpSyntaxFormattingOptionsWrapper(SyntaxFormattingOptions formattingOptions, SimplifierOptions simplifierOptions) + { + FormattingOptions = formattingOptions; + SimplifierOptions = simplifierOptions; + } public static async ValueTask FromDocumentAsync(Document document, CancellationToken cancellationToken) { - var options = await SyntaxFormattingOptions.FromDocumentAsync(document, cancellationToken).ConfigureAwait(false); - return new OmniSharpSyntaxFormattingOptionsWrapper(options); + var formattingOptions = await SyntaxFormattingOptions.FromDocumentAsync(document, cancellationToken).ConfigureAwait(false); + var simplifierOptions = await SimplifierOptions.FromDocumentAsync(document, fallbackOptions: null, cancellationToken).ConfigureAwait(false); + + return new OmniSharpSyntaxFormattingOptionsWrapper(formattingOptions, simplifierOptions); } } } diff --git a/src/Tools/ExternalAccess/OmniSharp/MetadataAsSource/OmniSharpMetadataAsSourceService.cs b/src/Tools/ExternalAccess/OmniSharp/MetadataAsSource/OmniSharpMetadataAsSourceService.cs index 63c4dc0921433..ff2e30751a96d 100644 --- a/src/Tools/ExternalAccess/OmniSharp/MetadataAsSource/OmniSharpMetadataAsSourceService.cs +++ b/src/Tools/ExternalAccess/OmniSharp/MetadataAsSource/OmniSharpMetadataAsSourceService.cs @@ -9,6 +9,7 @@ using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.MetadataAsSource; using Microsoft.CodeAnalysis.Shared.Extensions; +using Microsoft.CodeAnalysis.Simplification; namespace Microsoft.CodeAnalysis.ExternalAccess.OmniSharp.MetadataAsSource { @@ -28,8 +29,11 @@ internal static class OmniSharpMetadataAsSourceService public static async Task AddSourceToAsync(Document document, Compilation symbolCompilation, ISymbol symbol, CancellationToken cancellationToken) { var service = document.GetRequiredLanguageService(); + var formattingOptions = await SyntaxFormattingOptions.FromDocumentAsync(document, cancellationToken).ConfigureAwait(false); - return await service.AddSourceToAsync(document, symbolCompilation, symbol, formattingOptions, cancellationToken).ConfigureAwait(false); + var simplifierOptions = await SimplifierOptions.FromDocumentAsync(document, fallbackOptions: null, cancellationToken).ConfigureAwait(false); + + return await service.AddSourceToAsync(document, symbolCompilation, symbol, formattingOptions, simplifierOptions, cancellationToken).ConfigureAwait(false); } /// @@ -46,7 +50,7 @@ public static async Task AddSourceToAsync(Document document, Compilati public static Task AddSourceToAsync(Document document, Compilation symbolCompilation, ISymbol symbol, OmniSharpSyntaxFormattingOptionsWrapper formattingOptions, CancellationToken cancellationToken) { var service = document.GetRequiredLanguageService(); - return service.AddSourceToAsync(document, symbolCompilation, symbol, formattingOptions.UnderlyingObject, cancellationToken); + return service.AddSourceToAsync(document, symbolCompilation, symbol, formattingOptions.FormattingOptions, formattingOptions.SimplifierOptions, cancellationToken); } } } diff --git a/src/VisualStudio/Core/Def/CodeCleanup/AbstractCodeCleanUpFixer.cs b/src/VisualStudio/Core/Def/CodeCleanup/AbstractCodeCleanUpFixer.cs index f235a0fc5db71..564667b3c88f5 100644 --- a/src/VisualStudio/Core/Def/CodeCleanup/AbstractCodeCleanUpFixer.cs +++ b/src/VisualStudio/Core/Def/CodeCleanup/AbstractCodeCleanUpFixer.cs @@ -134,7 +134,7 @@ private async Task FixHierarchyContentAsync(IVsHierarchyCodeCleanupScope h } var document = solution.GetRequiredDocument(documentId); - var options = _globalOptions.GetCodeActionOptions(document.Project.Language); + var options = _globalOptions.GetCodeActionOptions(document.Project.LanguageServices); return await FixDocumentAsync(document, options, context).ConfigureAwait(true); } } @@ -203,7 +203,7 @@ async Task ApplyFixAsync(ProgressTracker progressTracker, Cancellation var document = buffer.CurrentSnapshot.GetOpenDocumentInCurrentContextWithChanges(); Contract.ThrowIfNull(document); - var options = _globalOptions.GetCodeActionOptions(document.Project.Language); + var options = _globalOptions.GetCodeActionOptions(document.Project.LanguageServices); var newDoc = await FixDocumentAsync(document, context.EnabledFixIds, progressTracker, options, cancellationToken).ConfigureAwait(true); return newDoc.Project.Solution; } @@ -290,7 +290,7 @@ private async Task FixProjectAsync( progressTracker.AddItems(project.DocumentIds.Count); } - var ideOptions = _globalOptions.GetCodeActionOptions(project.Language); + var ideOptions = _globalOptions.GetCodeActionOptions(project.LanguageServices); foreach (var documentId in project.DocumentIds) { diff --git a/src/VisualStudio/Core/Def/Implementation/AbstractEditorFactory.cs b/src/VisualStudio/Core/Def/Implementation/AbstractEditorFactory.cs index 56a7eef0495a3..4f0f721f5358f 100644 --- a/src/VisualStudio/Core/Def/Implementation/AbstractEditorFactory.cs +++ b/src/VisualStudio/Core/Def/Implementation/AbstractEditorFactory.cs @@ -9,6 +9,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CodeCleanup; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.Shared.Extensions; @@ -324,26 +325,26 @@ private async Task FormatDocumentCreatedFromTemplateAsync(IVsHierarchy hierarchy var documentId = DocumentId.CreateNewId(projectToAddTo.Id); var forkedSolution = projectToAddTo.Solution.AddDocument(DocumentInfo.Create(documentId, filePath, loader: new FileTextLoader(filePath, defaultEncoding: null), filePath: filePath)); - var addedDocument = forkedSolution.GetDocument(documentId)!; + var addedDocument = forkedSolution.GetRequiredDocument(documentId); - var formattingOptions = await SyntaxFormattingOptions.FromDocumentAsync(addedDocument, cancellationToken).ConfigureAwait(true); + var cleanupOptions = await CodeCleanupOptions.FromDocumentAsync(addedDocument, fallbackOptions: null, cancellationToken).ConfigureAwait(true); // Call out to various new document formatters to tweak what they want var formattingService = addedDocument.GetLanguageService(); if (formattingService is not null) { - addedDocument = await formattingService.FormatNewDocumentAsync(addedDocument, hintDocument: null, formattingOptions, cancellationToken).ConfigureAwait(true); + addedDocument = await formattingService.FormatNewDocumentAsync(addedDocument, hintDocument: null, cleanupOptions, cancellationToken).ConfigureAwait(true); } var rootToFormat = await addedDocument.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(true); // Format document var unformattedText = await addedDocument.GetTextAsync(cancellationToken).ConfigureAwait(true); - var formattedRoot = Formatter.Format(rootToFormat, workspace.Services, formattingOptions, cancellationToken); + var formattedRoot = Formatter.Format(rootToFormat, workspace.Services, cleanupOptions.FormattingOptions, cancellationToken); var formattedText = formattedRoot.GetText(unformattedText.Encoding, unformattedText.ChecksumAlgorithm); // Ensure the line endings are normalized. The formatter doesn't touch everything if it doesn't need to. - var targetLineEnding = formattingOptions.NewLine; + var targetLineEnding = cleanupOptions.FormattingOptions.NewLine; var originalText = formattedText; foreach (var originalLine in originalText.Lines) diff --git a/src/VisualStudio/Core/Def/Snippets/AbstractSnippetExpansionClient.cs b/src/VisualStudio/Core/Def/Snippets/AbstractSnippetExpansionClient.cs index a4cd5c55d4fef..52968f5c64c83 100644 --- a/src/VisualStudio/Core/Def/Snippets/AbstractSnippetExpansionClient.cs +++ b/src/VisualStudio/Core/Def/Snippets/AbstractSnippetExpansionClient.cs @@ -65,7 +65,7 @@ internal abstract class AbstractSnippetExpansionClient : ForegroundThreadAffinit protected readonly Guid LanguageServiceGuid; protected readonly ITextView TextView; protected readonly ITextBuffer SubjectBuffer; - protected readonly IGlobalOptionService GlobalOptions; + internal readonly IGlobalOptionService GlobalOptions; private readonly ImmutableArray> _allArgumentProviders; private ImmutableArray _argumentProviders; diff --git a/src/VisualStudio/Core/Def/Snippets/SnippetFunctions/SnippetFunctionGenerateSwitchCases.cs b/src/VisualStudio/Core/Def/Snippets/SnippetFunctions/SnippetFunctionGenerateSwitchCases.cs index e5ae82936d202..bffd8dfbe24e7 100644 --- a/src/VisualStudio/Core/Def/Snippets/SnippetFunctions/SnippetFunctionGenerateSwitchCases.cs +++ b/src/VisualStudio/Core/Def/Snippets/SnippetFunctions/SnippetFunctionGenerateSwitchCases.cs @@ -9,6 +9,7 @@ using Microsoft.CodeAnalysis.Editor.Shared.Extensions; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.Shared.Extensions; +using Microsoft.CodeAnalysis.Simplification; using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.Text; using VsTextSpan = Microsoft.VisualStudio.TextManager.Interop.TextSpan; @@ -56,7 +57,9 @@ protected override int FieldChanged(string field, out int requeryFunction) return (VSConstants.S_OK, snippetFunctionService.SwitchDefaultCaseForm, hasCurrentValue); } - var value = await snippetFunctionService.GetSwitchExpansionAsync(document, caseGenerationSpan.Value, switchExpressionSpan.Value, cancellationToken).ConfigureAwait(false); + var simplifierOptions = await document.GetSimplifierOptionsAsync(snippetExpansionClient.GlobalOptions, cancellationToken).ConfigureAwait(false); + + var value = await snippetFunctionService.GetSwitchExpansionAsync(document, caseGenerationSpan.Value, switchExpressionSpan.Value, simplifierOptions, cancellationToken).ConfigureAwait(false); if (value == null) { return (VSConstants.S_OK, snippetFunctionService.SwitchDefaultCaseForm, hasCurrentValue); diff --git a/src/VisualStudio/Core/Def/Snippets/SnippetFunctions/SnippetFunctionSimpleTypeName.cs b/src/VisualStudio/Core/Def/Snippets/SnippetFunctions/SnippetFunctionSimpleTypeName.cs index a4771e60f23c3..6a4aa15ccc149 100644 --- a/src/VisualStudio/Core/Def/Snippets/SnippetFunctions/SnippetFunctionSimpleTypeName.cs +++ b/src/VisualStudio/Core/Def/Snippets/SnippetFunctions/SnippetFunctionSimpleTypeName.cs @@ -7,7 +7,7 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; -using Microsoft.CodeAnalysis.Shared.Extensions; +using Microsoft.CodeAnalysis.Simplification; using Microsoft.VisualStudio.Text; using TextSpan = Microsoft.CodeAnalysis.Text.TextSpan; using VsTextSpan = Microsoft.VisualStudio.TextManager.Interop.TextSpan; @@ -45,7 +45,9 @@ public SnippetFunctionSimpleTypeName( return (VSConstants.E_FAIL, value, hasDefaultValue); } - var simplifiedTypeName = await SnippetFunctionService.GetSimplifiedTypeNameAsync(document, fieldSpan.Value, _fullyQualifiedName, cancellationToken).ConfigureAwait(false); + var simplifierOptions = await document.GetSimplifierOptionsAsync(snippetExpansionClient.GlobalOptions, cancellationToken).ConfigureAwait(false); + + var simplifiedTypeName = await SnippetFunctionService.GetSimplifiedTypeNameAsync(document, fieldSpan.Value, _fullyQualifiedName, simplifierOptions, cancellationToken).ConfigureAwait(false); if (string.IsNullOrEmpty(simplifiedTypeName)) { return (VSConstants.E_FAIL, value, hasDefaultValue); diff --git a/src/VisualStudio/Core/Def/TableDataSource/Suppression/VisualStudioSuppressionFixService.cs b/src/VisualStudio/Core/Def/TableDataSource/Suppression/VisualStudioSuppressionFixService.cs index d835b1f65e8d9..079bc5f2bc78e 100644 --- a/src/VisualStudio/Core/Def/TableDataSource/Suppression/VisualStudioSuppressionFixService.cs +++ b/src/VisualStudio/Core/Def/TableDataSource/Suppression/VisualStudioSuppressionFixService.cs @@ -18,6 +18,7 @@ using Microsoft.CodeAnalysis.Editor.Implementation.Suggestions; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.ErrorReporting; +using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Shared.Extensions; @@ -298,16 +299,17 @@ private async Task ApplySuppressionFixAsync(IEnumerable? diagnos // We have different suppression fixers for every language. // So we need to group diagnostics by the containing project language and apply fixes separately. - var languages = new HashSet(projectDiagnosticsToFixMap.Select(p => p.Key.Language).Concat(documentDiagnosticsToFixMap.Select(kvp => kvp.Key.Project.Language))); + var languageServices = new HashSet(projectDiagnosticsToFixMap.Select(p => p.Key.LanguageServices).Concat(documentDiagnosticsToFixMap.Select(kvp => kvp.Key.Project.LanguageServices))); - foreach (var language in languages) + foreach (var languageService in languageServices) { // Use the Fix multiple occurrences service to compute a bulk suppression fix for the specified document and project diagnostics, // show a preview changes dialog and then apply the fix to the workspace. cancellationToken.ThrowIfCancellationRequested(); - var options = _globalOptions.GetCodeActionOptions(language); + var language = languageService.Language; + var options = _globalOptions.GetCodeActionOptions(languageService); var optionsProvider = new CodeActionOptionsProvider(_ => options); var documentDiagnosticsPerLanguage = GetDocumentDiagnosticsMappedToNewSolution(documentDiagnosticsToFixMap, newSolution, language); @@ -372,7 +374,7 @@ private async Task ApplySuppressionFixAsync(IEnumerable? diagnos newSolution, fixAllPreviewChangesTitle: title, fixAllTopLevelHeader: title, - languageOpt: languages?.Count == 1 ? languages.Single() : null, + languageOpt: languageServices?.Count == 1 ? languageServices.Single().Language : null, workspace: _workspace); if (newSolution == null) { diff --git a/src/VisualStudio/Core/Def/Venus/ContainedLanguageCodeSupport.cs b/src/VisualStudio/Core/Def/Venus/ContainedLanguageCodeSupport.cs index 3f1705282b801..be96f2931f05a 100644 --- a/src/VisualStudio/Core/Def/Venus/ContainedLanguageCodeSupport.cs +++ b/src/VisualStudio/Core/Def/Venus/ContainedLanguageCodeSupport.cs @@ -217,6 +217,8 @@ public static Tuple EnsureEventHandler( throw new InvalidOperationException(ServicesVSResources.Can_t_find_where_to_insert_member); } + var globalOptions = targetDocument.Project.Solution.Workspace.Services.GetRequiredService().GlobalOptions; + var options = codeGenerationService.GetOptions( targetSyntaxTree.Options, documentOptions, @@ -225,11 +227,13 @@ public static Tuple EnsureEventHandler( var newType = codeGenerationService.AddMethod(destinationType, newMethod, options, cancellationToken); var newRoot = targetSyntaxTree.GetRoot(cancellationToken).ReplaceNode(destinationType, newType); + var formattingOptions = SyntaxFormattingOptions.FromDocumentAsync(targetDocument, cancellationToken).WaitAndGetResult_Venus(cancellationToken); + var simplifierOptions = targetDocument.GetSimplifierOptionsAsync(globalOptions, cancellationToken).WaitAndGetResult_Venus(cancellationToken); + newRoot = Simplifier.ReduceAsync( - targetDocument.WithSyntaxRoot(newRoot), Simplifier.Annotation, null, cancellationToken).WaitAndGetResult_Venus(cancellationToken).GetSyntaxRootSynchronously(cancellationToken); + targetDocument.WithSyntaxRoot(newRoot), Simplifier.Annotation, simplifierOptions, cancellationToken).WaitAndGetResult_Venus(cancellationToken).GetSyntaxRootSynchronously(cancellationToken); var formattingRules = additionalFormattingRule.Concat(Formatter.GetDefaultFormattingRules(targetDocument)); - var formattingOptions = SyntaxFormattingOptions.FromDocumentAsync(targetDocument, cancellationToken).WaitAndGetResult_Venus(cancellationToken); newRoot = Formatter.Format( newRoot, diff --git a/src/VisualStudio/Core/Def/Workspace/VisualStudioSymbolNavigationService.cs b/src/VisualStudio/Core/Def/Workspace/VisualStudioSymbolNavigationService.cs index b66f02e32a750..91e629a91de54 100644 --- a/src/VisualStudio/Core/Def/Workspace/VisualStudioSymbolNavigationService.cs +++ b/src/VisualStudio/Core/Def/Workspace/VisualStudioSymbolNavigationService.cs @@ -124,7 +124,7 @@ public VisualStudioSymbolNavigationService( private async Task GetNavigableLocationForMetadataAsync( Project project, ISymbol symbol, CancellationToken cancellationToken) { - var masOptions = _globalOptions.GetMetadataAsSourceOptions(); + var masOptions = _globalOptions.GetMetadataAsSourceOptions(project.LanguageServices); var result = await _metadataAsSourceFileService.GetGeneratedFileAsync(project, symbol, signaturesOnly: false, masOptions, cancellationToken).ConfigureAwait(false); diff --git a/src/VisualStudio/Core/Impl/CodeModel/AbstractCodeModelService.cs b/src/VisualStudio/Core/Impl/CodeModel/AbstractCodeModelService.cs index e841628c3c4b9..a82086259243f 100644 --- a/src/VisualStudio/Core/Impl/CodeModel/AbstractCodeModelService.cs +++ b/src/VisualStudio/Core/Impl/CodeModel/AbstractCodeModelService.cs @@ -1083,13 +1083,11 @@ private SyntaxNode InsertNode( if (!batchMode) { - document = _threadingContext.JoinableTaskFactory.Run(() => - Simplifier.ReduceAsync( - document, - annotation, - optionSet: null, - cancellationToken: cancellationToken) - ); + document = _threadingContext.JoinableTaskFactory.Run(async () => + { + var simplifierOptions = await SimplifierOptions.FromDocumentAsync(document, fallbackOptions: null, cancellationToken).ConfigureAwait(false); + return await Simplifier.ReduceAsync(document, annotation, simplifierOptions, cancellationToken).ConfigureAwait(false); + }); } document = FormatAnnotatedNode(document, annotation, new[] { _lineAdjustmentFormattingRule, _endRegionFormattingRule }, cancellationToken); diff --git a/src/VisualStudio/Core/Impl/CodeModel/FileCodeModel.cs b/src/VisualStudio/Core/Impl/CodeModel/FileCodeModel.cs index 849133f824a22..388795532ac15 100644 --- a/src/VisualStudio/Core/Impl/CodeModel/FileCodeModel.cs +++ b/src/VisualStudio/Core/Impl/CodeModel/FileCodeModel.cs @@ -703,8 +703,11 @@ int IVBFileCodeModelEvents.EndEdit() if (_batchDocument != null) { // perform expensive operations at once - var newDocument = State.ThreadingContext.JoinableTaskFactory.Run(() => - Simplifier.ReduceAsync(_batchDocument, Simplifier.Annotation, cancellationToken: CancellationToken.None)); + var newDocument = State.ThreadingContext.JoinableTaskFactory.Run(async () => + { + var simplifierOptions = await SimplifierOptions.FromDocumentAsync(_batchDocument, fallbackOptions: null, CancellationToken.None).ConfigureAwait(false); + return await Simplifier.ReduceAsync(_batchDocument, Simplifier.Annotation, simplifierOptions, CancellationToken.None).ConfigureAwait(false); + }); _batchDocument.Project.Solution.Workspace.TryApplyChanges(newDocument.Project.Solution); diff --git a/src/VisualStudio/Core/Test.Next/Services/VisualStudioDiagnosticAnalyzerExecutorTests.cs b/src/VisualStudio/Core/Test.Next/Services/VisualStudioDiagnosticAnalyzerExecutorTests.cs index 8720b87aa8428..cfbaaca97a9ba 100644 --- a/src/VisualStudio/Core/Test.Next/Services/VisualStudioDiagnosticAnalyzerExecutorTests.cs +++ b/src/VisualStudio/Core/Test.Next/Services/VisualStudioDiagnosticAnalyzerExecutorTests.cs @@ -13,6 +13,7 @@ using Microsoft.CodeAnalysis.CodeStyle; using Microsoft.CodeAnalysis.CSharp.CodeStyle; using Microsoft.CodeAnalysis.CSharp.Diagnostics.TypeStyle; +using Microsoft.CodeAnalysis.CSharp.Simplification; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Editor.UnitTests; using Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces; @@ -45,24 +46,22 @@ void Method() } }"; - using (var workspace = CreateWorkspace(LanguageNames.CSharp, code)) - { - var analyzerType = typeof(CSharpUseExplicitTypeDiagnosticAnalyzer); - var analyzerResult = await AnalyzeAsync(workspace, workspace.CurrentSolution.ProjectIds.First(), analyzerType); + using var workspace = CreateWorkspace(LanguageNames.CSharp, code); + var analyzerType = typeof(CSharpUseExplicitTypeDiagnosticAnalyzer); + var analyzerResult = await AnalyzeAsync(workspace, workspace.CurrentSolution.ProjectIds.First(), analyzerType, IdeAnalyzerOptions.Default); - var diagnostics = analyzerResult.GetDocumentDiagnostics(analyzerResult.DocumentIds.First(), AnalysisKind.Semantic); - Assert.Equal(IDEDiagnosticIds.UseExplicitTypeDiagnosticId, diagnostics[0].Id); - Assert.Equal(DiagnosticSeverity.Hidden, diagnostics[0].Severity); + var diagnostics = analyzerResult.GetDocumentDiagnostics(analyzerResult.DocumentIds.First(), AnalysisKind.Semantic); + Assert.Equal(IDEDiagnosticIds.UseExplicitTypeDiagnosticId, diagnostics[0].Id); + Assert.Equal(DiagnosticSeverity.Hidden, diagnostics[0].Severity); - // set option - workspace.TryApplyChanges(workspace.CurrentSolution.WithOptions(workspace.Options - .WithChangedOption(CSharpCodeStyleOptions.VarWhenTypeIsApparent, new CodeStyleOption(false, NotificationOption.Suggestion)))); - analyzerResult = await AnalyzeAsync(workspace, workspace.CurrentSolution.ProjectIds.First(), analyzerType); + var ideOptions = new IdeAnalyzerOptions( + SimplifierOptions: new CSharpSimplifierOptions(varWhenTypeIsApparent: new CodeStyleOption2(false, NotificationOption2.Suggestion))); - diagnostics = analyzerResult.GetDocumentDiagnostics(analyzerResult.DocumentIds.First(), AnalysisKind.Semantic); - Assert.Equal(IDEDiagnosticIds.UseExplicitTypeDiagnosticId, diagnostics[0].Id); - Assert.Equal(DiagnosticSeverity.Info, diagnostics[0].Severity); - } + analyzerResult = await AnalyzeAsync(workspace, workspace.CurrentSolution.ProjectIds.First(), analyzerType, ideOptions); + + diagnostics = analyzerResult.GetDocumentDiagnostics(analyzerResult.DocumentIds.First(), AnalysisKind.Semantic); + Assert.Equal(IDEDiagnosticIds.UseExplicitTypeDiagnosticId, diagnostics[0].Id); + Assert.Equal(DiagnosticSeverity.Info, diagnostics[0].Severity); } [Fact, Trait(Traits.Feature, Traits.Features.RemoteHost)] @@ -82,14 +81,14 @@ End Sub .WithChangedOption(CodeStyleOptions2.PreferNullPropagation, LanguageNames.VisualBasic, new CodeStyleOption2(false, NotificationOption2.Silent)))); var analyzerType = typeof(VisualBasicUseNullPropagationDiagnosticAnalyzer); - var analyzerResult = await AnalyzeAsync(workspace, workspace.CurrentSolution.ProjectIds.First(), analyzerType); + var analyzerResult = await AnalyzeAsync(workspace, workspace.CurrentSolution.ProjectIds.First(), analyzerType, IdeAnalyzerOptions.Default); Assert.True(analyzerResult.IsEmpty); // set option workspace.TryApplyChanges(workspace.CurrentSolution.WithOptions(workspace.Options .WithChangedOption(CodeStyleOptions2.PreferNullPropagation, LanguageNames.VisualBasic, new CodeStyleOption2(true, NotificationOption2.Error)))); - analyzerResult = await AnalyzeAsync(workspace, workspace.CurrentSolution.ProjectIds.First(), analyzerType); + analyzerResult = await AnalyzeAsync(workspace, workspace.CurrentSolution.ProjectIds.First(), analyzerType, IdeAnalyzerOptions.Default); var diagnostics = analyzerResult.GetDocumentDiagnostics(analyzerResult.DocumentIds.First(), AnalysisKind.Semantic); Assert.Equal(IDEDiagnosticIds.UseNullPropagationDiagnosticId, diagnostics[0].Id); @@ -111,7 +110,7 @@ public async Task TestCancellation() try { - var task = Task.Run(() => AnalyzeAsync(workspace, workspace.CurrentSolution.ProjectIds.First(), analyzerType, source.Token)); + var task = Task.Run(() => AnalyzeAsync(workspace, workspace.CurrentSolution.ProjectIds.First(), analyzerType, IdeAnalyzerOptions.Default, source.Token)); // wait random milli-second var random = new Random(Environment.TickCount); @@ -217,7 +216,7 @@ void Method() private static InProcOrRemoteHostAnalyzerRunner CreateAnalyzerRunner() => new(new DiagnosticAnalyzerInfoCache()); - private static async Task AnalyzeAsync(TestWorkspace workspace, ProjectId projectId, Type analyzerType, CancellationToken cancellationToken = default) + private static async Task AnalyzeAsync(TestWorkspace workspace, ProjectId projectId, Type analyzerType, IdeAnalyzerOptions ideOptions, CancellationToken cancellationToken = default) { var executor = CreateAnalyzerRunner(); @@ -226,7 +225,7 @@ private static async Task AnalyzeAsync(TestWorkspace w var analyzerDriver = (await project.GetCompilationAsync()).WithAnalyzers( analyzerReference.GetAnalyzers(project.Language).Where(a => a.GetType() == analyzerType).ToImmutableArray(), - new WorkspaceAnalyzerOptions(project.AnalyzerOptions, project.Solution, IdeAnalyzerOptions.Default)); + new WorkspaceAnalyzerOptions(project.AnalyzerOptions, project.Solution, ideOptions)); var result = await executor.AnalyzeProjectAsync(project, analyzerDriver, forceExecuteAllAnalyzers: true, logPerformanceInfo: false, getTelemetryInfo: false, cancellationToken); diff --git a/src/VisualStudio/Xaml/Impl/Implementation/LanguageServer/Handler/Definitions/GoToDefinitionHandler.cs b/src/VisualStudio/Xaml/Impl/Implementation/LanguageServer/Handler/Definitions/GoToDefinitionHandler.cs index cb2c3dc254201..adbcbe894fa56 100644 --- a/src/VisualStudio/Xaml/Impl/Implementation/LanguageServer/Handler/Definitions/GoToDefinitionHandler.cs +++ b/src/VisualStudio/Xaml/Impl/Implementation/LanguageServer/Handler/Definitions/GoToDefinitionHandler.cs @@ -173,7 +173,7 @@ public GoToDefinitionHandler(IMetadataAsSourceFileService metadataAsSourceFileSe var project = context.Document?.GetCodeProject(); if (project != null) { - var options = globalOptions.GetMetadataAsSourceOptions(); + var options = globalOptions.GetMetadataAsSourceOptions(project.LanguageServices); var declarationFile = await metadataAsSourceFileService.GetGeneratedFileAsync(project, symbol, signaturesOnly: true, options, cancellationToken).ConfigureAwait(false); var linePosSpan = declarationFile.IdentifierLocation.GetLineSpan().Span; locations.Add(new LSP.Location diff --git a/src/Workspaces/CSharp/Portable/Simplification/CSharpSimplificationService.NodesAndTokensToReduceComputer.cs b/src/Workspaces/CSharp/Portable/Simplification/CSharpSimplificationService.NodesAndTokensToReduceComputer.cs index c0567199845c8..23aed3551219c 100644 --- a/src/Workspaces/CSharp/Portable/Simplification/CSharpSimplificationService.NodesAndTokensToReduceComputer.cs +++ b/src/Workspaces/CSharp/Portable/Simplification/CSharpSimplificationService.NodesAndTokensToReduceComputer.cs @@ -14,7 +14,7 @@ namespace Microsoft.CodeAnalysis.CSharp.Simplification { - internal partial class CSharpSimplificationService : AbstractSimplificationService + internal partial class CSharpSimplificationService { private class NodesAndTokensToReduceComputer : CSharpSyntaxRewriter { diff --git a/src/Workspaces/CSharp/Portable/Simplification/CSharpSimplificationService.cs b/src/Workspaces/CSharp/Portable/Simplification/CSharpSimplificationService.cs index d281c3cf13c0e..6ee54271b0f42 100644 --- a/src/Workspaces/CSharp/Portable/Simplification/CSharpSimplificationService.cs +++ b/src/Workspaces/CSharp/Portable/Simplification/CSharpSimplificationService.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System; using System.Collections.Generic; using System.Collections.Immutable; @@ -12,6 +10,7 @@ using System.Threading; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.CSharp.Utilities; +using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Internal.Log; @@ -45,7 +44,13 @@ public CSharpSimplificationService() : base(s_reducers) { } - public override SyntaxNode Expand(SyntaxNode node, SemanticModel semanticModel, SyntaxAnnotation annotationForReplacedAliasIdentifier, Func expandInsideNode, bool expandParameter, CancellationToken cancellationToken) + public override SimplifierOptions DefaultOptions + => CSharpSimplifierOptions.Default; + + public override SimplifierOptions GetSimplifierOptions(AnalyzerConfigOptions options, SimplifierOptions? fallbackOptions) + => CSharpSimplifierOptions.Create(options, (CSharpSimplifierOptions?)fallbackOptions); + + public override SyntaxNode Expand(SyntaxNode node, SemanticModel semanticModel, SyntaxAnnotation? annotationForReplacedAliasIdentifier, Func? expandInsideNode, bool expandParameter, CancellationToken cancellationToken) { using (Logger.LogBlock(FunctionId.Simplifier_ExpandNode, cancellationToken)) { @@ -70,8 +75,10 @@ TypeConstraintSyntax or } } - public override SyntaxToken Expand(SyntaxToken token, SemanticModel semanticModel, Func expandInsideNode, CancellationToken cancellationToken) + public override SyntaxToken Expand(SyntaxToken token, SemanticModel semanticModel, Func? expandInsideNode, CancellationToken cancellationToken) { + Contract.ThrowIfNull(token.Parent); + using (Logger.LogBlock(FunctionId.Simplifier_ExpandToken, cancellationToken)) { var rewriter = new Expander(semanticModel, expandInsideNode, false, cancellationToken); @@ -105,14 +112,14 @@ public static SyntaxToken TryEscapeIdentifierToken(SyntaxToken syntaxToken, Synt } var parent = parentOfToken.Parent; - if (parentOfToken is SimpleNameSyntax && parent.Kind() == SyntaxKind.XmlNameAttribute) + if (parentOfToken is SimpleNameSyntax && parent.IsKind(SyntaxKind.XmlNameAttribute)) { // do not try to escape XML name attributes return syntaxToken; } // do not escape global in a namespace qualified name - if (parent.Kind() == SyntaxKind.AliasQualifiedName && + if (parent.IsKind(SyntaxKind.AliasQualifiedName) && syntaxToken.ValueText == "global") { return syntaxToken; diff --git a/src/Workspaces/CSharp/Portable/Simplification/Reducers/AbstractCSharpReducer.AbstractReductionRewriter.cs b/src/Workspaces/CSharp/Portable/Simplification/Reducers/AbstractCSharpReducer.AbstractReductionRewriter.cs index 40a92c1dc9529..a000589689374 100644 --- a/src/Workspaces/CSharp/Portable/Simplification/Reducers/AbstractCSharpReducer.AbstractReductionRewriter.cs +++ b/src/Workspaces/CSharp/Portable/Simplification/Reducers/AbstractCSharpReducer.AbstractReductionRewriter.cs @@ -2,17 +2,16 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System; using System.Collections.Generic; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Threading; using Microsoft.CodeAnalysis.CSharp.Syntax; -using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Simplification; +using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CSharp.Simplification { @@ -22,10 +21,10 @@ protected abstract class AbstractReductionRewriter : CSharpSyntaxRewriter, IRedu { private readonly ObjectPool _pool; - protected CSharpParseOptions ParseOptions { get; private set; } - protected OptionSet OptionSet { get; private set; } + protected CSharpParseOptions? ParseOptions { get; private set; } + protected CSharpSimplifierOptions? Options { get; private set; } protected CancellationToken CancellationToken { get; private set; } - protected SemanticModel SemanticModel { get; private set; } + protected SemanticModel? SemanticModel { get; private set; } public bool HasMoreWork { get; private set; } @@ -38,17 +37,19 @@ protected abstract class AbstractReductionRewriter : CSharpSyntaxRewriter, IRedu protected AbstractReductionRewriter(ObjectPool pool) => _pool = pool; - public void Initialize(ParseOptions parseOptions, OptionSet optionSet, CancellationToken cancellationToken) + public void Initialize(ParseOptions parseOptions, SimplifierOptions options, CancellationToken cancellationToken) { + Contract.ThrowIfNull(options); + ParseOptions = (CSharpParseOptions)parseOptions; - OptionSet = optionSet; + Options = (CSharpSimplifierOptions)options; CancellationToken = cancellationToken; } public void Dispose() { ParseOptions = null; - OptionSet = null; + Options = null; CancellationToken = CancellationToken.None; _processedParentNodes.Clear(); SemanticModel = null; @@ -58,7 +59,15 @@ public void Dispose() _pool.Free(this); } - private static SyntaxNode GetParentNode(SyntaxNode node) + [MemberNotNull(nameof(Options), nameof(ParseOptions), nameof(SemanticModel))] + public void RequireInitialized() + { + Contract.ThrowIfNull(ParseOptions); + Contract.ThrowIfNull(Options); + Contract.ThrowIfNull(SemanticModel); + } + + private static SyntaxNode? GetParentNode(SyntaxNode node) => node switch { ExpressionSyntax expression => GetParentNode(expression), @@ -70,7 +79,7 @@ private static SyntaxNode GetParentNode(SyntaxNode node) private static SyntaxNode GetParentNode(ExpressionSyntax expression) { var lastExpression = expression; - for (SyntaxNode current = expression; current != null; current = current.Parent) + for (SyntaxNode? current = expression; current != null; current = current.Parent) { if (current is ExpressionSyntax currentExpression) { @@ -78,13 +87,14 @@ private static SyntaxNode GetParentNode(ExpressionSyntax expression) } } + Contract.ThrowIfNull(lastExpression.Parent); return lastExpression.Parent; } private static SyntaxNode GetParentNode(PatternSyntax pattern) { var lastPattern = pattern; - for (SyntaxNode current = pattern; current != null; current = current.Parent) + for (SyntaxNode? current = pattern; current != null; current = current.Parent) { if (current is PatternSyntax currentPattern) { @@ -92,6 +102,7 @@ private static SyntaxNode GetParentNode(PatternSyntax pattern) } } + Contract.ThrowIfNull(lastPattern.Parent); return lastPattern.Parent; } @@ -102,6 +113,7 @@ private static SyntaxNode GetParentNode(CrefSyntax cref) .OfType() .LastOrDefault(); + Contract.ThrowIfNull(topMostCref.Parent); return topMostCref.Parent; } @@ -109,10 +121,10 @@ protected SyntaxNode SimplifyNode( TNode node, SyntaxNode newNode, SyntaxNode parentNode, - Func simplifier) + Func simplifier) where TNode : SyntaxNode { - Debug.Assert(parentNode != null); + RequireInitialized(); this.CancellationToken.ThrowIfCancellationRequested(); @@ -129,7 +141,7 @@ protected SyntaxNode SimplifyNode( if (!node.HasAnnotation(SimplificationHelpers.DontSimplifyAnnotation)) { - var simplifiedNode = simplifier(node, this.SemanticModel, this.OptionSet, this.CancellationToken); + var simplifiedNode = simplifier(node, this.SemanticModel, this.Options, this.CancellationToken); if (simplifiedNode != node) { _processedParentNodes.Add(parentNode); @@ -144,7 +156,7 @@ protected SyntaxNode SimplifyNode( protected SyntaxNode SimplifyExpression( TExpression expression, SyntaxNode newNode, - Func simplifier) + Func simplifier) where TExpression : SyntaxNode { var parentNode = GetParentNode(expression); @@ -154,12 +166,14 @@ protected SyntaxNode SimplifyExpression( return SimplifyNode(expression, newNode, parentNode, simplifier); } - protected SyntaxToken SimplifyToken(SyntaxToken token, Func simplifier) + protected SyntaxToken SimplifyToken(SyntaxToken token, Func simplifier) { + RequireInitialized(); + this.CancellationToken.ThrowIfCancellationRequested(); return token.HasAnnotation(Simplifier.Annotation) - ? simplifier(token, this.SemanticModel, this.OptionSet, this.CancellationToken) + ? simplifier(token, this.SemanticModel, this.Options, this.CancellationToken) : token; } diff --git a/src/Workspaces/CSharp/Portable/Simplification/Reducers/AbstractCSharpReducer.cs b/src/Workspaces/CSharp/Portable/Simplification/Reducers/AbstractCSharpReducer.cs index ab994785f46a4..e9d52550059cb 100644 --- a/src/Workspaces/CSharp/Portable/Simplification/Reducers/AbstractCSharpReducer.cs +++ b/src/Workspaces/CSharp/Portable/Simplification/Reducers/AbstractCSharpReducer.cs @@ -14,5 +14,10 @@ internal abstract partial class AbstractCSharpReducer : AbstractReducer protected AbstractCSharpReducer(ObjectPool pool) : base(pool) { } + + public sealed override bool IsApplicable(SimplifierOptions options) + => IsApplicable((CSharpSimplifierOptions)options); + + protected abstract bool IsApplicable(CSharpSimplifierOptions options); } } diff --git a/src/Workspaces/CSharp/Portable/Simplification/Reducers/CSharpCastReducer.cs b/src/Workspaces/CSharp/Portable/Simplification/Reducers/CSharpCastReducer.cs index b89cb525e4d0f..7c45a8d50b8f5 100644 --- a/src/Workspaces/CSharp/Portable/Simplification/Reducers/CSharpCastReducer.cs +++ b/src/Workspaces/CSharp/Portable/Simplification/Reducers/CSharpCastReducer.cs @@ -9,8 +9,8 @@ using Microsoft.CodeAnalysis.CSharp.Extensions; using Microsoft.CodeAnalysis.CSharp.Simplification.Simplifiers; using Microsoft.CodeAnalysis.CSharp.Syntax; -using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.PooledObjects; +using Microsoft.CodeAnalysis.Simplification; namespace Microsoft.CodeAnalysis.CSharp.Simplification { @@ -23,9 +23,12 @@ public CSharpCastReducer() : base(s_pool) { } - private static readonly Func s_simplifyCast = SimplifyCast; + protected override bool IsApplicable(CSharpSimplifierOptions options) + => true; - private static ExpressionSyntax SimplifyCast(CastExpressionSyntax node, SemanticModel semanticModel, OptionSet optionSet, CancellationToken cancellationToken) + private static readonly Func s_simplifyCast = SimplifyCast; + + private static ExpressionSyntax SimplifyCast(CastExpressionSyntax node, SemanticModel semanticModel, SimplifierOptions options, CancellationToken cancellationToken) { if (!CastSimplifier.IsUnnecessaryCast(node, semanticModel, cancellationToken)) { diff --git a/src/Workspaces/CSharp/Portable/Simplification/Reducers/CSharpDefaultExpressionReducer.Rewriter.cs b/src/Workspaces/CSharp/Portable/Simplification/Reducers/CSharpDefaultExpressionReducer.Rewriter.cs index c794d49d18217..5eaf06750c7fa 100644 --- a/src/Workspaces/CSharp/Portable/Simplification/Reducers/CSharpDefaultExpressionReducer.Rewriter.cs +++ b/src/Workspaces/CSharp/Portable/Simplification/Reducers/CSharpDefaultExpressionReducer.Rewriter.cs @@ -11,6 +11,7 @@ using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.PooledObjects; +using Microsoft.CodeAnalysis.Simplification; namespace Microsoft.CodeAnalysis.CSharp.Simplification { @@ -24,15 +25,15 @@ public Rewriter(ObjectPool pool) _simplifyDefaultExpression = SimplifyDefaultExpression; } - private readonly Func _simplifyDefaultExpression; + private readonly Func _simplifyDefaultExpression; private SyntaxNode SimplifyDefaultExpression( DefaultExpressionSyntax node, SemanticModel semanticModel, - OptionSet optionSet, + CSharpSimplifierOptions options, CancellationToken cancellationToken) { - var preferSimpleDefaultExpression = optionSet.GetOption(CSharpCodeStyleOptions.PreferSimpleDefaultExpression).Value; + var preferSimpleDefaultExpression = options.PreferSimpleDefaultExpression.Value; if (node.CanReplaceWithDefaultLiteral(ParseOptions, preferSimpleDefaultExpression, semanticModel, cancellationToken)) { diff --git a/src/Workspaces/CSharp/Portable/Simplification/Reducers/CSharpDefaultExpressionReducer.cs b/src/Workspaces/CSharp/Portable/Simplification/Reducers/CSharpDefaultExpressionReducer.cs index 560951edef4fa..8246972fde934 100644 --- a/src/Workspaces/CSharp/Portable/Simplification/Reducers/CSharpDefaultExpressionReducer.cs +++ b/src/Workspaces/CSharp/Portable/Simplification/Reducers/CSharpDefaultExpressionReducer.cs @@ -16,5 +16,8 @@ internal partial class CSharpDefaultExpressionReducer : AbstractCSharpReducer public CSharpDefaultExpressionReducer() : base(s_pool) { } + + protected override bool IsApplicable(CSharpSimplifierOptions options) + => true; } } diff --git a/src/Workspaces/CSharp/Portable/Simplification/Reducers/CSharpEscapingReducer.cs b/src/Workspaces/CSharp/Portable/Simplification/Reducers/CSharpEscapingReducer.cs index 724f077f6b1a6..15a9689552b61 100644 --- a/src/Workspaces/CSharp/Portable/Simplification/Reducers/CSharpEscapingReducer.cs +++ b/src/Workspaces/CSharp/Portable/Simplification/Reducers/CSharpEscapingReducer.cs @@ -21,16 +21,19 @@ internal partial class CSharpEscapingReducer : AbstractCSharpReducer private static readonly ObjectPool s_pool = new( () => new Rewriter(s_pool)); + private static readonly Func s_simplifyIdentifierToken = SimplifyIdentifierToken; + public CSharpEscapingReducer() : base(s_pool) { } - private static readonly Func s_simplifyIdentifierToken = SimplifyIdentifierToken; + protected override bool IsApplicable(CSharpSimplifierOptions options) + => true; private static SyntaxToken SimplifyIdentifierToken( SyntaxToken token, SemanticModel semanticModel, - OptionSet optionSet, + CSharpSimplifierOptions options, CancellationToken cancellationToken) { var unescapedIdentifier = token.ValueText; diff --git a/src/Workspaces/CSharp/Portable/Simplification/Reducers/CSharpExtensionMethodReducer.cs b/src/Workspaces/CSharp/Portable/Simplification/Reducers/CSharpExtensionMethodReducer.cs index ee889336e0897..52d48f8c2c31a 100644 --- a/src/Workspaces/CSharp/Portable/Simplification/Reducers/CSharpExtensionMethodReducer.cs +++ b/src/Workspaces/CSharp/Portable/Simplification/Reducers/CSharpExtensionMethodReducer.cs @@ -21,16 +21,19 @@ internal partial class CSharpExtensionMethodReducer : AbstractCSharpReducer private static readonly ObjectPool s_pool = new( () => new Rewriter(s_pool)); + private static readonly Func s_simplifyExtensionMethod = SimplifyExtensionMethod; + public CSharpExtensionMethodReducer() : base(s_pool) { } - private static readonly Func s_simplifyExtensionMethod = SimplifyExtensionMethod; + protected override bool IsApplicable(CSharpSimplifierOptions options) + => true; private static SyntaxNode SimplifyExtensionMethod( InvocationExpressionSyntax node, SemanticModel semanticModel, - OptionSet optionSet, + CSharpSimplifierOptions options, CancellationToken cancellationToken) { var rewrittenNode = node; diff --git a/src/Workspaces/CSharp/Portable/Simplification/Reducers/CSharpInferredMemberNameReducer.Rewriter.cs b/src/Workspaces/CSharp/Portable/Simplification/Reducers/CSharpInferredMemberNameReducer.Rewriter.cs index 8a9d24d349303..083b2604f1521 100644 --- a/src/Workspaces/CSharp/Portable/Simplification/Reducers/CSharpInferredMemberNameReducer.Rewriter.cs +++ b/src/Workspaces/CSharp/Portable/Simplification/Reducers/CSharpInferredMemberNameReducer.Rewriter.cs @@ -9,6 +9,7 @@ using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.PooledObjects; +using Microsoft.CodeAnalysis.Simplification; namespace Microsoft.CodeAnalysis.CSharp.Simplification { @@ -24,9 +25,9 @@ public Rewriter(ObjectPool pool) s_simplifyTupleName = SimplifyTupleName; } - private readonly Func s_simplifyTupleName; + private readonly Func s_simplifyTupleName; - private ArgumentSyntax SimplifyTupleName(ArgumentSyntax node, SemanticModel semanticModel, OptionSet optionSet, CancellationToken cancellationToken) + private ArgumentSyntax SimplifyTupleName(ArgumentSyntax node, SemanticModel semanticModel, SimplifierOptions options, CancellationToken cancellationToken) { if (CanSimplifyTupleElementName(node, this.ParseOptions)) { @@ -36,9 +37,9 @@ private ArgumentSyntax SimplifyTupleName(ArgumentSyntax node, SemanticModel sema return node; } - private static readonly Func s_simplifyAnonymousTypeMemberName = SimplifyAnonymousTypeMemberName; + private static readonly Func s_simplifyAnonymousTypeMemberName = SimplifyAnonymousTypeMemberName; - private static SyntaxNode SimplifyAnonymousTypeMemberName(AnonymousObjectMemberDeclaratorSyntax node, SemanticModel semanticModel, OptionSet optionSet, CancellationToken canellationToken) + private static SyntaxNode SimplifyAnonymousTypeMemberName(AnonymousObjectMemberDeclaratorSyntax node, SemanticModel semanticModel, SimplifierOptions options, CancellationToken canellationToken) { if (CanSimplifyAnonymousTypeMemberName(node)) diff --git a/src/Workspaces/CSharp/Portable/Simplification/Reducers/CSharpInferredMemberNameReducer.cs b/src/Workspaces/CSharp/Portable/Simplification/Reducers/CSharpInferredMemberNameReducer.cs index 5c6476d9fde7c..548fcd8eb098f 100644 --- a/src/Workspaces/CSharp/Portable/Simplification/Reducers/CSharpInferredMemberNameReducer.cs +++ b/src/Workspaces/CSharp/Portable/Simplification/Reducers/CSharpInferredMemberNameReducer.cs @@ -21,5 +21,8 @@ internal partial class CSharpInferredMemberNameReducer : AbstractCSharpReducer public CSharpInferredMemberNameReducer() : base(s_pool) { } + + protected override bool IsApplicable(CSharpSimplifierOptions options) + => true; } } diff --git a/src/Workspaces/CSharp/Portable/Simplification/Reducers/CSharpMiscellaneousReducer.cs b/src/Workspaces/CSharp/Portable/Simplification/Reducers/CSharpMiscellaneousReducer.cs index 060b459076970..3a4bc280da799 100644 --- a/src/Workspaces/CSharp/Portable/Simplification/Reducers/CSharpMiscellaneousReducer.cs +++ b/src/Workspaces/CSharp/Portable/Simplification/Reducers/CSharpMiscellaneousReducer.cs @@ -24,10 +24,15 @@ internal partial class CSharpMiscellaneousReducer : AbstractCSharpReducer private static readonly ObjectPool s_pool = new( () => new Rewriter(s_pool)); + private static readonly Func s_simplifyParameter = SimplifyParameter; + public CSharpMiscellaneousReducer() : base(s_pool) { } + protected override bool IsApplicable(CSharpSimplifierOptions options) + => true; + private static bool CanRemoveTypeFromParameter( ParameterSyntax parameterSyntax, SemanticModel semanticModel, @@ -61,12 +66,10 @@ private static bool CanRemoveTypeFromParameter( return false; } - private static readonly Func s_simplifyParameter = SimplifyParameter; - private static SyntaxNode SimplifyParameter( ParameterSyntax node, SemanticModel semanticModel, - OptionSet optionSet, + SimplifierOptions options, CancellationToken cancellationToken) { if (CanRemoveTypeFromParameter(node, semanticModel, cancellationToken)) @@ -79,12 +82,12 @@ private static SyntaxNode SimplifyParameter( return node; } - private static readonly Func s_simplifyParenthesizedLambdaExpression = SimplifyParenthesizedLambdaExpression; + private static readonly Func s_simplifyParenthesizedLambdaExpression = SimplifyParenthesizedLambdaExpression; private static SyntaxNode SimplifyParenthesizedLambdaExpression( ParenthesizedLambdaExpressionSyntax parenthesizedLambda, SemanticModel semanticModel, - OptionSet optionSet, + SimplifierOptions options, CancellationToken cancellationToken) { if (parenthesizedLambda.ParameterList != null && @@ -107,12 +110,12 @@ private static SyntaxNode SimplifyParenthesizedLambdaExpression( return parenthesizedLambda; } - private static readonly Func s_simplifyBlock = SimplifyBlock; + private static readonly Func s_simplifyBlock = SimplifyBlock; private static SyntaxNode SimplifyBlock( BlockSyntax node, SemanticModel semanticModel, - OptionSet optionSet, + CSharpSimplifierOptions options, CancellationToken cancellationToken) { if (node.Statements.Count != 1) @@ -125,7 +128,7 @@ private static SyntaxNode SimplifyBlock( return node; } - switch (optionSet.GetOption(CSharpCodeStyleOptions.PreferBraces).Value) + switch (options.PreferBraces.Value) { case PreferBracesPreference.Always: default: diff --git a/src/Workspaces/CSharp/Portable/Simplification/Reducers/CSharpNameReducer.cs b/src/Workspaces/CSharp/Portable/Simplification/Reducers/CSharpNameReducer.cs index 2aeaff2c19345..1f285d5c23a83 100644 --- a/src/Workspaces/CSharp/Portable/Simplification/Reducers/CSharpNameReducer.cs +++ b/src/Workspaces/CSharp/Portable/Simplification/Reducers/CSharpNameReducer.cs @@ -21,16 +21,19 @@ internal partial class CSharpNameReducer : AbstractCSharpReducer private static readonly ObjectPool s_pool = new( () => new Rewriter(s_pool)); + private static readonly Func s_simplifyName = SimplifyName; + public CSharpNameReducer() : base(s_pool) { } - private static readonly Func s_simplifyName = SimplifyName; + protected override bool IsApplicable(CSharpSimplifierOptions options) + => true; private static SyntaxNode SimplifyName( SyntaxNode node, SemanticModel semanticModel, - OptionSet optionSet, + CSharpSimplifierOptions options, CancellationToken cancellationToken) { SyntaxNode replacementNode; @@ -38,7 +41,7 @@ private static SyntaxNode SimplifyName( if (node.IsKind(SyntaxKind.QualifiedCref, out QualifiedCrefSyntax crefSyntax)) { if (!QualifiedCrefSimplifier.Instance.TrySimplify( - crefSyntax, semanticModel, optionSet, + crefSyntax, semanticModel, options, out var crefReplacement, out _, cancellationToken)) { return node; @@ -49,7 +52,7 @@ private static SyntaxNode SimplifyName( else { var expressionSyntax = (ExpressionSyntax)node; - if (!ExpressionSimplifier.Instance.TrySimplify(expressionSyntax, semanticModel, optionSet, out var expressionReplacement, out _, cancellationToken)) + if (!ExpressionSimplifier.Instance.TrySimplify(expressionSyntax, semanticModel, options, out var expressionReplacement, out _, cancellationToken)) { return node; } diff --git a/src/Workspaces/CSharp/Portable/Simplification/Reducers/CSharpNullableAnnotationReducer.cs b/src/Workspaces/CSharp/Portable/Simplification/Reducers/CSharpNullableAnnotationReducer.cs index 857fe8704dcd0..192c0474daed4 100644 --- a/src/Workspaces/CSharp/Portable/Simplification/Reducers/CSharpNullableAnnotationReducer.cs +++ b/src/Workspaces/CSharp/Portable/Simplification/Reducers/CSharpNullableAnnotationReducer.cs @@ -10,6 +10,7 @@ using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; +using Microsoft.CodeAnalysis.Simplification; namespace Microsoft.CodeAnalysis.CSharp.Simplification { @@ -18,16 +19,19 @@ internal sealed partial class CSharpNullableAnnotationReducer : AbstractCSharpRe private static readonly ObjectPool s_pool = new( () => new Rewriter(s_pool)); + private static readonly Func s_simplifyNullableType = SimplifyNullableType; + public CSharpNullableAnnotationReducer() : base(s_pool) { } - private static readonly Func s_simplifyNullableType = SimplifyNullableType; + protected override bool IsApplicable(CSharpSimplifierOptions options) + => true; private static SyntaxNode SimplifyNullableType( NullableTypeSyntax node, SemanticModel semanticModel, - OptionSet optionSet, + SimplifierOptions options, CancellationToken cancellationToken) { // If annotations are enabled, there's no further simplification to do diff --git a/src/Workspaces/CSharp/Portable/Simplification/Reducers/CSharpParenthesizedExpressionReducer.cs b/src/Workspaces/CSharp/Portable/Simplification/Reducers/CSharpParenthesizedExpressionReducer.cs index 8e632075d40b4..f4e5e9878d52d 100644 --- a/src/Workspaces/CSharp/Portable/Simplification/Reducers/CSharpParenthesizedExpressionReducer.cs +++ b/src/Workspaces/CSharp/Portable/Simplification/Reducers/CSharpParenthesizedExpressionReducer.cs @@ -19,16 +19,19 @@ internal partial class CSharpParenthesizedExpressionReducer : AbstractCSharpRedu private static readonly ObjectPool s_pool = new( () => new Rewriter(s_pool)); + private static readonly Func s_simplifyParentheses = SimplifyParentheses; + public CSharpParenthesizedExpressionReducer() : base(s_pool) { } - private static readonly Func s_simplifyParentheses = SimplifyParentheses; + protected override bool IsApplicable(CSharpSimplifierOptions options) + => true; private static SyntaxNode SimplifyParentheses( ParenthesizedExpressionSyntax node, SemanticModel semanticModel, - OptionSet optionSet, + SimplifierOptions options, CancellationToken cancellationToken) { if (node.CanRemoveParentheses(semanticModel, cancellationToken)) diff --git a/src/Workspaces/CSharp/Portable/Simplification/Reducers/CSharpParenthesizedPatternReducer.cs b/src/Workspaces/CSharp/Portable/Simplification/Reducers/CSharpParenthesizedPatternReducer.cs index 69ef2f312d569..06b0a5185ebfc 100644 --- a/src/Workspaces/CSharp/Portable/Simplification/Reducers/CSharpParenthesizedPatternReducer.cs +++ b/src/Workspaces/CSharp/Portable/Simplification/Reducers/CSharpParenthesizedPatternReducer.cs @@ -21,16 +21,19 @@ internal partial class CSharpParenthesizedPatternReducer : AbstractCSharpReducer private static readonly ObjectPool s_pool = new( () => new Rewriter(s_pool)); + private static readonly Func s_simplifyParentheses = SimplifyParentheses; + public CSharpParenthesizedPatternReducer() : base(s_pool) { } - private static readonly Func s_simplifyParentheses = SimplifyParentheses; + protected override bool IsApplicable(CSharpSimplifierOptions options) + => true; private static SyntaxNode SimplifyParentheses( ParenthesizedPatternSyntax node, SemanticModel semanticModel, - OptionSet optionSet, + SimplifierOptions options, CancellationToken cancellationToken) { if (node.CanRemoveParentheses()) diff --git a/src/Workspaces/CSharp/Portable/Simplification/Reducers/CSharpVarReducer.Rewriter.cs b/src/Workspaces/CSharp/Portable/Simplification/Reducers/CSharpVarReducer.Rewriter.cs index f613b68d9a43a..c3c14d905664e 100644 --- a/src/Workspaces/CSharp/Portable/Simplification/Reducers/CSharpVarReducer.Rewriter.cs +++ b/src/Workspaces/CSharp/Portable/Simplification/Reducers/CSharpVarReducer.Rewriter.cs @@ -37,7 +37,7 @@ private SyntaxNode ProcessTypeSyntax(TypeSyntax typeSyntax) } var typeStyle = CSharpUseImplicitTypeHelper.Instance.AnalyzeTypeName( - typeSyntax, this.SemanticModel, this.OptionSet, this.CancellationToken); + typeSyntax, this.SemanticModel, this.Options, this.CancellationToken); if (!typeStyle.IsStylePreferred || !typeStyle.CanConvert()) { diff --git a/src/Workspaces/CSharp/Portable/Simplification/Reducers/CSharpVarReducer.cs b/src/Workspaces/CSharp/Portable/Simplification/Reducers/CSharpVarReducer.cs index 5ab37200a8096..8a68cb8b07635 100644 --- a/src/Workspaces/CSharp/Portable/Simplification/Reducers/CSharpVarReducer.cs +++ b/src/Workspaces/CSharp/Portable/Simplification/Reducers/CSharpVarReducer.cs @@ -4,8 +4,6 @@ #nullable disable -using Microsoft.CodeAnalysis.CSharp.CodeStyle; -using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.PooledObjects; namespace Microsoft.CodeAnalysis.CSharp.Simplification @@ -19,9 +17,9 @@ public CSharpVarReducer() : base(s_pool) { } - public override bool IsApplicable(OptionSet optionSet) - => optionSet.GetOption(CSharpCodeStyleOptions.VarForBuiltInTypes).Value || - optionSet.GetOption(CSharpCodeStyleOptions.VarWhenTypeIsApparent).Value || - optionSet.GetOption(CSharpCodeStyleOptions.VarElsewhere).Value; + protected override bool IsApplicable(CSharpSimplifierOptions options) + => options.VarForBuiltInTypes.Value || + options.VarWhenTypeIsApparent.Value || + options.VarElsewhere.Value; } } diff --git a/src/Workspaces/CSharp/Portable/Simplification/Simplifiers/AbstractCSharpSimplifier.cs b/src/Workspaces/CSharp/Portable/Simplification/Simplifiers/AbstractCSharpSimplifier.cs index c384a213b07b7..c09c209b78425 100644 --- a/src/Workspaces/CSharp/Portable/Simplification/Simplifiers/AbstractCSharpSimplifier.cs +++ b/src/Workspaces/CSharp/Portable/Simplification/Simplifiers/AbstractCSharpSimplifier.cs @@ -9,11 +9,11 @@ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Extensions; using Microsoft.CodeAnalysis.CSharp.Syntax; -using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.Utilities; using Microsoft.CodeAnalysis.Simplification; using Microsoft.CodeAnalysis.Simplification.Simplifiers; +using Microsoft.CodeAnalysis.Text; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CSharp.Simplification.Simplifiers @@ -22,7 +22,7 @@ namespace Microsoft.CodeAnalysis.CSharp.Simplification.Simplifiers /// Contains helpers used by several simplifier subclasses. /// internal abstract class AbstractCSharpSimplifier - : AbstractSimplifier + : AbstractSimplifier where TSyntax : SyntaxNode where TSimplifiedSyntax : SyntaxNode { @@ -394,9 +394,9 @@ protected static bool InsideNameOfExpression(ExpressionSyntax expression, Semant return nameOfInvocationExpr != null; } - protected static bool PreferPredefinedTypeKeywordInMemberAccess(ExpressionSyntax expression, OptionSet optionSet, SemanticModel semanticModel) + protected static bool PreferPredefinedTypeKeywordInMemberAccess(ExpressionSyntax expression, CSharpSimplifierOptions options, SemanticModel semanticModel) { - if (!SimplificationHelpers.PreferPredefinedTypeKeywordInMemberAccess(optionSet, semanticModel.Language)) + if (!options.PreferPredefinedTypeKeywordInMemberAccess.Value) return false; return (expression.IsDirectChildOfMemberAccessExpression() || expression.InsideCrefReference()) && diff --git a/src/Workspaces/CSharp/Portable/Simplification/Simplifiers/ExpressionSimplifier.cs b/src/Workspaces/CSharp/Portable/Simplification/Simplifiers/ExpressionSimplifier.cs index a6457f3d5ab50..60d87fda5a7fd 100644 --- a/src/Workspaces/CSharp/Portable/Simplification/Simplifiers/ExpressionSimplifier.cs +++ b/src/Workspaces/CSharp/Portable/Simplification/Simplifiers/ExpressionSimplifier.cs @@ -33,12 +33,12 @@ private ExpressionSimplifier() public override bool TrySimplify( ExpressionSyntax expression, SemanticModel semanticModel, - OptionSet optionSet, + CSharpSimplifierOptions options, out ExpressionSyntax replacementNode, out TextSpan issueSpan, CancellationToken cancellationToken) { - if (TryReduceExplicitName(expression, semanticModel, out var replacementTypeNode, out issueSpan, optionSet, cancellationToken)) + if (TryReduceExplicitName(expression, semanticModel, out var replacementTypeNode, out issueSpan, options, cancellationToken)) { replacementNode = replacementTypeNode; return true; @@ -52,7 +52,7 @@ private static bool TryReduceExplicitName( SemanticModel semanticModel, out TypeSyntax replacementNode, out TextSpan issueSpan, - OptionSet optionSet, + CSharpSimplifierOptions options, CancellationToken cancellationToken) { replacementNode = null; @@ -62,10 +62,10 @@ private static bool TryReduceExplicitName( return false; if (expression.IsKind(SyntaxKind.SimpleMemberAccessExpression, out MemberAccessExpressionSyntax memberAccess)) - return TryReduceMemberAccessExpression(memberAccess, semanticModel, out replacementNode, out issueSpan, optionSet, cancellationToken); + return TryReduceMemberAccessExpression(memberAccess, semanticModel, out replacementNode, out issueSpan, options, cancellationToken); if (expression is NameSyntax name) - return NameSimplifier.Instance.TrySimplify(name, semanticModel, optionSet, out replacementNode, out issueSpan, cancellationToken); + return NameSimplifier.Instance.TrySimplify(name, semanticModel, options, out replacementNode, out issueSpan, cancellationToken); return false; } @@ -75,7 +75,7 @@ private static bool TryReduceMemberAccessExpression( SemanticModel semanticModel, out TypeSyntax replacementNode, out TextSpan issueSpan, - OptionSet optionSet, + CSharpSimplifierOptions options, CancellationToken cancellationToken) { replacementNode = null; @@ -108,7 +108,7 @@ private static bool TryReduceMemberAccessExpression( return false; if (memberAccess.Expression.IsKind(SyntaxKind.ThisExpression) && - !SimplificationHelpers.ShouldSimplifyThisOrMeMemberAccessExpression(semanticModel, optionSet, symbol)) + !SimplificationHelpers.ShouldSimplifyThisOrMeMemberAccessExpression(options, symbol)) { return false; } @@ -155,7 +155,7 @@ private static bool TryReduceMemberAccessExpression( } // Check if the Expression can be replaced by Predefined Type keyword - if (PreferPredefinedTypeKeywordInMemberAccess(memberAccess, optionSet, semanticModel)) + if (PreferPredefinedTypeKeywordInMemberAccess(memberAccess, options, semanticModel)) { if (symbol != null && symbol.IsKind(SymbolKind.NamedType)) { diff --git a/src/Workspaces/CSharp/Portable/Simplification/Simplifiers/NameSimplifier.cs b/src/Workspaces/CSharp/Portable/Simplification/Simplifiers/NameSimplifier.cs index 6e0a271a45bab..37d0a1a38e18f 100644 --- a/src/Workspaces/CSharp/Portable/Simplification/Simplifiers/NameSimplifier.cs +++ b/src/Workspaces/CSharp/Portable/Simplification/Simplifiers/NameSimplifier.cs @@ -33,7 +33,7 @@ private NameSimplifier() public override bool TrySimplify( NameSyntax name, SemanticModel semanticModel, - OptionSet optionSet, + CSharpSimplifierOptions options, out TypeSyntax replacementNode, out TextSpan issueSpan, CancellationToken cancellationToken) @@ -237,8 +237,8 @@ public override bool TrySimplify( // Don't simplify to predefined type if name is part of a QualifiedName. // QualifiedNames can't contain PredefinedTypeNames (although MemberAccessExpressions can). // In other words, the left side of a QualifiedName can't be a PredefinedTypeName. - var inDeclarationContext = PreferPredefinedTypeKeywordInDeclarations(name, optionSet, semanticModel); - var inMemberAccessContext = PreferPredefinedTypeKeywordInMemberAccess(name, optionSet, semanticModel); + var inDeclarationContext = PreferPredefinedTypeKeywordInDeclarations(name, options, semanticModel); + var inMemberAccessContext = PreferPredefinedTypeKeywordInMemberAccess(name, options, semanticModel); if (!name.Parent.IsKind(SyntaxKind.QualifiedName) && (inDeclarationContext || inMemberAccessContext)) { @@ -713,12 +713,12 @@ private static bool IsInScriptClass(SemanticModel model, NameSyntax name) return false; } - private static bool PreferPredefinedTypeKeywordInDeclarations(NameSyntax name, OptionSet optionSet, SemanticModel semanticModel) + private static bool PreferPredefinedTypeKeywordInDeclarations(NameSyntax name, CSharpSimplifierOptions options, SemanticModel semanticModel) { return !name.IsDirectChildOfMemberAccessExpression() && !name.InsideCrefReference() && !InsideNameOfExpression(name, semanticModel) && - SimplificationHelpers.PreferPredefinedTypeKeywordInDeclarations(optionSet, semanticModel.Language); + options.PreferPredefinedTypeKeywordInDeclaration.Value; } } } diff --git a/src/Workspaces/CSharp/Portable/Simplification/Simplifiers/QualifiedCrefSimplifier.cs b/src/Workspaces/CSharp/Portable/Simplification/Simplifiers/QualifiedCrefSimplifier.cs index e07e4437db4f5..a1210d65e6307 100644 --- a/src/Workspaces/CSharp/Portable/Simplification/Simplifiers/QualifiedCrefSimplifier.cs +++ b/src/Workspaces/CSharp/Portable/Simplification/Simplifiers/QualifiedCrefSimplifier.cs @@ -8,7 +8,6 @@ using Microsoft.CodeAnalysis.CodeStyle; using Microsoft.CodeAnalysis.CSharp.Extensions; using Microsoft.CodeAnalysis.CSharp.Syntax; -using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Simplification; using Microsoft.CodeAnalysis.Text; @@ -27,7 +26,7 @@ private QualifiedCrefSimplifier() public override bool TrySimplify( QualifiedCrefSyntax crefSyntax, SemanticModel semanticModel, - OptionSet optionSet, + CSharpSimplifierOptions options, out CrefSyntax replacementNode, out TextSpan issueSpan, CancellationToken cancellationToken) @@ -38,7 +37,7 @@ public override bool TrySimplify( var memberCref = crefSyntax.Member; // Currently we are dealing with only the NameMemberCrefs - if (SimplificationHelpers.PreferPredefinedTypeKeywordInMemberAccess(optionSet, semanticModel.Language) && + if (options.PreferPredefinedTypeKeywordInMemberAccess.Value && memberCref.IsKind(SyntaxKind.NameMemberCref, out NameMemberCrefSyntax nameMemberCref)) { var symbolInfo = semanticModel.GetSymbolInfo(nameMemberCref.Name, cancellationToken); diff --git a/src/Workspaces/CSharpTest/CodeGeneration/AddImportsTests.cs b/src/Workspaces/CSharpTest/CodeGeneration/AddImportsTests.cs index aa876c30812af..ad6f7fd99e0d4 100644 --- a/src/Workspaces/CSharpTest/CodeGeneration/AddImportsTests.cs +++ b/src/Workspaces/CSharpTest/CodeGeneration/AddImportsTests.cs @@ -10,6 +10,7 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis.AddImport; using Microsoft.CodeAnalysis.CSharp.Formatting; +using Microsoft.CodeAnalysis.CSharp.Simplification; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Editing; using Microsoft.CodeAnalysis.Formatting; @@ -81,6 +82,8 @@ private static async Task TestAsync( var formattingOptions = CSharpSyntaxFormattingOptions.Default; + var simplifierOptions = CSharpSimplifierOptions.Default; + var imported = useSymbolAnnotations ? await ImportAdder.AddImportsFromSymbolAnnotationAsync(doc, addImportOptions, CancellationToken.None) : await ImportAdder.AddImportsFromSyntaxesAsync(doc, addImportOptions, CancellationToken.None); @@ -94,7 +97,7 @@ private static async Task TestAsync( if (simplifiedText != null) { - var reduced = await Simplifier.ReduceAsync(imported); + var reduced = await Simplifier.ReduceAsync(imported, simplifierOptions, CancellationToken.None); var formatted = await Formatter.FormatAsync(reduced, SyntaxAnnotation.ElasticAnnotation, formattingOptions, CancellationToken.None); var actualText = (await formatted.GetTextAsync()).ToString(); diff --git a/src/Workspaces/CSharpTest/CodeGeneration/SymbolEditorTests.cs b/src/Workspaces/CSharpTest/CodeGeneration/SymbolEditorTests.cs index e9356e594fce4..4ebd4e27f1a53 100644 --- a/src/Workspaces/CSharpTest/CodeGeneration/SymbolEditorTests.cs +++ b/src/Workspaces/CSharpTest/CodeGeneration/SymbolEditorTests.cs @@ -9,6 +9,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.CSharp.Formatting; +using Microsoft.CodeAnalysis.CSharp.Simplification; using Microsoft.CodeAnalysis.Editing; using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.Simplification; @@ -52,7 +53,7 @@ private static async Task> GetSymbolsAsync(Solution solutio private static async Task GetActualAsync(Document document) { - document = await Simplifier.ReduceAsync(document); + document = await Simplifier.ReduceAsync(document, CSharpSimplifierOptions.Default, CancellationToken.None); document = await Formatter.FormatAsync(document, Formatter.Annotation, CSharpSyntaxFormattingOptions.Default, CancellationToken.None); document = await Formatter.FormatAsync(document, SyntaxAnnotation.ElasticAnnotation, CSharpSyntaxFormattingOptions.Default, CancellationToken.None); return (await document.GetSyntaxRootAsync()).ToFullString(); diff --git a/src/Workspaces/Core/Portable/ChangeNamespace/ChangeNamespaceOptions.cs b/src/Workspaces/Core/Portable/ChangeNamespace/ChangeNamespaceOptions.cs new file mode 100644 index 0000000000000..624e2dfdba43a --- /dev/null +++ b/src/Workspaces/Core/Portable/ChangeNamespace/ChangeNamespaceOptions.cs @@ -0,0 +1,47 @@ +// 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.Runtime.Serialization; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.AddImport; +using Microsoft.CodeAnalysis.CodeActions; +using Microsoft.CodeAnalysis.Formatting; +using Microsoft.CodeAnalysis.Host; +using Microsoft.CodeAnalysis.Simplification; + +namespace Microsoft.CodeAnalysis.ChangeNamespace; + +[DataContract] +internal readonly record struct ChangeNamespaceOptions( + [property: DataMember(Order = 0)] SyntaxFormattingOptions FormattingOptions, + [property: DataMember(Order = 1)] AddImportPlacementOptions AddImportOptions, + [property: DataMember(Order = 2)] SimplifierOptions SimplifierOptions) +{ + public static async ValueTask FromDocumentAsync(Document document, ChangeNamespaceOptions? fallbackOptions, CancellationToken cancellationToken) + { + var formattingOptions = await SyntaxFormattingOptions.FromDocumentAsync(document, cancellationToken).ConfigureAwait(false); + var addImportsOptions = await AddImportPlacementOptions.FromDocumentAsync(document, cancellationToken).ConfigureAwait(false); + var simplifierOptions = await SimplifierOptions.FromDocumentAsync(document, fallbackOptions?.SimplifierOptions, cancellationToken).ConfigureAwait(false); + + return new ChangeNamespaceOptions(formattingOptions, addImportsOptions, simplifierOptions); + } + + public static ChangeNamespaceOptions GetDefault(HostLanguageServices languageServices) + { + var formattingOptions = languageServices.GetRequiredService().DefaultOptions; + var addImportsOptions = AddImportPlacementOptions.Default; + var simplifierOptions = languageServices.GetRequiredService().DefaultOptions; + + return new ChangeNamespaceOptions(formattingOptions, addImportsOptions, simplifierOptions); + } + + public static ChangeNamespaceOptionsProvider CreateProvider(CodeActionOptionsProvider options) + => new(languageServices => new ChangeNamespaceOptions( + FormattingOptions: languageServices.GetRequiredService().DefaultOptions, + AddImportOptions: AddImportPlacementOptions.Default, + SimplifierOptions: options(languageServices).SimplifierOptions ?? languageServices.GetRequiredService().DefaultOptions)); +} + +internal delegate ChangeNamespaceOptions ChangeNamespaceOptionsProvider(HostLanguageServices languageServices); diff --git a/src/Workspaces/Core/Portable/Rename/IChangeNamespaceService.cs b/src/Workspaces/Core/Portable/ChangeNamespace/IChangeNamespaceService.cs similarity index 93% rename from src/Workspaces/Core/Portable/Rename/IChangeNamespaceService.cs rename to src/Workspaces/Core/Portable/ChangeNamespace/IChangeNamespaceService.cs index 27bb7f1d81eb4..6992bf3b149fe 100644 --- a/src/Workspaces/Core/Portable/Rename/IChangeNamespaceService.cs +++ b/src/Workspaces/Core/Portable/ChangeNamespace/IChangeNamespaceService.cs @@ -5,6 +5,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Host; +using Microsoft.CodeAnalysis.Simplification; namespace Microsoft.CodeAnalysis.ChangeNamespace { @@ -52,12 +53,12 @@ internal interface IChangeNamespaceService : ILanguageService /// If the declared namespace for is already identical to , then it will be /// a no-op and original solution will be returned. /// - Task ChangeNamespaceAsync(Document document, SyntaxNode container, string targetNamespace, CancellationToken cancellationToken); + Task ChangeNamespaceAsync(Document document, SyntaxNode container, string targetNamespace, ChangeNamespaceOptionsProvider options, CancellationToken cancellationToken); /// /// Using only the top level namespace declarations of a document, change all of them to the target namespace. Will only /// use namespace containers considered valid by /// - Task TryChangeTopLevelNamespacesAsync(Document document, string targetNamespace, CancellationToken cancellationToken); + Task TryChangeTopLevelNamespacesAsync(Document document, string targetNamespace, ChangeNamespaceOptionsProvider options, CancellationToken cancellationToken); } } diff --git a/src/Workspaces/Core/Portable/CodeActions/CodeAction.cs b/src/Workspaces/Core/Portable/CodeActions/CodeAction.cs index 708440802f964..4eea7b3ee3cfe 100644 --- a/src/Workspaces/Core/Portable/CodeActions/CodeAction.cs +++ b/src/Workspaces/Core/Portable/CodeActions/CodeAction.cs @@ -12,6 +12,7 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis.AddImport; using Microsoft.CodeAnalysis.CaseCorrection; +using Microsoft.CodeAnalysis.CodeCleanup; using Microsoft.CodeAnalysis.CodeFixes; using Microsoft.CodeAnalysis.CodeRefactorings; using Microsoft.CodeAnalysis.Editing; @@ -309,27 +310,27 @@ protected async Task PostProcessChangesAsync(Solution changedSolution, /// The document changed by the . /// A cancellation token. /// A document with the post processing changes applied. - protected virtual Task PostProcessChangesAsync(Document document, CancellationToken cancellationToken) - => CleanupDocumentAsync(document, cancellationToken); + protected virtual async Task PostProcessChangesAsync(Document document, CancellationToken cancellationToken) + { + var options = await CodeCleanupOptions.FromDocumentAsync(document, fallbackOptions: null, cancellationToken).ConfigureAwait(false); + return await CleanupDocumentAsync(document, options, cancellationToken).ConfigureAwait(false); + } internal static async Task CleanupDocumentAsync( - Document document, CancellationToken cancellationToken) + Document document, CodeCleanupOptions options, CancellationToken cancellationToken) { if (document.SupportsSyntaxTree) { - var addImportOptions = await AddImportPlacementOptions.FromDocumentAsync(document, cancellationToken).ConfigureAwait(false); - var formattingOptions = await SyntaxFormattingOptions.FromDocumentAsync(document, cancellationToken).ConfigureAwait(false); - document = await ImportAdder.AddImportsFromSymbolAnnotationAsync( - document, Simplifier.AddImportsAnnotation, addImportOptions, cancellationToken).ConfigureAwait(false); + document, Simplifier.AddImportsAnnotation, options.AddImportOptions, cancellationToken).ConfigureAwait(false); - document = await Simplifier.ReduceAsync(document, Simplifier.Annotation, cancellationToken: cancellationToken).ConfigureAwait(false); + document = await Simplifier.ReduceAsync(document, Simplifier.Annotation, options.SimplifierOptions, cancellationToken).ConfigureAwait(false); // format any node with explicit formatter annotation - document = await Formatter.FormatAsync(document, Formatter.Annotation, formattingOptions, cancellationToken).ConfigureAwait(false); + document = await Formatter.FormatAsync(document, Formatter.Annotation, options.FormattingOptions, cancellationToken).ConfigureAwait(false); // format any elastic whitespace - document = await Formatter.FormatAsync(document, SyntaxAnnotation.ElasticAnnotation, formattingOptions, cancellationToken).ConfigureAwait(false); + document = await Formatter.FormatAsync(document, SyntaxAnnotation.ElasticAnnotation, options.FormattingOptions, cancellationToken).ConfigureAwait(false); document = await CaseCorrector.CaseCorrectAsync(document, CaseCorrector.Annotation, cancellationToken).ConfigureAwait(false); } diff --git a/src/Workspaces/Core/Portable/CodeCleanup/AbstractCodeCleanerService.cs b/src/Workspaces/Core/Portable/CodeCleanup/AbstractCodeCleanerService.cs index b9a3a9f39cf3c..70097a479306d 100644 --- a/src/Workspaces/Core/Portable/CodeCleanup/AbstractCodeCleanerService.cs +++ b/src/Workspaces/Core/Portable/CodeCleanup/AbstractCodeCleanerService.cs @@ -27,7 +27,7 @@ internal abstract class AbstractCodeCleanerService : ICodeCleanerService public abstract ImmutableArray GetDefaultProviders(); protected abstract ImmutableArray GetSpansToAvoid(SyntaxNode root); - public async Task CleanupAsync(Document document, ImmutableArray spans, SyntaxFormattingOptions options, ImmutableArray providers, CancellationToken cancellationToken) + public async Task CleanupAsync(Document document, ImmutableArray spans, CodeCleanupOptions options, ImmutableArray providers, CancellationToken cancellationToken) { using (Logger.LogBlock(FunctionId.CodeCleanup_CleanupAsync, cancellationToken)) { @@ -455,7 +455,7 @@ private static bool CleanupWholeNode(TextSpan nodeSpan, ImmutableArray private async Task IterateAllCodeCleanupProvidersAsync( Document originalDocument, Document annotatedDocument, - SyntaxFormattingOptions options, + CodeCleanupOptions options, Func> spanGetter, ImmutableArray codeCleaners, CancellationToken cancellationToken) diff --git a/src/Workspaces/Core/Portable/CodeCleanup/CodeCleaner.cs b/src/Workspaces/Core/Portable/CodeCleanup/CodeCleaner.cs index aee43fe399a36..e82151c164474 100644 --- a/src/Workspaces/Core/Portable/CodeCleanup/CodeCleaner.cs +++ b/src/Workspaces/Core/Portable/CodeCleanup/CodeCleaner.cs @@ -13,6 +13,7 @@ using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Text; using Microsoft.CodeAnalysis.Formatting; +using Microsoft.CodeAnalysis.Simplification; namespace Microsoft.CodeAnalysis.CodeCleanup { @@ -78,7 +79,8 @@ public static Task CleanupAsync(Document document, TextSpan span, Immu public static async Task CleanupAsync(Document document, ImmutableArray spans, ImmutableArray providers = default, CancellationToken cancellationToken = default) { var cleanupService = document.GetRequiredLanguageService(); - var options = await SyntaxFormattingOptions.FromDocumentAsync(document, cancellationToken).ConfigureAwait(false); + var options = await CodeCleanupOptions.FromDocumentAsync(document, fallbackOptions: null, cancellationToken).ConfigureAwait(false); + return await cleanupService.CleanupAsync(document, spans, options, providers, cancellationToken).ConfigureAwait(false); } diff --git a/src/Workspaces/Core/Portable/CodeCleanup/CodeCleanupOptions.cs b/src/Workspaces/Core/Portable/CodeCleanup/CodeCleanupOptions.cs new file mode 100644 index 0000000000000..16be6e9049815 --- /dev/null +++ b/src/Workspaces/Core/Portable/CodeCleanup/CodeCleanupOptions.cs @@ -0,0 +1,28 @@ +// 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 System.Runtime.Serialization; +using Microsoft.CodeAnalysis.Formatting; +using Microsoft.CodeAnalysis.Simplification; +using Microsoft.CodeAnalysis.AddImport; + +namespace Microsoft.CodeAnalysis.CodeCleanup +{ + [DataContract] + internal readonly record struct CodeCleanupOptions( + [property: DataMember(Order = 0)] SyntaxFormattingOptions FormattingOptions, + [property: DataMember(Order = 1)] SimplifierOptions SimplifierOptions, + [property: DataMember(Order = 2)] AddImportPlacementOptions AddImportOptions) + { + public static async ValueTask FromDocumentAsync(Document document, CodeCleanupOptions? fallbackOptions, CancellationToken cancellationToken) + { + var formattingOptions = await SyntaxFormattingOptions.FromDocumentAsync(document, cancellationToken).ConfigureAwait(false); + var simplifierOptions = await SimplifierOptions.FromDocumentAsync(document, fallbackOptions?.SimplifierOptions, cancellationToken).ConfigureAwait(false); + var addImportOptions = await AddImportPlacementOptions.FromDocumentAsync(document, cancellationToken).ConfigureAwait(false); + return new CodeCleanupOptions(formattingOptions, simplifierOptions, addImportOptions); + } + } +} diff --git a/src/Workspaces/Core/Portable/CodeCleanup/ICodeCleanerService.cs b/src/Workspaces/Core/Portable/CodeCleanup/ICodeCleanerService.cs index f9f47a1551ea9..46e3eb71a1a41 100644 --- a/src/Workspaces/Core/Portable/CodeCleanup/ICodeCleanerService.cs +++ b/src/Workspaces/Core/Portable/CodeCleanup/ICodeCleanerService.cs @@ -27,7 +27,7 @@ internal interface ICodeCleanerService : ILanguageService /// /// This will run all provided code cleaners in an order that is given to the method. /// - Task CleanupAsync(Document document, ImmutableArray spans, SyntaxFormattingOptions options, ImmutableArray providers, CancellationToken cancellationToken); + Task CleanupAsync(Document document, ImmutableArray spans, CodeCleanupOptions options, ImmutableArray providers, CancellationToken cancellationToken); /// /// This will run all provided code cleaners in an order that is given to the method. diff --git a/src/Workspaces/Core/Portable/CodeCleanup/Providers/FormatCodeCleanupProvider.cs b/src/Workspaces/Core/Portable/CodeCleanup/Providers/FormatCodeCleanupProvider.cs index 707c1d34a32fa..21831e950b539 100644 --- a/src/Workspaces/Core/Portable/CodeCleanup/Providers/FormatCodeCleanupProvider.cs +++ b/src/Workspaces/Core/Portable/CodeCleanup/Providers/FormatCodeCleanupProvider.cs @@ -25,11 +25,11 @@ public FormatCodeCleanupProvider(IEnumerable? rules = nu public string Name => PredefinedCodeCleanupProviderNames.Format; - public async Task CleanupAsync(Document document, ImmutableArray spans, SyntaxFormattingOptions options, CancellationToken cancellationToken) + public async Task CleanupAsync(Document document, ImmutableArray spans, CodeCleanupOptions options, CancellationToken cancellationToken) { var formatter = document.GetRequiredLanguageService(); var root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); - var result = formatter.GetFormattingResult(root, spans, options, _rules, cancellationToken); + var result = formatter.GetFormattingResult(root, spans, options.FormattingOptions, _rules, cancellationToken); // apply changes to an old text if it already exists return document.TryGetText(out var oldText) ? diff --git a/src/Workspaces/Core/Portable/CodeCleanup/Providers/ICodeCleanupProvider.cs b/src/Workspaces/Core/Portable/CodeCleanup/Providers/ICodeCleanupProvider.cs index 52f2f2959a1be..04af6177ffb50 100644 --- a/src/Workspaces/Core/Portable/CodeCleanup/Providers/ICodeCleanupProvider.cs +++ b/src/Workspaces/Core/Portable/CodeCleanup/Providers/ICodeCleanupProvider.cs @@ -24,7 +24,7 @@ internal interface ICodeCleanupProvider /// /// This should apply its code clean up logic to the spans of the document. /// - Task CleanupAsync(Document document, ImmutableArray spans, SyntaxFormattingOptions options, CancellationToken cancellationToken); + Task CleanupAsync(Document document, ImmutableArray spans, CodeCleanupOptions options, CancellationToken cancellationToken); /// /// This will run all provided code cleaners in an order that is given to the method. diff --git a/src/Workspaces/Core/Portable/CodeCleanup/Providers/SimplificationCodeCleanupProvider.cs b/src/Workspaces/Core/Portable/CodeCleanup/Providers/SimplificationCodeCleanupProvider.cs index 70ea4aefd3909..d96c3b54f8657 100644 --- a/src/Workspaces/Core/Portable/CodeCleanup/Providers/SimplificationCodeCleanupProvider.cs +++ b/src/Workspaces/Core/Portable/CodeCleanup/Providers/SimplificationCodeCleanupProvider.cs @@ -16,8 +16,8 @@ internal class SimplificationCodeCleanupProvider : ICodeCleanupProvider { public string Name => PredefinedCodeCleanupProviderNames.Simplification; - public Task CleanupAsync(Document document, ImmutableArray spans, SyntaxFormattingOptions options, CancellationToken cancellationToken) - => Simplifier.ReduceAsync(document, spans, null, cancellationToken); + public Task CleanupAsync(Document document, ImmutableArray spans, CodeCleanupOptions options, CancellationToken cancellationToken) + => Simplifier.ReduceAsync(document, spans, options.SimplifierOptions, cancellationToken); public Task CleanupAsync(SyntaxNode root, ImmutableArray spans, SyntaxFormattingOptions options, HostWorkspaceServices services, CancellationToken cancellationToken) { diff --git a/src/Workspaces/Core/Portable/CodeFixes/CodeFixContext.cs b/src/Workspaces/Core/Portable/CodeFixes/CodeFixContext.cs index 62ebe6c86ce69..2621ebceaf0fd 100644 --- a/src/Workspaces/Core/Portable/CodeFixes/CodeFixContext.cs +++ b/src/Workspaces/Core/Portable/CodeFixes/CodeFixContext.cs @@ -57,7 +57,7 @@ namespace Microsoft.CodeAnalysis.CodeFixes [Obsolete] bool ITypeScriptCodeFixContext.IsBlocking - => Options("TypeScript").IsBlocking; + => Options(Document.Project.LanguageServices).IsBlocking; /// /// Creates a code fix context to be passed into method. diff --git a/src/Workspaces/Core/Portable/CodeRefactorings/CodeRefactoringContext.cs b/src/Workspaces/Core/Portable/CodeRefactorings/CodeRefactoringContext.cs index c2a3f38862c1d..51e14ba5b91b0 100644 --- a/src/Workspaces/Core/Portable/CodeRefactorings/CodeRefactoringContext.cs +++ b/src/Workspaces/Core/Portable/CodeRefactorings/CodeRefactoringContext.cs @@ -35,7 +35,7 @@ namespace Microsoft.CodeAnalysis.CodeRefactorings [Obsolete] bool ITypeScriptCodeRefactoringContext.IsBlocking - => Options("TypeScript").IsBlocking; + => Options(Document.Project.LanguageServices).IsBlocking; private readonly Action _registerRefactoring; diff --git a/src/Workspaces/Core/Portable/Editing/SyntaxGenerator.cs b/src/Workspaces/Core/Portable/Editing/SyntaxGenerator.cs index 7d5663897dfb3..07a0d90b694df 100644 --- a/src/Workspaces/Core/Portable/Editing/SyntaxGenerator.cs +++ b/src/Workspaces/Core/Portable/Editing/SyntaxGenerator.cs @@ -28,8 +28,7 @@ namespace Microsoft.CodeAnalysis.Editing /// The trees generated by this API will try to respect user preferences when /// possible. For example, generating /// will be done in a way such that "this." or "Me." will be simplified according to user - /// preference if any - /// overload is called. + /// preference if is used. /// public abstract class SyntaxGenerator : ILanguageService { diff --git a/src/Workspaces/Core/Portable/Options/IGlobalOptionService.cs b/src/Workspaces/Core/Portable/Options/IGlobalOptionService.cs index 3357cb27e9a84..f72e59031232d 100644 --- a/src/Workspaces/Core/Portable/Options/IGlobalOptionService.cs +++ b/src/Workspaces/Core/Portable/Options/IGlobalOptionService.cs @@ -6,6 +6,7 @@ using System.Collections.Generic; using System.Collections.Immutable; using System.Diagnostics.CodeAnalysis; +using Microsoft.CodeAnalysis.Host; namespace Microsoft.CodeAnalysis.Options { @@ -22,22 +23,22 @@ internal interface IGlobalOptionService /// /// Gets the current value of the specific option. /// - T? GetOption(Option option); + T GetOption(Option option); /// /// Gets the current value of the specific option. /// - T? GetOption(Option2 option); + T GetOption(Option2 option); /// /// Gets the current value of the specific option. /// - T? GetOption(PerLanguageOption option, string? languageName); + T GetOption(PerLanguageOption option, string? languageName); /// /// Gets the current value of the specific option. /// - T? GetOption(PerLanguageOption2 option, string? languageName); + T GetOption(PerLanguageOption2 option, string? languageName); /// /// Gets the current value of the specific option. diff --git a/src/Workspaces/Core/Portable/Rename/ConflictEngine/RenamedSpansTracker.cs b/src/Workspaces/Core/Portable/Rename/ConflictEngine/RenamedSpansTracker.cs index 81103af8b8978..507a5c1249a7a 100644 --- a/src/Workspaces/Core/Portable/Rename/ConflictEngine/RenamedSpansTracker.cs +++ b/src/Workspaces/Core/Portable/Rename/ConflictEngine/RenamedSpansTracker.cs @@ -159,8 +159,9 @@ internal async Task SimplifyAsync(Solution solution, IEnumerable.Empty) { _analysis = analysis; + _options = options; } public override string GetDescription(CultureInfo? culture) @@ -42,7 +44,7 @@ public override string GetDescription(CultureInfo? culture) internal override async Task GetModifiedSolutionAsync(Document document, DocumentRenameOptions options, CancellationToken cancellationToken) { var changeNamespaceService = document.GetRequiredLanguageService(); - var solution = await changeNamespaceService.TryChangeTopLevelNamespacesAsync(document, _analysis.TargetNamespace, cancellationToken).ConfigureAwait(false); + var solution = await changeNamespaceService.TryChangeTopLevelNamespacesAsync(document, _analysis.TargetNamespace, _options, cancellationToken).ConfigureAwait(false); // If the solution fails to update fail silently. The user will see no large // negative impact from not doing this modification, and it's possible the document @@ -50,13 +52,13 @@ internal override async Task GetModifiedSolutionAsync(Document documen return solution ?? document.Project.Solution; } - public static SyncNamespaceDocumentAction? TryCreate(Document document, IReadOnlyList newFolders, CancellationToken _) + public static SyncNamespaceDocumentAction? TryCreate(Document document, IReadOnlyList newFolders, ChangeNamespaceOptionsProvider options) { var analysisResult = Analyze(document, newFolders); if (analysisResult.HasValue) { - return new SyncNamespaceDocumentAction(analysisResult.Value); + return new SyncNamespaceDocumentAction(analysisResult.Value, options); } return null; diff --git a/src/Workspaces/Core/Portable/Rename/Renamer.cs b/src/Workspaces/Core/Portable/Rename/Renamer.cs index 163084fbccf22..7dc73d80dc5db 100644 --- a/src/Workspaces/Core/Portable/Rename/Renamer.cs +++ b/src/Workspaces/Core/Portable/Rename/Renamer.cs @@ -8,6 +8,7 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; +using Microsoft.CodeAnalysis.ChangeNamespace; using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.Internal.Log; using Microsoft.CodeAnalysis.Options; @@ -89,18 +90,24 @@ public static Task RenameDocumentAsync( /// The new name for the document. Pass null or the same name to keep unchanged. /// Options used to configure rename of a type contained in the document that matches the document's name. /// The new set of folders for the property - public static async Task RenameDocumentAsync( - Document document, + public static Task RenameDocumentAsync( + Document document!!, DocumentRenameOptions options, string? newDocumentName, IReadOnlyList? newDocumentFolders = null, CancellationToken cancellationToken = default) { - if (document is null) - { - throw new ArgumentNullException(nameof(document)); - } + return RenameDocumentAsync(document, options, ChangeNamespaceOptions.GetDefault, newDocumentName, newDocumentFolders, cancellationToken); + } + internal static async Task RenameDocumentAsync( + Document document, + DocumentRenameOptions options, + ChangeNamespaceOptionsProvider changeNamespaceOptions, + string? newDocumentName, + IReadOnlyList? newDocumentFolders, + CancellationToken cancellationToken) + { if (document.Services.GetService() != null) { // Don't advertise that we can file rename generated documents that map to a different file. @@ -117,7 +124,7 @@ public static async Task RenameDocumentAsync( if (newDocumentFolders != null && !newDocumentFolders.SequenceEqual(document.Folders)) { - var action = SyncNamespaceDocumentAction.TryCreate(document, newDocumentFolders, cancellationToken); + var action = SyncNamespaceDocumentAction.TryCreate(document, newDocumentFolders, changeNamespaceOptions); actions.AddIfNotNull(action); } diff --git a/src/Workspaces/Core/Portable/Simplification/AbstractReducer.IExpressionRewriter.cs b/src/Workspaces/Core/Portable/Simplification/AbstractReducer.IExpressionRewriter.cs index ab9cb2469b38f..5a46962ab857d 100644 --- a/src/Workspaces/Core/Portable/Simplification/AbstractReducer.IExpressionRewriter.cs +++ b/src/Workspaces/Core/Portable/Simplification/AbstractReducer.IExpressionRewriter.cs @@ -6,7 +6,6 @@ using System; using System.Threading; -using Microsoft.CodeAnalysis.Options; namespace Microsoft.CodeAnalysis.Simplification { @@ -14,7 +13,7 @@ internal abstract partial class AbstractReducer { internal interface IReductionRewriter : IDisposable { - void Initialize(ParseOptions parseOptions, OptionSet optionSet, CancellationToken cancellationToken); + void Initialize(ParseOptions parseOptions, SimplifierOptions options, CancellationToken cancellationToken); SyntaxNodeOrToken VisitNodeOrToken(SyntaxNodeOrToken nodeOrTokenToReduce, SemanticModel semanticModel, bool simplifyAllDescendants); diff --git a/src/Workspaces/Core/Portable/Simplification/AbstractReducer.cs b/src/Workspaces/Core/Portable/Simplification/AbstractReducer.cs index 1f8b033d556a1..909f59b0b110a 100644 --- a/src/Workspaces/Core/Portable/Simplification/AbstractReducer.cs +++ b/src/Workspaces/Core/Portable/Simplification/AbstractReducer.cs @@ -4,7 +4,6 @@ #nullable disable -using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.PooledObjects; namespace Microsoft.CodeAnalysis.Simplification @@ -19,6 +18,6 @@ protected AbstractReducer(ObjectPool pool) public IReductionRewriter GetOrCreateRewriter() => _pool.Allocate(); - public virtual bool IsApplicable(OptionSet optionSet) => true; + public abstract bool IsApplicable(SimplifierOptions options); } } diff --git a/src/Workspaces/Core/Portable/Simplification/AbstractSimplificationService.cs b/src/Workspaces/Core/Portable/Simplification/AbstractSimplificationService.cs index 3bc29b86ea608..5218bae207e0c 100644 --- a/src/Workspaces/Core/Portable/Simplification/AbstractSimplificationService.cs +++ b/src/Workspaces/Core/Portable/Simplification/AbstractSimplificationService.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System; using System.Collections.Concurrent; using System.Collections.Generic; @@ -12,17 +10,14 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Editing; using Microsoft.CodeAnalysis.Internal.Log; -using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Shared.Collections; +using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; using Roslyn.Utilities; -#if DEBUG -using Microsoft.CodeAnalysis.Shared.Extensions; -#endif - namespace Microsoft.CodeAnalysis.Simplification { internal abstract class AbstractSimplificationService : ISimplificationService @@ -42,16 +37,19 @@ protected AbstractSimplificationService(ImmutableArray reducers protected abstract SemanticModel GetSpeculativeSemanticModel(ref SyntaxNode nodeToSpeculate, SemanticModel originalSemanticModel, SyntaxNode originalNode); protected abstract bool NodeRequiresNonSpeculativeSemanticModel(SyntaxNode node); + public abstract SimplifierOptions DefaultOptions { get; } + public abstract SimplifierOptions GetSimplifierOptions(AnalyzerConfigOptions options, SimplifierOptions? fallbackOptions); + protected virtual SyntaxNode TransformReducedNode(SyntaxNode reducedNode, SyntaxNode originalNode) => reducedNode; - public abstract SyntaxNode Expand(SyntaxNode node, SemanticModel semanticModel, SyntaxAnnotation annotationForReplacedAliasIdentifier, Func expandInsideNode, bool expandParameter, CancellationToken cancellationToken); - public abstract SyntaxToken Expand(SyntaxToken token, SemanticModel semanticModel, Func expandInsideNode, CancellationToken cancellationToken); + public abstract SyntaxNode Expand(SyntaxNode node, SemanticModel semanticModel, SyntaxAnnotation? annotationForReplacedAliasIdentifier, Func? expandInsideNode, bool expandParameter, CancellationToken cancellationToken); + public abstract SyntaxToken Expand(SyntaxToken token, SemanticModel semanticModel, Func? expandInsideNode, CancellationToken cancellationToken); public async Task ReduceAsync( Document document, ImmutableArray spans, - OptionSet optionSet = null, + SimplifierOptions options, ImmutableArray reducers = default, CancellationToken cancellationToken = default) { @@ -65,9 +63,7 @@ public async Task ReduceAsync( return document; } - optionSet ??= await document.GetOptionsAsync(cancellationToken).ConfigureAwait(false); - - var semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); + var semanticModel = await document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false); // Chaining of the Speculative SemanticModel (i.e. Generating a speculative SemanticModel from an existing Speculative SemanticModel) is not supported // Hence make sure we always start working off of the actual SemanticModel instead of a speculative SemanticModel. @@ -79,7 +75,7 @@ public async Task ReduceAsync( var originalDocHasErrors = await document.HasAnyErrorsAsync(cancellationToken).ConfigureAwait(false); #endif - var reduced = await this.ReduceCoreAsync(document, spanList, optionSet, reducers, cancellationToken).ConfigureAwait(false); + var reduced = await this.ReduceCoreAsync(document, spanList, options, reducers, cancellationToken).ConfigureAwait(false); if (reduced != document) { @@ -98,7 +94,7 @@ public async Task ReduceAsync( private async Task ReduceCoreAsync( Document document, ImmutableArray spans, - OptionSet optionSet, + SimplifierOptions options, ImmutableArray reducers, CancellationToken cancellationToken) { @@ -108,7 +104,7 @@ private async Task ReduceCoreAsync( bool isNodeOrTokenOutsideSimplifySpans(SyntaxNodeOrToken nodeOrToken) => !spansTree.HasIntervalThatOverlapsWith(nodeOrToken.FullSpan.Start, nodeOrToken.FullSpan.Length); - var semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); + var semanticModel = await document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false); var root = await semanticModel.SyntaxTree.GetRootAsync(cancellationToken).ConfigureAwait(false); // prep namespace imports marked for simplification @@ -120,7 +116,7 @@ bool isNodeOrTokenOutsideSimplifySpans(SyntaxNodeOrToken nodeOrToken) => if (hasImportsToSimplify) { document = document.WithSyntaxRoot(root); - semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); + semanticModel = await document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false); root = await semanticModel.SyntaxTree.GetRootAsync(cancellationToken).ConfigureAwait(false); } @@ -137,7 +133,7 @@ bool isNodeOrTokenOutsideSimplifySpans(SyntaxNodeOrToken nodeOrToken) => // Take out any reducers that don't even apply with the current // set of users options. i.e. no point running 'reduce to var' // if the user doesn't have the 'var' preference set. - reducers = reducers.WhereAsArray(r => r.IsApplicable(optionSet)); + reducers = reducers.WhereAsArray(r => r.IsApplicable(options)); var reducedNodesMap = new ConcurrentDictionary(); var reducedTokensMap = new ConcurrentDictionary(); @@ -145,7 +141,7 @@ bool isNodeOrTokenOutsideSimplifySpans(SyntaxNodeOrToken nodeOrToken) => // Reduce all the nodesAndTokensToReduce using the given reducers/rewriters and // store the reduced nodes and/or tokens in the reduced nodes/tokens maps. // Note that this method doesn't update the original syntax tree. - await this.ReduceAsync(document, root, nodesAndTokensToReduce, reducers, optionSet, semanticModel, reducedNodesMap, reducedTokensMap, cancellationToken).ConfigureAwait(false); + await this.ReduceAsync(document, root, nodesAndTokensToReduce, reducers, options, semanticModel, reducedNodesMap, reducedTokensMap, cancellationToken).ConfigureAwait(false); if (reducedNodesMap.Any() || reducedTokensMap.Any()) { @@ -176,7 +172,7 @@ private async Task ReduceAsync( SyntaxNode root, ImmutableArray nodesAndTokensToReduce, ImmutableArray reducers, - OptionSet optionSet, + SimplifierOptions options, SemanticModel semanticModel, ConcurrentDictionary reducedNodesMap, ConcurrentDictionary reducedTokensMap, @@ -205,7 +201,7 @@ private async Task ReduceAsync( cancellationToken.ThrowIfCancellationRequested(); using var rewriter = reducer.GetOrCreateRewriter(); - rewriter.Initialize(document.Project.ParseOptions, optionSet, cancellationToken); + rewriter.Initialize(document.Project.ParseOptions, options, cancellationToken); do { @@ -228,7 +224,7 @@ private async Task ReduceAsync( currentNodeOrToken = currentNodeOrToken.WithAdditionalAnnotations(annotation); var replacedParent = isNode ? - nodeOrToken.Parent.ReplaceNode(nodeOrToken.AsNode(), currentNodeOrToken.AsNode()) : + nodeOrToken.Parent.ReplaceNode(nodeOrToken.AsNode()!, currentNodeOrToken.AsNode()!) : nodeOrToken.Parent.ReplaceToken(nodeOrToken.AsToken(), currentNodeOrToken.AsToken()); currentNodeOrToken = replacedParent @@ -238,21 +234,21 @@ private async Task ReduceAsync( if (isNode) { - var currentNode = currentNodeOrToken.AsNode(); - if (this.NodeRequiresNonSpeculativeSemanticModel(nodeOrToken.AsNode())) + var currentNode = currentNodeOrToken.AsNode()!; + if (this.NodeRequiresNonSpeculativeSemanticModel(nodeOrToken.AsNode()!)) { // Since this node cannot be speculated, we are replacing the Document with the changes and get a new SemanticModel var marker = new SyntaxAnnotation(); - var newRoot = root.ReplaceNode(nodeOrToken.AsNode(), currentNode.WithAdditionalAnnotations(marker)); + var newRoot = root.ReplaceNode(nodeOrToken.AsNode()!, currentNode.WithAdditionalAnnotations(marker)); var newDocument = document.WithSyntaxRoot(newRoot); - semanticModelForReduce = await newDocument.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); + semanticModelForReduce = await newDocument.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false); newRoot = await semanticModelForReduce.SyntaxTree.GetRootAsync(cancellationToken).ConfigureAwait(false); currentNodeOrToken = newRoot.DescendantNodes().Single(c => c.HasAnnotation(marker)); } else { // Create speculative semantic model for simplified node. - semanticModelForReduce = GetSpeculativeSemanticModel(ref currentNode, semanticModel, nodeOrToken.AsNode()); + semanticModelForReduce = GetSpeculativeSemanticModel(ref currentNode, semanticModel, nodeOrToken.AsNode()!); currentNodeOrToken = currentNode; } } @@ -269,7 +265,7 @@ private async Task ReduceAsync( { if (isNode) { - reducedNodesMap[nodeOrToken.AsNode()] = currentNodeOrToken.AsNode(); + reducedNodesMap[nodeOrToken.AsNode()!] = currentNodeOrToken.AsNode()!; } else { @@ -308,7 +304,7 @@ private async Task RemoveUnusedNamespaceImportsAsync( SyntaxAnnotation removeIfUnusedAnnotation, CancellationToken cancellationToken) { - var model = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); + var model = await document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false); var root = await model.SyntaxTree.GetRootAsync(cancellationToken).ConfigureAwait(false); var addedImports = root.GetAnnotatedNodes(removeIfUnusedAnnotation); var unusedImports = new HashSet(); diff --git a/src/Workspaces/Core/Portable/Simplification/ISimplificationService.cs b/src/Workspaces/Core/Portable/Simplification/ISimplificationService.cs index 5ad425b96df6b..aab4d215fc2c7 100644 --- a/src/Workspaces/Core/Portable/Simplification/ISimplificationService.cs +++ b/src/Workspaces/Core/Portable/Simplification/ISimplificationService.cs @@ -2,38 +2,39 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System; using System.Collections.Immutable; using System.Threading; using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Host; -using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Text; namespace Microsoft.CodeAnalysis.Simplification { internal interface ISimplificationService : ILanguageService { + SimplifierOptions DefaultOptions { get; } + SimplifierOptions GetSimplifierOptions(AnalyzerConfigOptions options, SimplifierOptions? fallbackOptions); + SyntaxNode Expand( SyntaxNode node, SemanticModel semanticModel, - SyntaxAnnotation annotationForReplacedAliasIdentifier, - Func expandInsideNode, + SyntaxAnnotation? annotationForReplacedAliasIdentifier, + Func? expandInsideNode, bool expandParameter, CancellationToken cancellationToken); SyntaxToken Expand( SyntaxToken token, SemanticModel semanticModel, - Func expandInsideNode, + Func? expandInsideNode, CancellationToken cancellationToken); Task ReduceAsync( Document document, ImmutableArray spans, - OptionSet optionSet = null, + SimplifierOptions options, ImmutableArray reducers = default, CancellationToken cancellationToken = default); } diff --git a/src/Workspaces/Core/Portable/Simplification/Simplifier.cs b/src/Workspaces/Core/Portable/Simplification/Simplifier.cs index e26c903fa565e..a2e5295f7ebac 100644 --- a/src/Workspaces/Core/Portable/Simplification/Simplifier.cs +++ b/src/Workspaces/Core/Portable/Simplification/Simplifier.cs @@ -145,7 +145,15 @@ public static async Task ReduceAsync(Document document, OptionSet? opt } var root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); +#pragma warning disable RS0030 // Do not used banned APIs return await ReduceAsync(document, root.FullSpan, optionSet, cancellationToken).ConfigureAwait(false); +#pragma warning restore + } + + internal static async Task ReduceAsync(Document document, SimplifierOptions options, CancellationToken cancellationToken) + { + var root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); + return await ReduceAsync(document, root.FullSpan, options, cancellationToken).ConfigureAwait(false); } /// @@ -165,7 +173,15 @@ public static async Task ReduceAsync(Document document, SyntaxAnnotati } var root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); +#pragma warning disable RS0030 // Do not used banned APIs return await ReduceAsync(document, root.GetAnnotatedNodesAndTokens(annotation).Select(t => t.FullSpan), optionSet, cancellationToken).ConfigureAwait(false); +#pragma warning restore + } + + internal static async Task ReduceAsync(Document document, SyntaxAnnotation annotation, SimplifierOptions options, CancellationToken cancellationToken) + { + var root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); + return await ReduceAsync(document, root.GetAnnotatedNodesAndTokens(annotation).Select(t => t.FullSpan), options, cancellationToken).ConfigureAwait(false); } /// @@ -179,14 +195,19 @@ public static Task ReduceAsync(Document document, TextSpan span, Optio throw new ArgumentNullException(nameof(document)); } +#pragma warning disable RS0030 // Do not used banned APIs return ReduceAsync(document, SpecializedCollections.SingletonEnumerable(span), optionSet, cancellationToken); } +#pragma warning restore + + internal static Task ReduceAsync(Document document, TextSpan span, SimplifierOptions options, CancellationToken cancellationToken) + => ReduceAsync(document, SpecializedCollections.SingletonEnumerable(span), options, cancellationToken); /// /// Reduce the sub-trees annotated with found within the specified spans. /// The annotated node and all child nodes will be reduced. /// - public static Task ReduceAsync(Document document, IEnumerable spans, OptionSet? optionSet = null, CancellationToken cancellationToken = default) + public static async Task ReduceAsync(Document document, IEnumerable spans, OptionSet? optionSet = null, CancellationToken cancellationToken = default) { if (document == null) { @@ -198,17 +219,30 @@ public static Task ReduceAsync(Document document, IEnumerable().ReduceAsync( - document, spans.ToImmutableArrayOrEmpty(), optionSet, cancellationToken: cancellationToken); + var options = await GetOptionsAsync(document, optionSet, cancellationToken).ConfigureAwait(false); + + return await document.GetRequiredLanguageService().ReduceAsync( + document, spans.ToImmutableArrayOrEmpty(), options, reducers: default, cancellationToken).ConfigureAwait(false); } + internal static Task ReduceAsync(Document document, IEnumerable spans, SimplifierOptions options, CancellationToken cancellationToken) + => document.GetRequiredLanguageService().ReduceAsync( + document, spans.ToImmutableArrayOrEmpty(), options, reducers: default, cancellationToken); + internal static async Task ReduceAsync( - Document document, ImmutableArray reducers, OptionSet? optionSet = null, CancellationToken cancellationToken = default) + Document document, ImmutableArray reducers, SimplifierOptions options, CancellationToken cancellationToken) { var root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); return await document.GetRequiredLanguageService() - .ReduceAsync(document, ImmutableArray.Create(root.FullSpan), optionSet, + .ReduceAsync(document, ImmutableArray.Create(root.FullSpan), options, reducers, cancellationToken).ConfigureAwait(false); } + + internal static async Task GetOptionsAsync(Document document, OptionSet? optionSet, CancellationToken cancellationToken) + { + return (optionSet != null) ? + SimplifierOptions.Create(optionSet, document.Project.Solution.Workspace.Services, fallbackOptions: null, document.Project.Language) : + await SimplifierOptions.FromDocumentAsync(document, fallbackOptions: null, cancellationToken).ConfigureAwait(false); + } } } diff --git a/src/Workspaces/Core/Portable/Simplification/Simplifiers/AbstractSimplifier.cs b/src/Workspaces/Core/Portable/Simplification/Simplifiers/AbstractSimplifier.cs index 8c828b8c0da39..2ffccd11d95d1 100644 --- a/src/Workspaces/Core/Portable/Simplification/Simplifiers/AbstractSimplifier.cs +++ b/src/Workspaces/Core/Portable/Simplification/Simplifiers/AbstractSimplifier.cs @@ -5,19 +5,19 @@ #nullable disable using System.Threading; -using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Text; namespace Microsoft.CodeAnalysis.Simplification.Simplifiers { - internal abstract class AbstractSimplifier + internal abstract class AbstractSimplifier where TSyntax : SyntaxNode where TSimplifiedSyntax : SyntaxNode + where TSimplifierOptions : SimplifierOptions { public abstract bool TrySimplify( TSyntax syntax, SemanticModel semanticModel, - OptionSet optionSet, + TSimplifierOptions options, out TSimplifiedSyntax replacementNode, out TextSpan issueSpan, CancellationToken cancellationToken); diff --git a/src/Workspaces/CoreTest/CodeCleanup/MockCodeCleanupProvider.cs b/src/Workspaces/CoreTest/CodeCleanup/MockCodeCleanupProvider.cs index 15195e451f58d..27bb54693dd23 100644 --- a/src/Workspaces/CoreTest/CodeCleanup/MockCodeCleanupProvider.cs +++ b/src/Workspaces/CoreTest/CodeCleanup/MockCodeCleanupProvider.cs @@ -6,10 +6,10 @@ using System.Collections.Immutable; using System.Threading; using System.Threading.Tasks; +using Microsoft.CodeAnalysis.CodeCleanup; using Microsoft.CodeAnalysis.CodeCleanup.Providers; using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.Host; -using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Text; namespace Microsoft.CodeAnalysis.UnitTests.CodeCleanup @@ -25,8 +25,8 @@ public MockCodeCleanupProvider() public string Name => nameof(MockCodeCleanupProvider); - public Task CleanupAsync(Document document, ImmutableArray spans, SyntaxFormattingOptions options, CancellationToken cancellationToken) - => (CleanupDocumentAsyncImpl ?? throw new NotImplementedException()).Invoke(document, spans, options, cancellationToken); + public Task CleanupAsync(Document document, ImmutableArray spans, CodeCleanupOptions options, CancellationToken cancellationToken) + => (CleanupDocumentAsyncImpl ?? throw new NotImplementedException()).Invoke(document, spans, options.FormattingOptions, cancellationToken); public Task CleanupAsync(SyntaxNode root, ImmutableArray spans, SyntaxFormattingOptions options, HostWorkspaceServices services, CancellationToken cancellationToken) => Task.FromResult((CleanupNodeImpl ?? throw new NotImplementedException()).Invoke(root, spans, options, services)); diff --git a/src/Workspaces/CoreTest/Remote/ServiceDescriptorTests.cs b/src/Workspaces/CoreTest/Remote/ServiceDescriptorTests.cs index 94c0c22680e45..ed40d5cc5dd75 100644 --- a/src/Workspaces/CoreTest/Remote/ServiceDescriptorTests.cs +++ b/src/Workspaces/CoreTest/Remote/ServiceDescriptorTests.cs @@ -15,6 +15,7 @@ using System.Threading; using System.Threading.Tasks; using MessagePack; +using MessagePack.Formatters; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Test.Utilities; using Roslyn.Test.Utilities; @@ -153,6 +154,19 @@ public void TypesUsedInRemoteApisMustBeMessagePackSerializable() { errors.Add($"{type} referenced by {declaringMember} is an internal enum and needs a custom formatter"); } + else if (type.IsAbstract) + { + // custom abstract types must be explicitly listed in MessagePackFormatters.AbstractTypeFormatters + if (!MessagePackFormatters.Formatters.Any( + formatter => formatter.GetType() is { IsGenericType: true } and var formatterType && + formatterType.GetGenericTypeDefinition() == typeof(ForceTypelessFormatter<>) && + formatterType.GenericTypeArguments[0] == type)) + { + errors.Add($"{type} referenced by {declaringMember} is abstract but ForceTypelessFormatter<{type}> is not listed in {nameof(MessagePackFormatters)}.{nameof(MessagePackFormatters.Formatters)}"); + } + + continue; + } else { errors.Add($"{type} referenced by {declaringMember} failed to serialize with exception: {e}"); diff --git a/src/Workspaces/CoreTest/Simplifier/SimplifierTests.cs b/src/Workspaces/CoreTest/Simplifier/SimplifierTests.cs new file mode 100644 index 0000000000000..c4849e3621f84 --- /dev/null +++ b/src/Workspaces/CoreTest/Simplifier/SimplifierTests.cs @@ -0,0 +1,159 @@ +// 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; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.CodeStyle; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.CodeStyle; +using Microsoft.CodeAnalysis.CSharp.Simplification; +using Microsoft.CodeAnalysis.Options; +using Microsoft.CodeAnalysis.Shared.Extensions; +using Microsoft.CodeAnalysis.Simplification; +using Microsoft.CodeAnalysis.Test.Utilities; +using Microsoft.CodeAnalysis.Text; +using Microsoft.CodeAnalysis.VisualBasic.Simplification; +using Xunit; + +namespace Microsoft.CodeAnalysis.Editor.UnitTests.Simplification; + +[UseExportProvider] +[Trait(Traits.Feature, Traits.Features.Simplification)] +public class SimplifierTests +{ + private static Document GetDocument() + { + var workspace = new AdhocWorkspace(); + var project = workspace.AddProject("CSharpTest", LanguageNames.CSharp); + return workspace.AddDocument(project.Id, "CSharpFile.cs", SourceText.From("class C { }")); + } + + [Fact] + public async Task ExpandAsync_BadArguments() + { + var node = SyntaxFactory.IdentifierName(SyntaxFactory.Identifier("Test")); + var semanticModel = await GetDocument().GetRequiredSemanticModelAsync(CancellationToken.None); + + await Assert.ThrowsAsync("node", () => Simplifier.ExpandAsync(node: null!, document: null!)); + await Assert.ThrowsAsync("document", () => Simplifier.ExpandAsync(node: node, document: null!)); + await Assert.ThrowsAsync("document", () => Simplifier.ExpandAsync(token: default, document: null!)); + } + + [Fact] + public async Task Expand_BadArguments() + { + var node = SyntaxFactory.IdentifierName(SyntaxFactory.Identifier("Test")); + var semanticModel = await GetDocument().GetRequiredSemanticModelAsync(CancellationToken.None); + + Assert.Throws("node", () => Simplifier.Expand(node: null!, semanticModel: null!, workspace: null!)); + Assert.Throws("semanticModel", () => Simplifier.Expand(node, semanticModel: null!, workspace: null!)); + Assert.Throws("workspace", () => Simplifier.Expand(node, semanticModel, workspace: null!)); + Assert.Throws("semanticModel", () => Simplifier.Expand(token: default, semanticModel: null!, workspace: null!)); + Assert.Throws("workspace", () => Simplifier.Expand(token: default, semanticModel, workspace: null!)); + } + + [Fact] + public async Task ReduceAsync_BadArguments() + { + var document = GetDocument(); + +#pragma warning disable RS0030 // Do not used banned APIs + await Assert.ThrowsAsync("document", () => Simplifier.ReduceAsync(document: null!)); + await Assert.ThrowsAsync("document", () => Simplifier.ReduceAsync(document: null!, annotation: null!)); + await Assert.ThrowsAsync("annotation", () => Simplifier.ReduceAsync(document, annotation: null!)); + await Assert.ThrowsAsync("document", () => Simplifier.ReduceAsync(document: null!, span: default)); + await Assert.ThrowsAsync("document", () => Simplifier.ReduceAsync(document: null!, spans: null!)); + await Assert.ThrowsAsync("spans", () => Simplifier.ReduceAsync(document, spans: null!)); +#pragma warning restore + } + + [Fact] + public async Task ReduceAsync_Options() + { + using var workspace = new AdhocWorkspace(); + var csProject = workspace.AddProject("CS", LanguageNames.CSharp); + var vbProject = workspace.AddProject("VB", LanguageNames.VisualBasic); + var csDocument = workspace.AddDocument(csProject.Id, "File.cs", SourceText.From("class C { }")); + var vbDocument = workspace.AddDocument(vbProject.Id, "File.vb", SourceText.From("Class C : End Class")); + + var updatedOptions = GetOptionSetWithChangedPublicOptions(workspace.CurrentSolution.Options); + + // Validate that options are read from specified OptionSet: + + ValidateCSharpOptions((CSharpSimplifierOptions)await Simplifier.GetOptionsAsync(csDocument, updatedOptions, CancellationToken.None)); + ValidateVisualBasicOptions((VisualBasicSimplifierOptions)await Simplifier.GetOptionsAsync(vbDocument, updatedOptions, CancellationToken.None)); + + // Validate that options are read from solution snapshot as a fallback (we have no editorconfig file, so all options should fall back): + + var solutionWithUpdatedOptions = workspace.CurrentSolution.WithOptions(updatedOptions); + var csDocumentWithUpdatedOptions = solutionWithUpdatedOptions.GetRequiredDocument(csDocument.Id); + var vbDocumentWithUpdatedOptions = solutionWithUpdatedOptions.GetRequiredDocument(vbDocument.Id); + + ValidateCSharpOptions((CSharpSimplifierOptions)await Simplifier.GetOptionsAsync(csDocumentWithUpdatedOptions, optionSet: null, CancellationToken.None)); + ValidateVisualBasicOptions((VisualBasicSimplifierOptions)await Simplifier.GetOptionsAsync(vbDocumentWithUpdatedOptions, optionSet: null, CancellationToken.None)); + + static OptionSet GetOptionSetWithChangedPublicOptions(OptionSet options) + { + // all public options and their non-default values: + + var publicOptions = new (IOption, object)[] + { + (CodeStyleOptions.QualifyFieldAccess, false), + (CodeStyleOptions.QualifyPropertyAccess, false), + (CodeStyleOptions.QualifyMethodAccess, false), + (CodeStyleOptions.QualifyEventAccess, false), + (CodeStyleOptions.PreferIntrinsicPredefinedTypeKeywordInMemberAccess, false), + (CodeStyleOptions.PreferIntrinsicPredefinedTypeKeywordInDeclaration, false), + (CSharpCodeStyleOptions.VarForBuiltInTypes, false), + (CSharpCodeStyleOptions.VarWhenTypeIsApparent, false), + (CSharpCodeStyleOptions.VarElsewhere, false), + (CSharpCodeStyleOptions.PreferSimpleDefaultExpression, false), + (CSharpCodeStyleOptions.PreferBraces, PreferBracesPreference.WhenMultiline), + }; + + var updatedOptions = options; + foreach (var (option, newValue) in publicOptions) + { + var languages = (option is IPerLanguageOption) ? new[] { LanguageNames.CSharp, LanguageNames.VisualBasic } : new string?[] { null }; + + foreach (var language in languages) + { + var key = new OptionKey(option, language); + var current = (ICodeStyleOption)options.GetOption(key)!; + updatedOptions = updatedOptions.WithChangedOption(key, current.WithValue(newValue)); + } + } + + return updatedOptions; + } + + static void ValidateCommonOptions(SimplifierOptions simplifierOptions) + { + Assert.False(simplifierOptions.QualifyFieldAccess.Value); + Assert.False(simplifierOptions.QualifyPropertyAccess.Value); + Assert.False(simplifierOptions.QualifyMethodAccess.Value); + Assert.False(simplifierOptions.QualifyEventAccess.Value); + Assert.False(simplifierOptions.PreferPredefinedTypeKeywordInMemberAccess.Value); + Assert.False(simplifierOptions.PreferPredefinedTypeKeywordInDeclaration.Value); + } + + static void ValidateCSharpOptions(CSharpSimplifierOptions simplifierOptions) + { + ValidateCommonOptions(simplifierOptions); + + Assert.False(simplifierOptions.VarForBuiltInTypes.Value); + Assert.False(simplifierOptions.VarWhenTypeIsApparent.Value); + Assert.False(simplifierOptions.VarElsewhere.Value); + Assert.False(simplifierOptions.PreferSimpleDefaultExpression.Value); + Assert.Equal(PreferBracesPreference.WhenMultiline, simplifierOptions.PreferBraces.Value); + } + + static void ValidateVisualBasicOptions(VisualBasicSimplifierOptions simplifierOptions) + { + ValidateCommonOptions(simplifierOptions); + } + } +} diff --git a/src/Workspaces/Remote/Core/Serialization/MessagePackFormatters.cs b/src/Workspaces/Remote/Core/Serialization/MessagePackFormatters.cs index 18dc308593fac..bebad327e4f4b 100644 --- a/src/Workspaces/Remote/Core/Serialization/MessagePackFormatters.cs +++ b/src/Workspaces/Remote/Core/Serialization/MessagePackFormatters.cs @@ -8,6 +8,8 @@ using MessagePack; using MessagePack.Formatters; using MessagePack.Resolvers; +using Microsoft.CodeAnalysis.Formatting; +using Microsoft.CodeAnalysis.Simplification; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Remote @@ -18,18 +20,22 @@ namespace Microsoft.CodeAnalysis.Remote /// internal sealed class MessagePackFormatters { - private static readonly ImmutableArray s_formatters = ImmutableArray.Create( + internal static readonly ImmutableArray Formatters = ImmutableArray.Create( SolutionIdFormatter.Instance, ProjectIdFormatter.Instance, - DocumentIdFormatter.Instance); + DocumentIdFormatter.Instance, + // ForceTypelessFormatter needs to be listed here for each Roslyn abstract type T that is being serialized OOP. + // TODO: add a resolver that provides these https://github.com/dotnet/roslyn/issues/60724 + new ForceTypelessFormatter(), + new ForceTypelessFormatter()); private static readonly ImmutableArray s_resolvers = ImmutableArray.Create( StandardResolverAllowPrivate.Instance); - internal static readonly IFormatterResolver DefaultResolver = CompositeResolver.Create(s_formatters, s_resolvers); + internal static readonly IFormatterResolver DefaultResolver = CompositeResolver.Create(Formatters, s_resolvers); internal static IFormatterResolver CreateResolver(ImmutableArray additionalFormatters, ImmutableArray additionalResolvers) - => (additionalFormatters.IsEmpty && additionalResolvers.IsEmpty) ? DefaultResolver : CompositeResolver.Create(s_formatters.AddRange(additionalFormatters), s_resolvers.AddRange(additionalResolvers)); + => (additionalFormatters.IsEmpty && additionalResolvers.IsEmpty) ? DefaultResolver : CompositeResolver.Create(Formatters.AddRange(additionalFormatters), s_resolvers.AddRange(additionalResolvers)); internal sealed class SolutionIdFormatter : IMessagePackFormatter { diff --git a/src/Workspaces/Remote/ServiceHub/Services/ConvertTupleToStructCodeRefactoringProvider/RemoteConvertTupleToStructCodeRefactoringService.cs b/src/Workspaces/Remote/ServiceHub/Services/ConvertTupleToStructCodeRefactoringProvider/RemoteConvertTupleToStructCodeRefactoringService.cs index fb0b5cb700709..188a9b4f787d9 100644 --- a/src/Workspaces/Remote/ServiceHub/Services/ConvertTupleToStructCodeRefactoringProvider/RemoteConvertTupleToStructCodeRefactoringService.cs +++ b/src/Workspaces/Remote/ServiceHub/Services/ConvertTupleToStructCodeRefactoringProvider/RemoteConvertTupleToStructCodeRefactoringService.cs @@ -7,6 +7,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeActions; +using Microsoft.CodeAnalysis.CodeCleanup; using Microsoft.CodeAnalysis.ConvertTupleToStruct; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; @@ -79,8 +80,11 @@ private static async Task CleanupAsync(Solution oldSolution, Solution foreach (var docId in changes) { - var cleaned = await CodeAction.CleanupDocumentAsync( - newSolution.GetDocument(docId), cancellationToken).ConfigureAwait(false); + var document = newSolution.GetDocument(docId); + + var options = await CodeCleanupOptions.FromDocumentAsync(document, fallbackOptions: null, cancellationToken).ConfigureAwait(false); + var cleaned = await CodeAction.CleanupDocumentAsync(document, options, cancellationToken).ConfigureAwait(false); + var cleanedRoot = await cleaned.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); final = final.WithDocumentSyntaxRoot(docId, cleanedRoot); } diff --git a/src/Workspaces/Remote/ServiceHub/Services/EncapsulateField/RemoteEncapsulateFieldService.cs b/src/Workspaces/Remote/ServiceHub/Services/EncapsulateField/RemoteEncapsulateFieldService.cs index db5f56e87ed84..a2c9ca8e15c9e 100644 --- a/src/Workspaces/Remote/ServiceHub/Services/EncapsulateField/RemoteEncapsulateFieldService.cs +++ b/src/Workspaces/Remote/ServiceHub/Services/EncapsulateField/RemoteEncapsulateFieldService.cs @@ -32,6 +32,7 @@ public RemoteEncapsulateFieldService(in ServiceConstructionArguments arguments) PinnedSolutionInfo solutionInfo, DocumentId documentId, ImmutableArray fieldSymbolKeys, + EncapsulateFieldOptions fallbackOptions, bool updateReferences, CancellationToken cancellationToken) { @@ -54,7 +55,7 @@ public RemoteEncapsulateFieldService(in ServiceConstructionArguments arguments) var service = document.GetLanguageService(); var newSolution = await service.EncapsulateFieldsAsync( - document, fields.ToImmutable(), updateReferences, cancellationToken).ConfigureAwait(false); + document, fields.ToImmutable(), fallbackOptions, updateReferences, cancellationToken).ConfigureAwait(false); return await RemoteUtilities.GetDocumentTextChangesAsync( solution, newSolution, cancellationToken).ConfigureAwait(false); }, cancellationToken); diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/CSharpCompilerExtensions.projitems b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/CSharpCompilerExtensions.projitems index 5cdd4a00dc47c..4d82ba5af601d 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/CSharpCompilerExtensions.projitems +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/CSharpCompilerExtensions.projitems @@ -102,6 +102,7 @@ + diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Formatting/CSharpSyntaxFormatting.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Formatting/CSharpSyntaxFormatting.cs index 974186ddbd5c5..0eebd58006a10 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Formatting/CSharpSyntaxFormatting.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Formatting/CSharpSyntaxFormatting.cs @@ -35,6 +35,9 @@ internal class CSharpSyntaxFormatting : AbstractSyntaxFormatting public override ImmutableArray GetDefaultFormattingRules() => _rules; + public override SyntaxFormattingOptions DefaultOptions + => CSharpSyntaxFormattingOptions.Default; + public override SyntaxFormattingOptions GetFormattingOptions(AnalyzerConfigOptions options) => CSharpSyntaxFormattingOptions.Create(options); diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Simplification/CSharpSimplifierOptions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Simplification/CSharpSimplifierOptions.cs new file mode 100644 index 0000000000000..e5fa3865c875e --- /dev/null +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Simplification/CSharpSimplifierOptions.cs @@ -0,0 +1,90 @@ +// 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; +using System.Runtime.Serialization; +using Microsoft.CodeAnalysis.CodeStyle; +using Microsoft.CodeAnalysis.CSharp.CodeStyle; +using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Simplification; + +namespace Microsoft.CodeAnalysis.CSharp.Simplification +{ + [DataContract] + internal sealed class CSharpSimplifierOptions : SimplifierOptions + { + [DataMember(Order = BaseMemberCount + 0)] + public readonly CodeStyleOption2 VarForBuiltInTypes; + + [DataMember(Order = BaseMemberCount + 1)] + public readonly CodeStyleOption2 VarWhenTypeIsApparent; + + [DataMember(Order = BaseMemberCount + 2)] + public readonly CodeStyleOption2 VarElsewhere; + + [DataMember(Order = BaseMemberCount + 3)] + public readonly CodeStyleOption2 PreferSimpleDefaultExpression; + + [DataMember(Order = BaseMemberCount + 4)] + public readonly CodeStyleOption2 PreferBraces; + + public CSharpSimplifierOptions( + CodeStyleOption2? qualifyFieldAccess = null, + CodeStyleOption2? qualifyPropertyAccess = null, + CodeStyleOption2? qualifyMethodAccess = null, + CodeStyleOption2? qualifyEventAccess = null, + CodeStyleOption2? preferPredefinedTypeKeywordInMemberAccess = null, + CodeStyleOption2? preferPredefinedTypeKeywordInDeclaration = null, + CodeStyleOption2? varForBuiltInTypes = null, + CodeStyleOption2? varWhenTypeIsApparent = null, + CodeStyleOption2? varElsewhere = null, + CodeStyleOption2? preferSimpleDefaultExpression = null, + CodeStyleOption2? preferBraces = null) + : base( + qualifyFieldAccess: qualifyFieldAccess ?? Default.QualifyFieldAccess, + qualifyPropertyAccess: qualifyPropertyAccess ?? Default.QualifyPropertyAccess, + qualifyMethodAccess: qualifyMethodAccess ?? Default.QualifyMethodAccess, + qualifyEventAccess: qualifyEventAccess ?? Default.QualifyEventAccess, + preferPredefinedTypeKeywordInMemberAccess: preferPredefinedTypeKeywordInMemberAccess ?? Default.PreferPredefinedTypeKeywordInMemberAccess, + preferPredefinedTypeKeywordInDeclaration: preferPredefinedTypeKeywordInDeclaration ?? Default.PreferPredefinedTypeKeywordInDeclaration) + { + VarForBuiltInTypes = varForBuiltInTypes ?? Default.VarForBuiltInTypes; + VarWhenTypeIsApparent = varWhenTypeIsApparent ?? Default.VarWhenTypeIsApparent; + VarElsewhere = varElsewhere ?? Default.VarElsewhere; + PreferSimpleDefaultExpression = preferSimpleDefaultExpression ?? Default.PreferSimpleDefaultExpression; + PreferBraces = preferBraces ?? Default.PreferBraces; + } + + public static readonly CSharpSimplifierOptions Default = new( + qualifyFieldAccess: CodeStyleOptions2.QualifyFieldAccess.DefaultValue, + qualifyPropertyAccess: CodeStyleOptions2.QualifyPropertyAccess.DefaultValue, + qualifyMethodAccess: CodeStyleOptions2.QualifyMethodAccess.DefaultValue, + qualifyEventAccess: CodeStyleOptions2.QualifyEventAccess.DefaultValue, + preferPredefinedTypeKeywordInMemberAccess: CodeStyleOptions2.PreferIntrinsicPredefinedTypeKeywordInMemberAccess.DefaultValue, + preferPredefinedTypeKeywordInDeclaration: CodeStyleOptions2.PreferIntrinsicPredefinedTypeKeywordInDeclaration.DefaultValue, + varForBuiltInTypes: CSharpCodeStyleOptions.VarForBuiltInTypes.DefaultValue, + varWhenTypeIsApparent: CSharpCodeStyleOptions.VarWhenTypeIsApparent.DefaultValue, + varElsewhere: CSharpCodeStyleOptions.VarElsewhere.DefaultValue, + preferSimpleDefaultExpression: CSharpCodeStyleOptions.PreferSimpleDefaultExpression.DefaultValue, + preferBraces: CSharpCodeStyleOptions.PreferBraces.DefaultValue); + + internal static CSharpSimplifierOptions Create(AnalyzerConfigOptions options, CSharpSimplifierOptions? fallbackOptions) + { + fallbackOptions ??= Default; + + return new( + qualifyFieldAccess: options.GetEditorConfigOption(CodeStyleOptions2.QualifyFieldAccess, fallbackOptions.QualifyFieldAccess), + qualifyPropertyAccess: options.GetEditorConfigOption(CodeStyleOptions2.QualifyPropertyAccess, fallbackOptions.QualifyPropertyAccess), + qualifyMethodAccess: options.GetEditorConfigOption(CodeStyleOptions2.QualifyMethodAccess, fallbackOptions.QualifyMethodAccess), + qualifyEventAccess: options.GetEditorConfigOption(CodeStyleOptions2.QualifyEventAccess, fallbackOptions.QualifyEventAccess), + preferPredefinedTypeKeywordInMemberAccess: options.GetEditorConfigOption(CodeStyleOptions2.PreferIntrinsicPredefinedTypeKeywordInMemberAccess, fallbackOptions.PreferPredefinedTypeKeywordInMemberAccess), + preferPredefinedTypeKeywordInDeclaration: options.GetEditorConfigOption(CodeStyleOptions2.PreferIntrinsicPredefinedTypeKeywordInDeclaration, fallbackOptions.PreferPredefinedTypeKeywordInDeclaration), + varForBuiltInTypes: options.GetEditorConfigOption(CSharpCodeStyleOptions.VarForBuiltInTypes, fallbackOptions.VarForBuiltInTypes), + varWhenTypeIsApparent: options.GetEditorConfigOption(CSharpCodeStyleOptions.VarWhenTypeIsApparent, fallbackOptions.VarWhenTypeIsApparent), + varElsewhere: options.GetEditorConfigOption(CSharpCodeStyleOptions.VarElsewhere, fallbackOptions.VarElsewhere), + preferSimpleDefaultExpression: options.GetEditorConfigOption(CSharpCodeStyleOptions.PreferSimpleDefaultExpression, fallbackOptions.PreferSimpleDefaultExpression), + preferBraces: options.GetEditorConfigOption(CSharpCodeStyleOptions.PreferBraces, fallbackOptions.PreferBraces)); + } + } +} diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Utilities/TypeStyle/CSharpTypeStyleHelper.State.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Utilities/TypeStyle/CSharpTypeStyleHelper.State.cs index 4c5d9fbb68870..78e5ffe0bc6e6 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Utilities/TypeStyle/CSharpTypeStyleHelper.State.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Utilities/TypeStyle/CSharpTypeStyleHelper.State.cs @@ -7,6 +7,7 @@ using Microsoft.CodeAnalysis.CSharp.CodeStyle; using Microsoft.CodeAnalysis.CSharp.CodeStyle.TypeStyle; using Microsoft.CodeAnalysis.CSharp.Extensions; +using Microsoft.CodeAnalysis.CSharp.Simplification; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Shared.Extensions; @@ -33,15 +34,15 @@ protected readonly struct State public State( SyntaxNode declaration, SemanticModel semanticModel, - OptionSet optionSet, CancellationToken cancellationToken) + CSharpSimplifierOptions options, CancellationToken cancellationToken) { TypeStylePreference = default; IsInIntrinsicTypeContext = default; IsTypeApparentInContext = default; - var styleForIntrinsicTypes = optionSet.GetOption(CSharpCodeStyleOptions.VarForBuiltInTypes); - var styleForApparent = optionSet.GetOption(CSharpCodeStyleOptions.VarWhenTypeIsApparent); - var styleForElsewhere = optionSet.GetOption(CSharpCodeStyleOptions.VarElsewhere); + var styleForIntrinsicTypes = options.VarForBuiltInTypes; + var styleForApparent = options.VarWhenTypeIsApparent; + var styleForElsewhere = options.VarElsewhere; _forBuiltInTypes = styleForIntrinsicTypes.Notification.Severity; _whenTypeIsApparent = styleForApparent.Notification.Severity; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Utilities/TypeStyle/CSharpTypeStyleHelper.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Utilities/TypeStyle/CSharpTypeStyleHelper.cs index 1f497769bcaee..189f3c9a2bbe5 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Utilities/TypeStyle/CSharpTypeStyleHelper.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Utilities/TypeStyle/CSharpTypeStyleHelper.cs @@ -6,6 +6,7 @@ using System.Linq; using System.Threading; using Microsoft.CodeAnalysis.CSharp.Extensions; +using Microsoft.CodeAnalysis.CSharp.Simplification; using Microsoft.CodeAnalysis.CSharp.Syntax; #if CODE_STYLE @@ -21,7 +22,7 @@ internal struct TypeStyleResult private readonly CSharpTypeStyleHelper _helper; private readonly TypeSyntax _typeName; private readonly SemanticModel _semanticModel; - private readonly OptionSet _optionSet; + private readonly CSharpSimplifierOptions _options; private readonly CancellationToken _cancellationToken; /// @@ -39,12 +40,12 @@ internal struct TypeStyleResult public readonly bool IsStylePreferred; public readonly ReportDiagnostic Severity; - public TypeStyleResult(CSharpTypeStyleHelper helper, TypeSyntax typeName, SemanticModel semanticModel, OptionSet optionSet, bool isStylePreferred, ReportDiagnostic severity, CancellationToken cancellationToken) : this() + public TypeStyleResult(CSharpTypeStyleHelper helper, TypeSyntax typeName, SemanticModel semanticModel, CSharpSimplifierOptions options, bool isStylePreferred, ReportDiagnostic severity, CancellationToken cancellationToken) : this() { _helper = helper; _typeName = typeName; _semanticModel = semanticModel; - _optionSet = optionSet; + _options = options; _cancellationToken = cancellationToken; IsStylePreferred = isStylePreferred; @@ -52,7 +53,7 @@ public TypeStyleResult(CSharpTypeStyleHelper helper, TypeSyntax typeName, Semant } public bool CanConvert() - => _helper.TryAnalyzeVariableDeclaration(_typeName, _semanticModel, _optionSet, _cancellationToken); + => _helper.TryAnalyzeVariableDeclaration(_typeName, _semanticModel, _options, _cancellationToken); } internal abstract partial class CSharpTypeStyleHelper @@ -61,7 +62,7 @@ internal abstract partial class CSharpTypeStyleHelper public virtual TypeStyleResult AnalyzeTypeName( TypeSyntax typeName, SemanticModel semanticModel, - OptionSet optionSet, CancellationToken cancellationToken) + CSharpSimplifierOptions options, CancellationToken cancellationToken) { if (typeName?.FirstAncestorOrSelf(a => a.IsKind(SyntaxKind.DeclarationExpression, SyntaxKind.VariableDeclaration, SyntaxKind.ForEachStatement)) is not { } declaration) { @@ -69,18 +70,19 @@ public virtual TypeStyleResult AnalyzeTypeName( } var state = new State( - declaration, semanticModel, optionSet, cancellationToken); + declaration, semanticModel, options, cancellationToken); var isStylePreferred = this.IsStylePreferred(in state); var severity = state.GetDiagnosticSeverityPreference(); return new TypeStyleResult( - this, typeName, semanticModel, optionSet, isStylePreferred, severity, cancellationToken); + this, typeName, semanticModel, options, isStylePreferred, severity, cancellationToken); } internal abstract bool TryAnalyzeVariableDeclaration( - TypeSyntax typeName, SemanticModel semanticModel, OptionSet optionSet, CancellationToken cancellationToken); + TypeSyntax typeName, SemanticModel semanticModel, CSharpSimplifierOptions options, CancellationToken cancellationToken); - protected abstract bool AssignmentSupportsStylePreference(SyntaxToken identifier, TypeSyntax typeName, ExpressionSyntax initializer, SemanticModel semanticModel, OptionSet optionSet, CancellationToken cancellationToken); + protected abstract bool AssignmentSupportsStylePreference( + SyntaxToken identifier, TypeSyntax typeName, ExpressionSyntax initializer, SemanticModel semanticModel, CSharpSimplifierOptions options, CancellationToken cancellationToken); internal TypeSyntax? FindAnalyzableType(SyntaxNode node, SemanticModel semanticModel, CancellationToken cancellationToken) { diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Utilities/TypeStyle/CSharpUseExplicitTypeHelper.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Utilities/TypeStyle/CSharpUseExplicitTypeHelper.cs index f664091fb300f..4c702e9137bd7 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Utilities/TypeStyle/CSharpUseExplicitTypeHelper.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Utilities/TypeStyle/CSharpUseExplicitTypeHelper.cs @@ -6,6 +6,7 @@ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.CodeStyle.TypeStyle; using Microsoft.CodeAnalysis.CSharp.Extensions; +using Microsoft.CodeAnalysis.CSharp.Simplification; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Shared.Extensions; using Roslyn.Utilities; @@ -70,7 +71,7 @@ protected override bool ShouldAnalyzeForEachStatement(ForEachStatementSyntax for internal override bool TryAnalyzeVariableDeclaration( TypeSyntax typeName, SemanticModel semanticModel, - OptionSet optionSet, CancellationToken cancellationToken) + CSharpSimplifierOptions options, CancellationToken cancellationToken) { // var (x, y) = e; // foreach (var (x, y) in e) ... @@ -95,7 +96,7 @@ internal override bool TryAnalyzeVariableDeclaration( RoslynDebug.AssertNotNull(variable.Initializer); if (!AssignmentSupportsStylePreference( variable.Identifier, typeName, variable.Initializer.Value, - semanticModel, optionSet, cancellationToken)) + semanticModel, options, cancellationToken)) { return false; } @@ -111,7 +112,7 @@ internal override bool TryAnalyzeVariableDeclaration( { if (!AssignmentSupportsStylePreference( foreachStatement.Identifier, typeName, foreachStatement.Expression, - semanticModel, optionSet, cancellationToken)) + semanticModel, options, cancellationToken)) { return false; } @@ -144,7 +145,7 @@ protected override bool AssignmentSupportsStylePreference( TypeSyntax typeName, ExpressionSyntax initializer, SemanticModel semanticModel, - OptionSet optionSet, + CSharpSimplifierOptions options, CancellationToken cancellationToken) { // is or contains an anonymous type diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Utilities/TypeStyle/CSharpUseImplicitTypeHelper.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Utilities/TypeStyle/CSharpUseImplicitTypeHelper.cs index a836866613880..a424248347bda 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Utilities/TypeStyle/CSharpUseImplicitTypeHelper.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Utilities/TypeStyle/CSharpUseImplicitTypeHelper.cs @@ -14,6 +14,7 @@ using Microsoft.CodeAnalysis.Shared.Utilities; using Microsoft.CodeAnalysis.Simplification; using Microsoft.CodeAnalysis.Operations; +using Microsoft.CodeAnalysis.CSharp.Simplification; #if CODE_STYLE using OptionSet = Microsoft.CodeAnalysis.Diagnostics.AnalyzerConfigOptions; @@ -33,7 +34,7 @@ private CSharpUseImplicitTypeHelper() public override TypeStyleResult AnalyzeTypeName( TypeSyntax typeName, SemanticModel semanticModel, - OptionSet optionSet, CancellationToken cancellationToken) + CSharpSimplifierOptions options, CancellationToken cancellationToken) { if (typeName.StripRefIfNeeded().IsVar) { @@ -46,7 +47,7 @@ public override TypeStyleResult AnalyzeTypeName( } return base.AnalyzeTypeName( - typeName, semanticModel, optionSet, cancellationToken); + typeName, semanticModel, options, cancellationToken); } public override bool ShouldAnalyzeVariableDeclaration(VariableDeclarationSyntax variableDeclaration, CancellationToken cancellationToken) @@ -95,7 +96,7 @@ protected override bool IsStylePreferred(in State state) internal override bool TryAnalyzeVariableDeclaration( TypeSyntax typeName, SemanticModel semanticModel, - OptionSet optionSet, CancellationToken cancellationToken) + CSharpSimplifierOptions options, CancellationToken cancellationToken) { Debug.Assert(!typeName.StripRefIfNeeded().IsVar, "'var' special case should have prevented analysis of this variable."); @@ -146,7 +147,7 @@ internal override bool TryAnalyzeVariableDeclaration( if (AssignmentSupportsStylePreference( variable.Identifier, typeName, initializer, - semanticModel, optionSet, cancellationToken)) + semanticModel, options, cancellationToken)) { return true; } @@ -274,7 +275,7 @@ protected override bool AssignmentSupportsStylePreference( TypeSyntax typeName, ExpressionSyntax initializer, SemanticModel semanticModel, - OptionSet optionSet, + CSharpSimplifierOptions options, CancellationToken cancellationToken) { var expression = GetInitializerExpression(initializer); diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CodeStyle/CodeStyleOption2`1.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CodeStyle/CodeStyleOption2`1.cs index c40d2ff605060..80a777ac97b4a 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CodeStyle/CodeStyleOption2`1.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CodeStyle/CodeStyleOption2`1.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; +using System.Runtime.Serialization; using System.Xml.Linq; using Microsoft.CodeAnalysis.Diagnostics; using Roslyn.Utilities; @@ -37,6 +38,7 @@ internal interface ICodeStyleOption : IObjectWritable /// hosts that expect the value to be a boolean. Specifically, if the enum value is 0 or 1 /// then those values will write back as false/true. /// + [DataContract] internal sealed partial class CodeStyleOption2 : ICodeStyleOption, IEquatable?> { static CodeStyleOption2() @@ -48,16 +50,18 @@ static CodeStyleOption2() private const int SerializationVersion = 1; - private readonly NotificationOption2 _notification; + [DataMember(Order = 0)] + public T Value { get; } + + [DataMember(Order = 1)] + public NotificationOption2 Notification { get; } public CodeStyleOption2(T value, NotificationOption2 notification) { Value = value; - _notification = notification; + Notification = notification; } - public T Value { get; } - object? ICodeStyleOption.Value => this.Value; ICodeStyleOption ICodeStyleOption.WithValue(object value) => new CodeStyleOption2((T)value, Notification); ICodeStyleOption ICodeStyleOption.WithNotification(NotificationOption2 notification) => new CodeStyleOption2(Value, notification); @@ -72,11 +76,6 @@ ICodeStyleOption ICodeStyleOption.AsCodeStyleOption() private int EnumValueAsInt32 => (int)(object)Value!; - public NotificationOption2 Notification - { - get => _notification; - } - public XElement ToXElement() => new("CodeStyleOption", // Ensure that we use "CodeStyleOption" as the name for back compat. new XAttribute(nameof(SerializationVersion), SerializationVersion), diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CodeStyle/CodeStyleOptions2.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CodeStyle/CodeStyleOptions2.cs index c68ba4f1e92f9..41b498d3d7a50 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CodeStyle/CodeStyleOptions2.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CodeStyle/CodeStyleOptions2.cs @@ -5,6 +5,7 @@ using System.Collections.Immutable; using System.Diagnostics; using Microsoft.CodeAnalysis.Options; +using Microsoft.CodeAnalysis.CodeStyle; using Roslyn.Utilities; using static Microsoft.CodeAnalysis.CodeStyle.CodeStyleHelpers; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CompilerExtensions.projitems b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CompilerExtensions.projitems index ec9796f1fcfb0..c59148beee61e 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CompilerExtensions.projitems +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CompilerExtensions.projitems @@ -404,6 +404,7 @@ + diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/AnalyzerConfigOptionsExtensions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/AnalyzerConfigOptionsExtensions.cs index 483bc0fce1a49..31d34a2ff238f 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/AnalyzerConfigOptionsExtensions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/AnalyzerConfigOptionsExtensions.cs @@ -6,6 +6,7 @@ using System.Diagnostics.CodeAnalysis; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Options; +using Roslyn.Utilities; #if CODE_STYLE using TOption = Microsoft.CodeAnalysis.Options.IOption2; @@ -54,12 +55,15 @@ private static T GetOptionWithAssertOnFailure(AnalyzerConfigOptions analyzerC } public static bool TryGetEditorConfigOptionOrDefault(this AnalyzerConfigOptions analyzerConfigOptions, TOption option, out T value) - => TryGetEditorConfigOption(analyzerConfigOptions, option, useDefaultIfMissing: true, out value!); + => TryGetEditorConfigOption(analyzerConfigOptions, option, (T?)option.DefaultValue, out value!); public static bool TryGetEditorConfigOption(this AnalyzerConfigOptions analyzerConfigOptions, TOption option, [MaybeNullWhen(false)] out T value) - => TryGetEditorConfigOption(analyzerConfigOptions, option, useDefaultIfMissing: false, out value); + => TryGetEditorConfigOption(analyzerConfigOptions, option, defaultValue: default, out value); - private static bool TryGetEditorConfigOption(this AnalyzerConfigOptions analyzerConfigOptions, TOption option, bool useDefaultIfMissing, out T? value) + public static T GetEditorConfigOption(this AnalyzerConfigOptions analyzerConfigOptions, TOption option, T defaultValue) + => TryGetEditorConfigOption(analyzerConfigOptions, option, new Optional(defaultValue), out var value) ? value! : throw ExceptionUtilities.Unreachable; + + private static bool TryGetEditorConfigOption(this AnalyzerConfigOptions analyzerConfigOptions, TOption option, Optional defaultValue, out T? value) { var hasEditorConfigStorage = false; foreach (var storageLocation in option.StorageLocations) @@ -87,9 +91,9 @@ private static bool TryGetEditorConfigOption(this AnalyzerConfigOptions analy } } - if (useDefaultIfMissing) + if (defaultValue.HasValue) { - value = (T?)option.DefaultValue; + value = defaultValue.Value; return hasEditorConfigStorage; } else diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/AbstractSyntaxFormattingService.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/AbstractSyntaxFormattingService.cs index 887b5b23f345e..caa6018f7a7c1 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/AbstractSyntaxFormattingService.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/AbstractSyntaxFormattingService.cs @@ -25,6 +25,7 @@ protected AbstractSyntaxFormatting() { } + public abstract SyntaxFormattingOptions DefaultOptions { get; } public abstract SyntaxFormattingOptions GetFormattingOptions(AnalyzerConfigOptions options); public abstract ImmutableArray GetDefaultFormattingRules(); diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/ISyntaxFormatting.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/ISyntaxFormatting.cs index 73af81ac1d358..79ee7fb40e671 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/ISyntaxFormatting.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/ISyntaxFormatting.cs @@ -21,7 +21,9 @@ namespace Microsoft.CodeAnalysis.Formatting { internal interface ISyntaxFormatting { + SyntaxFormattingOptions DefaultOptions { get; } SyntaxFormattingOptions GetFormattingOptions(AnalyzerConfigOptions options); + ImmutableArray GetDefaultFormattingRules(); IFormattingResult GetFormattingResult(SyntaxNode node, IEnumerable? spans, SyntaxFormattingOptions options, IEnumerable? rules, CancellationToken cancellationToken); } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Simplification/SimplifierOptions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Simplification/SimplifierOptions.cs new file mode 100644 index 0000000000000..f3903c79ff275 --- /dev/null +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Simplification/SimplifierOptions.cs @@ -0,0 +1,81 @@ +// 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.Runtime.Serialization; +using Microsoft.CodeAnalysis.CodeStyle; +using Roslyn.Utilities; + +#if !CODE_STYLE +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Host; +using Microsoft.CodeAnalysis.Options; +#endif + +namespace Microsoft.CodeAnalysis.Simplification +{ + internal abstract class SimplifierOptions + { + [DataMember(Order = 0)] + public readonly CodeStyleOption2 QualifyFieldAccess; + + [DataMember(Order = 1)] + public readonly CodeStyleOption2 QualifyPropertyAccess; + + [DataMember(Order = 2)] + public readonly CodeStyleOption2 QualifyMethodAccess; + + [DataMember(Order = 3)] + public readonly CodeStyleOption2 QualifyEventAccess; + + [DataMember(Order = 4)] + public readonly CodeStyleOption2 PreferPredefinedTypeKeywordInMemberAccess; + + [DataMember(Order = 5)] + public readonly CodeStyleOption2 PreferPredefinedTypeKeywordInDeclaration; + + protected const int BaseMemberCount = 6; + + protected SimplifierOptions( + CodeStyleOption2 qualifyFieldAccess, + CodeStyleOption2 qualifyPropertyAccess, + CodeStyleOption2 qualifyMethodAccess, + CodeStyleOption2 qualifyEventAccess, + CodeStyleOption2 preferPredefinedTypeKeywordInMemberAccess, + CodeStyleOption2 preferPredefinedTypeKeywordInDeclaration) + { + QualifyFieldAccess = qualifyFieldAccess; + QualifyPropertyAccess = qualifyPropertyAccess; + QualifyMethodAccess = qualifyMethodAccess; + QualifyEventAccess = qualifyEventAccess; + PreferPredefinedTypeKeywordInMemberAccess = preferPredefinedTypeKeywordInMemberAccess; + PreferPredefinedTypeKeywordInDeclaration = preferPredefinedTypeKeywordInDeclaration; + } + + public CodeStyleOption2 QualifyMemberAccess(SymbolKind symbolKind) + => symbolKind switch + { + SymbolKind.Field => QualifyFieldAccess, + SymbolKind.Property => QualifyPropertyAccess, + SymbolKind.Method => QualifyMethodAccess, + SymbolKind.Event => QualifyEventAccess, + _ => throw ExceptionUtilities.UnexpectedValue(symbolKind), + }; + +#if !CODE_STYLE + public static SimplifierOptions Create(OptionSet options, HostWorkspaceServices services, SimplifierOptions? fallbackOptions, string language) + { + var simplificationService = services.GetRequiredLanguageService(language); + var configOptions = options.AsAnalyzerConfigOptions(services.GetRequiredService(), language); + return simplificationService.GetSimplifierOptions(configOptions, fallbackOptions); + } + + public static async Task FromDocumentAsync(Document document, SimplifierOptions? fallbackOptions, CancellationToken cancellationToken) + { + var documentOptions = await document.GetOptionsAsync(cancellationToken).ConfigureAwait(false); + return Create(documentOptions, document.Project.Solution.Workspace.Services, fallbackOptions, document.Project.Language); + } +#endif + } +} diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/VisualBasic/Simplification/VisualBasicSimplifierOptions.vb b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/VisualBasic/Simplification/VisualBasicSimplifierOptions.vb new file mode 100644 index 0000000000000..a22efd25c5a1a --- /dev/null +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/VisualBasic/Simplification/VisualBasicSimplifierOptions.vb @@ -0,0 +1,52 @@ +' 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. + +Imports Microsoft.CodeAnalysis.Diagnostics +Imports Microsoft.CodeAnalysis.Simplification +Imports Microsoft.CodeAnalysis.CodeStyle +Imports System.Runtime.Serialization + +Namespace Microsoft.CodeAnalysis.VisualBasic.Simplification + + Friend NotInheritable Class VisualBasicSimplifierOptions + Inherits SimplifierOptions + + Public Sub New( + qualifyFieldAccess As CodeStyleOption2(Of Boolean), + qualifyPropertyAccess As CodeStyleOption2(Of Boolean), + qualifyMethodAccess As CodeStyleOption2(Of Boolean), + qualifyEventAccess As CodeStyleOption2(Of Boolean), + preferPredefinedTypeKeywordInMemberAccess As CodeStyleOption2(Of Boolean), + preferPredefinedTypeKeywordInDeclaration As CodeStyleOption2(Of Boolean)) + + MyBase.New( + qualifyFieldAccess, + qualifyPropertyAccess, + qualifyMethodAccess, + qualifyEventAccess, + preferPredefinedTypeKeywordInMemberAccess, + preferPredefinedTypeKeywordInDeclaration) + End Sub + + Public Shared ReadOnly [Default] As New VisualBasicSimplifierOptions( + qualifyFieldAccess:=CodeStyleOptions2.QualifyFieldAccess.DefaultValue, + qualifyPropertyAccess:=CodeStyleOptions2.QualifyPropertyAccess.DefaultValue, + qualifyMethodAccess:=CodeStyleOptions2.QualifyMethodAccess.DefaultValue, + qualifyEventAccess:=CodeStyleOptions2.QualifyEventAccess.DefaultValue, + preferPredefinedTypeKeywordInMemberAccess:=CodeStyleOptions2.PreferIntrinsicPredefinedTypeKeywordInMemberAccess.DefaultValue, + preferPredefinedTypeKeywordInDeclaration:=CodeStyleOptions2.PreferIntrinsicPredefinedTypeKeywordInDeclaration.DefaultValue) + + Friend Overloads Shared Function Create(options As AnalyzerConfigOptions, fallbackOptions As VisualBasicSimplifierOptions) As VisualBasicSimplifierOptions + fallbackOptions = If(fallbackOptions, VisualBasicSimplifierOptions.Default) + + Return New VisualBasicSimplifierOptions( + qualifyFieldAccess:=options.GetEditorConfigOption(CodeStyleOptions2.QualifyFieldAccess, fallbackOptions.QualifyFieldAccess), + qualifyPropertyAccess:=options.GetEditorConfigOption(CodeStyleOptions2.QualifyPropertyAccess, fallbackOptions.QualifyPropertyAccess), + qualifyMethodAccess:=options.GetEditorConfigOption(CodeStyleOptions2.QualifyMethodAccess, fallbackOptions.QualifyMethodAccess), + qualifyEventAccess:=options.GetEditorConfigOption(CodeStyleOptions2.QualifyEventAccess, fallbackOptions.QualifyEventAccess), + preferPredefinedTypeKeywordInMemberAccess:=options.GetEditorConfigOption(CodeStyleOptions2.PreferIntrinsicPredefinedTypeKeywordInMemberAccess, fallbackOptions.PreferPredefinedTypeKeywordInMemberAccess), + preferPredefinedTypeKeywordInDeclaration:=options.GetEditorConfigOption(CodeStyleOptions2.PreferIntrinsicPredefinedTypeKeywordInDeclaration, fallbackOptions.PreferPredefinedTypeKeywordInDeclaration)) + End Function + End Class +End Namespace diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/VisualBasic/VisualBasicCompilerExtensions.projitems b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/VisualBasic/VisualBasicCompilerExtensions.projitems index 713aac3187b9c..d9c054f576520 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/VisualBasic/VisualBasicCompilerExtensions.projitems +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/VisualBasic/VisualBasicCompilerExtensions.projitems @@ -38,6 +38,7 @@ + diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Extensions/ITypeSymbolExtensions.TypeSyntaxGeneratorVisitor.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Extensions/ITypeSymbolExtensions.TypeSyntaxGeneratorVisitor.cs index 05ca44c08662c..db4aeaf9b00a2 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Extensions/ITypeSymbolExtensions.TypeSyntaxGeneratorVisitor.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Extensions/ITypeSymbolExtensions.TypeSyntaxGeneratorVisitor.cs @@ -333,8 +333,7 @@ public override TypeSyntax VisitNamespace(INamespaceSymbol symbol) /// /// We always unilaterally add "global::" to all named types/namespaces. This - /// will then be trimmed off if possible by calls to - /// + /// will then be trimmed off if possible by the simplifier. /// private static TypeSyntax AddGlobalAlias(INamespaceOrTypeSymbol symbol, SimpleNameSyntax syntax) { diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeFixes/CodeActionOptions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeFixes/CodeActionOptions.cs index a496b709e4c4e..bf486b845cf3a 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeFixes/CodeActionOptions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeFixes/CodeActionOptions.cs @@ -4,7 +4,10 @@ using System.Runtime.Serialization; using Microsoft.CodeAnalysis.ExtractMethod; +using Microsoft.CodeAnalysis.Formatting; +using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.ImplementType; +using Microsoft.CodeAnalysis.Simplification; using Microsoft.CodeAnalysis.SymbolSearch; namespace Microsoft.CodeAnalysis.CodeActions @@ -21,14 +24,16 @@ internal readonly struct CodeActionOptions /// Options available to code fixes that are supplied by the IDE (i.e. not stored in editorconfig). /// [DataContract] - internal readonly record struct CodeActionOptions( - [property: DataMember(Order = 0)] SymbolSearchOptions SearchOptions, - [property: DataMember(Order = 1)] ImplementTypeOptions ImplementTypeOptions, - [property: DataMember(Order = 2)] ExtractMethodOptions ExtractMethodOptions, - [property: DataMember(Order = 3)] bool HideAdvancedMembers = false, - [property: DataMember(Order = 4)] bool IsBlocking = false, - [property: DataMember(Order = 5)] int WrappingColumn = CodeActionOptions.DefaultWrappingColumn) + internal readonly record struct CodeActionOptions { + [DataMember(Order = 0)] public SymbolSearchOptions SearchOptions { get; init; } + [DataMember(Order = 1)] public ImplementTypeOptions ImplementTypeOptions { get; init; } + [DataMember(Order = 2)] public ExtractMethodOptions ExtractMethodOptions { get; init; } + [DataMember(Order = 3)] public SimplifierOptions? SimplifierOptions { get; init; } + [DataMember(Order = 4)] public bool HideAdvancedMembers { get; init; } + [DataMember(Order = 5)] public bool IsBlocking { get; init; } + [DataMember(Order = 6)] public int WrappingColumn { get; init; } + /// /// Default value of 120 was picked based on the amount of code in a github.com diff at 1080p. /// That resolution is the most common value as per the last DevDiv survey as well as the latest @@ -41,18 +46,26 @@ internal readonly record struct CodeActionOptions( /// public const int DefaultWrappingColumn = 120; - public CodeActionOptions() - : this(searchOptions: null) + public CodeActionOptions( + SymbolSearchOptions? SearchOptions = null, + ImplementTypeOptions? ImplementTypeOptions = null, + ExtractMethodOptions? ExtractMethodOptions = null, + SimplifierOptions? SimplifierOptions = null, + bool HideAdvancedMembers = false, + bool IsBlocking = false, + int WrappingColumn = DefaultWrappingColumn) { + this.SearchOptions = SearchOptions ?? SymbolSearchOptions.Default; + this.ImplementTypeOptions = ImplementTypeOptions ?? ImplementType.ImplementTypeOptions.Default; + this.ExtractMethodOptions = ExtractMethodOptions ?? ExtractMethod.ExtractMethodOptions.Default; + this.SimplifierOptions = SimplifierOptions; + this.HideAdvancedMembers = HideAdvancedMembers; + this.IsBlocking = IsBlocking; + this.WrappingColumn = WrappingColumn; } - public CodeActionOptions( - SymbolSearchOptions? searchOptions = null, - ImplementTypeOptions? implementTypeOptions = null, - ExtractMethodOptions? extractMethodOptions = null) - : this(SearchOptions: searchOptions ?? SymbolSearchOptions.Default, - ImplementTypeOptions: implementTypeOptions ?? ImplementTypeOptions.Default, - ExtractMethodOptions: extractMethodOptions ?? ExtractMethodOptions.Default) + public CodeActionOptions() + : this(SearchOptions: null) { } @@ -60,5 +73,5 @@ public CodeActionOptions( } #endif - internal delegate CodeActionOptions CodeActionOptionsProvider(string language); + internal delegate CodeActionOptions CodeActionOptionsProvider(HostLanguageServices languageService); } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/LanguageServices/AddImports/IAddImportsService.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/LanguageServices/AddImports/IAddImportsService.cs index 3929b0465ec9f..faa02701a9a4f 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/LanguageServices/AddImports/IAddImportsService.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/LanguageServices/AddImports/IAddImportsService.cs @@ -22,10 +22,17 @@ namespace Microsoft.CodeAnalysis.AddImport { [DataContract] internal record struct AddImportPlacementOptions( - [property: DataMember(Order = 0)] bool PlaceSystemNamespaceFirst, - [property: DataMember(Order = 1)] bool PlaceImportsInsideNamespaces, - [property: DataMember(Order = 2)] bool AllowInHiddenRegions) + [property: DataMember(Order = 0)] bool PlaceSystemNamespaceFirst = true, + [property: DataMember(Order = 1)] bool PlaceImportsInsideNamespaces = false, + [property: DataMember(Order = 2)] bool AllowInHiddenRegions = false) { + public AddImportPlacementOptions() + : this(PlaceSystemNamespaceFirst: true) + { + } + + public static readonly AddImportPlacementOptions Default = new(); + public static async Task FromDocumentAsync(Document document, CancellationToken cancellationToken) { #if CODE_STYLE diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Helpers/SimplificationHelpers.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Simplification/SimplificationHelpers.cs similarity index 78% rename from src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Helpers/SimplificationHelpers.cs rename to src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Simplification/SimplificationHelpers.cs index 43467029eae4e..feceeca6d1cff 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Helpers/SimplificationHelpers.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Simplification/SimplificationHelpers.cs @@ -5,16 +5,9 @@ #nullable disable using System.Linq; -using Microsoft.CodeAnalysis.CodeStyle; using Microsoft.CodeAnalysis.Shared.Extensions; using Roslyn.Utilities; -#if CODE_STYLE -using OptionSet = Microsoft.CodeAnalysis.Diagnostics.AnalyzerConfigOptions; -#else -using OptionSet = Microsoft.CodeAnalysis.Options.OptionSet; -#endif - namespace Microsoft.CodeAnalysis.Simplification { internal static class SimplificationHelpers @@ -110,8 +103,7 @@ internal static bool IsValidSymbolInfo(ISymbol symbol) return symbol != null && !symbol.IsErrorType(); } - internal static bool ShouldSimplifyThisOrMeMemberAccessExpression( - SemanticModel semanticModel, OptionSet optionSet, ISymbol symbol) + internal static bool ShouldSimplifyThisOrMeMemberAccessExpression(SimplifierOptions options, ISymbol symbol) { // If we're accessing a static member off of this/me then we should always consider this // simplifiable. Note: in C# this isn't even legal to access a static off of `this`, @@ -119,21 +111,15 @@ internal static bool ShouldSimplifyThisOrMeMemberAccessExpression( if (symbol.IsStatic) return true; - if ((symbol.IsKind(SymbolKind.Field) && optionSet.GetOption(CodeStyleOptions2.QualifyFieldAccess, semanticModel.Language).Value || - (symbol.IsKind(SymbolKind.Property) && optionSet.GetOption(CodeStyleOptions2.QualifyPropertyAccess, semanticModel.Language).Value) || - (symbol.IsKind(SymbolKind.Method) && optionSet.GetOption(CodeStyleOptions2.QualifyMethodAccess, semanticModel.Language).Value) || - (symbol.IsKind(SymbolKind.Event) && optionSet.GetOption(CodeStyleOptions2.QualifyEventAccess, semanticModel.Language).Value))) + if ((symbol.IsKind(SymbolKind.Field) && options.QualifyFieldAccess.Value || + (symbol.IsKind(SymbolKind.Property) && options.QualifyPropertyAccess.Value) || + (symbol.IsKind(SymbolKind.Method) && options.QualifyMethodAccess.Value) || + (symbol.IsKind(SymbolKind.Event) && options.QualifyEventAccess.Value))) { return false; } return true; } - - internal static bool PreferPredefinedTypeKeywordInDeclarations(OptionSet optionSet, string language) - => optionSet.GetOption(CodeStyleOptions2.PreferIntrinsicPredefinedTypeKeywordInDeclaration, language).Value; - - internal static bool PreferPredefinedTypeKeywordInMemberAccess(OptionSet optionSet, string language) - => optionSet.GetOption(CodeStyleOptions2.PreferIntrinsicPredefinedTypeKeywordInMemberAccess, language).Value; } } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/WorkspaceExtensions.projitems b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/WorkspaceExtensions.projitems index 8d54b8d6496ce..9137f6e29efa0 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/WorkspaceExtensions.projitems +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/WorkspaceExtensions.projitems @@ -20,7 +20,7 @@ - + diff --git a/src/Workspaces/VisualBasic/Portable/CodeCleanup/Providers/AbstractTokensCodeCleanupProvider.vb b/src/Workspaces/VisualBasic/Portable/CodeCleanup/Providers/AbstractTokensCodeCleanupProvider.vb index 9eef93cdd24c1..c7ff2a0c4b23c 100644 --- a/src/Workspaces/VisualBasic/Portable/CodeCleanup/Providers/AbstractTokensCodeCleanupProvider.vb +++ b/src/Workspaces/VisualBasic/Portable/CodeCleanup/Providers/AbstractTokensCodeCleanupProvider.vb @@ -19,7 +19,7 @@ Namespace Microsoft.CodeAnalysis.CodeCleanup.Providers Protected MustOverride Function GetRewriterAsync( document As Document, root As SyntaxNode, spans As ImmutableArray(Of TextSpan), cancellationToken As CancellationToken) As Task(Of Rewriter) - Public Async Function CleanupAsync(document As Document, spans As ImmutableArray(Of TextSpan), options As SyntaxFormattingOptions, cancellationToken As CancellationToken) As Task(Of Document) Implements ICodeCleanupProvider.CleanupAsync + Public Async Function CleanupAsync(document As Document, spans As ImmutableArray(Of TextSpan), options As CodeCleanupOptions, cancellationToken As CancellationToken) As Task(Of Document) Implements ICodeCleanupProvider.CleanupAsync Dim root = Await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(False) Dim rewriter As Rewriter = Await GetRewriterAsync(document, root, spans, cancellationToken).ConfigureAwait(False) Dim newRoot = rewriter.Visit(root) diff --git a/src/Workspaces/VisualBasic/Portable/CodeCleanup/Providers/CaseCorrectionCodeCleanupProvider.vb b/src/Workspaces/VisualBasic/Portable/CodeCleanup/Providers/CaseCorrectionCodeCleanupProvider.vb index e4cd067bbaf8f..6917e660f9053 100644 --- a/src/Workspaces/VisualBasic/Portable/CodeCleanup/Providers/CaseCorrectionCodeCleanupProvider.vb +++ b/src/Workspaces/VisualBasic/Portable/CodeCleanup/Providers/CaseCorrectionCodeCleanupProvider.vb @@ -28,7 +28,7 @@ Namespace Microsoft.CodeAnalysis.CodeCleanup.Providers End Get End Property - Public Function CleanupAsync(document As Document, spans As ImmutableArray(Of TextSpan), options As SyntaxFormattingOptions, cancellationToken As CancellationToken) As Task(Of Document) Implements ICodeCleanupProvider.CleanupAsync + Public Function CleanupAsync(document As Document, spans As ImmutableArray(Of TextSpan), options As CodeCleanupOptions, cancellationToken As CancellationToken) As Task(Of Document) Implements ICodeCleanupProvider.CleanupAsync Return CaseCorrector.CaseCorrectAsync(document, spans, cancellationToken) End Function diff --git a/src/Workspaces/VisualBasic/Portable/CodeCleanup/Providers/NormalizeModifiersOrOperatorsCodeCleanupProvider.vb b/src/Workspaces/VisualBasic/Portable/CodeCleanup/Providers/NormalizeModifiersOrOperatorsCodeCleanupProvider.vb index 7ad4b805deded..f75b77fcdfc13 100644 --- a/src/Workspaces/VisualBasic/Portable/CodeCleanup/Providers/NormalizeModifiersOrOperatorsCodeCleanupProvider.vb +++ b/src/Workspaces/VisualBasic/Portable/CodeCleanup/Providers/NormalizeModifiersOrOperatorsCodeCleanupProvider.vb @@ -31,9 +31,9 @@ Namespace Microsoft.CodeAnalysis.CodeCleanup.Providers End Get End Property - Public Async Function CleanupAsync(document As Document, spans As ImmutableArray(Of TextSpan), options As SyntaxFormattingOptions, cancellationToken As CancellationToken) As Task(Of Document) Implements ICodeCleanupProvider.CleanupAsync + Public Async Function CleanupAsync(document As Document, spans As ImmutableArray(Of TextSpan), options As CodeCleanupOptions, cancellationToken As CancellationToken) As Task(Of Document) Implements ICodeCleanupProvider.CleanupAsync Dim root = Await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(False) - Dim newRoot = Await CleanupAsync(root, spans, options, document.Project.Solution.Workspace.Services, cancellationToken).ConfigureAwait(False) + Dim newRoot = Await CleanupAsync(root, spans, options.FormattingOptions, document.Project.Solution.Workspace.Services, cancellationToken).ConfigureAwait(False) Return If(root Is newRoot, document, document.WithSyntaxRoot(newRoot)) End Function diff --git a/src/Workspaces/VisualBasic/Portable/CodeCleanup/Providers/RemoveUnnecessaryLineContinuationCodeCleanupProvider.vb b/src/Workspaces/VisualBasic/Portable/CodeCleanup/Providers/RemoveUnnecessaryLineContinuationCodeCleanupProvider.vb index 9bcd1c84bfdfc..842092f714594 100644 --- a/src/Workspaces/VisualBasic/Portable/CodeCleanup/Providers/RemoveUnnecessaryLineContinuationCodeCleanupProvider.vb +++ b/src/Workspaces/VisualBasic/Portable/CodeCleanup/Providers/RemoveUnnecessaryLineContinuationCodeCleanupProvider.vb @@ -29,7 +29,7 @@ Namespace Microsoft.CodeAnalysis.CodeCleanup.Providers End Get End Property - Public Async Function CleanupAsync(document As Document, spans As ImmutableArray(Of TextSpan), options As SyntaxFormattingOptions, cancellationToken As CancellationToken) As Task(Of Document) Implements ICodeCleanupProvider.CleanupAsync + Public Async Function CleanupAsync(document As Document, spans As ImmutableArray(Of TextSpan), options As CodeCleanupOptions, cancellationToken As CancellationToken) As Task(Of Document) Implements ICodeCleanupProvider.CleanupAsync ' Is this VB 9? If so, we shouldn't remove line continuations because implicit line continuation was introduced in VB 10. Dim parseOptions = TryCast(document.Project.ParseOptions, VisualBasicParseOptions) If parseOptions?.LanguageVersion <= LanguageVersion.VisualBasic9 Then @@ -37,7 +37,7 @@ Namespace Microsoft.CodeAnalysis.CodeCleanup.Providers End If Dim root = Await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(False) - Dim newRoot = Await CleanupAsync(root, spans, options, document.Project.Solution.Workspace.Services, cancellationToken).ConfigureAwait(False) + Dim newRoot = Await CleanupAsync(root, spans, options.FormattingOptions, document.Project.Solution.Workspace.Services, cancellationToken).ConfigureAwait(False) Return If(newRoot Is root, document, document.WithSyntaxRoot(newRoot)) End Function diff --git a/src/Workspaces/VisualBasic/Portable/Formatting/VisualBasicSyntaxFormatting.vb b/src/Workspaces/VisualBasic/Portable/Formatting/VisualBasicSyntaxFormatting.vb index 4e0a60a5a3e25..adea2938f1526 100644 --- a/src/Workspaces/VisualBasic/Portable/Formatting/VisualBasicSyntaxFormatting.vb +++ b/src/Workspaces/VisualBasic/Portable/Formatting/VisualBasicSyntaxFormatting.vb @@ -28,6 +28,12 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Formatting Return _rules End Function + Public Overrides ReadOnly Property DefaultOptions As SyntaxFormattingOptions + Get + Return VisualBasicSyntaxFormattingOptions.Default + End Get + End Property + Public Overrides Function GetFormattingOptions(options As AnalyzerConfigOptions) As SyntaxFormattingOptions Return VisualBasicSyntaxFormattingOptions.Create(options) End Function diff --git a/src/Workspaces/VisualBasic/Portable/Simplification/Reducers/AbstractVisualBasicReducer.AbstractReductionRewriter.vb b/src/Workspaces/VisualBasic/Portable/Simplification/Reducers/AbstractVisualBasicReducer.AbstractReductionRewriter.vb index 8b98b289b8199..e822248d01aa4 100644 --- a/src/Workspaces/VisualBasic/Portable/Simplification/Reducers/AbstractVisualBasicReducer.AbstractReductionRewriter.vb +++ b/src/Workspaces/VisualBasic/Portable/Simplification/Reducers/AbstractVisualBasicReducer.AbstractReductionRewriter.vb @@ -18,7 +18,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Simplification Protected CancellationToken As CancellationToken Protected Property ParseOptions As VisualBasicParseOptions - Private _simplificationOptions As OptionSet + Private _simplificationOptions As VisualBasicSimplifierOptions Private ReadOnly _processedParentNodes As HashSet(Of SyntaxNode) = New HashSet(Of SyntaxNode)() Private _semanticModel As SemanticModel @@ -30,9 +30,9 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Simplification _pool = pool End Sub - Public Sub Initialize(parseOptions As ParseOptions, optionSet As OptionSet, cancellationToken As CancellationToken) Implements IReductionRewriter.Initialize + Public Sub Initialize(parseOptions As ParseOptions, options As SimplifierOptions, cancellationToken As CancellationToken) Implements IReductionRewriter.Initialize Me.ParseOptions = DirectCast(parseOptions, VisualBasicParseOptions) - _simplificationOptions = optionSet + _simplificationOptions = DirectCast(options, VisualBasicSimplifierOptions) Me.CancellationToken = cancellationToken End Sub @@ -49,6 +49,12 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Simplification _pool.Free(Me) End Sub + Public Sub RequireInitialized() + Contract.ThrowIfNull(ParseOptions) + Debug.Assert(_simplificationOptions IsNot Nothing) + Debug.Assert(_semanticModel IsNot Nothing) + End Sub + Public ReadOnly Property HasMoreWork As Boolean Implements IReductionRewriter.HasMoreWork Get Return _hasMoreWork @@ -74,9 +80,10 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Simplification node As TNode, newNode As SyntaxNode, parentNode As SyntaxNode, - simplifyFunc As Func(Of TNode, SemanticModel, OptionSet, CancellationToken, SyntaxNode) + simplifyFunc As Func(Of TNode, SemanticModel, VisualBasicSimplifierOptions, CancellationToken, SyntaxNode) ) As SyntaxNode + RequireInitialized() Debug.Assert(parentNode IsNot Nothing) CancellationToken.ThrowIfCancellationRequested() @@ -105,7 +112,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Simplification Protected Function SimplifyToken( token As SyntaxToken, newToken As SyntaxToken, - simplifyFunc As Func(Of SyntaxToken, SemanticModel, OptionSet, CancellationToken, SyntaxToken) + simplifyFunc As Func(Of SyntaxToken, SemanticModel, VisualBasicSimplifierOptions, CancellationToken, SyntaxToken) ) As SyntaxToken If token.Kind = SyntaxKind.None Then @@ -149,7 +156,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Simplification Protected Function SimplifyExpression(Of TExpression As ExpressionSyntax)( expression As TExpression, newNode As SyntaxNode, - simplifier As Func(Of TExpression, SemanticModel, OptionSet, CancellationToken, SyntaxNode) + simplifier As Func(Of TExpression, SemanticModel, VisualBasicSimplifierOptions, CancellationToken, SyntaxNode) ) As SyntaxNode Return SimplifyNode(expression, newNode, GetParentNode(expression), simplifier) @@ -158,7 +165,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Simplification Protected Function SimplifyStatement(Of TStatement As StatementSyntax)( statement As TStatement, newNode As SyntaxNode, - simplifier As Func(Of TStatement, SemanticModel, OptionSet, CancellationToken, SyntaxNode) + simplifier As Func(Of TStatement, SemanticModel, SimplifierOptions, CancellationToken, SyntaxNode) ) As SyntaxNode Return SimplifyNode(statement, newNode, GetParentNode(statement), simplifier) diff --git a/src/Workspaces/VisualBasic/Portable/Simplification/Reducers/AbstractVisualBasicReducer.vb b/src/Workspaces/VisualBasic/Portable/Simplification/Reducers/AbstractVisualBasicReducer.vb index be1da80192c07..d31704bfdfb4c 100644 --- a/src/Workspaces/VisualBasic/Portable/Simplification/Reducers/AbstractVisualBasicReducer.vb +++ b/src/Workspaces/VisualBasic/Portable/Simplification/Reducers/AbstractVisualBasicReducer.vb @@ -18,12 +18,12 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Simplification MyBase.New(pool) End Sub - Protected Shared ReadOnly s_reduceParentheses As Func(Of ParenthesizedExpressionSyntax, SemanticModel, OptionSet, CancellationToken, SyntaxNode) = AddressOf ReduceParentheses + Protected Shared ReadOnly s_reduceParentheses As Func(Of ParenthesizedExpressionSyntax, SemanticModel, SimplifierOptions, CancellationToken, SyntaxNode) = AddressOf ReduceParentheses Protected Shared Function ReduceParentheses( node As ParenthesizedExpressionSyntax, semanticModel As SemanticModel, - optionSet As OptionSet, + options As SimplifierOptions, cancellationToken As CancellationToken ) As SyntaxNode @@ -42,5 +42,11 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Simplification ' We don't know how to simplify this. Return node End Function + + Public NotOverridable Overrides Function IsApplicable(options As SimplifierOptions) As Boolean + Return IsApplicable(CType(options, VisualBasicSimplifierOptions)) + End Function + + Public MustOverride Overloads Function IsApplicable(options As VisualBasicSimplifierOptions) As Boolean End Class End Namespace diff --git a/src/Workspaces/VisualBasic/Portable/Simplification/Reducers/VisualBasicCallReducer.vb b/src/Workspaces/VisualBasic/Portable/Simplification/Reducers/VisualBasicCallReducer.vb index 37a1b5f6a67f1..22e148896c827 100644 --- a/src/Workspaces/VisualBasic/Portable/Simplification/Reducers/VisualBasicCallReducer.vb +++ b/src/Workspaces/VisualBasic/Portable/Simplification/Reducers/VisualBasicCallReducer.vb @@ -15,16 +15,20 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Simplification Private Shared ReadOnly s_pool As ObjectPool(Of IReductionRewriter) = New ObjectPool(Of IReductionRewriter)(Function() New Rewriter(s_pool)) + Private Shared ReadOnly s_simplifyCallStatement As Func(Of CallStatementSyntax, SemanticModel, SimplifierOptions, CancellationToken, SyntaxNode) = AddressOf SimplifyCallStatement + Public Sub New() MyBase.New(s_pool) End Sub - Private Shared ReadOnly s_simplifyCallStatement As Func(Of CallStatementSyntax, SemanticModel, OptionSet, CancellationToken, SyntaxNode) = AddressOf SimplifyCallStatement + Public Overrides Function IsApplicable(options As VisualBasicSimplifierOptions) As Boolean + Return True + End Function Private Shared Function SimplifyCallStatement( callStatement As CallStatementSyntax, semanticModel As SemanticModel, - optionSet As OptionSet, + options As SimplifierOptions, cancellationToken As CancellationToken ) As ExecutableStatementSyntax diff --git a/src/Workspaces/VisualBasic/Portable/Simplification/Reducers/VisualBasicCastReducer.vb b/src/Workspaces/VisualBasic/Portable/Simplification/Reducers/VisualBasicCastReducer.vb index 82680ea3e8712..a11ab9f3e84b1 100644 --- a/src/Workspaces/VisualBasic/Portable/Simplification/Reducers/VisualBasicCastReducer.vb +++ b/src/Workspaces/VisualBasic/Portable/Simplification/Reducers/VisualBasicCastReducer.vb @@ -5,6 +5,7 @@ Imports System.Threading Imports Microsoft.CodeAnalysis.Options Imports Microsoft.CodeAnalysis.PooledObjects +Imports Microsoft.CodeAnalysis.Simplification Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Namespace Microsoft.CodeAnalysis.VisualBasic.Simplification @@ -14,16 +15,20 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Simplification Private Shared ReadOnly s_pool As ObjectPool(Of IReductionRewriter) = New ObjectPool(Of IReductionRewriter)(Function() New Rewriter(s_pool)) + Private Shared ReadOnly s_simplifyCast As Func(Of CastExpressionSyntax, SemanticModel, SimplifierOptions, CancellationToken, SyntaxNode) = AddressOf SimplifyCast + Public Sub New() MyBase.New(s_pool) End Sub - Private Shared ReadOnly s_simplifyCast As Func(Of CastExpressionSyntax, SemanticModel, OptionSet, CancellationToken, SyntaxNode) = AddressOf SimplifyCast + Public Overrides Function IsApplicable(options As VisualBasicSimplifierOptions) As Boolean + Return True + End Function Private Overloads Shared Function SimplifyCast( node As CastExpressionSyntax, semanticModel As SemanticModel, - optionSet As OptionSet, + options As SimplifierOptions, cancellationToken As CancellationToken ) As ExpressionSyntax @@ -34,12 +39,12 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Simplification Return node.Uncast() End Function - Private Shared ReadOnly s_simplifyPredefinedCast As Func(Of PredefinedCastExpressionSyntax, SemanticModel, OptionSet, CancellationToken, SyntaxNode) = AddressOf SimplifyPredefinedCast + Private Shared ReadOnly s_simplifyPredefinedCast As Func(Of PredefinedCastExpressionSyntax, SemanticModel, SimplifierOptions, CancellationToken, SyntaxNode) = AddressOf SimplifyPredefinedCast Private Overloads Shared Function SimplifyPredefinedCast( node As PredefinedCastExpressionSyntax, semanticModel As SemanticModel, - optionSet As OptionSet, + options As SimplifierOptions, cancellationToken As CancellationToken ) As ExpressionSyntax diff --git a/src/Workspaces/VisualBasic/Portable/Simplification/Reducers/VisualBasicEscapingReducer.vb b/src/Workspaces/VisualBasic/Portable/Simplification/Reducers/VisualBasicEscapingReducer.vb index bb16ef4da24e1..9646191cfa63f 100644 --- a/src/Workspaces/VisualBasic/Portable/Simplification/Reducers/VisualBasicEscapingReducer.vb +++ b/src/Workspaces/VisualBasic/Portable/Simplification/Reducers/VisualBasicEscapingReducer.vb @@ -19,9 +19,13 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Simplification MyBase.New(s_pool) End Sub + Public Overrides Function IsApplicable(options As VisualBasicSimplifierOptions) As Boolean + Return True + End Function + #Disable Warning IDE0060 ' Remove unused parameter - False positive, used as a delegate in a nested type. ' https://github.com/dotnet/roslyn/issues/44226 - Private Shared Function TryUnescapeToken(identifier As SyntaxToken, semanticModel As SemanticModel, optionSet As OptionSet, cancellationToken As CancellationToken) As SyntaxToken + Private Shared Function TryUnescapeToken(identifier As SyntaxToken, semanticModel As SemanticModel, options As VisualBasicSimplifierOptions, cancellationToken As CancellationToken) As SyntaxToken #Enable Warning IDE0060 ' Remove unused parameter If Not identifier.IsBracketed Then Return identifier diff --git a/src/Workspaces/VisualBasic/Portable/Simplification/Reducers/VisualBasicExtensionMethodReducer.vb b/src/Workspaces/VisualBasic/Portable/Simplification/Reducers/VisualBasicExtensionMethodReducer.vb index b7e67bd324505..8bd16d2d385b1 100644 --- a/src/Workspaces/VisualBasic/Portable/Simplification/Reducers/VisualBasicExtensionMethodReducer.vb +++ b/src/Workspaces/VisualBasic/Portable/Simplification/Reducers/VisualBasicExtensionMethodReducer.vb @@ -14,16 +14,20 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Simplification Private Shared ReadOnly s_pool As ObjectPool(Of IReductionRewriter) = New ObjectPool(Of IReductionRewriter)(Function() New Rewriter(s_pool)) + Private Shared ReadOnly s_simplifyInvocationExpression As Func(Of InvocationExpressionSyntax, SemanticModel, VisualBasicSimplifierOptions, CancellationToken, SyntaxNode) = AddressOf SimplifyInvocationExpression + Public Sub New() MyBase.New(s_pool) End Sub - Private Shared ReadOnly s_simplifyInvocationExpression As Func(Of InvocationExpressionSyntax, SemanticModel, OptionSet, CancellationToken, SyntaxNode) = AddressOf SimplifyInvocationExpression + Public Overrides Function IsApplicable(options As VisualBasicSimplifierOptions) As Boolean + Return True + End Function Private Shared Function SimplifyInvocationExpression( invocationExpression As InvocationExpressionSyntax, semanticModel As SemanticModel, - optionSet As OptionSet, + options As VisualBasicSimplifierOptions, cancellationToken As CancellationToken ) As InvocationExpressionSyntax diff --git a/src/Workspaces/VisualBasic/Portable/Simplification/Reducers/VisualBasicInferredMemberNameReducer.Rewriter.vb b/src/Workspaces/VisualBasic/Portable/Simplification/Reducers/VisualBasicInferredMemberNameReducer.Rewriter.vb index f2184a671a53d..26ff8009b40c2 100644 --- a/src/Workspaces/VisualBasic/Portable/Simplification/Reducers/VisualBasicInferredMemberNameReducer.Rewriter.vb +++ b/src/Workspaces/VisualBasic/Portable/Simplification/Reducers/VisualBasicInferredMemberNameReducer.Rewriter.vb @@ -5,6 +5,7 @@ Imports System.Threading Imports Microsoft.CodeAnalysis.Options Imports Microsoft.CodeAnalysis.PooledObjects +Imports Microsoft.CodeAnalysis.Simplification Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Namespace Microsoft.CodeAnalysis.VisualBasic.Simplification @@ -17,10 +18,10 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Simplification MyBase.New(pool) End Sub - Private ReadOnly s_simplifyTupleName As Func(Of SimpleArgumentSyntax, SemanticModel, OptionSet, CancellationToken, SimpleArgumentSyntax) = AddressOf SimplifyTupleName - Private ReadOnly s_simplifyNamedFieldInitializer As Func(Of NamedFieldInitializerSyntax, SemanticModel, OptionSet, CancellationToken, SyntaxNode) = AddressOf SimplifyNamedFieldInitializer + Private ReadOnly s_simplifyTupleName As Func(Of SimpleArgumentSyntax, SemanticModel, SimplifierOptions, CancellationToken, SimpleArgumentSyntax) = AddressOf SimplifyTupleName + Private ReadOnly s_simplifyNamedFieldInitializer As Func(Of NamedFieldInitializerSyntax, SemanticModel, SimplifierOptions, CancellationToken, SyntaxNode) = AddressOf SimplifyNamedFieldInitializer - Private Function SimplifyNamedFieldInitializer(node As NamedFieldInitializerSyntax, arg2 As SemanticModel, optionSet As OptionSet, arg4 As CancellationToken) As SyntaxNode + Private Function SimplifyNamedFieldInitializer(node As NamedFieldInitializerSyntax, arg2 As SemanticModel, options As SimplifierOptions, arg4 As CancellationToken) As SyntaxNode If CanSimplifyNamedFieldInitializer(node) Then Return SyntaxFactory.InferredFieldInitializer(node.Expression).WithTriviaFrom(node) End If @@ -31,7 +32,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Simplification Private Function SimplifyTupleName( node As SimpleArgumentSyntax, semanticModel As SemanticModel, - optionSet As OptionSet, + options As SimplifierOptions, cancellationToken As CancellationToken ) As SimpleArgumentSyntax diff --git a/src/Workspaces/VisualBasic/Portable/Simplification/Reducers/VisualBasicInferredMemberNameReducer.vb b/src/Workspaces/VisualBasic/Portable/Simplification/Reducers/VisualBasicInferredMemberNameReducer.vb index 6d810474604ff..876497afa8e6c 100644 --- a/src/Workspaces/VisualBasic/Portable/Simplification/Reducers/VisualBasicInferredMemberNameReducer.vb +++ b/src/Workspaces/VisualBasic/Portable/Simplification/Reducers/VisualBasicInferredMemberNameReducer.vb @@ -19,5 +19,9 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Simplification Public Sub New() MyBase.New(s_pool) End Sub + + Public Overrides Function IsApplicable(options As VisualBasicSimplifierOptions) As Boolean + Return True + End Function End Class End Namespace diff --git a/src/Workspaces/VisualBasic/Portable/Simplification/Reducers/VisualBasicMiscellaneousReducer.vb b/src/Workspaces/VisualBasic/Portable/Simplification/Reducers/VisualBasicMiscellaneousReducer.vb index 4f132ecafa80e..f87a4abdfe1b9 100644 --- a/src/Workspaces/VisualBasic/Portable/Simplification/Reducers/VisualBasicMiscellaneousReducer.vb +++ b/src/Workspaces/VisualBasic/Portable/Simplification/Reducers/VisualBasicMiscellaneousReducer.vb @@ -15,16 +15,20 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Simplification Private Shared ReadOnly s_pool As ObjectPool(Of IReductionRewriter) = New ObjectPool(Of IReductionRewriter)(Function() New Rewriter(s_pool)) + Private Shared ReadOnly s_simplifyParameter As Func(Of ParameterSyntax, SemanticModel, SimplifierOptions, CancellationToken, ParameterSyntax) = AddressOf SimplifyParameter + Public Sub New() MyBase.New(s_pool) End Sub - Private Shared ReadOnly s_simplifyParameter As Func(Of ParameterSyntax, SemanticModel, OptionSet, CancellationToken, ParameterSyntax) = AddressOf SimplifyParameter + Public Overrides Function IsApplicable(options As VisualBasicSimplifierOptions) As Boolean + Return True + End Function Private Shared Function SimplifyParameter( parameter As ParameterSyntax, semanticModel As SemanticModel, - optionSet As OptionSet, + options As SimplifierOptions, cancellationToken As CancellationToken ) As ParameterSyntax If parameter.CanRemoveAsClause(semanticModel, cancellationToken) Then @@ -36,12 +40,12 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Simplification Return parameter End Function - Private Shared ReadOnly s_simplifyInvocationExpression As Func(Of InvocationExpressionSyntax, SemanticModel, OptionSet, CancellationToken, SyntaxNode) = AddressOf SimplifyInvocationExpression + Private Shared ReadOnly s_simplifyInvocationExpression As Func(Of InvocationExpressionSyntax, SemanticModel, SimplifierOptions, CancellationToken, SyntaxNode) = AddressOf SimplifyInvocationExpression Private Shared Function SimplifyInvocationExpression( invocationExpression As InvocationExpressionSyntax, semanticModel As SemanticModel, - optionSet As OptionSet, + options As SimplifierOptions, cancellationToken As CancellationToken ) As InvocationExpressionSyntax @@ -59,12 +63,12 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Simplification Return invocationExpression End Function - Private Shared ReadOnly s_simplifyObjectCreationExpression As Func(Of ObjectCreationExpressionSyntax, SemanticModel, OptionSet, CancellationToken, SyntaxNode) = AddressOf SimplifyObjectCreationExpression + Private Shared ReadOnly s_simplifyObjectCreationExpression As Func(Of ObjectCreationExpressionSyntax, SemanticModel, SimplifierOptions, CancellationToken, SyntaxNode) = AddressOf SimplifyObjectCreationExpression Private Shared Function SimplifyObjectCreationExpression( objectCreationExpression As ObjectCreationExpressionSyntax, semanticModel As SemanticModel, - optionSet As OptionSet, + options As SimplifierOptions, cancellationToken As CancellationToken ) As ObjectCreationExpressionSyntax diff --git a/src/Workspaces/VisualBasic/Portable/Simplification/Reducers/VisualBasicNameReducer.vb b/src/Workspaces/VisualBasic/Portable/Simplification/Reducers/VisualBasicNameReducer.vb index 2326cefe8b8a6..6ce8c2a21f676 100644 --- a/src/Workspaces/VisualBasic/Portable/Simplification/Reducers/VisualBasicNameReducer.vb +++ b/src/Workspaces/VisualBasic/Portable/Simplification/Reducers/VisualBasicNameReducer.vb @@ -19,23 +19,27 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Simplification Private Shared ReadOnly s_pool As ObjectPool(Of IReductionRewriter) = New ObjectPool(Of IReductionRewriter)(Function() New Rewriter(s_pool)) + Private Shared ReadOnly s_simplifyName As Func(Of ExpressionSyntax, SemanticModel, SimplifierOptions, CancellationToken, SyntaxNode) = AddressOf SimplifyName + Public Sub New() MyBase.New(s_pool) End Sub - Private Shared ReadOnly s_simplifyName As Func(Of ExpressionSyntax, SemanticModel, OptionSet, CancellationToken, SyntaxNode) = AddressOf SimplifyName + Public Overrides Function IsApplicable(options As VisualBasicSimplifierOptions) As Boolean + Return True + End Function Private Overloads Shared Function SimplifyName( node As ExpressionSyntax, semanticModel As SemanticModel, - optionSet As OptionSet, + options As SimplifierOptions, cancellationToken As CancellationToken ) As ExpressionSyntax Dim replacementNode As ExpressionSyntax = Nothing Dim issueSpan As TextSpan If Not ExpressionSimplifier.Instance.TrySimplify( - node, semanticModel, optionSet, + node, semanticModel, DirectCast(options, VisualBasicSimplifierOptions), replacementNode, issueSpan, cancellationToken) Then Return node diff --git a/src/Workspaces/VisualBasic/Portable/Simplification/Reducers/VisualBasicParenthesesReducer.vb b/src/Workspaces/VisualBasic/Portable/Simplification/Reducers/VisualBasicParenthesesReducer.vb index a29d15bc3599c..edabaedbc7e29 100644 --- a/src/Workspaces/VisualBasic/Portable/Simplification/Reducers/VisualBasicParenthesesReducer.vb +++ b/src/Workspaces/VisualBasic/Portable/Simplification/Reducers/VisualBasicParenthesesReducer.vb @@ -13,5 +13,9 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Simplification Public Sub New() MyBase.New(s_pool) End Sub + + Public Overrides Function IsApplicable(options As VisualBasicSimplifierOptions) As Boolean + Return True + End Function End Class End Namespace diff --git a/src/Workspaces/VisualBasic/Portable/Simplification/Reducers/VisualBasicVariableDeclaratorReducer.vb b/src/Workspaces/VisualBasic/Portable/Simplification/Reducers/VisualBasicVariableDeclaratorReducer.vb index 4526f40c0de12..6e1271f8d602d 100644 --- a/src/Workspaces/VisualBasic/Portable/Simplification/Reducers/VisualBasicVariableDeclaratorReducer.vb +++ b/src/Workspaces/VisualBasic/Portable/Simplification/Reducers/VisualBasicVariableDeclaratorReducer.vb @@ -18,16 +18,20 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Simplification Private Shared ReadOnly s_pool As ObjectPool(Of IReductionRewriter) = New ObjectPool(Of IReductionRewriter)(Function() New Rewriter(s_pool)) + Private Shared ReadOnly s_simplifyVariableDeclarator As Func(Of VariableDeclaratorSyntax, SemanticModel, VisualBasicSimplifierOptions, CancellationToken, SyntaxNode) = AddressOf SimplifyVariableDeclarator + Public Sub New() MyBase.New(s_pool) End Sub - Private Shared ReadOnly s_simplifyVariableDeclarator As Func(Of VariableDeclaratorSyntax, SemanticModel, OptionSet, CancellationToken, SyntaxNode) = AddressOf SimplifyVariableDeclarator + Public Overrides Function IsApplicable(options As VisualBasicSimplifierOptions) As Boolean + Return True + End Function Private Overloads Shared Function SimplifyVariableDeclarator( node As VariableDeclaratorSyntax, semanticModel As SemanticModel, - optionSet As OptionSet, + options As VisualBasicSimplifierOptions, cancellationToken As CancellationToken ) As SyntaxNode Dim replacementNode As SyntaxNode = Nothing diff --git a/src/Workspaces/VisualBasic/Portable/Simplification/Simplifiers/AbstractVisualBasicSimplifier.vb b/src/Workspaces/VisualBasic/Portable/Simplification/Simplifiers/AbstractVisualBasicSimplifier.vb index 9e0183be63796..07a47d4bfdef6 100644 --- a/src/Workspaces/VisualBasic/Portable/Simplification/Simplifiers/AbstractVisualBasicSimplifier.vb +++ b/src/Workspaces/VisualBasic/Portable/Simplification/Simplifiers/AbstractVisualBasicSimplifier.vb @@ -11,7 +11,7 @@ Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Namespace Microsoft.CodeAnalysis.VisualBasic.Simplification.Simplifiers Friend MustInherit Class AbstractVisualBasicSimplifier(Of TSyntax As SyntaxNode, TSimplifiedSyntax As SyntaxNode) - Inherits AbstractSimplifier(Of TSyntax, TSimplifiedSyntax) + Inherits AbstractSimplifier(Of TSyntax, TSimplifiedSyntax, VisualBasicSimplifierOptions) ''' ''' Returns the predefined keyword kind for a given special type. @@ -180,10 +180,10 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Simplification.Simplifiers Return False End Function - Protected Shared Function PreferPredefinedTypeKeywordInMemberAccess(expression As ExpressionSyntax, optionSet As OptionSet) As Boolean + Protected Shared Function PreferPredefinedTypeKeywordInMemberAccess(expression As ExpressionSyntax, options As VisualBasicSimplifierOptions) As Boolean Return (IsDirectChildOfMemberAccessExpression(expression) OrElse IsInCrefReferenceForPredefinedTypeInMemberAccessContext(expression)) AndAlso (Not InsideNameOfExpression(expression)) AndAlso - SimplificationHelpers.PreferPredefinedTypeKeywordInMemberAccess(optionSet, LanguageNames.VisualBasic) + options.PreferPredefinedTypeKeywordInMemberAccess.Value End Function Protected Shared Function InsideNameOfExpression(expr As ExpressionSyntax) As Boolean diff --git a/src/Workspaces/VisualBasic/Portable/Simplification/Simplifiers/ExpressionSimplifier.vb b/src/Workspaces/VisualBasic/Portable/Simplification/Simplifiers/ExpressionSimplifier.vb index 6a205ee2caaa2..bdf8a1f4487cf 100644 --- a/src/Workspaces/VisualBasic/Portable/Simplification/Simplifiers/ExpressionSimplifier.vb +++ b/src/Workspaces/VisualBasic/Portable/Simplification/Simplifiers/ExpressionSimplifier.vb @@ -23,11 +23,11 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Simplification.Simplifiers Public Overrides Function TrySimplify(expression As ExpressionSyntax, semanticModel As SemanticModel, - optionSet As OptionSet, + options As VisualBasicSimplifierOptions, ByRef replacementNode As ExpressionSyntax, ByRef issueSpan As TextSpan, cancellationToken As CancellationToken) As Boolean - If TryReduceExplicitName(expression, semanticModel, replacementNode, issueSpan, optionSet, cancellationToken) Then + If TryReduceExplicitName(expression, semanticModel, replacementNode, issueSpan, options, cancellationToken) Then Return True End If @@ -39,7 +39,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Simplification.Simplifiers semanticModel As SemanticModel, ByRef replacementNode As ExpressionSyntax, ByRef issueSpan As TextSpan, - optionSet As OptionSet, + options As VisualBasicSimplifierOptions, cancellationToken As CancellationToken ) As Boolean replacementNode = Nothing @@ -50,12 +50,12 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Simplification.Simplifiers Return TryReduce(memberAccess, semanticModel, replacementNode, issueSpan, - optionSet, + options, cancellationToken) ElseIf TypeOf expression Is NameSyntax Then Dim name = DirectCast(expression, NameSyntax) Return NameSimplifier.Instance.TrySimplify( - name, semanticModel, optionSet, + name, semanticModel, options, replacementNode, issueSpan, cancellationToken) End If @@ -65,9 +65,9 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Simplification.Simplifiers Private Shared Function TryReduce( memberAccess As MemberAccessExpressionSyntax, semanticModel As SemanticModel, - ByRef replacementNode As ExpressionSyntax, - ByRef issueSpan As TextSpan, - optionSet As OptionSet, + ByRef replacementNode As ExpressionSyntax, + ByRef issueSpan As TextSpan, + options As VisualBasicSimplifierOptions, cancellationToken As CancellationToken ) As Boolean If memberAccess.Expression Is Nothing OrElse memberAccess.Name Is Nothing Then @@ -96,7 +96,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Simplification.Simplifiers End If If memberAccess.Expression.IsKind(SyntaxKind.MeExpression) AndAlso - Not SimplificationHelpers.ShouldSimplifyThisOrMeMemberAccessExpression(semanticModel, optionSet, symbol) Then + Not SimplificationHelpers.ShouldSimplifyThisOrMeMemberAccessExpression(options, symbol) Then Return False End If @@ -123,7 +123,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Simplification.Simplifiers Return True End If - If PreferPredefinedTypeKeywordInMemberAccess(memberAccess, optionSet) Then + If PreferPredefinedTypeKeywordInMemberAccess(memberAccess, options) Then If (symbol IsNot Nothing AndAlso symbol.IsKind(SymbolKind.NamedType)) Then Dim keywordKind = GetPredefinedKeywordKind(DirectCast(symbol, INamedTypeSymbol).SpecialType) If keywordKind <> SyntaxKind.None Then diff --git a/src/Workspaces/VisualBasic/Portable/Simplification/Simplifiers/NameSimplifier.vb b/src/Workspaces/VisualBasic/Portable/Simplification/Simplifiers/NameSimplifier.vb index cffebfafa94e9..784800c2847dd 100644 --- a/src/Workspaces/VisualBasic/Portable/Simplification/Simplifiers/NameSimplifier.vb +++ b/src/Workspaces/VisualBasic/Portable/Simplification/Simplifiers/NameSimplifier.vb @@ -25,7 +25,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Simplification.Simplifiers Public Overrides Function TrySimplify( name As NameSyntax, semanticModel As SemanticModel, - optionSet As OptionSet, + options As VisualBasicSimplifierOptions, ByRef replacementNode As ExpressionSyntax, ByRef issueSpan As TextSpan, cancellationToken As CancellationToken) As Boolean @@ -164,8 +164,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Simplification.Simplifiers keywordKind, name.GetTrailingTrivia()) Dim valueText = TryCast(name, IdentifierNameSyntax)?.Identifier.ValueText - Dim inDeclarationContext = PreferPredefinedTypeKeywordInDeclarations(name, optionSet) - Dim inMemberAccessContext = PreferPredefinedTypeKeywordInMemberAccess(name, optionSet) + Dim inDeclarationContext = PreferPredefinedTypeKeywordInDeclarations(name, options) + Dim inMemberAccessContext = PreferPredefinedTypeKeywordInMemberAccess(name, options) If token.Text = valueText OrElse (inDeclarationContext OrElse inMemberAccessContext) Then Dim codeStyleOptionName As String = Nothing @@ -390,11 +390,11 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Simplification.Simplifiers Return False End Function - Private Shared Function PreferPredefinedTypeKeywordInDeclarations(name As NameSyntax, optionSet As OptionSet) As Boolean + Private Shared Function PreferPredefinedTypeKeywordInDeclarations(name As NameSyntax, options As VisualBasicSimplifierOptions) As Boolean Return (Not IsDirectChildOfMemberAccessExpression(name)) AndAlso (Not InsideCrefReference(name)) AndAlso (Not InsideNameOfExpression(name)) AndAlso - SimplificationHelpers.PreferPredefinedTypeKeywordInDeclarations(optionSet, LanguageNames.VisualBasic) + options.PreferPredefinedTypeKeywordInDeclaration.Value End Function Private Shared Function CanSimplifyNullable(type As INamedTypeSymbol, name As NameSyntax) As Boolean diff --git a/src/Workspaces/VisualBasic/Portable/Simplification/VisualBasicSimplificationService.vb b/src/Workspaces/VisualBasic/Portable/Simplification/VisualBasicSimplificationService.vb index 2bff6aaaec0e4..f46b72f4f0845 100644 --- a/src/Workspaces/VisualBasic/Portable/Simplification/VisualBasicSimplificationService.vb +++ b/src/Workspaces/VisualBasic/Portable/Simplification/VisualBasicSimplificationService.vb @@ -6,6 +6,7 @@ Imports System.Collections.Immutable Imports System.Composition Imports System.Threading Imports Microsoft.CodeAnalysis +Imports Microsoft.CodeAnalysis.Diagnostics Imports Microsoft.CodeAnalysis.Host.Mef Imports Microsoft.CodeAnalysis.Internal.Log Imports Microsoft.CodeAnalysis.Simplification @@ -36,6 +37,16 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Simplification MyBase.New(s_reducers) End Sub + Public Overrides ReadOnly Property DefaultOptions As SimplifierOptions + Get + Return VisualBasicSimplifierOptions.Default + End Get + End Property + + Public Overrides Function GetSimplifierOptions(options As AnalyzerConfigOptions, fallbackOptions As SimplifierOptions) As SimplifierOptions + Return VisualBasicSimplifierOptions.Create(options, DirectCast(fallbackOptions, VisualBasicSimplifierOptions)) + End Function + Public Overrides Function Expand(node As SyntaxNode, semanticModel As SemanticModel, aliasReplacementAnnotation As SyntaxAnnotation, expandInsideNode As Func(Of SyntaxNode, Boolean), expandParameter As Boolean, cancellationToken As CancellationToken) As SyntaxNode Using Logger.LogBlock(FunctionId.Simplifier_ExpandNode, cancellationToken) If TypeOf node Is ExpressionSyntax OrElse diff --git a/src/Workspaces/VisualBasicTest/CodeGeneration/AddImportsTests.vb b/src/Workspaces/VisualBasicTest/CodeGeneration/AddImportsTests.vb index 3ff21757710de..b14c8a58a0041 100644 --- a/src/Workspaces/VisualBasicTest/CodeGeneration/AddImportsTests.vb +++ b/src/Workspaces/VisualBasicTest/CodeGeneration/AddImportsTests.vb @@ -9,6 +9,7 @@ Imports Microsoft.CodeAnalysis.Formatting Imports Microsoft.CodeAnalysis.Simplification Imports Microsoft.CodeAnalysis.Test.Utilities Imports Microsoft.CodeAnalysis.VisualBasic.Formatting +Imports Microsoft.CodeAnalysis.VisualBasic.Simplification Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Imports Roslyn.Test.Utilities Imports Xunit @@ -88,6 +89,7 @@ End NameSpace" AllowInHiddenRegions:=False) Dim formattingOptions = VisualBasicSyntaxFormattingOptions.Default + Dim simplifierOptions = VisualBasicSimplifierOptions.Default Dim imported = If( useSymbolAnnotations, @@ -101,7 +103,7 @@ End NameSpace" End If If simplifiedText IsNot Nothing Then - Dim reduced = Await Simplifier.ReduceAsync(imported) + Dim reduced = Await Simplifier.ReduceAsync(imported, simplifierOptions, CancellationToken.None) Dim formatted = Await Formatter.FormatAsync(reduced, SyntaxAnnotation.ElasticAnnotation, formattingOptions, CancellationToken.None) Dim actualText = (Await formatted.GetTextAsync()).ToString() Assert.Equal(simplifiedText, actualText) From 646e3c4ef7b93b27c698fbb79d545eb4f469a682 Mon Sep 17 00:00:00 2001 From: Siegfried Pammer Date: Thu, 14 Apr 2022 23:24:11 +0200 Subject: [PATCH 66/66] Fix #55183: Add SymbolVisitor (#56530) * Fix #55183: Add SymbolVisitor --- .../Symbols/PublicModel/AliasSymbol.cs | 5 + .../Symbols/PublicModel/ArrayTypeSymbol.cs | 5 + .../Symbols/PublicModel/AssemblySymbol.cs | 5 + .../Symbols/PublicModel/DiscardSymbol.cs | 1 + .../Symbols/PublicModel/DynamicTypeSymbol.cs | 5 + .../Symbols/PublicModel/EventSymbol.cs | 5 + .../Symbols/PublicModel/FieldSymbol.cs | 5 + .../PublicModel/FunctionPointerTypeSymbol.cs | 5 + .../Symbols/PublicModel/LabelSymbol.cs | 5 + .../Symbols/PublicModel/LocalSymbol.cs | 5 + .../Symbols/PublicModel/MethodSymbol.cs | 5 + .../Symbols/PublicModel/ModuleSymbol.cs | 5 + .../Symbols/PublicModel/NamedTypeSymbol.cs | 5 + .../Symbols/PublicModel/NamespaceSymbol.cs | 5 + .../Symbols/PublicModel/ParameterSymbol.cs | 5 + .../Symbols/PublicModel/PointerTypeSymbol.cs | 5 + .../PublicModel/PreprocessingSymbol.cs | 2 + .../Symbols/PublicModel/PropertySymbol.cs | 5 + .../PublicModel/RangeVariableSymbol.cs | 5 + .../Portable/Symbols/PublicModel/Symbol.cs | 7 + .../PublicModel/TypeParameterSymbol.cs | 5 + .../Semantic/Semantics/DelegateTypeTests.cs | 1 + .../Symbol/Compilation/SymbolVisitorTests.cs | 813 ++++++++++++++++++ .../Core/Portable/PublicAPI.Unshipped.txt | 28 +- .../Core/Portable/Symbols/ISymbol.cs | 1 + .../Core/Portable/Symbols/SymbolVisitor`2.cs | 121 +++ .../Portable/Symbols/AliasSymbol.vb | 4 + .../Portable/Symbols/ArrayTypeSymbol.vb | 4 + .../Portable/Symbols/AssemblySymbol.vb | 4 + .../Portable/Symbols/EventSymbol.vb | 4 + .../Portable/Symbols/FieldSymbol.vb | 4 + .../Portable/Symbols/LabelSymbol.vb | 4 + .../Portable/Symbols/MethodSymbol.vb | 4 + .../Portable/Symbols/ModuleSymbol.vb | 4 + .../Portable/Symbols/NamedTypeSymbol.vb | 4 + .../Portable/Symbols/NamespaceSymbol.vb | 4 + .../Portable/Symbols/ParameterSymbol.vb | 4 + .../Portable/Symbols/PreprocessingSymbol.vb | 4 + .../Portable/Symbols/PropertySymbol.vb | 4 + .../Portable/Symbols/Source/LocalSymbol.vb | 4 + .../Symbols/Source/RangeVariableSymbol.vb | 4 + .../VisualBasic/Portable/Symbols/Symbol.vb | 2 + .../Portable/Symbols/TypeParameterSymbol.vb | 4 + ...taAsSourceService.AbstractWrappedSymbol.cs | 3 + .../CodeGenerationAbstractMethodSymbol.cs | 3 + .../CodeGenerationAbstractNamedTypeSymbol.cs | 3 + .../Symbols/CodeGenerationArrayTypeSymbol.cs | 3 + .../Symbols/CodeGenerationEventSymbol.cs | 3 + .../Symbols/CodeGenerationFieldSymbol.cs | 3 + .../Symbols/CodeGenerationNamespaceSymbol.cs | 3 + .../Symbols/CodeGenerationParameterSymbol.cs | 3 + .../CodeGenerationPointerTypeSymbol.cs | 3 + .../Symbols/CodeGenerationPropertySymbol.cs | 3 + .../Symbols/CodeGenerationSymbol.cs | 2 + .../CodeGenerationTypeParameterSymbol.cs | 3 + 55 files changed, 1163 insertions(+), 2 deletions(-) create mode 100644 src/Compilers/CSharp/Test/Symbol/Compilation/SymbolVisitorTests.cs create mode 100644 src/Compilers/Core/Portable/Symbols/SymbolVisitor`2.cs diff --git a/src/Compilers/CSharp/Portable/Symbols/PublicModel/AliasSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/PublicModel/AliasSymbol.cs index ca57fc6fc45da..0035d4b2a3e61 100644 --- a/src/Compilers/CSharp/Portable/Symbols/PublicModel/AliasSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/PublicModel/AliasSymbol.cs @@ -39,6 +39,11 @@ protected override void Accept(SymbolVisitor visitor) return visitor.VisitAlias(this); } + protected override TResult Accept(SymbolVisitor visitor, TArgument argument) + { + return visitor.VisitAlias(this, argument); + } + #endregion } } diff --git a/src/Compilers/CSharp/Portable/Symbols/PublicModel/ArrayTypeSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/PublicModel/ArrayTypeSymbol.cs index 979a3e0594ab7..eda642eac5986 100644 --- a/src/Compilers/CSharp/Portable/Symbols/PublicModel/ArrayTypeSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/PublicModel/ArrayTypeSymbol.cs @@ -81,6 +81,11 @@ protected override void Accept(SymbolVisitor visitor) return visitor.VisitArrayType(this); } + protected override TResult Accept(SymbolVisitor visitor, TArgument argument) + { + return visitor.VisitArrayType(this, argument); + } + #endregion } } diff --git a/src/Compilers/CSharp/Portable/Symbols/PublicModel/AssemblySymbol.cs b/src/Compilers/CSharp/Portable/Symbols/PublicModel/AssemblySymbol.cs index e4c64a6df80c8..7d09577dd59ac 100644 --- a/src/Compilers/CSharp/Portable/Symbols/PublicModel/AssemblySymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/PublicModel/AssemblySymbol.cs @@ -117,6 +117,11 @@ protected override TResult Accept(SymbolVisitor visitor) return visitor.VisitAssembly(this); } + protected override TResult Accept(SymbolVisitor visitor, TArgument argument) + { + return visitor.VisitAssembly(this, argument); + } + #endregion } } diff --git a/src/Compilers/CSharp/Portable/Symbols/PublicModel/DiscardSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/PublicModel/DiscardSymbol.cs index 58acae639bce2..37a268b3969a4 100644 --- a/src/Compilers/CSharp/Portable/Symbols/PublicModel/DiscardSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/PublicModel/DiscardSymbol.cs @@ -37,5 +37,6 @@ ITypeSymbol IDiscardSymbol.Type protected override void Accept(SymbolVisitor visitor) => visitor.VisitDiscard(this); protected override TResult? Accept(SymbolVisitor visitor) where TResult : default => visitor.VisitDiscard(this); + protected override TResult Accept(SymbolVisitor visitor, TArgument argument) => visitor.VisitDiscard(this, argument); } } diff --git a/src/Compilers/CSharp/Portable/Symbols/PublicModel/DynamicTypeSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/PublicModel/DynamicTypeSymbol.cs index 9b093368261cc..0dd87ce51a5bd 100644 --- a/src/Compilers/CSharp/Portable/Symbols/PublicModel/DynamicTypeSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/PublicModel/DynamicTypeSymbol.cs @@ -42,6 +42,11 @@ protected override void Accept(SymbolVisitor visitor) return visitor.VisitDynamicType(this); } + protected override TResult Accept(SymbolVisitor visitor, TArgument argument) + { + return visitor.VisitDynamicType(this, argument); + } + #endregion } } diff --git a/src/Compilers/CSharp/Portable/Symbols/PublicModel/EventSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/PublicModel/EventSymbol.cs index fa4cbbb5d08e6..9bf557e085674 100644 --- a/src/Compilers/CSharp/Portable/Symbols/PublicModel/EventSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/PublicModel/EventSymbol.cs @@ -101,6 +101,11 @@ protected override void Accept(SymbolVisitor visitor) return visitor.VisitEvent(this); } + protected override TResult Accept(SymbolVisitor visitor, TArgument argument) + { + return visitor.VisitEvent(this, argument); + } + #endregion } } diff --git a/src/Compilers/CSharp/Portable/Symbols/PublicModel/FieldSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/PublicModel/FieldSymbol.cs index e277d95d12fd5..cdb351051f5f0 100644 --- a/src/Compilers/CSharp/Portable/Symbols/PublicModel/FieldSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/PublicModel/FieldSymbol.cs @@ -101,6 +101,11 @@ protected override TResult Accept(SymbolVisitor visitor) return visitor.VisitField(this); } + protected override TResult Accept(SymbolVisitor visitor, TArgument argument) + { + return visitor.VisitField(this, argument); + } + #endregion } } diff --git a/src/Compilers/CSharp/Portable/Symbols/PublicModel/FunctionPointerTypeSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/PublicModel/FunctionPointerTypeSymbol.cs index 84e1938e5273b..97463c7944755 100644 --- a/src/Compilers/CSharp/Portable/Symbols/PublicModel/FunctionPointerTypeSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/PublicModel/FunctionPointerTypeSymbol.cs @@ -32,6 +32,11 @@ protected override void Accept(SymbolVisitor visitor) return visitor.VisitFunctionPointerType(this); } + protected override TResult Accept(SymbolVisitor visitor, TArgument argument) + { + return visitor.VisitFunctionPointerType(this, argument); + } + protected override ITypeSymbol WithNullableAnnotation(CodeAnalysis.NullableAnnotation nullableAnnotation) { Debug.Assert(nullableAnnotation != this.NullableAnnotation); diff --git a/src/Compilers/CSharp/Portable/Symbols/PublicModel/LabelSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/PublicModel/LabelSymbol.cs index 135e0617dbd4d..98de55c8980c4 100644 --- a/src/Compilers/CSharp/Portable/Symbols/PublicModel/LabelSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/PublicModel/LabelSymbol.cs @@ -39,6 +39,11 @@ protected override void Accept(SymbolVisitor visitor) return visitor.VisitLabel(this); } + protected override TResult Accept(SymbolVisitor visitor, TArgument argument) + { + return visitor.VisitLabel(this, argument); + } + #endregion } } diff --git a/src/Compilers/CSharp/Portable/Symbols/PublicModel/LocalSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/PublicModel/LocalSymbol.cs index be20bcc9b6a79..bc4308bce207c 100644 --- a/src/Compilers/CSharp/Portable/Symbols/PublicModel/LocalSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/PublicModel/LocalSymbol.cs @@ -69,6 +69,11 @@ protected sealed override TResult Accept(SymbolVisitor visitor return visitor.VisitLocal(this); } + protected override TResult Accept(SymbolVisitor visitor, TArgument argument) + { + return visitor.VisitLocal(this, argument); + } + #endregion } } diff --git a/src/Compilers/CSharp/Portable/Symbols/PublicModel/MethodSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/PublicModel/MethodSymbol.cs index 378deff3457b5..8345c43ac118e 100644 --- a/src/Compilers/CSharp/Portable/Symbols/PublicModel/MethodSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/PublicModel/MethodSymbol.cs @@ -341,6 +341,11 @@ protected override TResult Accept(SymbolVisitor visitor) return visitor.VisitMethod(this); } + protected override TResult Accept(SymbolVisitor visitor, TArgument argument) + { + return visitor.VisitMethod(this, argument); + } + #endregion } } diff --git a/src/Compilers/CSharp/Portable/Symbols/PublicModel/ModuleSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/PublicModel/ModuleSymbol.cs index 577bd70351dc1..43a1bcd525318 100644 --- a/src/Compilers/CSharp/Portable/Symbols/PublicModel/ModuleSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/PublicModel/ModuleSymbol.cs @@ -58,6 +58,11 @@ protected override TResult Accept(SymbolVisitor visitor) return visitor.VisitModule(this); } + protected override TResult Accept(SymbolVisitor visitor, TArgument argument) + { + return visitor.VisitModule(this, argument); + } + #endregion } } diff --git a/src/Compilers/CSharp/Portable/Symbols/PublicModel/NamedTypeSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/PublicModel/NamedTypeSymbol.cs index c3006a0ede617..f5173fe3d8665 100644 --- a/src/Compilers/CSharp/Portable/Symbols/PublicModel/NamedTypeSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/PublicModel/NamedTypeSymbol.cs @@ -208,6 +208,11 @@ protected sealed override TResult Accept(SymbolVisitor visitor return visitor.VisitNamedType(this); } + protected sealed override TResult Accept(SymbolVisitor visitor, TArgument argument) + { + return visitor.VisitNamedType(this, argument); + } + #endregion } } diff --git a/src/Compilers/CSharp/Portable/Symbols/PublicModel/NamespaceSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/PublicModel/NamespaceSymbol.cs index f3b6148ec5324..a9be118c42304 100644 --- a/src/Compilers/CSharp/Portable/Symbols/PublicModel/NamespaceSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/PublicModel/NamespaceSymbol.cs @@ -74,6 +74,11 @@ protected override TResult Accept(SymbolVisitor visitor) return visitor.VisitNamespace(this); } + protected override TResult Accept(SymbolVisitor visitor, TArgument argument) + { + return visitor.VisitNamespace(this, argument); + } + #endregion } } diff --git a/src/Compilers/CSharp/Portable/Symbols/PublicModel/ParameterSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/PublicModel/ParameterSymbol.cs index 1504282ae7e3c..4248d36d27694 100644 --- a/src/Compilers/CSharp/Portable/Symbols/PublicModel/ParameterSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/PublicModel/ParameterSymbol.cs @@ -84,6 +84,11 @@ protected override TResult Accept(SymbolVisitor visitor) return visitor.VisitParameter(this); } + protected override TResult Accept(SymbolVisitor visitor, TArgument argument) + { + return visitor.VisitParameter(this, argument); + } + #endregion } } diff --git a/src/Compilers/CSharp/Portable/Symbols/PublicModel/PointerTypeSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/PublicModel/PointerTypeSymbol.cs index d18896dfe3b4b..fc802d371f08e 100644 --- a/src/Compilers/CSharp/Portable/Symbols/PublicModel/PointerTypeSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/PublicModel/PointerTypeSymbol.cs @@ -63,6 +63,11 @@ protected override TResult Accept(SymbolVisitor visitor) return visitor.VisitPointerType(this); } + protected override TResult Accept(SymbolVisitor visitor, TArgument argument) + { + return visitor.VisitPointerType(this, argument); + } + #endregion } } diff --git a/src/Compilers/CSharp/Portable/Symbols/PublicModel/PreprocessingSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/PublicModel/PreprocessingSymbol.cs index b288a6f35b792..4f9ff880d9db9 100644 --- a/src/Compilers/CSharp/Portable/Symbols/PublicModel/PreprocessingSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/PublicModel/PreprocessingSymbol.cs @@ -71,6 +71,8 @@ bool ISymbol.Equals(ISymbol other, CodeAnalysis.SymbolEqualityComparer equalityC TResult ISymbol.Accept(SymbolVisitor visitor) => throw new System.NotSupportedException(); + TResult ISymbol.Accept(SymbolVisitor visitor, TArgument argument) => throw new System.NotSupportedException(); + string ISymbol.GetDocumentationCommentId() => null; string ISymbol.GetDocumentationCommentXml(CultureInfo preferredCulture, bool expandIncludes, CancellationToken cancellationToken) => null; diff --git a/src/Compilers/CSharp/Portable/Symbols/PublicModel/PropertySymbol.cs b/src/Compilers/CSharp/Portable/Symbols/PublicModel/PropertySymbol.cs index bd74b98ea0dc3..da7ba61459435 100644 --- a/src/Compilers/CSharp/Portable/Symbols/PublicModel/PropertySymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/PublicModel/PropertySymbol.cs @@ -119,6 +119,11 @@ protected override TResult Accept(SymbolVisitor visitor) return visitor.VisitProperty(this); } + protected override TResult Accept(SymbolVisitor visitor, TArgument argument) + { + return visitor.VisitProperty(this, argument); + } + #endregion } } diff --git a/src/Compilers/CSharp/Portable/Symbols/PublicModel/RangeVariableSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/PublicModel/RangeVariableSymbol.cs index 5dedd9a9fff81..2368d55948f46 100644 --- a/src/Compilers/CSharp/Portable/Symbols/PublicModel/RangeVariableSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/PublicModel/RangeVariableSymbol.cs @@ -29,5 +29,10 @@ protected override TResult Accept(SymbolVisitor visitor) { return visitor.VisitRangeVariable(this); } + + protected override TResult Accept(SymbolVisitor visitor, TArgument argument) + { + return visitor.VisitRangeVariable(this, argument); + } } } diff --git a/src/Compilers/CSharp/Portable/Symbols/PublicModel/Symbol.cs b/src/Compilers/CSharp/Portable/Symbols/PublicModel/Symbol.cs index 4c464a2f0f294..bf59a69f818c6 100644 --- a/src/Compilers/CSharp/Portable/Symbols/PublicModel/Symbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/PublicModel/Symbol.cs @@ -144,6 +144,13 @@ TResult ISymbol.Accept(SymbolVisitor visitor) protected abstract TResult Accept(SymbolVisitor visitor); + TResult ISymbol.Accept(SymbolVisitor visitor, TArgument argument) + { + return Accept(visitor, argument); + } + + protected abstract TResult Accept(SymbolVisitor visitor, TArgument argument); + string ISymbol.GetDocumentationCommentId() { return UnderlyingSymbol.GetDocumentationCommentId(); diff --git a/src/Compilers/CSharp/Portable/Symbols/PublicModel/TypeParameterSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/PublicModel/TypeParameterSymbol.cs index 6dd5f488dbbc2..a12d1cd45e2a1 100644 --- a/src/Compilers/CSharp/Portable/Symbols/PublicModel/TypeParameterSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/PublicModel/TypeParameterSymbol.cs @@ -106,6 +106,11 @@ protected override TResult Accept(SymbolVisitor visitor) return visitor.VisitTypeParameter(this); } + protected override TResult Accept(SymbolVisitor visitor, TArgument argument) + { + return visitor.VisitTypeParameter(this, argument); + } + #endregion } } diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/DelegateTypeTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/DelegateTypeTests.cs index acd5748d3895c..7fab8749b41a9 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/DelegateTypeTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/DelegateTypeTests.cs @@ -10466,6 +10466,7 @@ internal FunctionTypeSymbol_PublicModel(FunctionTypeSymbol underlying) : protected override void Accept(SymbolVisitor visitor) => throw new NotImplementedException(); protected override TResult Accept(SymbolVisitor visitor) => throw new NotImplementedException(); + protected override TResult Accept(SymbolVisitor visitor, TArgument argument) => throw new NotImplementedException(); protected override ITypeSymbol WithNullableAnnotation(CodeAnalysis.NullableAnnotation nullableAnnotation) => this; } diff --git a/src/Compilers/CSharp/Test/Symbol/Compilation/SymbolVisitorTests.cs b/src/Compilers/CSharp/Test/Symbol/Compilation/SymbolVisitorTests.cs new file mode 100644 index 0000000000000..a2cf05251ec59 --- /dev/null +++ b/src/Compilers/CSharp/Test/Symbol/Compilation/SymbolVisitorTests.cs @@ -0,0 +1,813 @@ +// 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. + +#nullable disable + +using System; +using System.Collections.Generic; +using System.Text; +using Microsoft.CodeAnalysis.CSharp.Symbols.PublicModel; +using Microsoft.CodeAnalysis.CSharp.Test.Utilities; +using Microsoft.CodeAnalysis.Test.Utilities; +using Xunit; + +namespace Microsoft.CodeAnalysis.CSharp +{ + public class SymbolVisitorTests : CSharpTestBase + { + private class LoggingSymbolVisitor : SymbolVisitor + { + private readonly StringBuilder _output = new(); + private int _indent; + + public override string ToString() => _output.ToString(); + + void VisitChildren(params T[] children) + where T : ISymbol + => VisitChildren((IEnumerable)children); + + void VisitChildren(IEnumerable children) + where T : ISymbol + { + foreach (var item in children) + { + item.Accept(this); + } + } + + public override void DefaultVisit(ISymbol symbol) + { + _output.AppendLine(new string(' ', 2 * _indent) + symbol.GetType().Name + " " + symbol.Name); + } + + public override void VisitAlias(IAliasSymbol symbol) + { + _output.Append(symbol.GetType().Name + " of "); + symbol.Target.Accept(this); + } + + public override void VisitArrayType(IArrayTypeSymbol symbol) + { + _output.Append(symbol.GetType().Name + " of "); + symbol.ElementType.Accept(this); + } + + public override void VisitAssembly(IAssemblySymbol symbol) + { + _output.AppendLine(new string(' ', 2 * _indent) + symbol.GetType().Name + " " + symbol.Name); + _indent++; + VisitChildren(symbol.Modules); + _indent--; + } + + public override void VisitDiscard(IDiscardSymbol symbol) + { + base.VisitDiscard(symbol); + } + + public override void VisitDynamicType(IDynamicTypeSymbol symbol) + { + _output.Append(""); + } + + public override void VisitEvent(IEventSymbol symbol) + { + _output.Append(new string(' ', 2 * _indent) + symbol.GetType().Name + " " + symbol.Name + ": "); + symbol.Type.Accept(this); + _output.AppendLine(); + } + + public override void VisitField(IFieldSymbol symbol) + { + _output.Append(new string(' ', 2 * _indent) + symbol.GetType().Name + " " + symbol.Name + ": "); + symbol.Type.Accept(this); + _output.AppendLine(); + } + + public override void VisitLabel(ILabelSymbol symbol) + { + base.VisitLabel(symbol); + } + + public override void VisitLocal(ILocalSymbol symbol) + { + base.VisitLocal(symbol); + } + + public override void VisitMethod(IMethodSymbol symbol) + { + _output.AppendLine(new string(' ', 2 * _indent) + symbol.GetType().Name + " " + symbol.Name); + _indent++; + VisitChildren(symbol.TypeArguments); + VisitChildren(symbol.Parameters); + _indent--; + } + + public override void VisitModule(IModuleSymbol symbol) + { + _output.AppendLine(new string(' ', 2 * _indent) + symbol.GetType().Name + " " + symbol.Name); + _indent++; + VisitChildren(symbol.GlobalNamespace); + _indent--; + } + + public override void VisitNamedType(INamedTypeSymbol symbol) + { + if (_indent < 4) + { + _output.AppendLine(new string(' ', 2 * _indent) + symbol.GetType().Name + " " + symbol.Name); + _indent++; + VisitChildren(symbol.TypeArguments); + VisitChildren(symbol.GetMembers()); + _indent--; + } + else + { + _output.Append(symbol.GetType().Name + " " + symbol.Name); + if (symbol.TypeArguments.Length > 0) + { + _output.Append(" of "); + VisitChildren(symbol.TypeArguments); + } + } + } + + public override void VisitNamespace(INamespaceSymbol symbol) + { + _output.AppendLine(new string(' ', 2 * _indent) + symbol.GetType().Name + " " + symbol.Name); + _indent++; + VisitChildren(symbol.GetMembers()); + _indent--; + } + + public override void VisitParameter(IParameterSymbol symbol) + { + _output.Append(new string(' ', 2 * _indent) + symbol.GetType().Name + " " + symbol.Name + ": "); + symbol.Type.Accept(this); + _output.AppendLine(); + } + + public override void VisitPointerType(IPointerTypeSymbol symbol) + { + _output.Append(symbol.GetType().Name + " of "); + symbol.PointedAtType.Accept(this); + } + + public override void VisitFunctionPointerType(IFunctionPointerTypeSymbol symbol) + { + base.VisitFunctionPointerType(symbol); + } + + public override void VisitProperty(IPropertySymbol symbol) + { + _output.Append(new string(' ', 2 * _indent) + symbol.GetType().Name + " " + symbol.Name); + symbol.Type.Accept(this); + _output.AppendLine(); + } + + public override void VisitRangeVariable(IRangeVariableSymbol symbol) + { + base.VisitRangeVariable(symbol); + } + + public override void VisitTypeParameter(ITypeParameterSymbol symbol) + { + if (_indent < 5) + { + _output.AppendLine(new string(' ', 2 * _indent) + symbol.GetType().Name + " " + symbol.Name); + } + else + { + _output.Append(symbol.GetType().Name + " " + symbol.Name); + } + } + } + + private class LoggingSymbolVisitorWithReturnValue : SymbolVisitor + { + private readonly StringBuilder _output = new(); + private int _indent; + + public override string ToString() => _output.ToString(); + + void VisitChildren(params T[] children) + where T : ISymbol + => VisitChildren((IEnumerable)children); + + void VisitChildren(IEnumerable children) + where T : ISymbol + { + foreach (var item in children) + { + item.Accept(this); + } + } + + public override string DefaultVisit(ISymbol symbol) + { + _output.AppendLine(new string(' ', 2 * _indent) + symbol.GetType().Name + " " + symbol.Name); + return null; + } + + public override string VisitAlias(IAliasSymbol symbol) + { + _output.Append(symbol.GetType().Name + " of "); + symbol.Target.Accept(this); + return null; + } + + public override string VisitArrayType(IArrayTypeSymbol symbol) + { + _output.Append(symbol.GetType().Name + " of "); + symbol.ElementType.Accept(this); + return null; + } + + public override string VisitAssembly(IAssemblySymbol symbol) + { + _output.AppendLine(new string(' ', 2 * _indent) + symbol.GetType().Name + " " + symbol.Name); + _indent++; + VisitChildren(symbol.Modules); + _indent--; + return null; + } + + public override string VisitDiscard(IDiscardSymbol symbol) + { + base.VisitDiscard(symbol); + return null; + } + + public override string VisitDynamicType(IDynamicTypeSymbol symbol) + { + _output.Append(""); + return null; + } + + public override string VisitEvent(IEventSymbol symbol) + { + _output.Append(new string(' ', 2 * _indent) + symbol.GetType().Name + " " + symbol.Name + ": "); + symbol.Type.Accept(this); + _output.AppendLine(); + return null; + } + + public override string VisitField(IFieldSymbol symbol) + { + _output.Append(new string(' ', 2 * _indent) + symbol.GetType().Name + " " + symbol.Name + ": "); + symbol.Type.Accept(this); + _output.AppendLine(); + return null; + } + + public override string VisitLabel(ILabelSymbol symbol) + { + base.VisitLabel(symbol); + return null; + } + + public override string VisitLocal(ILocalSymbol symbol) + { + base.VisitLocal(symbol); + return null; + } + + public override string VisitMethod(IMethodSymbol symbol) + { + _output.AppendLine(new string(' ', 2 * _indent) + symbol.GetType().Name + " " + symbol.Name); + _indent++; + VisitChildren(symbol.TypeArguments); + VisitChildren(symbol.Parameters); + _indent--; + return null; + } + + public override string VisitModule(IModuleSymbol symbol) + { + _output.AppendLine(new string(' ', 2 * _indent) + symbol.GetType().Name + " " + symbol.Name); + _indent++; + VisitChildren(symbol.GlobalNamespace); + _indent--; + return null; + } + + public override string VisitNamedType(INamedTypeSymbol symbol) + { + if (_indent < 4) + { + _output.AppendLine(new string(' ', 2 * _indent) + symbol.GetType().Name + " " + symbol.Name); + _indent++; + VisitChildren(symbol.TypeArguments); + VisitChildren(symbol.GetMembers()); + _indent--; + } + else + { + _output.Append(symbol.GetType().Name + " " + symbol.Name); + if (symbol.TypeArguments.Length > 0) + { + _output.Append(" of "); + VisitChildren(symbol.TypeArguments); + } + } + return null; + } + + public override string VisitNamespace(INamespaceSymbol symbol) + { + _output.AppendLine(new string(' ', 2 * _indent) + symbol.GetType().Name + " " + symbol.Name); + _indent++; + VisitChildren(symbol.GetMembers()); + _indent--; + return null; + } + + public override string VisitParameter(IParameterSymbol symbol) + { + _output.Append(new string(' ', 2 * _indent) + symbol.GetType().Name + " " + symbol.Name + ": "); + symbol.Type.Accept(this); + _output.AppendLine(); + return null; + } + + public override string VisitPointerType(IPointerTypeSymbol symbol) + { + _output.Append(symbol.GetType().Name + " of "); + symbol.PointedAtType.Accept(this); + return null; + } + + public override string VisitFunctionPointerType(IFunctionPointerTypeSymbol symbol) + { + base.VisitFunctionPointerType(symbol); + return null; + } + + public override string VisitProperty(IPropertySymbol symbol) + { + _output.Append(new string(' ', 2 * _indent) + symbol.GetType().Name + " " + symbol.Name); + symbol.Type.Accept(this); + _output.AppendLine(); + return null; + } + + public override string VisitRangeVariable(IRangeVariableSymbol symbol) + { + base.VisitRangeVariable(symbol); + return null; + } + + public override string VisitTypeParameter(ITypeParameterSymbol symbol) + { + if (_indent < 5) + { + _output.AppendLine(new string(' ', 2 * _indent) + symbol.GetType().Name + " " + symbol.Name); + } + else + { + _output.Append(symbol.GetType().Name + " " + symbol.Name); + } + return null; + } + } + + private class LoggingSymbolVisitorWithReturnValueAndContext : SymbolVisitor + { + private int _indent; + + protected override int DefaultResult => -1; + + void VisitChildren(IEnumerable children, StringBuilder argument) + where T : ISymbol + { + foreach (var item in children) + { + item.Accept(this, argument); + } + } + + public override int VisitAssembly(IAssemblySymbol symbol, StringBuilder argument) + { + argument.AppendLine(new string(' ', 2 * _indent) + symbol.GetType().Name + " " + symbol.Name); + _indent++; + VisitChildren(symbol.Modules, argument); + _indent--; + return _indent; + } + + public override int VisitModule(IModuleSymbol symbol, StringBuilder argument) + { + argument.AppendLine(new string(' ', 2 * _indent) + symbol.GetType().Name + " " + symbol.Name); + _indent++; + VisitChildren(new[] { symbol.GlobalNamespace }, argument); + _indent--; + return _indent; + } + + public override int VisitNamespace(INamespaceSymbol symbol, StringBuilder argument) + { + argument.AppendLine(new string(' ', 2 * _indent) + symbol.GetType().Name + " " + symbol.Name); + _indent++; + VisitChildren(symbol.GetMembers(), argument); + _indent--; + return _indent; + } + + public override int VisitNamedType(INamedTypeSymbol symbol, StringBuilder argument) + { + if (_indent < 4) + { + argument.AppendLine(new string(' ', 2 * _indent) + symbol.GetType().Name + " " + symbol.Name); + _indent++; + VisitChildren(symbol.TypeArguments, argument); + VisitChildren(symbol.GetMembers(), argument); + _indent--; + } + else + { + argument.Append(symbol.GetType().Name + " " + symbol.Name); + if (symbol.TypeArguments.Length > 0) + { + argument.Append(" of "); + VisitChildren(symbol.TypeArguments, argument); + } + } + return _indent; + } + + public override int VisitEvent(IEventSymbol symbol, StringBuilder argument) + { + argument.Append(new string(' ', 2 * _indent) + symbol.GetType().Name + " " + symbol.Name + ": "); + symbol.Type.Accept(this, argument); + argument.AppendLine(); + return _indent; + } + + public override int VisitField(IFieldSymbol symbol, StringBuilder argument) + { + argument.Append(new string(' ', 2 * _indent) + symbol.GetType().Name + " " + symbol.Name + ": "); + symbol.Type.Accept(this, argument); + argument.AppendLine(); + return _indent; + } + + public override int VisitMethod(IMethodSymbol symbol, StringBuilder argument) + { + argument.AppendLine(new string(' ', 2 * _indent) + symbol.GetType().Name + " " + symbol.Name); + _indent++; + VisitChildren(symbol.TypeArguments, argument); + VisitChildren(symbol.Parameters, argument); + _indent--; + return _indent; + } + + public override int VisitParameter(IParameterSymbol symbol, StringBuilder argument) + { + argument.Append(new string(' ', 2 * _indent) + symbol.GetType().Name + " " + symbol.Name + ": "); + symbol.Type.Accept(this, argument); + argument.AppendLine(); + return _indent; + } + + public override int VisitDynamicType(IDynamicTypeSymbol symbol, StringBuilder argument) + { + argument.Append(""); + return _indent; + } + + public override int VisitArrayType(IArrayTypeSymbol symbol, StringBuilder argument) + { + argument.Append(symbol.GetType().Name + " of "); + symbol.ElementType.Accept(this, argument); + return _indent; + } + + public override int VisitPointerType(IPointerTypeSymbol symbol, StringBuilder argument) + { + argument.Append(symbol.GetType().Name + " of "); + symbol.PointedAtType.Accept(this, argument); + return _indent; + } + + public override int VisitFunctionPointerType(IFunctionPointerTypeSymbol symbol, StringBuilder argument) + { + return base.VisitFunctionPointerType(symbol, argument); + } + + public override int VisitProperty(IPropertySymbol symbol, StringBuilder argument) + { + argument.Append(new string(' ', 2 * _indent) + symbol.GetType().Name + " " + symbol.Name); + symbol.Type.Accept(this, argument); + argument.AppendLine(); + return _indent; + } + + public override int VisitRangeVariable(IRangeVariableSymbol symbol, StringBuilder argument) + { + return base.VisitRangeVariable(symbol, argument); + } + + public override int VisitTypeParameter(ITypeParameterSymbol symbol, StringBuilder argument) + { + if (_indent < 5) + { + argument.AppendLine(new string(' ', 2 * _indent) + symbol.GetType().Name + " " + symbol.Name); + } + else + { + argument.Append(symbol.GetType().Name + " " + symbol.Name); + } + return _indent; + } + } + + [Fact] + public void NamedType_LoggingSymbolVisitor() + { + var c = CreateCompilation( + "using System;" + + "class C { }" + + "struct S { int i; }" + + "class Generic {}" + + "enum ABC { A, B, C }" + + "delegate TReturn Function(T arg);", + assemblyName: "SymbolVisitorTests"); + IAssemblySymbol asm = new SourceAssemblySymbol(c.SourceAssembly); + var visitor = new LoggingSymbolVisitor(); + asm.Accept(visitor); + + string expectedOutput = @"SourceAssemblySymbol SymbolVisitorTests + ModuleSymbol SymbolVisitorTests.dll + NamespaceSymbol + NonErrorNamedTypeSymbol C + MethodSymbol .ctor + NonErrorNamedTypeSymbol S + FieldSymbol i: NonErrorNamedTypeSymbol Int32 + MethodSymbol .ctor + NonErrorNamedTypeSymbol Generic + TypeParameterSymbol T + MethodSymbol .ctor + NonErrorNamedTypeSymbol ABC + FieldSymbol A: NonErrorNamedTypeSymbol ABC + FieldSymbol B: NonErrorNamedTypeSymbol ABC + FieldSymbol C: NonErrorNamedTypeSymbol ABC + MethodSymbol .ctor + NonErrorNamedTypeSymbol Function + TypeParameterSymbol T + TypeParameterSymbol TReturn + MethodSymbol .ctor + ParameterSymbol object: NonErrorNamedTypeSymbol Object + ParameterSymbol method: NonErrorNamedTypeSymbol IntPtr + MethodSymbol Invoke + ParameterSymbol arg: TypeParameterSymbol T + MethodSymbol BeginInvoke + ParameterSymbol arg: TypeParameterSymbol T + ParameterSymbol callback: NonErrorNamedTypeSymbol AsyncCallback + ParameterSymbol object: NonErrorNamedTypeSymbol Object + MethodSymbol EndInvoke + ParameterSymbol result: NonErrorNamedTypeSymbol IAsyncResult +"; + + string resultOutput = visitor.ToString(); + Assert.Equal(expectedOutput, resultOutput); + } + + [Fact] + public void NamedType_LoggingSymbolVisitorWithReturnValue() + { + var c = CreateCompilation( + "using System;" + + "class C { }" + + "struct S { int i; }" + + "class Generic {}" + + "enum ABC { A, B, C }" + + "delegate TReturn Function(T arg);", + assemblyName: "SymbolVisitorTests"); + IAssemblySymbol asm = new SourceAssemblySymbol(c.SourceAssembly); + var visitor = new LoggingSymbolVisitorWithReturnValue(); + asm.Accept(visitor); + + string expectedOutput = @"SourceAssemblySymbol SymbolVisitorTests + ModuleSymbol SymbolVisitorTests.dll + NamespaceSymbol + NonErrorNamedTypeSymbol C + MethodSymbol .ctor + NonErrorNamedTypeSymbol S + FieldSymbol i: NonErrorNamedTypeSymbol Int32 + MethodSymbol .ctor + NonErrorNamedTypeSymbol Generic + TypeParameterSymbol T + MethodSymbol .ctor + NonErrorNamedTypeSymbol ABC + FieldSymbol A: NonErrorNamedTypeSymbol ABC + FieldSymbol B: NonErrorNamedTypeSymbol ABC + FieldSymbol C: NonErrorNamedTypeSymbol ABC + MethodSymbol .ctor + NonErrorNamedTypeSymbol Function + TypeParameterSymbol T + TypeParameterSymbol TReturn + MethodSymbol .ctor + ParameterSymbol object: NonErrorNamedTypeSymbol Object + ParameterSymbol method: NonErrorNamedTypeSymbol IntPtr + MethodSymbol Invoke + ParameterSymbol arg: TypeParameterSymbol T + MethodSymbol BeginInvoke + ParameterSymbol arg: TypeParameterSymbol T + ParameterSymbol callback: NonErrorNamedTypeSymbol AsyncCallback + ParameterSymbol object: NonErrorNamedTypeSymbol Object + MethodSymbol EndInvoke + ParameterSymbol result: NonErrorNamedTypeSymbol IAsyncResult +"; + + string resultOutput = visitor.ToString(); + Assert.Equal(expectedOutput, resultOutput); + } + + [Fact] + public void NamedType_LoggingSymbolVisitorWithReturnValueAndContext() + { + var c = CreateCompilation( + "using System;" + + "class C { }" + + "struct S { int i; }" + + "class Generic {}" + + "enum ABC { A, B, C }" + + "delegate TReturn Function(T arg);", + assemblyName: "SymbolVisitorTests"); + IAssemblySymbol asm = new SourceAssemblySymbol(c.SourceAssembly); + var visitor = new LoggingSymbolVisitorWithReturnValueAndContext(); + var sb = new StringBuilder(); + asm.Accept(visitor, sb); + + string expectedOutput = @"SourceAssemblySymbol SymbolVisitorTests + ModuleSymbol SymbolVisitorTests.dll + NamespaceSymbol + NonErrorNamedTypeSymbol C + MethodSymbol .ctor + NonErrorNamedTypeSymbol S + FieldSymbol i: NonErrorNamedTypeSymbol Int32 + MethodSymbol .ctor + NonErrorNamedTypeSymbol Generic + TypeParameterSymbol T + MethodSymbol .ctor + NonErrorNamedTypeSymbol ABC + FieldSymbol A: NonErrorNamedTypeSymbol ABC + FieldSymbol B: NonErrorNamedTypeSymbol ABC + FieldSymbol C: NonErrorNamedTypeSymbol ABC + MethodSymbol .ctor + NonErrorNamedTypeSymbol Function + TypeParameterSymbol T + TypeParameterSymbol TReturn + MethodSymbol .ctor + ParameterSymbol object: NonErrorNamedTypeSymbol Object + ParameterSymbol method: NonErrorNamedTypeSymbol IntPtr + MethodSymbol Invoke + ParameterSymbol arg: TypeParameterSymbol T + MethodSymbol BeginInvoke + ParameterSymbol arg: TypeParameterSymbol T + ParameterSymbol callback: NonErrorNamedTypeSymbol AsyncCallback + ParameterSymbol object: NonErrorNamedTypeSymbol Object + MethodSymbol EndInvoke + ParameterSymbol result: NonErrorNamedTypeSymbol IAsyncResult +"; + + string resultOutput = sb.ToString(); + Assert.Equal(expectedOutput, resultOutput); + } + + [Fact] + public void TypeMembers_LoggingSymbolVisitor() + { + var c = CreateCompilation( + "using System;" + + "using System.Collections.Generic;" + + "unsafe class C { " + + "public C() {} " + + "int* field; " + + "string[] field2; " + + "List generics; " + + "dynamic d; " + + "public int Value { get; set; } " + + "public event EventHandler Event; " + + "}", + assemblyName: "SymbolVisitorTests"); + IAssemblySymbol asm = new SourceAssemblySymbol(c.SourceAssembly); + var visitor = new LoggingSymbolVisitor(); + asm.Accept(visitor); + + string expectedOutput = @"SourceAssemblySymbol SymbolVisitorTests + ModuleSymbol SymbolVisitorTests.dll + NamespaceSymbol + NonErrorNamedTypeSymbol C + MethodSymbol .ctor + FieldSymbol field: PointerTypeSymbol of NonErrorNamedTypeSymbol Int32 + FieldSymbol field2: ArrayTypeSymbol of NonErrorNamedTypeSymbol String + FieldSymbol generics: NonErrorNamedTypeSymbol List of NonErrorNamedTypeSymbol String + FieldSymbol d: + FieldSymbol k__BackingField: NonErrorNamedTypeSymbol Int32 + PropertySymbol ValueNonErrorNamedTypeSymbol Int32 + MethodSymbol get_Value + MethodSymbol set_Value + ParameterSymbol value: NonErrorNamedTypeSymbol Int32 + MethodSymbol add_Event + ParameterSymbol value: NonErrorNamedTypeSymbol EventHandler + MethodSymbol remove_Event + ParameterSymbol value: NonErrorNamedTypeSymbol EventHandler + EventSymbol Event: NonErrorNamedTypeSymbol EventHandler +"; + + string resultOutput = visitor.ToString(); + Assert.Equal(expectedOutput, resultOutput); + } + [Fact] + public void TypeMembers_LoggingSymbolVisitorWithReturnValue() + { + var c = CreateCompilation( + "using System;" + + "using System.Collections.Generic;" + + "unsafe class C { " + + "public C() {} " + + "int* field; " + + "string[] field2; " + + "List generics; " + + "dynamic d; " + + "public int Value { get; set; } " + + "public event EventHandler Event; " + + "}", + assemblyName: "SymbolVisitorTests"); + IAssemblySymbol asm = new SourceAssemblySymbol(c.SourceAssembly); + var visitor = new LoggingSymbolVisitorWithReturnValue(); + asm.Accept(visitor); + + string expectedOutput = @"SourceAssemblySymbol SymbolVisitorTests + ModuleSymbol SymbolVisitorTests.dll + NamespaceSymbol + NonErrorNamedTypeSymbol C + MethodSymbol .ctor + FieldSymbol field: PointerTypeSymbol of NonErrorNamedTypeSymbol Int32 + FieldSymbol field2: ArrayTypeSymbol of NonErrorNamedTypeSymbol String + FieldSymbol generics: NonErrorNamedTypeSymbol List of NonErrorNamedTypeSymbol String + FieldSymbol d: + FieldSymbol k__BackingField: NonErrorNamedTypeSymbol Int32 + PropertySymbol ValueNonErrorNamedTypeSymbol Int32 + MethodSymbol get_Value + MethodSymbol set_Value + ParameterSymbol value: NonErrorNamedTypeSymbol Int32 + MethodSymbol add_Event + ParameterSymbol value: NonErrorNamedTypeSymbol EventHandler + MethodSymbol remove_Event + ParameterSymbol value: NonErrorNamedTypeSymbol EventHandler + EventSymbol Event: NonErrorNamedTypeSymbol EventHandler +"; + + string resultOutput = visitor.ToString(); + Assert.Equal(expectedOutput, resultOutput); + } + [Fact] + public void TypeMembers_LoggingSymbolVisitorWithReturnValueAndContext() + { + var c = CreateCompilation( + "using System;" + + "using System.Collections.Generic;" + + "unsafe class C { " + + "public C() {} " + + "int* field; " + + "string[] field2; " + + "List generics; " + + "dynamic d; " + + "public int Value { get; set; } " + + "public event EventHandler Event; " + + "}", + assemblyName: "SymbolVisitorTests"); + IAssemblySymbol asm = new SourceAssemblySymbol(c.SourceAssembly); + var visitor = new LoggingSymbolVisitorWithReturnValueAndContext(); + var sb = new StringBuilder(); + asm.Accept(visitor, sb); + + string expectedOutput = @"SourceAssemblySymbol SymbolVisitorTests + ModuleSymbol SymbolVisitorTests.dll + NamespaceSymbol + NonErrorNamedTypeSymbol C + MethodSymbol .ctor + FieldSymbol field: PointerTypeSymbol of NonErrorNamedTypeSymbol Int32 + FieldSymbol field2: ArrayTypeSymbol of NonErrorNamedTypeSymbol String + FieldSymbol generics: NonErrorNamedTypeSymbol List of NonErrorNamedTypeSymbol String + FieldSymbol d: + FieldSymbol k__BackingField: NonErrorNamedTypeSymbol Int32 + PropertySymbol ValueNonErrorNamedTypeSymbol Int32 + MethodSymbol get_Value + MethodSymbol set_Value + ParameterSymbol value: NonErrorNamedTypeSymbol Int32 + MethodSymbol add_Event + ParameterSymbol value: NonErrorNamedTypeSymbol EventHandler + MethodSymbol remove_Event + ParameterSymbol value: NonErrorNamedTypeSymbol EventHandler + EventSymbol Event: NonErrorNamedTypeSymbol EventHandler +"; + + string resultOutput = sb.ToString(); + Assert.Equal(expectedOutput, resultOutput); + } + } +} diff --git a/src/Compilers/Core/Portable/PublicAPI.Unshipped.txt b/src/Compilers/Core/Portable/PublicAPI.Unshipped.txt index 385fe1fef7d17..544b8e60a9ea8 100644 --- a/src/Compilers/Core/Portable/PublicAPI.Unshipped.txt +++ b/src/Compilers/Core/Portable/PublicAPI.Unshipped.txt @@ -1,4 +1,5 @@ *REMOVED*override abstract Microsoft.CodeAnalysis.Diagnostic.Equals(object? obj) -> bool +abstract Microsoft.CodeAnalysis.SymbolVisitor.DefaultResult.get -> TResult Microsoft.CodeAnalysis.Compilation.GetTypesByMetadataName(string! fullyQualifiedMetadataName) -> System.Collections.Immutable.ImmutableArray Microsoft.CodeAnalysis.IOperation.ChildOperations.get -> Microsoft.CodeAnalysis.IOperation.OperationList Microsoft.CodeAnalysis.IOperation.OperationList @@ -25,10 +26,12 @@ Microsoft.CodeAnalysis.IOperation.OperationList.Reversed.Reversed() -> void Microsoft.CodeAnalysis.IOperation.OperationList.Reversed.Count.get -> int Microsoft.CodeAnalysis.IOperation.OperationList.Reversed.GetEnumerator() -> Microsoft.CodeAnalysis.IOperation.OperationList.Reversed.Enumerator Microsoft.CodeAnalysis.IOperation.OperationList.Reversed.ToImmutableArray() -> System.Collections.Immutable.ImmutableArray +Microsoft.CodeAnalysis.ISymbol.Accept(Microsoft.CodeAnalysis.SymbolVisitor! visitor, TArgument argument) -> TResult +Microsoft.CodeAnalysis.SymbolVisitor +Microsoft.CodeAnalysis.SymbolVisitor.SymbolVisitor() -> void override sealed Microsoft.CodeAnalysis.Diagnostic.Equals(object? obj) -> bool *REMOVED*static Microsoft.CodeAnalysis.SyntaxNodeExtensions.ReplaceSyntax(this TRoot! root, System.Collections.Generic.IEnumerable! nodes, System.Func! computeReplacementNode, System.Collections.Generic.IEnumerable! tokens, System.Func! computeReplacementToken, System.Collections.Generic.IEnumerable! trivia, System.Func! computeReplacementTrivia) -> TRoot! static Microsoft.CodeAnalysis.SyntaxNodeExtensions.ReplaceSyntax(this TRoot! root, System.Collections.Generic.IEnumerable? nodes, System.Func? computeReplacementNode, System.Collections.Generic.IEnumerable? tokens, System.Func? computeReplacementToken, System.Collections.Generic.IEnumerable? trivia, System.Func? computeReplacementTrivia) -> TRoot! - const Microsoft.CodeAnalysis.WellKnownMemberNames.CheckedDecrementOperatorName = "op_CheckedDecrement" -> string! const Microsoft.CodeAnalysis.WellKnownMemberNames.CheckedIncrementOperatorName = "op_CheckedIncrement" -> string! const Microsoft.CodeAnalysis.WellKnownMemberNames.CheckedUnaryNegationOperatorName = "op_CheckedUnaryNegation" -> string! @@ -41,4 +44,25 @@ Microsoft.CodeAnalysis.OperationKind.UTF8String = 124 -> Microsoft.CodeAnalysis. Microsoft.CodeAnalysis.Operations.IUTF8StringOperation Microsoft.CodeAnalysis.Operations.IUTF8StringOperation.Value.get -> string! virtual Microsoft.CodeAnalysis.Operations.OperationVisitor.VisitUTF8String(Microsoft.CodeAnalysis.Operations.IUTF8StringOperation! operation) -> void -virtual Microsoft.CodeAnalysis.Operations.OperationVisitor.VisitUTF8String(Microsoft.CodeAnalysis.Operations.IUTF8StringOperation! operation, TArgument argument) -> TResult? \ No newline at end of file +virtual Microsoft.CodeAnalysis.Operations.OperationVisitor.VisitUTF8String(Microsoft.CodeAnalysis.Operations.IUTF8StringOperation! operation, TArgument argument) -> TResult? +virtual Microsoft.CodeAnalysis.SymbolVisitor.DefaultVisit(Microsoft.CodeAnalysis.ISymbol! symbol, TArgument argument) -> TResult +virtual Microsoft.CodeAnalysis.SymbolVisitor.Visit(Microsoft.CodeAnalysis.ISymbol? symbol, TArgument argument) -> TResult +virtual Microsoft.CodeAnalysis.SymbolVisitor.VisitAlias(Microsoft.CodeAnalysis.IAliasSymbol! symbol, TArgument argument) -> TResult +virtual Microsoft.CodeAnalysis.SymbolVisitor.VisitArrayType(Microsoft.CodeAnalysis.IArrayTypeSymbol! symbol, TArgument argument) -> TResult +virtual Microsoft.CodeAnalysis.SymbolVisitor.VisitAssembly(Microsoft.CodeAnalysis.IAssemblySymbol! symbol, TArgument argument) -> TResult +virtual Microsoft.CodeAnalysis.SymbolVisitor.VisitDiscard(Microsoft.CodeAnalysis.IDiscardSymbol! symbol, TArgument argument) -> TResult +virtual Microsoft.CodeAnalysis.SymbolVisitor.VisitDynamicType(Microsoft.CodeAnalysis.IDynamicTypeSymbol! symbol, TArgument argument) -> TResult +virtual Microsoft.CodeAnalysis.SymbolVisitor.VisitEvent(Microsoft.CodeAnalysis.IEventSymbol! symbol, TArgument argument) -> TResult +virtual Microsoft.CodeAnalysis.SymbolVisitor.VisitField(Microsoft.CodeAnalysis.IFieldSymbol! symbol, TArgument argument) -> TResult +virtual Microsoft.CodeAnalysis.SymbolVisitor.VisitFunctionPointerType(Microsoft.CodeAnalysis.IFunctionPointerTypeSymbol! symbol, TArgument argument) -> TResult +virtual Microsoft.CodeAnalysis.SymbolVisitor.VisitLabel(Microsoft.CodeAnalysis.ILabelSymbol! symbol, TArgument argument) -> TResult +virtual Microsoft.CodeAnalysis.SymbolVisitor.VisitLocal(Microsoft.CodeAnalysis.ILocalSymbol! symbol, TArgument argument) -> TResult +virtual Microsoft.CodeAnalysis.SymbolVisitor.VisitMethod(Microsoft.CodeAnalysis.IMethodSymbol! symbol, TArgument argument) -> TResult +virtual Microsoft.CodeAnalysis.SymbolVisitor.VisitModule(Microsoft.CodeAnalysis.IModuleSymbol! symbol, TArgument argument) -> TResult +virtual Microsoft.CodeAnalysis.SymbolVisitor.VisitNamedType(Microsoft.CodeAnalysis.INamedTypeSymbol! symbol, TArgument argument) -> TResult +virtual Microsoft.CodeAnalysis.SymbolVisitor.VisitNamespace(Microsoft.CodeAnalysis.INamespaceSymbol! symbol, TArgument argument) -> TResult +virtual Microsoft.CodeAnalysis.SymbolVisitor.VisitParameter(Microsoft.CodeAnalysis.IParameterSymbol! symbol, TArgument argument) -> TResult +virtual Microsoft.CodeAnalysis.SymbolVisitor.VisitPointerType(Microsoft.CodeAnalysis.IPointerTypeSymbol! symbol, TArgument argument) -> TResult +virtual Microsoft.CodeAnalysis.SymbolVisitor.VisitProperty(Microsoft.CodeAnalysis.IPropertySymbol! symbol, TArgument argument) -> TResult +virtual Microsoft.CodeAnalysis.SymbolVisitor.VisitRangeVariable(Microsoft.CodeAnalysis.IRangeVariableSymbol! symbol, TArgument argument) -> TResult +virtual Microsoft.CodeAnalysis.SymbolVisitor.VisitTypeParameter(Microsoft.CodeAnalysis.ITypeParameterSymbol! symbol, TArgument argument) -> TResult \ No newline at end of file diff --git a/src/Compilers/Core/Portable/Symbols/ISymbol.cs b/src/Compilers/Core/Portable/Symbols/ISymbol.cs index 36d62ed2a494f..285f1ac0efc40 100644 --- a/src/Compilers/Core/Portable/Symbols/ISymbol.cs +++ b/src/Compilers/Core/Portable/Symbols/ISymbol.cs @@ -211,6 +211,7 @@ public interface ISymbol : IEquatable void Accept(SymbolVisitor visitor); TResult? Accept(SymbolVisitor visitor); + TResult Accept(SymbolVisitor visitor, TArgument argument); /// /// Returns the Documentation Comment ID for the symbol, or null if the symbol doesn't diff --git a/src/Compilers/Core/Portable/Symbols/SymbolVisitor`2.cs b/src/Compilers/Core/Portable/Symbols/SymbolVisitor`2.cs new file mode 100644 index 0000000000000..ea9d2eba5e8fd --- /dev/null +++ b/src/Compilers/Core/Portable/Symbols/SymbolVisitor`2.cs @@ -0,0 +1,121 @@ +// 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. + +namespace Microsoft.CodeAnalysis +{ + public abstract class SymbolVisitor + { + protected abstract TResult DefaultResult { get; } + + public virtual TResult Visit(ISymbol? symbol, TArgument argument) + { + if (symbol != null) + { + return symbol.Accept(this, argument); + } + + return DefaultResult; + } + + public virtual TResult DefaultVisit(ISymbol symbol, TArgument argument) + { + return DefaultResult; + } + + public virtual TResult VisitAlias(IAliasSymbol symbol, TArgument argument) + { + return DefaultVisit(symbol, argument); + } + + public virtual TResult VisitArrayType(IArrayTypeSymbol symbol, TArgument argument) + { + return DefaultVisit(symbol, argument); + } + + public virtual TResult VisitAssembly(IAssemblySymbol symbol, TArgument argument) + { + return DefaultVisit(symbol, argument); + } + + public virtual TResult VisitDiscard(IDiscardSymbol symbol, TArgument argument) + { + return DefaultVisit(symbol, argument); + } + + public virtual TResult VisitDynamicType(IDynamicTypeSymbol symbol, TArgument argument) + { + return DefaultVisit(symbol, argument); + } + + public virtual TResult VisitEvent(IEventSymbol symbol, TArgument argument) + { + return DefaultVisit(symbol, argument); + } + + public virtual TResult VisitField(IFieldSymbol symbol, TArgument argument) + { + return DefaultVisit(symbol, argument); + } + + public virtual TResult VisitLabel(ILabelSymbol symbol, TArgument argument) + { + return DefaultVisit(symbol, argument); + } + + public virtual TResult VisitLocal(ILocalSymbol symbol, TArgument argument) + { + return DefaultVisit(symbol, argument); + } + + public virtual TResult VisitMethod(IMethodSymbol symbol, TArgument argument) + { + return DefaultVisit(symbol, argument); + } + + public virtual TResult VisitModule(IModuleSymbol symbol, TArgument argument) + { + return DefaultVisit(symbol, argument); + } + + public virtual TResult VisitNamedType(INamedTypeSymbol symbol, TArgument argument) + { + return DefaultVisit(symbol, argument); + } + + public virtual TResult VisitNamespace(INamespaceSymbol symbol, TArgument argument) + { + return DefaultVisit(symbol, argument); + } + + public virtual TResult VisitParameter(IParameterSymbol symbol, TArgument argument) + { + return DefaultVisit(symbol, argument); + } + + public virtual TResult VisitPointerType(IPointerTypeSymbol symbol, TArgument argument) + { + return DefaultVisit(symbol, argument); + } + + public virtual TResult VisitFunctionPointerType(IFunctionPointerTypeSymbol symbol, TArgument argument) + { + return DefaultVisit(symbol, argument); + } + + public virtual TResult VisitProperty(IPropertySymbol symbol, TArgument argument) + { + return DefaultVisit(symbol, argument); + } + + public virtual TResult VisitRangeVariable(IRangeVariableSymbol symbol, TArgument argument) + { + return DefaultVisit(symbol, argument); + } + + public virtual TResult VisitTypeParameter(ITypeParameterSymbol symbol, TArgument argument) + { + return DefaultVisit(symbol, argument); + } + } +} diff --git a/src/Compilers/VisualBasic/Portable/Symbols/AliasSymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/AliasSymbol.vb index 6e3e9907e2e6f..f1d8efd4b929b 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/AliasSymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/AliasSymbol.vb @@ -265,6 +265,10 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols Return visitor.VisitAlias(Me) End Function + Public Overrides Function Accept(Of TArgument, TResult)(visitor As SymbolVisitor(Of TArgument, TResult), argument As TArgument) As TResult + Return visitor.VisitAlias(Me, argument) + End Function + Public Overrides Sub Accept(visitor As VisualBasicSymbolVisitor) visitor.VisitAlias(Me) End Sub diff --git a/src/Compilers/VisualBasic/Portable/Symbols/ArrayTypeSymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/ArrayTypeSymbol.vb index 86ec08f92b493..fe5c553eaf68a 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/ArrayTypeSymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/ArrayTypeSymbol.vb @@ -445,6 +445,10 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols Return visitor.VisitArrayType(Me) End Function + Public Overrides Function Accept(Of TArgument, TResult)(visitor As SymbolVisitor(Of TArgument, TResult), argument As TArgument) As TResult + Return visitor.VisitArrayType(Me, argument) + End Function + Public Overrides Sub Accept(visitor As VisualBasicSymbolVisitor) visitor.VisitArrayType(Me) End Sub diff --git a/src/Compilers/VisualBasic/Portable/Symbols/AssemblySymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/AssemblySymbol.vb index eb9c6a5e7d30a..58e0d0b7096eb 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/AssemblySymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/AssemblySymbol.vb @@ -702,6 +702,10 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols Return visitor.VisitAssembly(Me) End Function + Public Overrides Function Accept(Of TArgument, TResult)(visitor As SymbolVisitor(Of TArgument, TResult), argument As TArgument) As TResult + Return visitor.VisitAssembly(Me, argument) + End Function + Public Overrides Sub Accept(visitor As VisualBasicSymbolVisitor) visitor.VisitAssembly(Me) End Sub diff --git a/src/Compilers/VisualBasic/Portable/Symbols/EventSymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/EventSymbol.vb index 8d85254824cfa..70241f7359c4b 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/EventSymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/EventSymbol.vb @@ -333,6 +333,10 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols Return visitor.VisitEvent(Me) End Function + Public Overrides Function Accept(Of TArgument, TResult)(visitor As SymbolVisitor(Of TArgument, TResult), argument As TArgument) As TResult + Return visitor.VisitEvent(Me, argument) + End Function + Public Overrides Sub Accept(visitor As VisualBasicSymbolVisitor) visitor.VisitEvent(Me) End Sub diff --git a/src/Compilers/VisualBasic/Portable/Symbols/FieldSymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/FieldSymbol.vb index b3d2bad9d4042..88924bd0e60d8 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/FieldSymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/FieldSymbol.vb @@ -490,6 +490,10 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols Return visitor.VisitField(Me) End Function + Public Overrides Function Accept(Of TArgument, TResult)(visitor As SymbolVisitor(Of TArgument, TResult), argument As TArgument) As TResult + Return visitor.VisitField(Me, argument) + End Function + Public Overrides Sub Accept(visitor As VisualBasicSymbolVisitor) visitor.VisitField(Me) End Sub diff --git a/src/Compilers/VisualBasic/Portable/Symbols/LabelSymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/LabelSymbol.vb index 4a4b10a1b9585..980fce1a52fe3 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/LabelSymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/LabelSymbol.vb @@ -125,6 +125,10 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols Return visitor.VisitLabel(Me) End Function + Public Overrides Function Accept(Of TArgument, TResult)(visitor As SymbolVisitor(Of TArgument, TResult), argument As TArgument) As TResult + Return visitor.VisitLabel(Me, argument) + End Function + Public Overrides Sub Accept(visitor As VisualBasicSymbolVisitor) visitor.VisitLabel(Me) End Sub diff --git a/src/Compilers/VisualBasic/Portable/Symbols/MethodSymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/MethodSymbol.vb index 29a305bf7c492..e0e2004668807 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/MethodSymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/MethodSymbol.vb @@ -1157,6 +1157,10 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols Return visitor.VisitMethod(Me) End Function + Public Overrides Function Accept(Of TArgument, TResult)(visitor As SymbolVisitor(Of TArgument, TResult), argument As TArgument) As TResult + Return visitor.VisitMethod(Me, argument) + End Function + Public Overrides Sub Accept(visitor As VisualBasicSymbolVisitor) visitor.VisitMethod(Me) End Sub diff --git a/src/Compilers/VisualBasic/Portable/Symbols/ModuleSymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/ModuleSymbol.vb index cedc50efb529c..f94edafc8d35d 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/ModuleSymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/ModuleSymbol.vb @@ -328,6 +328,10 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols Return visitor.VisitModule(Me) End Function + Public Overrides Function Accept(Of TArgument, TResult)(visitor As SymbolVisitor(Of TArgument, TResult), argument As TArgument) As TResult + Return visitor.VisitModule(Me, argument) + End Function + Public Overrides Sub Accept(visitor As VisualBasicSymbolVisitor) visitor.VisitModule(Me) End Sub diff --git a/src/Compilers/VisualBasic/Portable/Symbols/NamedTypeSymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/NamedTypeSymbol.vb index ba37369b1598b..2e4a4604268ca 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/NamedTypeSymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/NamedTypeSymbol.vb @@ -1257,6 +1257,10 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols Return visitor.VisitNamedType(Me) End Function + Public Overrides Function Accept(Of TArgument, TResult)(visitor As SymbolVisitor(Of TArgument, TResult), argument As TArgument) As TResult + Return visitor.VisitNamedType(Me, argument) + End Function + Public Overrides Sub Accept(visitor As VisualBasicSymbolVisitor) visitor.VisitNamedType(Me) End Sub diff --git a/src/Compilers/VisualBasic/Portable/Symbols/NamespaceSymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/NamespaceSymbol.vb index ab40ce94cd986..bc4de607b01f3 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/NamespaceSymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/NamespaceSymbol.vb @@ -564,6 +564,10 @@ Done: Return visitor.VisitNamespace(Me) End Function + Public Overrides Function Accept(Of TArgument, TResult)(visitor As SymbolVisitor(Of TArgument, TResult), argument As TArgument) As TResult + Return visitor.VisitNamespace(Me, argument) + End Function + Public Overrides Sub Accept(visitor As VisualBasicSymbolVisitor) visitor.VisitNamespace(Me) End Sub diff --git a/src/Compilers/VisualBasic/Portable/Symbols/ParameterSymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/ParameterSymbol.vb index 9a726b552ca70..632da5069692e 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/ParameterSymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/ParameterSymbol.vb @@ -367,6 +367,10 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols Return visitor.VisitParameter(Me) End Function + Public Overrides Function Accept(Of TArgument, TResult)(visitor As SymbolVisitor(Of TArgument, TResult), argument As TArgument) As TResult + Return visitor.VisitParameter(Me, argument) + End Function + Public Overrides Sub Accept(visitor As VisualBasicSymbolVisitor) visitor.VisitParameter(Me) End Sub diff --git a/src/Compilers/VisualBasic/Portable/Symbols/PreprocessingSymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/PreprocessingSymbol.vb index ab41e2116fd0d..20d7d30a8d5ec 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/PreprocessingSymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/PreprocessingSymbol.vb @@ -120,6 +120,10 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols Throw New NotSupportedException() End Function + Public Overrides Function Accept(Of TArgument, TResult)(visitor As SymbolVisitor(Of TArgument, TResult), argument As TArgument) As TResult + Throw New NotSupportedException() + End Function + Public Overloads Overrides Function Accept(Of TResult)(visitor As VisualBasicSymbolVisitor(Of TResult)) As TResult Throw New NotSupportedException() End Function diff --git a/src/Compilers/VisualBasic/Portable/Symbols/PropertySymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/PropertySymbol.vb index 0a111016409a4..857d89fc10f57 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/PropertySymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/PropertySymbol.vb @@ -627,6 +627,10 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols Return visitor.VisitProperty(Me) End Function + Public Overrides Function Accept(Of TArgument, TResult)(visitor As SymbolVisitor(Of TArgument, TResult), argument As TArgument) As TResult + Return visitor.VisitProperty(Me, argument) + End Function + Public Overrides Sub Accept(visitor As VisualBasicSymbolVisitor) visitor.VisitProperty(Me) End Sub diff --git a/src/Compilers/VisualBasic/Portable/Symbols/Source/LocalSymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/Source/LocalSymbol.vb index 5ec4de3e4b4cf..d6ad4fce28242 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/Source/LocalSymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/Source/LocalSymbol.vb @@ -423,6 +423,10 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols Return visitor.VisitLocal(Me) End Function + Public Overrides Function Accept(Of TArgument, TResult)(visitor As SymbolVisitor(Of TArgument, TResult), argument As TArgument) As TResult + Return visitor.VisitLocal(Me, argument) + End Function + Public Overrides Sub Accept(visitor As VisualBasicSymbolVisitor) visitor.VisitLocal(Me) End Sub diff --git a/src/Compilers/VisualBasic/Portable/Symbols/Source/RangeVariableSymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/Source/RangeVariableSymbol.vb index 5e9dce7248710..c71659e42ac46 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/Source/RangeVariableSymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/Source/RangeVariableSymbol.vb @@ -108,6 +108,10 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols Return visitor.VisitRangeVariable(DirectCast(Me, IRangeVariableSymbol)) End Function + Public Overrides Function Accept(Of TArgument, TResult)(visitor As SymbolVisitor(Of TArgument, TResult), argument As TArgument) As TResult + Return visitor.VisitRangeVariable(Me, argument) + End Function + Public Overrides Sub Accept(visitor As VisualBasicSymbolVisitor) visitor.VisitRangeVariable(Me) End Sub diff --git a/src/Compilers/VisualBasic/Portable/Symbols/Symbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/Symbol.vb index 0bc1d1721869b..22fec68b94238 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/Symbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/Symbol.vb @@ -1117,6 +1117,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic Public MustOverride Function Accept(Of TResult)(visitor As SymbolVisitor(Of TResult)) As TResult Implements ISymbol.Accept + Public MustOverride Function Accept(Of TArgument, TResult)(visitor As SymbolVisitor(Of TArgument, TResult), argument As TArgument) As TResult Implements ISymbol.Accept + Public MustOverride Sub Accept(visitor As VisualBasicSymbolVisitor) Public MustOverride Function Accept(Of TResult)(visitor As VisualBasicSymbolVisitor(Of TResult)) As TResult diff --git a/src/Compilers/VisualBasic/Portable/Symbols/TypeParameterSymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/TypeParameterSymbol.vb index 5e62b8ad9e7d9..7f76621542b37 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/TypeParameterSymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/TypeParameterSymbol.vb @@ -420,6 +420,10 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols Return visitor.VisitTypeParameter(Me) End Function + Public Overrides Function Accept(Of TArgument, TResult)(visitor As SymbolVisitor(Of TArgument, TResult), argument As TArgument) As TResult + Return visitor.VisitTypeParameter(Me, argument) + End Function + Public Overrides Sub Accept(visitor As VisualBasicSymbolVisitor) visitor.VisitTypeParameter(Me) End Sub diff --git a/src/Features/Core/Portable/MetadataAsSource/AbstractMetadataAsSourceService.AbstractWrappedSymbol.cs b/src/Features/Core/Portable/MetadataAsSource/AbstractMetadataAsSourceService.AbstractWrappedSymbol.cs index 52dcfdc96c594..4dcd097d70b23 100644 --- a/src/Features/Core/Portable/MetadataAsSource/AbstractMetadataAsSourceService.AbstractWrappedSymbol.cs +++ b/src/Features/Core/Portable/MetadataAsSource/AbstractMetadataAsSourceService.AbstractWrappedSymbol.cs @@ -80,6 +80,9 @@ public void Accept(SymbolVisitor visitor) public TResult Accept(SymbolVisitor visitor) => _symbol.Accept(visitor); + public TResult Accept(SymbolVisitor visitor, TArgument argument) + => _symbol.Accept(visitor, argument); + public ImmutableArray GetAttributes() => _symbol.GetAttributes(); diff --git a/src/Workspaces/Core/Portable/CodeGeneration/Symbols/CodeGenerationAbstractMethodSymbol.cs b/src/Workspaces/Core/Portable/CodeGeneration/Symbols/CodeGenerationAbstractMethodSymbol.cs index c040bccc0cdd0..989b2b17f87f3 100644 --- a/src/Workspaces/Core/Portable/CodeGeneration/Symbols/CodeGenerationAbstractMethodSymbol.cs +++ b/src/Workspaces/Core/Portable/CodeGeneration/Symbols/CodeGenerationAbstractMethodSymbol.cs @@ -66,6 +66,9 @@ public override void Accept(SymbolVisitor visitor) public override TResult Accept(SymbolVisitor visitor) => visitor.VisitMethod(this); + public override TResult Accept(SymbolVisitor visitor, TArgument argument) + => visitor.VisitMethod(this, argument); + public virtual MethodKind MethodKind => MethodKind.Ordinary; public override SymbolKind Kind => SymbolKind.Method; diff --git a/src/Workspaces/Core/Portable/CodeGeneration/Symbols/CodeGenerationAbstractNamedTypeSymbol.cs b/src/Workspaces/Core/Portable/CodeGeneration/Symbols/CodeGenerationAbstractNamedTypeSymbol.cs index afb4c096ccf9d..ba6e428ebc76f 100644 --- a/src/Workspaces/Core/Portable/CodeGeneration/Symbols/CodeGenerationAbstractNamedTypeSymbol.cs +++ b/src/Workspaces/Core/Portable/CodeGeneration/Symbols/CodeGenerationAbstractNamedTypeSymbol.cs @@ -47,6 +47,9 @@ public override void Accept(SymbolVisitor visitor) public override TResult Accept(SymbolVisitor visitor) => visitor.VisitNamedType(this); + public override TResult Accept(SymbolVisitor visitor, TArgument argument) + => visitor.VisitNamedType(this, argument); + public INamedTypeSymbol Construct(params ITypeSymbol[] typeArguments) { if (typeArguments.Length == 0) diff --git a/src/Workspaces/Core/Portable/CodeGeneration/Symbols/CodeGenerationArrayTypeSymbol.cs b/src/Workspaces/Core/Portable/CodeGeneration/Symbols/CodeGenerationArrayTypeSymbol.cs index 910642719db16..5b9c8126e0b60 100644 --- a/src/Workspaces/Core/Portable/CodeGeneration/Symbols/CodeGenerationArrayTypeSymbol.cs +++ b/src/Workspaces/Core/Portable/CodeGeneration/Symbols/CodeGenerationArrayTypeSymbol.cs @@ -58,6 +58,9 @@ public override void Accept(SymbolVisitor visitor) where TResult : default => visitor.VisitArrayType(this); + public override TResult Accept(SymbolVisitor visitor, TArgument argument) + => visitor.VisitArrayType(this, argument); + public ImmutableArray CustomModifiers { get diff --git a/src/Workspaces/Core/Portable/CodeGeneration/Symbols/CodeGenerationEventSymbol.cs b/src/Workspaces/Core/Portable/CodeGeneration/Symbols/CodeGenerationEventSymbol.cs index 7b7949f8b12d3..a811c32da9fbd 100644 --- a/src/Workspaces/Core/Portable/CodeGeneration/Symbols/CodeGenerationEventSymbol.cs +++ b/src/Workspaces/Core/Portable/CodeGeneration/Symbols/CodeGenerationEventSymbol.cs @@ -55,6 +55,9 @@ public override void Accept(SymbolVisitor visitor) where TResult : default => visitor.VisitEvent(this); + public override TResult Accept(SymbolVisitor visitor, TArgument argument) + => visitor.VisitEvent(this, argument); + public new IEventSymbol OriginalDefinition => this; public bool IsWindowsRuntimeEvent => false; diff --git a/src/Workspaces/Core/Portable/CodeGeneration/Symbols/CodeGenerationFieldSymbol.cs b/src/Workspaces/Core/Portable/CodeGeneration/Symbols/CodeGenerationFieldSymbol.cs index ceb695c493def..08db582288b0b 100644 --- a/src/Workspaces/Core/Portable/CodeGeneration/Symbols/CodeGenerationFieldSymbol.cs +++ b/src/Workspaces/Core/Portable/CodeGeneration/Symbols/CodeGenerationFieldSymbol.cs @@ -57,6 +57,9 @@ public override void Accept(SymbolVisitor visitor) public override TResult Accept(SymbolVisitor visitor) => visitor.VisitField(this); + public override TResult Accept(SymbolVisitor visitor, TArgument argument) + => visitor.VisitField(this, argument); + public bool IsConst { get diff --git a/src/Workspaces/Core/Portable/CodeGeneration/Symbols/CodeGenerationNamespaceSymbol.cs b/src/Workspaces/Core/Portable/CodeGeneration/Symbols/CodeGenerationNamespaceSymbol.cs index 3d087f9e5dfc0..3abdc3e60df66 100644 --- a/src/Workspaces/Core/Portable/CodeGeneration/Symbols/CodeGenerationNamespaceSymbol.cs +++ b/src/Workspaces/Core/Portable/CodeGeneration/Symbols/CodeGenerationNamespaceSymbol.cs @@ -36,6 +36,9 @@ public override void Accept(SymbolVisitor visitor) public override TResult Accept(SymbolVisitor visitor) => visitor.VisitNamespace(this); + public override TResult Accept(SymbolVisitor visitor, TArgument argument) + => visitor.VisitNamespace(this, argument); + public new IEnumerable GetMembers() => _members; diff --git a/src/Workspaces/Core/Portable/CodeGeneration/Symbols/CodeGenerationParameterSymbol.cs b/src/Workspaces/Core/Portable/CodeGeneration/Symbols/CodeGenerationParameterSymbol.cs index 5c24c75230aaa..36caad767784c 100644 --- a/src/Workspaces/Core/Portable/CodeGeneration/Symbols/CodeGenerationParameterSymbol.cs +++ b/src/Workspaces/Core/Portable/CodeGeneration/Symbols/CodeGenerationParameterSymbol.cs @@ -59,6 +59,9 @@ public override void Accept(SymbolVisitor visitor) public override TResult Accept(SymbolVisitor visitor) => visitor.VisitParameter(this); + public override TResult Accept(SymbolVisitor visitor, TArgument argument) + => visitor.VisitParameter(this, argument); + public bool IsThis => false; public ImmutableArray RefCustomModifiers => ImmutableArray.Create(); diff --git a/src/Workspaces/Core/Portable/CodeGeneration/Symbols/CodeGenerationPointerTypeSymbol.cs b/src/Workspaces/Core/Portable/CodeGeneration/Symbols/CodeGenerationPointerTypeSymbol.cs index 814d6e40db196..89ba5302798a5 100644 --- a/src/Workspaces/Core/Portable/CodeGeneration/Symbols/CodeGenerationPointerTypeSymbol.cs +++ b/src/Workspaces/Core/Portable/CodeGeneration/Symbols/CodeGenerationPointerTypeSymbol.cs @@ -34,6 +34,9 @@ public override void Accept(SymbolVisitor visitor) public override TResult Accept(SymbolVisitor visitor) => visitor.VisitPointerType(this); + public override TResult Accept(SymbolVisitor visitor, TArgument argument) + => visitor.VisitPointerType(this, argument); + public ImmutableArray CustomModifiers { get diff --git a/src/Workspaces/Core/Portable/CodeGeneration/Symbols/CodeGenerationPropertySymbol.cs b/src/Workspaces/Core/Portable/CodeGeneration/Symbols/CodeGenerationPropertySymbol.cs index 7909d1f0a6ca4..01fd6dc9c256c 100644 --- a/src/Workspaces/Core/Portable/CodeGeneration/Symbols/CodeGenerationPropertySymbol.cs +++ b/src/Workspaces/Core/Portable/CodeGeneration/Symbols/CodeGenerationPropertySymbol.cs @@ -69,6 +69,9 @@ public override void Accept(SymbolVisitor visitor) public override TResult Accept(SymbolVisitor visitor) => visitor.VisitProperty(this); + public override TResult Accept(SymbolVisitor visitor, TArgument argument) + => visitor.VisitProperty(this, argument); + public bool IsReadOnly => this.GetMethod != null && this.SetMethod == null; public bool IsWriteOnly => this.GetMethod == null && this.SetMethod != null; diff --git a/src/Workspaces/Core/Portable/CodeGeneration/Symbols/CodeGenerationSymbol.cs b/src/Workspaces/Core/Portable/CodeGeneration/Symbols/CodeGenerationSymbol.cs index d120665f77ef4..6c0ec56153e69 100644 --- a/src/Workspaces/Core/Portable/CodeGeneration/Symbols/CodeGenerationSymbol.cs +++ b/src/Workspaces/Core/Portable/CodeGeneration/Symbols/CodeGenerationSymbol.cs @@ -177,6 +177,8 @@ public ISymbol OriginalDefinition public abstract TResult Accept(SymbolVisitor visitor); + public abstract TResult Accept(SymbolVisitor visitor, TArgument argument); + public string GetDocumentationCommentId() => null; diff --git a/src/Workspaces/Core/Portable/CodeGeneration/Symbols/CodeGenerationTypeParameterSymbol.cs b/src/Workspaces/Core/Portable/CodeGeneration/Symbols/CodeGenerationTypeParameterSymbol.cs index 5e9909cc9b04e..852e315c0ddd2 100644 --- a/src/Workspaces/Core/Portable/CodeGeneration/Symbols/CodeGenerationTypeParameterSymbol.cs +++ b/src/Workspaces/Core/Portable/CodeGeneration/Symbols/CodeGenerationTypeParameterSymbol.cs @@ -64,6 +64,9 @@ public override void Accept(SymbolVisitor visitor) public override TResult Accept(SymbolVisitor visitor) => visitor.VisitTypeParameter(this); + public override TResult Accept(SymbolVisitor visitor, TArgument argument) + => visitor.VisitTypeParameter(this, argument); + public override TypeKind TypeKind => TypeKind.TypeParameter; public TypeParameterKind TypeParameterKind