diff --git a/Roslyn.sln b/Roslyn.sln
index b54926c007207..848adc0f76206 100644
--- a/Roslyn.sln
+++ b/Roslyn.sln
@@ -547,8 +547,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Replay", "src\Tools\Replay\
EndProject
Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "Microsoft.CommonLanguageServerProtocol.Framework.Shared", "src\Features\LanguageServer\Microsoft.CommonLanguageServerProtocol.Framework\Microsoft.CommonLanguageServerProtocol.Framework.Shared.shproj", "{64EADED3-4B5D-4431-BBE5-A4ABA1C38C00}"
EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CommonLanguageServerProtocol.Framework.Binary", "src\Features\LanguageServer\Microsoft.CommonLanguageServerProtocol.Framework.Binary\Microsoft.CommonLanguageServerProtocol.Framework.Binary.csproj", "{730CADBA-701F-4722-9B6F-1FCC0DF2C95D}"
-EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CodeAnalysis.CSharp.Emit3.UnitTests", "src\Compilers\CSharp\Test\Emit3\Microsoft.CodeAnalysis.CSharp.Emit3.UnitTests.csproj", "{4E273CBC-BB1D-4AC1-91DB-C62FC83E0350}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SemanticSearch", "SemanticSearch", "{52ABB0E4-C3A1-4897-B51B-18EDA83F5D20}"
@@ -1365,10 +1363,6 @@ Global
{DB96C25F-39A9-4A6A-92BC-D1E42717308F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{DB96C25F-39A9-4A6A-92BC-D1E42717308F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{DB96C25F-39A9-4A6A-92BC-D1E42717308F}.Release|Any CPU.Build.0 = Release|Any CPU
- {730CADBA-701F-4722-9B6F-1FCC0DF2C95D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {730CADBA-701F-4722-9B6F-1FCC0DF2C95D}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {730CADBA-701F-4722-9B6F-1FCC0DF2C95D}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {730CADBA-701F-4722-9B6F-1FCC0DF2C95D}.Release|Any CPU.Build.0 = Release|Any CPU
{4E273CBC-BB1D-4AC1-91DB-C62FC83E0350}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{4E273CBC-BB1D-4AC1-91DB-C62FC83E0350}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4E273CBC-BB1D-4AC1-91DB-C62FC83E0350}.Release|Any CPU.ActiveCfg = Release|Any CPU
@@ -1636,7 +1630,6 @@ Global
{6D819E80-BA2F-4317-8368-37F8F4434D3A} = {8977A560-45C2-4EC2-A849-97335B382C74}
{DB96C25F-39A9-4A6A-92BC-D1E42717308F} = {FD0FAF5F-1DED-485C-99FA-84B97F3A8EEC}
{64EADED3-4B5D-4431-BBE5-A4ABA1C38C00} = {D449D505-CC6A-4E0B-AF1B-976E2D0AE67A}
- {730CADBA-701F-4722-9B6F-1FCC0DF2C95D} = {D449D505-CC6A-4E0B-AF1B-976E2D0AE67A}
{4E273CBC-BB1D-4AC1-91DB-C62FC83E0350} = {32A48625-F0AD-419D-828B-A50BDABA38EA}
{52ABB0E4-C3A1-4897-B51B-18EDA83F5D20} = {FD0FAF5F-1DED-485C-99FA-84B97F3A8EEC}
{FCE88BBD-9BBD-4871-B9B0-DE176D73A6B0} = {52ABB0E4-C3A1-4897-B51B-18EDA83F5D20}
@@ -1686,7 +1679,6 @@ Global
src\Features\LanguageServer\Microsoft.CommonLanguageServerProtocol.Framework\Microsoft.CommonLanguageServerProtocol.Framework.Shared.projitems*{64eaded3-4b5d-4431-bbe5-a4aba1c38c00}*SharedItemsImports = 13
src\Features\LanguageServer\Microsoft.CommonLanguageServerProtocol.Framework\Microsoft.CommonLanguageServerProtocol.Framework.Shared.projitems*{686bf57e-a6ff-467b-aab3-44de916a9772}*SharedItemsImports = 5
src\Workspaces\SharedUtilitiesAndExtensions\Compiler\CSharp\CSharpCompilerExtensions.projitems*{699fea05-aea7-403d-827e-53cf4e826955}*SharedItemsImports = 13
- src\Features\LanguageServer\Microsoft.CommonLanguageServerProtocol.Framework\Microsoft.CommonLanguageServerProtocol.Framework.Shared.projitems*{730cadba-701f-4722-9b6f-1fcc0df2c95d}*SharedItemsImports = 5
src\ExpressionEvaluator\VisualBasic\Source\ResultProvider\BasicResultProvider.projitems*{76242a2d-2600-49dd-8c15-fea07ecb1843}*SharedItemsImports = 5
src\Analyzers\Core\Analyzers\Analyzers.projitems*{76e96966-4780-4040-8197-bde2879516f4}*SharedItemsImports = 13
src\Analyzers\VisualBasic\Tests\VisualBasicAnalyzers.UnitTests.projitems*{7b7f4153-ae93-4908-b8f0-430871589f83}*SharedItemsImports = 13
diff --git a/azure-pipelines-official.yml b/azure-pipelines-official.yml
index 1a86360a0fcb0..5f681633869f5 100644
--- a/azure-pipelines-official.yml
+++ b/azure-pipelines-official.yml
@@ -85,7 +85,7 @@ extends:
sdl:
sourceAnalysisPool:
name: NetCore1ESPool-Svc-Internal
- image: 1es-windows-2022-pt
+ image: 1es-windows-2022
os: windows
sbom:
enabled: false
diff --git a/docs/Language Feature Status.md b/docs/Language Feature Status.md
index 3ba66cf3fe790..6a36d6df37b25 100644
--- a/docs/Language Feature Status.md
+++ b/docs/Language Feature Status.md
@@ -10,6 +10,7 @@ efforts behind them.
| Feature | Branch | State | Developer | Reviewer | IDE Buddy | LDM Champ |
| ------- | ------ | ----- | --------- | -------- | --------- | --------- |
+| [Partial properties](https://github.com/dotnet/csharplang/issues/6420) | [partial-properties](https://github.com/dotnet/roslyn/tree/features/partial-properties) | [In Progress](https://github.com/dotnet/roslyn/issues/73090) | [RikkiGibson](https://github.com/RikkiGibson) | [jcouv](https://github.com/jcouv), [333fred](https://github.com/333fred) | TBD | [333fred](https://github.com/333fred), [RikkiGibson](https://github.com/RikkiGibson) |
| Ref/unsafe in iterators/async | [RefInAsync](https://github.com/dotnet/roslyn/tree/features/RefInAsync) | [In Progress](https://github.com/dotnet/roslyn/issues/72662) | [jjonescz](https://github.com/jjonescz) | [AlekseyTs](https://github.com/AlekseyTs), [cston](https://github.com/cston) | [ToddGrun](https://github.com/ToddGrun) | |
| [Ref Struct Interfaces](https://github.com/dotnet/csharplang/issues/7608) | [RefStructInterfaces](https://github.com/dotnet/roslyn/tree/features/RefStructInterfaces) | [In Progress](https://github.com/dotnet/roslyn/issues/72124) | [AlekseyTs](https://github.com/AlekseyTs) | [cston](https://github.com/cston), [jjonescz](https://github.com/jjonescz) | [ToddGrun](https://github.com/ToddGrun) | [agocke](https://github.com/agocke), [jaredpar](https://github.com/jaredpar) |
| [Semi-auto-properties](https://github.com/dotnet/csharplang/issues/140) | [semi-auto-props](https://github.com/dotnet/roslyn/tree/features/semi-auto-props) | [In Progress](https://github.com/dotnet/roslyn/issues/57012) | [Youssef1313](https://github.com/Youssef1313) | [333fred](https://github.com/333fred), [RikkiGibson](https://github.com/RikkiGibson) | | [CyrusNajmabadi](https://github.com/CyrusNajmabadi) |
diff --git a/docs/contributing/Bootstrap Builds.md b/docs/contributing/Bootstrap Builds.md
index 52e1a638cc877..128a4d59fe740 100644
--- a/docs/contributing/Bootstrap Builds.md
+++ b/docs/contributing/Bootstrap Builds.md
@@ -104,5 +104,5 @@ https://github.com/dotnet/roslyn/blob/d73d31cbccb9aa850f3582afb464b709fef88fd7/s
Next just run the bootstrap build locally, wait for the `Debug.Assert` to trigger which pops up a dialog. From there you can attach to the VBCSCompiler process and debug through the problem
```cmd
-> Build.cmd -bootstrap -bootstrapConfiguration Debug
+> Build.cmd -bootstrap
```
diff --git a/docs/features/incremental-generators.cookbook.md b/docs/features/incremental-generators.cookbook.md
index 9bbb0b9134c9d..3cf0870f6bf57 100644
--- a/docs/features/incremental-generators.cookbook.md
+++ b/docs/features/incremental-generators.cookbook.md
@@ -191,7 +191,7 @@ public class FileTransformGenerator : IIncrementalGenerator
public void Initialize(IncrementalGeneratorInitializationContext context)
{
var pipeline = context.AdditionalTextsProvider
- .Where(static (text, cancellationToken) => text.Path.EndsWith(".xml"))
+ .Where(static (text) => text.Path.EndsWith(".xml"))
.Select(static (text, cancellationToken) =>
{
var name = Path.GetFileName(text.Path);
diff --git a/eng/Directory.Packages.props b/eng/Directory.Packages.props
index 97ff84ec7abe2..d9970c400f1f0 100644
--- a/eng/Directory.Packages.props
+++ b/eng/Directory.Packages.props
@@ -103,14 +103,14 @@
-
+
-
+
diff --git a/src/Analyzers/CSharp/Analyzers/MisplacedUsingDirectives/MisplacedUsingDirectivesDiagnosticAnalyzer.cs b/src/Analyzers/CSharp/Analyzers/MisplacedUsingDirectives/MisplacedUsingDirectivesDiagnosticAnalyzer.cs
index 0295d3a9908cc..7072dff8597cf 100644
--- a/src/Analyzers/CSharp/Analyzers/MisplacedUsingDirectives/MisplacedUsingDirectivesDiagnosticAnalyzer.cs
+++ b/src/Analyzers/CSharp/Analyzers/MisplacedUsingDirectives/MisplacedUsingDirectivesDiagnosticAnalyzer.cs
@@ -3,15 +3,12 @@
// See the LICENSE file in the project root for more information.
using System.Collections.Generic;
-using System.Collections.Immutable;
using System.Linq;
using Microsoft.CodeAnalysis.AddImport;
using Microsoft.CodeAnalysis.CodeStyle;
using Microsoft.CodeAnalysis.CSharp.CodeStyle;
-using Microsoft.CodeAnalysis.CSharp.Extensions;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Diagnostics;
-using Microsoft.CodeAnalysis.Options;
namespace Microsoft.CodeAnalysis.CSharp.MisplacedUsingDirectives;
@@ -40,9 +37,11 @@ internal sealed class MisplacedUsingDirectivesDiagnosticAnalyzer : AbstractBuilt
s_localizableTitle, s_localizableInsideMessage);
public MisplacedUsingDirectivesDiagnosticAnalyzer()
- : base(ImmutableDictionary.Empty
- .Add(s_outsideDiagnosticDescriptor, CSharpCodeStyleOptions.PreferredUsingDirectivePlacement)
- .Add(s_insideDiagnosticDescriptor, CSharpCodeStyleOptions.PreferredUsingDirectivePlacement))
+ : base(
+ [
+ (s_outsideDiagnosticDescriptor, CSharpCodeStyleOptions.PreferredUsingDirectivePlacement),
+ (s_insideDiagnosticDescriptor, CSharpCodeStyleOptions.PreferredUsingDirectivePlacement)
+ ])
{
}
diff --git a/src/Analyzers/CSharp/Analyzers/UseCollectionExpression/AbstractCSharpUseCollectionExpressionDiagnosticAnalyzer.cs b/src/Analyzers/CSharp/Analyzers/UseCollectionExpression/AbstractCSharpUseCollectionExpressionDiagnosticAnalyzer.cs
index 7fe59d662f13d..b1daeecb8190a 100644
--- a/src/Analyzers/CSharp/Analyzers/UseCollectionExpression/AbstractCSharpUseCollectionExpressionDiagnosticAnalyzer.cs
+++ b/src/Analyzers/CSharp/Analyzers/UseCollectionExpression/AbstractCSharpUseCollectionExpressionDiagnosticAnalyzer.cs
@@ -7,7 +7,6 @@
using Microsoft.CodeAnalysis.CSharp.Extensions;
using Microsoft.CodeAnalysis.CSharp.Shared.Extensions;
using Microsoft.CodeAnalysis.Diagnostics;
-using Microsoft.CodeAnalysis.Options;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Microsoft.CodeAnalysis.UseCollectionInitializer;
@@ -22,18 +21,15 @@ internal abstract class AbstractCSharpUseCollectionExpressionDiagnosticAnalyzer
public static readonly ImmutableDictionary ChangesSemantics =
ImmutableDictionary.Empty.Add(UseCollectionInitializerHelpers.ChangesSemanticsName, "");
- protected new readonly DiagnosticDescriptor Descriptor;
protected readonly DiagnosticDescriptor UnnecessaryCodeDescriptor;
protected AbstractCSharpUseCollectionExpressionDiagnosticAnalyzer(string diagnosticId, EnforceOnBuild enforceOnBuild)
- : base(ImmutableDictionary.Empty
- // Ugly hack. We need to create a descriptor to pass to our base *and* assign to one of our fields.
- // The conditional pattern form lets us do that.
- .Add(CreateDescriptor(diagnosticId, enforceOnBuild, isUnnecessary: false) is var descriptor ? descriptor : null, CodeStyleOptions2.PreferCollectionExpression)
- .Add(CreateDescriptor(diagnosticId, enforceOnBuild, isUnnecessary: true) is var unnecessaryCodeDescriptor ? unnecessaryCodeDescriptor : null, CodeStyleOptions2.PreferCollectionExpression))
+ : base(
+ [
+ (CreateDescriptor(diagnosticId, enforceOnBuild, isUnnecessary: false), CodeStyleOptions2.PreferCollectionExpression)
+ ])
{
- Descriptor = descriptor;
- UnnecessaryCodeDescriptor = unnecessaryCodeDescriptor;
+ UnnecessaryCodeDescriptor = CreateDescriptor(diagnosticId, enforceOnBuild, isUnnecessary: true);
}
private static DiagnosticDescriptor CreateDescriptor(string diagnosticId, EnforceOnBuild enforceOnBuild, bool isUnnecessary)
diff --git a/src/Analyzers/CSharp/Analyzers/UseExpressionBody/UseExpressionBodyDiagnosticAnalyzer.cs b/src/Analyzers/CSharp/Analyzers/UseExpressionBody/UseExpressionBodyDiagnosticAnalyzer.cs
index bed23c5b6d1a6..fa00a7e87a56b 100644
--- a/src/Analyzers/CSharp/Analyzers/UseExpressionBody/UseExpressionBodyDiagnosticAnalyzer.cs
+++ b/src/Analyzers/CSharp/Analyzers/UseExpressionBody/UseExpressionBodyDiagnosticAnalyzer.cs
@@ -3,7 +3,6 @@
// See the LICENSE file in the project root for more information.
using System.Collections.Immutable;
-using System.Linq;
using System.Threading;
using Microsoft.CodeAnalysis.CodeStyle;
using Microsoft.CodeAnalysis.CSharp.CodeGeneration;
@@ -14,7 +13,7 @@
namespace Microsoft.CodeAnalysis.CSharp.UseExpressionBody;
[DiagnosticAnalyzer(LanguageNames.CSharp)]
-internal class UseExpressionBodyDiagnosticAnalyzer : AbstractBuiltInCodeStyleDiagnosticAnalyzer
+internal sealed class UseExpressionBodyDiagnosticAnalyzer : AbstractBuiltInCodeStyleDiagnosticAnalyzer
{
public const string FixesError = nameof(FixesError);
@@ -28,16 +27,16 @@ public UseExpressionBodyDiagnosticAnalyzer()
_syntaxKinds = _helpers.SelectManyAsArray(h => h.SyntaxKinds);
}
- private static ImmutableDictionary GetSupportedDescriptorsWithOptions()
+ private static ImmutableArray<(DiagnosticDescriptor, IOption2)> GetSupportedDescriptorsWithOptions()
{
- var builder = ImmutableDictionary.CreateBuilder();
+ var builder = new FixedSizeArrayBuilder<(DiagnosticDescriptor, IOption2)>(_helpers.Length);
foreach (var helper in _helpers)
{
var descriptor = CreateDescriptorWithId(helper.DiagnosticId, helper.EnforceOnBuild, hasAnyCodeStyleOption: true, helper.UseExpressionBodyTitle, helper.UseExpressionBodyTitle);
- builder.Add(descriptor, helper.Option);
+ builder.Add((descriptor, helper.Option));
}
- return builder.ToImmutable();
+ return builder.MoveToImmutable();
}
public override DiagnosticAnalyzerCategory GetAnalyzerCategory()
diff --git a/src/Analyzers/CSharp/Analyzers/UseExpressionBodyForLambda/UseExpressionBodyForLambdaDiagnosticAnalyzer.cs b/src/Analyzers/CSharp/Analyzers/UseExpressionBodyForLambda/UseExpressionBodyForLambdaDiagnosticAnalyzer.cs
index d4248991e4b42..21af7ba3f40bd 100644
--- a/src/Analyzers/CSharp/Analyzers/UseExpressionBodyForLambda/UseExpressionBodyForLambdaDiagnosticAnalyzer.cs
+++ b/src/Analyzers/CSharp/Analyzers/UseExpressionBodyForLambda/UseExpressionBodyForLambdaDiagnosticAnalyzer.cs
@@ -3,7 +3,6 @@
// See the LICENSE file in the project root for more information.
using System.Collections.Immutable;
-using System.Diagnostics.CodeAnalysis;
using System.Threading;
using Microsoft.CodeAnalysis.CodeStyle;
using Microsoft.CodeAnalysis.CSharp.CodeStyle;
@@ -21,9 +20,10 @@ internal sealed class UseExpressionBodyForLambdaDiagnosticAnalyzer : AbstractBui
private static readonly DiagnosticDescriptor s_useBlockBodyForLambda = CreateDescriptorWithId(UseExpressionBodyForLambdaHelpers.UseBlockBodyTitle, UseExpressionBodyForLambdaHelpers.UseBlockBodyTitle);
public UseExpressionBodyForLambdaDiagnosticAnalyzer() : base(
- ImmutableDictionary.Empty
- .Add(s_useExpressionBodyForLambda, CSharpCodeStyleOptions.PreferExpressionBodiedLambdas)
- .Add(s_useBlockBodyForLambda, CSharpCodeStyleOptions.PreferExpressionBodiedLambdas))
+ [
+ (s_useExpressionBodyForLambda, CSharpCodeStyleOptions.PreferExpressionBodiedLambdas),
+ (s_useBlockBodyForLambda, CSharpCodeStyleOptions.PreferExpressionBodiedLambdas)
+ ])
{
}
diff --git a/src/Analyzers/CSharp/Tests/AbstractBuiltInCodeStyleDiagnosticAnalyzer/AbstractBuiltInCodeStyleDiagnosticAnalyzerTests.cs b/src/Analyzers/CSharp/Tests/AbstractBuiltInCodeStyleDiagnosticAnalyzer/AbstractBuiltInCodeStyleDiagnosticAnalyzerTests.cs
new file mode 100644
index 0000000000000..616ccf33ffd80
--- /dev/null
+++ b/src/Analyzers/CSharp/Tests/AbstractBuiltInCodeStyleDiagnosticAnalyzer/AbstractBuiltInCodeStyleDiagnosticAnalyzerTests.cs
@@ -0,0 +1,59 @@
+// 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.Editor.CSharp.UnitTests.AbstractBuiltInCodeStyleDiagnosticAnalyzer;
+
+using System.Collections.Generic;
+using System.Collections.Immutable;
+using System.Linq;
+using Microsoft.CodeAnalysis.CodeStyle;
+using Microsoft.CodeAnalysis.Diagnostics;
+using Microsoft.CodeAnalysis.Options;
+using Roslyn.Utilities;
+using Xunit;
+
+public sealed class AbstractBuiltInCodeStyleDiagnosticAnalyzerTests
+{
+ [Fact]
+ public void VerifyDiagnosticDescriptorOrderingMaintained()
+ {
+ var ids = Enumerable.Range(10, 20).Select(item => "IDE_" + item);
+
+ var analyzer = new TestAnalyzer(ids);
+
+ Assert.Equal(analyzer.SupportedDiagnostics.Select(static diagnostic => diagnostic.Id), ids);
+ }
+
+ private sealed class TestAnalyzer : AbstractBuiltInCodeStyleDiagnosticAnalyzer
+ {
+ public TestAnalyzer(IEnumerable ids)
+ : base(CreateSupportedDiagnosticsWithOptionsFromIds(ids))
+ {
+ }
+
+ private static ImmutableArray<(DiagnosticDescriptor, ImmutableHashSet)> CreateSupportedDiagnosticsWithOptionsFromIds(IEnumerable ids)
+ {
+ var builder = ImmutableArray.CreateBuilder<(DiagnosticDescriptor, ImmutableHashSet)>();
+ foreach (var id in ids)
+ {
+ var descriptor = CreateDescriptorWithId(
+ id: id,
+ enforceOnBuild: EnforceOnBuild.Never,
+ hasAnyCodeStyleOption: false,
+ title: string.Empty);
+
+ builder.Add((descriptor, []));
+ }
+
+ return builder.ToImmutableAndClear();
+ }
+
+ public override DiagnosticAnalyzerCategory GetAnalyzerCategory()
+ => throw new System.NotImplementedException();
+
+ protected override void InitializeWorker(AnalysisContext context)
+ {
+ }
+ }
+}
diff --git a/src/Analyzers/CSharp/Tests/CSharpAnalyzers.UnitTests.projitems b/src/Analyzers/CSharp/Tests/CSharpAnalyzers.UnitTests.projitems
index 1ce11ff7471ba..472b6d7133ff3 100644
--- a/src/Analyzers/CSharp/Tests/CSharpAnalyzers.UnitTests.projitems
+++ b/src/Analyzers/CSharp/Tests/CSharpAnalyzers.UnitTests.projitems
@@ -9,6 +9,7 @@
Microsoft.CodeAnalysis.CSharp.Analyzers.UnitTests
+
@@ -181,4 +182,7 @@
+
+
+
\ No newline at end of file
diff --git a/src/Analyzers/Core/Analyzers/AbstractBuiltInCodeStyleDiagnosticAnalyzer.cs b/src/Analyzers/Core/Analyzers/AbstractBuiltInCodeStyleDiagnosticAnalyzer.cs
index 2a9338532b838..9b8b81878119e 100644
--- a/src/Analyzers/Core/Analyzers/AbstractBuiltInCodeStyleDiagnosticAnalyzer.cs
+++ b/src/Analyzers/Core/Analyzers/AbstractBuiltInCodeStyleDiagnosticAnalyzer.cs
@@ -4,7 +4,6 @@
using System.Collections.Immutable;
using System.Diagnostics;
-using System.Diagnostics.CodeAnalysis;
using System.Linq;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Options;
@@ -81,8 +80,8 @@ protected AbstractBuiltInCodeStyleDiagnosticAnalyzer(
///
/// Constructor for a code style analyzer with a multiple diagnostic descriptors with a code style editorconfig option that can be used to configure each descriptor.
///
- protected AbstractBuiltInCodeStyleDiagnosticAnalyzer(ImmutableDictionary supportedDiagnosticsWithOptions)
- : this(supportedDiagnosticsWithOptions.Keys.ToImmutableArray())
+ protected AbstractBuiltInCodeStyleDiagnosticAnalyzer(ImmutableArray<(DiagnosticDescriptor Descriptor, IOption2 Option)> supportedDiagnosticsWithOptions)
+ : this(supportedDiagnosticsWithOptions.SelectAsArray(static item => item.Descriptor))
{
foreach (var (descriptor, option) in supportedDiagnosticsWithOptions)
{
@@ -94,8 +93,8 @@ protected AbstractBuiltInCodeStyleDiagnosticAnalyzer(ImmutableDictionary
/// Constructor for a code style analyzer with multiple diagnostic descriptors with zero or more code style editorconfig options that can be used to configure each descriptor.
///
- protected AbstractBuiltInCodeStyleDiagnosticAnalyzer(ImmutableDictionary> supportedDiagnosticsWithOptions)
- : this(supportedDiagnosticsWithOptions.Keys.ToImmutableArray())
+ protected AbstractBuiltInCodeStyleDiagnosticAnalyzer(ImmutableArray<(DiagnosticDescriptor Descriptor, ImmutableHashSet Options)> supportedDiagnosticsWithOptions)
+ : this(supportedDiagnosticsWithOptions.SelectAsArray(static item => item.Descriptor))
{
foreach (var (descriptor, options) in supportedDiagnosticsWithOptions)
{
diff --git a/src/Analyzers/Core/Analyzers/AbstractBuiltInCodeStyleDiagnosticAnalyzer_Core.cs b/src/Analyzers/Core/Analyzers/AbstractBuiltInCodeStyleDiagnosticAnalyzer_Core.cs
index 59d80030b5808..b91fd230bf02f 100644
--- a/src/Analyzers/Core/Analyzers/AbstractBuiltInCodeStyleDiagnosticAnalyzer_Core.cs
+++ b/src/Analyzers/Core/Analyzers/AbstractBuiltInCodeStyleDiagnosticAnalyzer_Core.cs
@@ -2,14 +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.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using Microsoft.CodeAnalysis.Diagnostics;
-using Microsoft.CodeAnalysis.Options;
-using Microsoft.CodeAnalysis.PooledObjects;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.CodeStyle;
diff --git a/src/Analyzers/Core/Analyzers/AbstractBuiltInUnnecessaryCodeStyleDiagnosticAnalyzer.cs b/src/Analyzers/Core/Analyzers/AbstractBuiltInUnnecessaryCodeStyleDiagnosticAnalyzer.cs
index 4ca8ddd49631f..922dc5ad9ff11 100644
--- a/src/Analyzers/Core/Analyzers/AbstractBuiltInUnnecessaryCodeStyleDiagnosticAnalyzer.cs
+++ b/src/Analyzers/Core/Analyzers/AbstractBuiltInUnnecessaryCodeStyleDiagnosticAnalyzer.cs
@@ -100,19 +100,19 @@ protected AbstractBuiltInUnnecessaryCodeStyleDiagnosticAnalyzer(ImmutableArray
/// Constructor for a code style analyzer with a multiple diagnostic descriptors with a code style options that can be used to configure each descriptor.
///
- protected AbstractBuiltInUnnecessaryCodeStyleDiagnosticAnalyzer(ImmutableDictionary supportedDiagnosticsWithOptions, PerLanguageOption2? fadingOption)
+ protected AbstractBuiltInUnnecessaryCodeStyleDiagnosticAnalyzer(ImmutableArray<(DiagnosticDescriptor Descriptor, IOption2 Option)> supportedDiagnosticsWithOptions, PerLanguageOption2? fadingOption)
: base(supportedDiagnosticsWithOptions)
{
- AddDescriptorsToFadingOptionMapping(supportedDiagnosticsWithOptions.Keys, fadingOption);
+ AddDescriptorsToFadingOptionMapping(supportedDiagnosticsWithOptions.Select(static item => item.Descriptor), fadingOption);
}
///
/// Constructor for a code style analyzer with multiple diagnostic descriptors with zero or more code style options that can be used to configure each descriptor.
///
- protected AbstractBuiltInUnnecessaryCodeStyleDiagnosticAnalyzer(ImmutableDictionary> supportedDiagnosticsWithOptions, PerLanguageOption2? fadingOption)
+ protected AbstractBuiltInUnnecessaryCodeStyleDiagnosticAnalyzer(ImmutableArray<(DiagnosticDescriptor Descriptor, ImmutableHashSet Options)> supportedDiagnosticsWithOptions, PerLanguageOption2? fadingOption)
: base(supportedDiagnosticsWithOptions)
{
- AddDescriptorsToFadingOptionMapping(supportedDiagnosticsWithOptions.Keys, fadingOption);
+ AddDescriptorsToFadingOptionMapping(supportedDiagnosticsWithOptions.Select(static item => item.Descriptor), fadingOption);
}
private static void AddDiagnosticIdToFadingOptionMapping(string diagnosticId, PerLanguageOption2? fadingOption)
diff --git a/src/Analyzers/Core/Analyzers/FileHeaders/AbstractFileHeaderDiagnosticAnalyzer.cs b/src/Analyzers/Core/Analyzers/FileHeaders/AbstractFileHeaderDiagnosticAnalyzer.cs
index e356bc1c9b206..9f8bfae89f846 100644
--- a/src/Analyzers/Core/Analyzers/FileHeaders/AbstractFileHeaderDiagnosticAnalyzer.cs
+++ b/src/Analyzers/Core/Analyzers/FileHeaders/AbstractFileHeaderDiagnosticAnalyzer.cs
@@ -2,11 +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.
-using System.Collections.Immutable;
using System.IO;
using Microsoft.CodeAnalysis.CodeStyle;
using Microsoft.CodeAnalysis.Diagnostics;
-using Microsoft.CodeAnalysis.Options;
namespace Microsoft.CodeAnalysis.FileHeaders;
@@ -24,9 +22,11 @@ private static DiagnosticDescriptor CreateDescriptorForFileHeader(LocalizableStr
=> CreateDescriptorWithId(IDEDiagnosticIds.FileHeaderMismatch, EnforceOnBuildValues.FileHeaderMismatch, hasAnyCodeStyleOption: true, title, message);
protected AbstractFileHeaderDiagnosticAnalyzer()
- : base(ImmutableDictionary.Empty
- .Add(s_invalidHeaderDescriptor, CodeStyleOptions2.FileHeaderTemplate)
- .Add(s_missingHeaderDescriptor, CodeStyleOptions2.FileHeaderTemplate))
+ : base(
+ [
+ (s_invalidHeaderDescriptor, CodeStyleOptions2.FileHeaderTemplate),
+ (s_missingHeaderDescriptor, CodeStyleOptions2.FileHeaderTemplate)
+ ])
{
}
diff --git a/src/Analyzers/Core/Analyzers/IDEDiagnosticIdToOptionMappingHelper.cs b/src/Analyzers/Core/Analyzers/IDEDiagnosticIdToOptionMappingHelper.cs
index 7c3a5d350984d..b657d4cd0f720 100644
--- a/src/Analyzers/Core/Analyzers/IDEDiagnosticIdToOptionMappingHelper.cs
+++ b/src/Analyzers/Core/Analyzers/IDEDiagnosticIdToOptionMappingHelper.cs
@@ -69,7 +69,7 @@ public static void AddOptionMapping(string diagnosticId, ImmutableHashSet new ConcurrentDictionary>());
- AddOptionMapping(map, diagnosticId, languageGroup.ToImmutableHashSet());
+ AddOptionMapping(map, diagnosticId, [.. languageGroup]);
}
}
}
diff --git a/src/Analyzers/Core/Analyzers/RemoveUnnecessaryImports/AbstractRemoveUnnecessaryImportsDiagnosticAnalyzer.cs b/src/Analyzers/Core/Analyzers/RemoveUnnecessaryImports/AbstractRemoveUnnecessaryImportsDiagnosticAnalyzer.cs
index 690ac016a84b8..09655f4fec19a 100644
--- a/src/Analyzers/Core/Analyzers/RemoveUnnecessaryImports/AbstractRemoveUnnecessaryImportsDiagnosticAnalyzer.cs
+++ b/src/Analyzers/Core/Analyzers/RemoveUnnecessaryImports/AbstractRemoveUnnecessaryImportsDiagnosticAnalyzer.cs
@@ -40,7 +40,7 @@ internal abstract class AbstractRemoveUnnecessaryImportsDiagnosticAnalyzer> unusedValueExpressionStatementOption,
Option2> unusedValueAssignmentOption)
- : base(ImmutableDictionary.Empty
- .Add(s_expressionValueIsUnusedRule, unusedValueExpressionStatementOption)
- .Add(s_valueAssignedIsUnusedRule, unusedValueAssignmentOption)
- .Add(s_unusedParameterRule, CodeStyleOptions2.UnusedParameters),
- fadingOption: null)
+ : base(
+ [
+ (s_expressionValueIsUnusedRule, unusedValueExpressionStatementOption),
+ (s_valueAssignedIsUnusedRule, unusedValueAssignmentOption),
+ (s_unusedParameterRule, CodeStyleOptions2.UnusedParameters)
+ ],
+ fadingOption: null)
{
}
diff --git a/src/Analyzers/Core/Analyzers/SimplifyTypeNames/SimplifyTypeNamesDiagnosticAnalyzerBase.cs b/src/Analyzers/Core/Analyzers/SimplifyTypeNames/SimplifyTypeNamesDiagnosticAnalyzerBase.cs
index a37aa66a8d07f..fdaf88e7069f3 100644
--- a/src/Analyzers/Core/Analyzers/SimplifyTypeNames/SimplifyTypeNamesDiagnosticAnalyzerBase.cs
+++ b/src/Analyzers/Core/Analyzers/SimplifyTypeNames/SimplifyTypeNamesDiagnosticAnalyzerBase.cs
@@ -4,19 +4,16 @@
// #define LOG
-using System;
using System.Collections.Concurrent;
using System.Collections.Immutable;
using System.Diagnostics.CodeAnalysis;
-using System.Linq;
using System.Runtime.CompilerServices;
using System.Threading;
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.Simplification;
using Microsoft.CodeAnalysis.Text;
using Roslyn.Utilities;
@@ -64,15 +61,17 @@ internal abstract class SimplifyTypeNamesDiagnosticAnalyzerBase>.Empty
- .Add(s_descriptorSimplifyNames, [])
- .Add(s_descriptorSimplifyMemberAccess, [])
- .Add(s_descriptorPreferBuiltinOrFrameworkType,
- [
- CodeStyleOptions2.PreferIntrinsicPredefinedTypeKeywordInDeclaration,
- CodeStyleOptions2.PreferIntrinsicPredefinedTypeKeywordInMemberAccess,
- ]),
- fadingOption: null)
+ : base(
+ [
+ (s_descriptorSimplifyNames, []),
+ (s_descriptorSimplifyMemberAccess, []),
+ (s_descriptorPreferBuiltinOrFrameworkType,
+ [
+ CodeStyleOptions2.PreferIntrinsicPredefinedTypeKeywordInDeclaration,
+ CodeStyleOptions2.PreferIntrinsicPredefinedTypeKeywordInMemberAccess,
+ ])
+ ],
+ fadingOption: null)
{
}
diff --git a/src/Analyzers/Core/Analyzers/UseCollectionInitializer/AbstractUseCollectionInitializerDiagnosticAnalyzer.cs b/src/Analyzers/Core/Analyzers/UseCollectionInitializer/AbstractUseCollectionInitializerDiagnosticAnalyzer.cs
index ea645fb31ee2a..a663612d196d2 100644
--- a/src/Analyzers/Core/Analyzers/UseCollectionInitializer/AbstractUseCollectionInitializerDiagnosticAnalyzer.cs
+++ b/src/Analyzers/Core/Analyzers/UseCollectionInitializer/AbstractUseCollectionInitializerDiagnosticAnalyzer.cs
@@ -8,7 +8,6 @@
using Microsoft.CodeAnalysis.CodeStyle;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.LanguageService;
-using Microsoft.CodeAnalysis.Options;
using Microsoft.CodeAnalysis.Shared.CodeStyle;
using Microsoft.CodeAnalysis.Shared.Collections;
using Microsoft.CodeAnalysis.Shared.Extensions;
@@ -82,9 +81,10 @@ public override DiagnosticAnalyzerCategory GetAnalyzerCategory()
isUnnecessary: true);
protected AbstractUseCollectionInitializerDiagnosticAnalyzer()
- : base(ImmutableDictionary.Empty
- .Add(s_descriptor, CodeStyleOptions2.PreferCollectionInitializer)
- .Add(s_unnecessaryCodeDescriptor, CodeStyleOptions2.PreferCollectionInitializer))
+ : base(
+ [
+ (s_descriptor, CodeStyleOptions2.PreferCollectionInitializer)
+ ])
{
}
diff --git a/src/Analyzers/Core/Analyzers/UseObjectInitializer/AbstractUseObjectInitializerDiagnosticAnalyzer.cs b/src/Analyzers/Core/Analyzers/UseObjectInitializer/AbstractUseObjectInitializerDiagnosticAnalyzer.cs
index 8e1c39d240270..aabbb18b1eb49 100644
--- a/src/Analyzers/Core/Analyzers/UseObjectInitializer/AbstractUseObjectInitializerDiagnosticAnalyzer.cs
+++ b/src/Analyzers/Core/Analyzers/UseObjectInitializer/AbstractUseObjectInitializerDiagnosticAnalyzer.cs
@@ -7,7 +7,6 @@
using Microsoft.CodeAnalysis.CodeStyle;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.LanguageService;
-using Microsoft.CodeAnalysis.Options;
using Microsoft.CodeAnalysis.Shared.Collections;
using Microsoft.CodeAnalysis.Text;
@@ -62,9 +61,10 @@ internal abstract partial class AbstractUseObjectInitializerDiagnosticAnalyzer<
protected abstract TAnalyzer GetAnalyzer();
protected AbstractUseObjectInitializerDiagnosticAnalyzer()
- : base(ImmutableDictionary.Empty
- .Add(s_descriptor, CodeStyleOptions2.PreferObjectInitializer)
- .Add(s_unnecessaryCodeDescriptor, CodeStyleOptions2.PreferObjectInitializer))
+ : base(
+ [
+ (s_descriptor, CodeStyleOptions2.PreferObjectInitializer)
+ ])
{
}
diff --git a/src/Compilers/CSharp/Portable/Binder/RefSafetyAnalysis.cs b/src/Compilers/CSharp/Portable/Binder/RefSafetyAnalysis.cs
index 2029d8d5aa669..04ac043860e7d 100644
--- a/src/Compilers/CSharp/Portable/Binder/RefSafetyAnalysis.cs
+++ b/src/Compilers/CSharp/Portable/Binder/RefSafetyAnalysis.cs
@@ -258,6 +258,24 @@ private bool ContainsPlaceholderScope(BoundValuePlaceholderBase placeholder)
public override BoundNode? Visit(BoundNode? node)
{
#if DEBUG
+ TrackVisit(node);
+#endif
+ return base.Visit(node);
+ }
+
+#if DEBUG
+ protected override void BeforeVisitingSkippedBoundBinaryOperatorChildren(BoundBinaryOperator node)
+ {
+ TrackVisit(node);
+ }
+
+ protected override void BeforeVisitingSkippedBoundCallChildren(BoundCall node)
+ {
+ TrackVisit(node);
+ }
+
+ private void TrackVisit(BoundNode? node)
+ {
if (node is BoundValuePlaceholderBase placeholder)
{
Debug.Assert(ContainsPlaceholderScope(placeholder));
@@ -267,14 +285,11 @@ private bool ContainsPlaceholderScope(BoundValuePlaceholderBase placeholder)
if (_visited is { } && _visited.Count <= MaxTrackVisited)
{
bool added = _visited.Add(expr);
- Debug.Assert(added);
+ Debug.Assert(added, $"Expression {expr} `{expr.Syntax}` visited more than once.");
}
}
-#endif
- return base.Visit(node);
}
-#if DEBUG
private void AssertVisited(BoundExpression expr)
{
if (expr is BoundValuePlaceholderBase placeholder)
@@ -283,7 +298,7 @@ private void AssertVisited(BoundExpression expr)
}
else if (_visited is { } && _visited.Count <= MaxTrackVisited)
{
- Debug.Assert(_visited.Contains(expr));
+ Debug.Assert(_visited.Contains(expr), $"Expected {expr} `{expr.Syntax}` to be visited.");
}
}
#endif
@@ -659,13 +674,6 @@ protected override void VisitArguments(BoundCall node)
_localScopeDepth,
_diagnostics);
}
-
-#if DEBUG
- if (_visited is { } && _visited.Count <= MaxTrackVisited)
- {
- _visited.Add(node);
- }
-#endif
}
private void GetInterpolatedStringPlaceholders(
diff --git a/src/Compilers/CSharp/Portable/BoundTree/BoundTreeWalker.cs b/src/Compilers/CSharp/Portable/BoundTree/BoundTreeWalker.cs
index a8ed41a6f003c..8f0df23b1e56c 100644
--- a/src/Compilers/CSharp/Portable/BoundTree/BoundTreeWalker.cs
+++ b/src/Compilers/CSharp/Portable/BoundTree/BoundTreeWalker.cs
@@ -114,6 +114,7 @@ protected BoundTreeWalkerWithStackGuardWithoutRecursionOnTheLeftOfBinaryOperator
var binary = (BoundBinaryOperator)node.Left;
+ BeforeVisitingSkippedBoundBinaryOperatorChildren(binary);
rightOperands.Push(binary.Right);
BoundExpression current = binary.Left;
@@ -121,6 +122,7 @@ protected BoundTreeWalkerWithStackGuardWithoutRecursionOnTheLeftOfBinaryOperator
while (current.Kind == BoundKind.BinaryOperator)
{
binary = (BoundBinaryOperator)current;
+ BeforeVisitingSkippedBoundBinaryOperatorChildren(binary);
rightOperands.Push(binary.Right);
current = binary.Left;
}
@@ -136,6 +138,10 @@ protected BoundTreeWalkerWithStackGuardWithoutRecursionOnTheLeftOfBinaryOperator
return null;
}
+ protected virtual void BeforeVisitingSkippedBoundBinaryOperatorChildren(BoundBinaryOperator node)
+ {
+ }
+
public sealed override BoundNode? VisitCall(BoundCall node)
{
if (node.ReceiverOpt is BoundCall receiver1)
@@ -147,10 +153,13 @@ protected BoundTreeWalkerWithStackGuardWithoutRecursionOnTheLeftOfBinaryOperator
node = receiver1;
while (node.ReceiverOpt is BoundCall receiver2)
{
+ BeforeVisitingSkippedBoundCallChildren(node);
calls.Push(node);
node = receiver2;
}
+ BeforeVisitingSkippedBoundCallChildren(node);
+
VisitReceiver(node);
do
@@ -170,6 +179,10 @@ protected BoundTreeWalkerWithStackGuardWithoutRecursionOnTheLeftOfBinaryOperator
return null;
}
+ protected virtual void BeforeVisitingSkippedBoundCallChildren(BoundCall node)
+ {
+ }
+
///
/// Called only for the first (in evaluation order) in the chain.
///
diff --git a/src/Compilers/CSharp/Portable/Parser/Blender.Cursor.cs b/src/Compilers/CSharp/Portable/Parser/Blender.Cursor.cs
index 4f9b6796441b9..cab4183fbee13 100644
--- a/src/Compilers/CSharp/Portable/Parser/Blender.Cursor.cs
+++ b/src/Compilers/CSharp/Portable/Parser/Blender.Cursor.cs
@@ -55,7 +55,11 @@ private static bool IsNonZeroWidthOrIsEndOfFile(SyntaxNodeOrToken token)
return token.Kind() == SyntaxKind.EndOfFileToken || token.FullWidth != 0;
}
- public Cursor MoveToNextSibling()
+ ///
+ /// Returns the cursor of our next non-empty (or EOF) sibling in our parent if one exists, or `default` if
+ /// if doesn't.
+ ///
+ private Cursor TryFindNextNonZeroWidthOrIsEndOfFileSibling()
{
if (this.CurrentNodeOrToken.Parent != null)
{
@@ -70,10 +74,6 @@ public Cursor MoveToNextSibling()
return new Cursor(sibling, i);
}
}
-
- // We're at the end of this sibling chain. Walk up to the parent and see who is
- // the next sibling of that.
- return MoveToParent().MoveToNextSibling();
}
return default(Cursor);
@@ -86,6 +86,26 @@ private Cursor MoveToParent()
return new Cursor(parent, index);
}
+ public static Cursor MoveToNextSibling(Cursor cursor)
+ {
+ // Iteratively walk over the tree so that we don't stack overflow trying to recurse into anything.
+ while (cursor.CurrentNodeOrToken.UnderlyingNode != null)
+ {
+ var nextSibling = cursor.TryFindNextNonZeroWidthOrIsEndOfFileSibling();
+
+ // If we got a valid sibling, return it.
+ if (nextSibling.CurrentNodeOrToken.UnderlyingNode != null)
+ return nextSibling;
+
+ // We're at the end of this sibling chain. Walk up to the parent and see who is
+ // the next sibling of that.
+ cursor = cursor.MoveToParent();
+ }
+
+ // Couldn't find anything, bail out.
+ return default;
+ }
+
private static int IndexOfNodeInParent(SyntaxNode node)
{
if (node.Parent == null)
diff --git a/src/Compilers/CSharp/Portable/Parser/Blender.Reader.cs b/src/Compilers/CSharp/Portable/Parser/Blender.Reader.cs
index f0e6877589899..4181b444e1c75 100644
--- a/src/Compilers/CSharp/Portable/Parser/Blender.Reader.cs
+++ b/src/Compilers/CSharp/Portable/Parser/Blender.Reader.cs
@@ -118,7 +118,7 @@ private void SkipOldToken()
// Now, skip past it.
_changeDelta += node.FullWidth;
_oldDirectives = node.ApplyDirectives(_oldDirectives);
- _oldTreeCursor = _oldTreeCursor.MoveToNextSibling();
+ _oldTreeCursor = Cursor.MoveToNextSibling(_oldTreeCursor);
// If our cursor is now after any changes, then just skip past them while upping
// the changeDelta length. This will let us know that we need to read tokens
@@ -204,7 +204,7 @@ private bool TryTakeOldNodeOrToken(
// We can reuse this node or token. Move us forward in the new text, and move to the
// next sibling.
_newPosition += currentNodeOrToken.FullWidth;
- _oldTreeCursor = _oldTreeCursor.MoveToNextSibling();
+ _oldTreeCursor = Cursor.MoveToNextSibling(_oldTreeCursor);
_newDirectives = currentNodeOrToken.ApplyDirectives(_newDirectives);
_oldDirectives = currentNodeOrToken.ApplyDirectives(_oldDirectives);
diff --git a/src/Compilers/CSharp/Portable/Syntax/SyntaxEquivalence.cs b/src/Compilers/CSharp/Portable/Syntax/SyntaxEquivalence.cs
index 6484b75a769c9..cba16e079df44 100644
--- a/src/Compilers/CSharp/Portable/Syntax/SyntaxEquivalence.cs
+++ b/src/Compilers/CSharp/Portable/Syntax/SyntaxEquivalence.cs
@@ -5,6 +5,7 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
+using Microsoft.CodeAnalysis.PooledObjects;
namespace Microsoft.CodeAnalysis.CSharp.Syntax
{
@@ -100,130 +101,147 @@ private static bool AreTokensEquivalent(GreenNode? before, GreenNode? after, Fun
private static bool AreEquivalentRecursive(GreenNode? before, GreenNode? after, Func? ignoreChildNode, bool topLevel)
{
- if (before == after)
- {
- return true;
- }
+ // Use an explicit stack so we can walk down deep trees without blowing the real stack.
+ var stack = ArrayBuilder<(GreenNode? before, GreenNode? after)>.GetInstance();
+ stack.Push((before, after));
- if (before == null || after == null)
+ try
{
- return false;
- }
+ while (stack.TryPop(out var current))
+ {
+ if (!areEquivalentSingleLevel(current.before, current.after))
+ return false;
+ }
- if (before.RawKind != after.RawKind)
- {
- return false;
+ return true;
}
-
- if (before.IsToken)
+ finally
{
- Debug.Assert(after.IsToken);
- return AreTokensEquivalent(before, after, ignoreChildNode);
+ stack.Free();
}
- if (topLevel)
+ bool areEquivalentSingleLevel(GreenNode? before, GreenNode? after)
{
- // Once we get down to the body level we don't need to go any further and we can
- // consider these trees equivalent.
- switch ((SyntaxKind)before.RawKind)
+ if (before == after)
{
- case SyntaxKind.Block:
- case SyntaxKind.ArrowExpressionClause:
- return AreNullableDirectivesEquivalent(before, after, ignoreChildNode);
+ return true;
}
- // If we're only checking top level equivalence, then we don't have to go down into
- // the initializer for a field. However, we can't put that optimization for all
- // fields. For example, fields that are 'const' do need their initializers checked as
- // changing them can affect binding results.
- if ((SyntaxKind)before.RawKind == SyntaxKind.FieldDeclaration)
+ if (before == null || after == null)
{
- var fieldBefore = (Green.FieldDeclarationSyntax)before;
- var fieldAfter = (Green.FieldDeclarationSyntax)after;
-
- var isConstBefore = fieldBefore.Modifiers.Any((int)SyntaxKind.ConstKeyword);
- var isConstAfter = fieldAfter.Modifiers.Any((int)SyntaxKind.ConstKeyword);
+ return false;
+ }
- if (!isConstBefore && !isConstAfter)
- {
- ignoreChildNode = childKind => childKind == SyntaxKind.EqualsValueClause;
- }
+ if (before.RawKind != after.RawKind)
+ {
+ return false;
}
- // NOTE(cyrusn): Do we want to avoid going down into attribute expressions? I don't
- // think we can avoid it as there are likely places in the compiler that use these
- // expressions. For example, if the user changes [InternalsVisibleTo("goo")] to
- // [InternalsVisibleTo("bar")] then that must count as a top level change as it
- // affects symbol visibility. Perhaps we could enumerate the places in the compiler
- // that use the values inside source attributes and we can check if we're in an
- // attribute with that name. It wouldn't be 100% correct (because of annoying things
- // like using aliases), but would likely be good enough for the incremental cases in
- // the IDE.
- }
+ if (before.IsToken)
+ {
+ Debug.Assert(after.IsToken);
+ return AreTokensEquivalent(before, after, ignoreChildNode);
+ }
- if (ignoreChildNode != null)
- {
- var e1 = before.ChildNodesAndTokens().GetEnumerator();
- var e2 = after.ChildNodesAndTokens().GetEnumerator();
- while (true)
+ if (topLevel)
{
- GreenNode? child1 = null;
- GreenNode? child2 = null;
+ // Once we get down to the body level we don't need to go any further and we can
+ // consider these trees equivalent.
+ switch ((SyntaxKind)before.RawKind)
+ {
+ case SyntaxKind.Block:
+ case SyntaxKind.ArrowExpressionClause:
+ return AreNullableDirectivesEquivalent(before, after, ignoreChildNode);
+ }
- // skip ignored children:
- while (e1.MoveNext())
+ // If we're only checking top level equivalence, then we don't have to go down into
+ // the initializer for a field. However, we can't put that optimization for all
+ // fields. For example, fields that are 'const' do need their initializers checked as
+ // changing them can affect binding results.
+ if ((SyntaxKind)before.RawKind == SyntaxKind.FieldDeclaration)
{
- var c = e1.Current;
- if (c != null && (c.IsToken || !ignoreChildNode((SyntaxKind)c.RawKind)))
+ var fieldBefore = (Green.FieldDeclarationSyntax)before;
+ var fieldAfter = (Green.FieldDeclarationSyntax)after;
+
+ var isConstBefore = fieldBefore.Modifiers.Any((int)SyntaxKind.ConstKeyword);
+ var isConstAfter = fieldAfter.Modifiers.Any((int)SyntaxKind.ConstKeyword);
+
+ if (!isConstBefore && !isConstAfter)
{
- child1 = c;
- break;
+ ignoreChildNode = static childKind => childKind == SyntaxKind.EqualsValueClause;
}
}
- while (e2.MoveNext())
+ // NOTE(cyrusn): Do we want to avoid going down into attribute expressions? I don't
+ // think we can avoid it as there are likely places in the compiler that use these
+ // expressions. For example, if the user changes [InternalsVisibleTo("goo")] to
+ // [InternalsVisibleTo("bar")] then that must count as a top level change as it
+ // affects symbol visibility. Perhaps we could enumerate the places in the compiler
+ // that use the values inside source attributes and we can check if we're in an
+ // attribute with that name. It wouldn't be 100% correct (because of annoying things
+ // like using aliases), but would likely be good enough for the incremental cases in
+ // the IDE.
+ }
+
+ if (ignoreChildNode != null)
+ {
+ var e1 = before.ChildNodesAndTokens().GetEnumerator();
+ var e2 = after.ChildNodesAndTokens().GetEnumerator();
+ while (true)
{
- var c = e2.Current;
- if (c != null && (c.IsToken || !ignoreChildNode((SyntaxKind)c.RawKind)))
+ GreenNode? child1 = null;
+ GreenNode? child2 = null;
+
+ // skip ignored children:
+ while (e1.MoveNext())
{
- child2 = c;
- break;
+ var c = e1.Current;
+ if (c != null && (c.IsToken || !ignoreChildNode((SyntaxKind)c.RawKind)))
+ {
+ child1 = c;
+ break;
+ }
}
- }
- if (child1 == null || child2 == null)
- {
- // false if some children remained
- return child1 == child2;
- }
+ while (e2.MoveNext())
+ {
+ var c = e2.Current;
+ if (c != null && (c.IsToken || !ignoreChildNode((SyntaxKind)c.RawKind)))
+ {
+ child2 = c;
+ break;
+ }
+ }
- if (!AreEquivalentRecursive(child1, child2, ignoreChildNode, topLevel))
- {
- return false;
- }
- }
- }
- else
- {
- // simple comparison - not ignoring children
+ if (child1 == null || child2 == null)
+ {
+ // false if some children remained
+ return child1 == child2;
+ }
- int slotCount = before.SlotCount;
- if (slotCount != after.SlotCount)
- {
- return false;
+ stack.Push((child1, child2));
+ }
}
-
- for (int i = 0; i < slotCount; i++)
+ else
{
- var child1 = before.GetSlot(i);
- var child2 = after.GetSlot(i);
+ // simple comparison - not ignoring children
- if (!AreEquivalentRecursive(child1, child2, ignoreChildNode, topLevel))
+ int slotCount = before.SlotCount;
+ if (slotCount != after.SlotCount)
{
return false;
}
+
+ // Walk the children backwards so that we can push them onto the stack and continue walking in DFS order.
+ for (var i = slotCount - 1; i >= 0; i--)
+ {
+ var child1 = before.GetSlot(i);
+ var child2 = after.GetSlot(i);
+ stack.Push((child1, child2));
+ }
}
+ // So far these are equivalent. Continue checking the children.
return true;
}
}
diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/RefEscapingTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/RefEscapingTests.cs
index 6da08b9784005..0cd3ee133280d 100644
--- a/src/Compilers/CSharp/Test/Semantic/Semantics/RefEscapingTests.cs
+++ b/src/Compilers/CSharp/Test/Semantic/Semantics/RefEscapingTests.cs
@@ -7871,6 +7871,37 @@ ref struct S
Diagnostic(ErrorCode.ERR_EscapeVariable, "s").WithArguments("s").WithLocation(47, 16));
}
+ [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/71773")]
+ public void UserDefinedBinaryOperator_RefStruct_Nested()
+ {
+ var source = """
+ class C
+ {
+ S M()
+ {
+ S s;
+ s = default(S) + 100 + 200;
+ return s;
+ }
+ }
+
+ ref struct S
+ {
+ public static S operator+(S y, in int x) => throw null;
+ }
+ """;
+ CreateCompilation(source).VerifyDiagnostics(
+ // (6,13): error CS8347: Cannot use a result of 'S.operator +(S, in int)' in this context because it may expose variables referenced by parameter 'x' outside of their declaration scope
+ // s = default(S) + 100 + 200;
+ Diagnostic(ErrorCode.ERR_EscapeCall, "default(S) + 100").WithArguments("S.operator +(S, in int)", "x").WithLocation(6, 13),
+ // (6,13): error CS8347: Cannot use a result of 'S.operator +(S, in int)' in this context because it may expose variables referenced by parameter 'y' outside of their declaration scope
+ // s = default(S) + 100 + 200;
+ Diagnostic(ErrorCode.ERR_EscapeCall, "default(S) + 100 + 200").WithArguments("S.operator +(S, in int)", "y").WithLocation(6, 13),
+ // (6,26): error CS8156: An expression cannot be used in this context because it may not be passed or returned by reference
+ // s = default(S) + 100 + 200;
+ Diagnostic(ErrorCode.ERR_RefReturnLvalueExpected, "100").WithLocation(6, 26));
+ }
+
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/71773")]
public void UserDefinedBinaryOperator_RefStruct_Scoped_Left()
{
@@ -8531,5 +8562,16 @@ static R F2()
// return new R(1) | new R(2);
Diagnostic(ErrorCode.ERR_RefReturnLvalueExpected, "1").WithLocation(18, 22));
}
+
+ [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/72873")]
+ public void Utf8Addition()
+ {
+ var code = """
+ using System;
+ ReadOnlySpan x = "Hello"u8 + " "u8 + "World!"u8;
+ Console.WriteLine(x.Length);
+ """;
+ CreateCompilation(code, targetFramework: TargetFramework.Net70).VerifyDiagnostics();
+ }
}
}
diff --git a/src/Compilers/CSharp/Test/Syntax/Syntax/SyntaxEquivalenceTests.cs b/src/Compilers/CSharp/Test/Syntax/Syntax/SyntaxEquivalenceTests.cs
index 00f2a1223c791..4094cc28447d9 100644
--- a/src/Compilers/CSharp/Test/Syntax/Syntax/SyntaxEquivalenceTests.cs
+++ b/src/Compilers/CSharp/Test/Syntax/Syntax/SyntaxEquivalenceTests.cs
@@ -5,6 +5,7 @@
#nullable disable
using System;
+using System.Linq;
using Roslyn.Test.Utilities;
using Xunit;
@@ -1284,5 +1285,61 @@ void M()
VerifyNotEquivalent(tree1, tree2, topLevel: false);
VerifyEquivalent(tree1, tree2, topLevel: true);
}
+
+ [Fact, WorkItem("https://devdiv.visualstudio.com/DevDiv/_workitems/edit/2018744")]
+ public void TestDeeplyNested1()
+ {
+ var expr = string.Join(" + ", Enumerable.Range(0, 10000).Select(_ => "a"));
+
+ var tree1 = SyntaxFactory.ParseSyntaxTree($$""""
+ class C
+ {
+ void M(int a, int b, int c)
+ {
+ var v = {{expr}} + b;
+ }
+ }
+ """");
+
+ var tree2 = SyntaxFactory.ParseSyntaxTree($$""""
+ class C
+ {
+ void M(int a, int b, int c)
+ {
+ var v = {{expr}} + c;
+ }
+ }
+ """");
+
+ VerifyNotEquivalent(tree1, tree2, topLevel: false);
+ }
+
+ [Fact, WorkItem("https://devdiv.visualstudio.com/DevDiv/_workitems/edit/2018744")]
+ public void TestDeeplyNested2()
+ {
+ var expr = string.Join(" + ", Enumerable.Range(0, 10000).Select(_ => "a"));
+
+ var tree1 = SyntaxFactory.ParseSyntaxTree($$""""
+ class C
+ {
+ void M(int a)
+ {
+ var v = {{expr}};
+ }
+ }
+ """");
+
+ var tree2 = SyntaxFactory.ParseSyntaxTree($$""""
+ class C
+ {
+ void M(int a)
+ {
+ var v = {{expr}};
+ }
+ }
+ """");
+
+ VerifyEquivalent(tree1, tree2, topLevel: false);
+ }
}
}
diff --git a/src/Compilers/Core/CodeAnalysisTest/Analyzers/AnalyzerConfigTests.cs b/src/Compilers/Core/CodeAnalysisTest/Analyzers/AnalyzerConfigTests.cs
index d309e6fad88f4..0fb4efa394de5 100644
--- a/src/Compilers/Core/CodeAnalysisTest/Analyzers/AnalyzerConfigTests.cs
+++ b/src/Compilers/Core/CodeAnalysisTest/Analyzers/AnalyzerConfigTests.cs
@@ -1083,6 +1083,28 @@ public void MultipleEditorConfigs()
}, options.Select(o => o.TreeOptions).ToArray());
}
+ [Fact]
+ public void FolderNamePrefixOfFileName()
+ {
+ var configs = ArrayBuilder.GetInstance();
+ configs.Add(Parse(@"
+[*.cs]
+dotnet_diagnostic.cs000.severity = suggestion", "/root/.editorconfig"));
+ configs.Add(Parse(@"
+root=true", "/root/test/.editorconfig"));
+
+ var options = GetAnalyzerConfigOptions(
+ new[] { "/root/testing.cs" },
+ configs);
+ configs.Free();
+
+ Assert.Equal(new[]
+ {
+ CreateImmutableDictionary(
+ ("cs000", ReportDiagnostic.Info)),
+ }, options.Select(o => o.TreeOptions).ToArray());
+ }
+
[Fact]
public void InheritOuterConfig()
{
diff --git a/src/Compilers/Core/CodeAnalysisTest/FileSystem/PathUtilitiesTests.cs b/src/Compilers/Core/CodeAnalysisTest/FileSystem/PathUtilitiesTests.cs
index c660ffa62b568..123f0ba58d5d1 100644
--- a/src/Compilers/Core/CodeAnalysisTest/FileSystem/PathUtilitiesTests.cs
+++ b/src/Compilers/Core/CodeAnalysisTest/FileSystem/PathUtilitiesTests.cs
@@ -4,6 +4,7 @@
#nullable disable
+using System;
using System.IO;
using Roslyn.Test.Utilities;
using Roslyn.Utilities;
@@ -291,6 +292,26 @@ public void IsSameDirectoryOrChildOfNegativeTests()
Assert.False(PathUtilities.IsSameDirectoryOrChildOf(@"C:\A\B\C", @"C:\A\B\C\D"));
}
+ [ConditionalFact(typeof(WindowsOnly))]
+ public void IsSameDirectoryOrChildOfSpecifyingCaseSensitivity_Windows()
+ {
+ Assert.True(PathUtilities.IsSameDirectoryOrChildOf(@"C:\a\B\C", @"C:\A\B", StringComparison.OrdinalIgnoreCase));
+ Assert.True(PathUtilities.IsSameDirectoryOrChildOf(@"C:\A\b\C", @"C:\A\B", StringComparison.OrdinalIgnoreCase));
+
+ Assert.False(PathUtilities.IsSameDirectoryOrChildOf(@"C:\a\B\C", @"C:\A\B", StringComparison.Ordinal));
+ Assert.False(PathUtilities.IsSameDirectoryOrChildOf(@"C:\A\b\C", @"C:\A\B", StringComparison.Ordinal));
+ }
+
+ [ConditionalFact(typeof(UnixLikeOnly))]
+ public void IsSameDirectoryOrChildOfSpecifyingCaseSensitivity_Unix()
+ {
+ Assert.True(PathUtilities.IsSameDirectoryOrChildOf(@"/a/B/C", @"/A/B", StringComparison.OrdinalIgnoreCase));
+ Assert.True(PathUtilities.IsSameDirectoryOrChildOf(@"/A/b/C", @"/A/B", StringComparison.OrdinalIgnoreCase));
+
+ Assert.False(PathUtilities.IsSameDirectoryOrChildOf(@"/a/B/C", @"/A/B", StringComparison.Ordinal));
+ Assert.False(PathUtilities.IsSameDirectoryOrChildOf(@"/A/b/C", @"/A/B", StringComparison.Ordinal));
+ }
+
[Fact]
public void IsValidFilePath()
{
diff --git a/src/Compilers/Core/Portable/CommandLine/AnalyzerConfigSet.cs b/src/Compilers/Core/Portable/CommandLine/AnalyzerConfigSet.cs
index eaa8de216fe95..2296b51ec33ce 100644
--- a/src/Compilers/Core/Portable/CommandLine/AnalyzerConfigSet.cs
+++ b/src/Compilers/Core/Portable/CommandLine/AnalyzerConfigSet.cs
@@ -204,7 +204,7 @@ public AnalyzerConfigOptionsResult GetOptionsForSourcePath(string sourcePath)
{
var config = _analyzerConfigs[analyzerConfigIndex];
- if (normalizedPath.StartsWith(config.NormalizedDirectory, StringComparison.Ordinal))
+ if (PathUtilities.IsSameDirectoryOrChildOf(normalizedPath, config.NormalizedDirectory, StringComparison.Ordinal))
{
// If this config is a root config, then clear earlier options since they don't apply
// to this source file.
diff --git a/src/Compilers/Core/Portable/FileSystem/PathUtilities.cs b/src/Compilers/Core/Portable/FileSystem/PathUtilities.cs
index 0617a16e08dfd..570121ad3d3bb 100644
--- a/src/Compilers/Core/Portable/FileSystem/PathUtilities.cs
+++ b/src/Compilers/Core/Portable/FileSystem/PathUtilities.cs
@@ -159,7 +159,7 @@ public static string RemoveExtension(string path)
return null;
}
- internal static bool IsSameDirectoryOrChildOf(string child, string parent)
+ internal static bool IsSameDirectoryOrChildOf(string child, string parent, StringComparison comparison = StringComparison.OrdinalIgnoreCase)
{
parent = RemoveTrailingDirectorySeparator(parent);
string? currentChild = child;
@@ -167,7 +167,7 @@ internal static bool IsSameDirectoryOrChildOf(string child, string parent)
{
currentChild = RemoveTrailingDirectorySeparator(currentChild);
- if (currentChild.Equals(parent, StringComparison.OrdinalIgnoreCase))
+ if (currentChild.Equals(parent, comparison))
{
return true;
}
diff --git a/src/EditorFeatures/CSharp/AutomaticCompletion/AutomaticLineEnderCommandHandler_Helpers.cs b/src/EditorFeatures/CSharp/AutomaticCompletion/AutomaticLineEnderCommandHandler_Helpers.cs
index 2b955627c7b21..4986a0098536b 100644
--- a/src/EditorFeatures/CSharp/AutomaticCompletion/AutomaticLineEnderCommandHandler_Helpers.cs
+++ b/src/EditorFeatures/CSharp/AutomaticCompletion/AutomaticLineEnderCommandHandler_Helpers.cs
@@ -155,7 +155,7 @@ WhileStatementSyntax or ForEachStatementSyntax or ForStatementSyntax or LockStat
oldNode: embeddedStatementOwner,
newNode: AddBlockToEmbeddedStatementOwner(embeddedStatementOwner, formattingOptions),
anchorNode: embeddedStatementOwner,
- nodesToInsert: ImmutableArray.Empty.Add(statement),
+ nodesToInsert: [statement],
formattingOptions,
cancellationToken),
DoStatementSyntax doStatementNode => AddBraceToDoStatement(services, root, doStatementNode, formattingOptions, statement, cancellationToken),
@@ -195,7 +195,7 @@ private static (SyntaxNode newRoot, int nextCaretPosition) AddBraceToDoStatement
oldNode: doStatementNode,
newNode: AddBlockToEmbeddedStatementOwner(doStatementNode, formattingOptions),
anchorNode: doStatementNode,
- nodesToInsert: ImmutableArray.Empty.Add(innerStatement),
+ nodesToInsert: [innerStatement],
formattingOptions,
cancellationToken);
}
@@ -251,7 +251,7 @@ private static (SyntaxNode newRoot, int nextCaretPosition) AddBraceToIfStatement
ifStatementNode,
AddBlockToEmbeddedStatementOwner(ifStatementNode, formattingOptions),
ifStatementNode,
- ImmutableArray.Empty.Add(innerStatement),
+ [innerStatement],
formattingOptions,
cancellationToken);
}
@@ -319,7 +319,7 @@ private static (SyntaxNode newRoot, int nextCaretPosition) AddBraceToElseClause(
elseClauseNode,
WithBraces(elseClauseNode, formattingOptions),
elseClauseNode.Parent!,
- ImmutableArray.Empty.Add(innerStatement),
+ [innerStatement],
formattingOptions,
cancellationToken);
}
diff --git a/src/EditorFeatures/CSharpTest/InlineDiagnostics/InlineDiagnosticsTaggerProviderTests.cs b/src/EditorFeatures/CSharpTest/InlineDiagnostics/InlineDiagnosticsTaggerProviderTests.cs
index 339bf5c7e32b2..8462f9b447d79 100644
--- a/src/EditorFeatures/CSharpTest/InlineDiagnostics/InlineDiagnosticsTaggerProviderTests.cs
+++ b/src/EditorFeatures/CSharpTest/InlineDiagnostics/InlineDiagnosticsTaggerProviderTests.cs
@@ -55,6 +55,6 @@ private static async Task>> GetTag
private static async Task>> GetTagSpansAsync(EditorTestWorkspace workspace)
{
workspace.GlobalOptions.SetGlobalOption(InlineDiagnosticsOptionsStorage.EnableInlineDiagnostics, LanguageNames.CSharp, true);
- return (await TestDiagnosticTagProducer.GetDiagnosticsAndErrorSpans(workspace)).Item2;
+ return await TestDiagnosticTagProducer.GetTagSpansAsync(workspace);
}
}
diff --git a/src/EditorFeatures/CSharpTest/NavigateTo/NavigateToSearcherTests.cs b/src/EditorFeatures/CSharpTest/NavigateTo/NavigateToSearcherTests.cs
index 24c066414e32d..fca8d0d529356 100644
--- a/src/EditorFeatures/CSharpTest/NavigateTo/NavigateToSearcherTests.cs
+++ b/src/EditorFeatures/CSharpTest/NavigateTo/NavigateToSearcherTests.cs
@@ -7,8 +7,8 @@
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
+using Microsoft.CodeAnalysis.Editor.Test;
using Microsoft.CodeAnalysis.Editor.UnitTests;
-using Microsoft.CodeAnalysis.Editor.UnitTests.NavigateTo;
using Microsoft.CodeAnalysis.NavigateTo;
using Microsoft.CodeAnalysis.Navigation;
using Microsoft.CodeAnalysis.PatternMatching;
@@ -24,7 +24,7 @@ namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.NavigateTo
[Trait(Traits.Feature, Traits.Features.NavigateTo)]
public sealed class NavigateToSearcherTests
{
- private static readonly TestComposition FirstActiveAndVisibleComposition = EditorTestCompositions.EditorFeatures.AddParts(typeof(FirstDocIsActiveAndVisibleDocumentTrackingService.Factory));
+ private static readonly TestComposition FirstActiveAndVisibleComposition = EditorTestCompositions.EditorFeatures.AddParts(typeof(FirstDocumentIsActiveAndVisibleDocumentTrackingService.Factory));
private static void SetupSearchProject(
Mock searchService,
diff --git a/src/EditorFeatures/Core.Wpf/InlineRename/UI/Dashboard/RenameDashboard.xaml.cs b/src/EditorFeatures/Core.Wpf/InlineRename/UI/Dashboard/RenameDashboard.xaml.cs
index 5cd92953a1c02..482304aa00701 100644
--- a/src/EditorFeatures/Core.Wpf/InlineRename/UI/Dashboard/RenameDashboard.xaml.cs
+++ b/src/EditorFeatures/Core.Wpf/InlineRename/UI/Dashboard/RenameDashboard.xaml.cs
@@ -52,7 +52,7 @@ public RenameDashboard(
_model = model;
InitializeComponent();
- _tabNavigableChildren = new UIElement[] { this.OverloadsCheckbox, this.CommentsCheckbox, this.StringsCheckbox, this.FileRenameCheckbox, this.PreviewChangesCheckbox, this.ApplyButton, this.CloseButton }.ToList();
+ _tabNavigableChildren = [this.OverloadsCheckbox, this.CommentsCheckbox, this.StringsCheckbox, this.FileRenameCheckbox, this.PreviewChangesCheckbox, this.ApplyButton, this.CloseButton];
_textView = textView;
this.DataContext = model;
diff --git a/src/EditorFeatures/Core.Wpf/QuickInfo/ProjectionBufferContent.cs b/src/EditorFeatures/Core.Wpf/QuickInfo/ProjectionBufferContent.cs
index 9cfa06e7b685b..6c18010ae0371 100644
--- a/src/EditorFeatures/Core.Wpf/QuickInfo/ProjectionBufferContent.cs
+++ b/src/EditorFeatures/Core.Wpf/QuickInfo/ProjectionBufferContent.cs
@@ -97,7 +97,7 @@ private IWpfTextView CreateView(ITextBuffer buffer)
private IProjectionBuffer CreateBuffer()
{
return _projectionBufferFactoryService.CreateProjectionBufferWithoutIndentation(
- _editorOptionsService.Factory.GlobalOptions, _contentType, _spans.ToArray());
+ _editorOptionsService.Factory.GlobalOptions, _contentType, [.. _spans]);
}
}
}
diff --git a/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSource.cs b/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSource.cs
index be975381ed17e..f4f2be82f379a 100644
--- a/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSource.cs
+++ b/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSource.cs
@@ -21,6 +21,7 @@
using Microsoft.VisualStudio.Language.Intellisense;
using Microsoft.VisualStudio.Text;
using Microsoft.VisualStudio.Text.Editor;
+using Microsoft.VisualStudio.Threading;
using Roslyn.Utilities;
using IUIThreadOperationContext = Microsoft.VisualStudio.Utilities.IUIThreadOperationContext;
@@ -60,11 +61,7 @@ public SuggestedActionsSource(
}
public void Dispose()
- {
- _state.Dispose();
- }
-
- private ReferenceCountedDisposable SourceState => _state;
+ => _state.Dispose();
public bool TryGetTelemetryId(out Guid telemetryId)
{
@@ -122,21 +119,6 @@ public bool TryGetTelemetryId(out Guid telemetryId)
IUIThreadOperationContext operationContext)
=> null;
- private static string GetFixCategory(DiagnosticSeverity severity)
- {
- switch (severity)
- {
- case DiagnosticSeverity.Hidden:
- case DiagnosticSeverity.Info:
- case DiagnosticSeverity.Warning:
- return PredefinedSuggestedActionCategoryNames.CodeFix;
- case DiagnosticSeverity.Error:
- return PredefinedSuggestedActionCategoryNames.ErrorFix;
- default:
- throw ExceptionUtilities.Unreachable();
- }
- }
-
public Task HasSuggestedActionsAsync(
ISuggestedActionCategorySet requestedActionCategories,
SnapshotSpan range,
@@ -146,143 +128,6 @@ public Task HasSuggestedActionsAsync(
throw new NotImplementedException($"We implement {nameof(GetSuggestedActionCategoriesAsync)}. This should not be called.");
}
- private async Task GetSpanAsync(ReferenceCountedDisposable state, SnapshotSpan range, CancellationToken cancellationToken)
- {
- // First, ensure that the snapshot we're being asked about is for an actual
- // roslyn document. This can fail, for example, in projection scenarios where
- // we are called with a range snapshot that refers to the projection buffer
- // and not the actual roslyn code that is being projected into it.
- var document = range.Snapshot.GetOpenTextDocumentInCurrentContextWithChanges();
- if (document == null)
- {
- return null;
- }
-
- // Also make sure the range is from the same buffer that this source was created for
- Contract.ThrowIfFalse(
- range.Snapshot.TextBuffer.Equals(state.Target.SubjectBuffer),
- $"Invalid text buffer passed to {nameof(HasSuggestedActionsAsync)}");
-
- // Next, before we do any async work, acquire the user's selection, directly grabbing
- // it from the UI thread if that's what we're on. That way we don't have any reentrancy
- // blocking concerns if VS wants to block on this call (for example, if the user
- // explicitly invokes the 'show smart tag' command).
- //
- // This work must happen on the UI thread as it needs to access the _textView's mutable
- // state.
- //
- // Note: we may be called in one of two VS scenarios:
- // 1) User has moved caret to a new line. In this case VS will call into us in the
- // bg to see if we have any suggested actions for this line. In order to figure
- // this out, we need to see what selection the user has (for refactorings), which
- // necessitates going back to the fg.
- //
- // 2) User moves to a line and immediately hits ctrl-dot. In this case, on the UI
- // thread VS will kick us off and then immediately block to get the results so
- // that they can expand the light-bulb. In this case we cannot do BG work first,
- // then call back into the UI thread to try to get the user selection. This will
- // deadlock as the UI thread is blocked on us.
- //
- // There are two solution to '2'. Either introduce reentrancy (which we really don't
- // like to do), or just ensure that we acquire and get the users selection up front.
- // This means that when we're called from the UI thread, we never try to go back to the
- // UI thread.
- TextSpan? selection = null;
- if (_threadingContext.JoinableTaskContext.IsOnMainThread)
- {
- selection = TryGetCodeRefactoringSelection(state, range);
- }
- else
- {
- await _threadingContext.InvokeBelowInputPriorityAsync(() =>
- {
- // Make sure we were not disposed between kicking off this work and getting to this point.
- using var state = _state.TryAddReference();
- if (state is null)
- return;
-
- selection = TryGetCodeRefactoringSelection(state, range);
- }, cancellationToken).ConfigureAwait(false);
- }
-
- return selection;
- }
-
- private static async Task GetFixLevelAsync(
- ReferenceCountedDisposable state,
- TextDocument document,
- SnapshotSpan range,
- CodeActionOptionsProvider fallbackOptions,
- CancellationToken cancellationToken)
- {
- var lowPriorityAnalyzers = new ConcurrentSet();
-
- foreach (var order in Orderings)
- {
- var priority = TryGetPriority(order);
- Contract.ThrowIfNull(priority);
- var priorityProvider = new SuggestedActionPriorityProvider(priority.Value, lowPriorityAnalyzers);
-
- var result = await GetFixLevelAsync(priorityProvider).ConfigureAwait(false);
- if (result != null)
- return result;
- }
-
- return null;
-
- async Task GetFixLevelAsync(ICodeActionRequestPriorityProvider priorityProvider)
- {
- if (state.Target.Owner._codeFixService != null &&
- state.Target.SubjectBuffer.SupportsCodeFixes())
- {
- var result = await state.Target.Owner._codeFixService.GetMostSevereFixAsync(
- document, range.Span.ToTextSpan(), priorityProvider, fallbackOptions, cancellationToken).ConfigureAwait(false);
-
- if (result.HasFix)
- {
- Logger.Log(FunctionId.SuggestedActions_HasSuggestedActionsAsync);
- return GetFixCategory(result.CodeFixCollection.FirstDiagnostic.Severity);
- }
-
- if (!result.UpToDate)
- return null;
- }
-
- return null;
- }
- }
-
- private async Task TryGetRefactoringSuggestedActionCategoryAsync(
- TextDocument document,
- TextSpan? selection,
- CodeActionOptionsProvider fallbackOptions,
- CancellationToken cancellationToken)
- {
- using var state = _state.TryAddReference();
- if (state is null)
- return null;
-
- if (!selection.HasValue)
- {
- // this is here to fail test and see why it is failed.
- Trace.WriteLine("given range is not current");
- return null;
- }
-
- if (GlobalOptions.GetOption(EditorComponentOnOffOptions.CodeRefactorings) &&
- state.Target.Owner._codeRefactoringService != null &&
- state.Target.SubjectBuffer.SupportsRefactorings())
- {
- if (await state.Target.Owner._codeRefactoringService.HasRefactoringsAsync(
- document, selection.Value, fallbackOptions, cancellationToken).ConfigureAwait(false))
- {
- return PredefinedSuggestedActionCategoryNames.Refactoring;
- }
- }
-
- return null;
- }
-
private TextSpan? TryGetCodeRefactoringSelection(ReferenceCountedDisposable state, SnapshotSpan range)
{
_threadingContext.ThrowIfNotOnUIThread();
@@ -294,17 +139,13 @@ await _threadingContext.InvokeBelowInputPriorityAsync(() =>
// We only support refactorings when there is a single selection in the document.
if (selectedSpans.Count != 1)
- {
return null;
- }
var translatedSpan = selectedSpans[0].TranslateTo(range.Snapshot, SpanTrackingMode.EdgeInclusive);
// We only support refactorings when selected span intersects with the span that the light bulb is asking for.
if (!translatedSpan.IntersectsWith(range))
- {
return null;
- }
return translatedSpan.Span.ToTextSpan();
}
@@ -318,6 +159,11 @@ private void OnTextViewClosed(object sender, EventArgs e)
if (state is null)
return null;
+ // Make sure the range is from the same buffer that this source was created for.
+ Contract.ThrowIfFalse(
+ range.Snapshot.TextBuffer.Equals(state.Target.SubjectBuffer),
+ $"Invalid text buffer passed to {nameof(HasSuggestedActionsAsync)}");
+
var workspace = state.Target.Workspace;
if (workspace == null)
return null;
@@ -336,18 +182,22 @@ private void OnTextViewClosed(object sender, EventArgs e)
var fallbackOptions = GlobalOptions.GetCodeActionOptionsProvider();
using var linkedTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
- var linkedToken = linkedTokenSource.Token;
+ // Assign over cancellation token so no one accidentally uses the wrong token.
+ cancellationToken = linkedTokenSource.Token;
- var errorTask = Task.Run(() => GetFixLevelAsync(state, document, range, fallbackOptions, linkedToken), linkedToken);
+ // Kick off the work to get errors.
+ var errorTask = GetFixLevelAsync();
- var selection = await GetSpanAsync(state, range, linkedToken).ConfigureAwait(false);
+ // Make a quick jump back to the UI thread to get the user's selection, then go back to the thread pool..
+ await _threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(alwaysYield: true, cancellationToken);
- var refactoringTask = SpecializedTasks.Null();
- if (selection != null)
- {
- refactoringTask = Task.Run(
- () => TryGetRefactoringSuggestedActionCategoryAsync(document, selection, fallbackOptions, linkedToken), linkedToken);
- }
+ var selection = TryGetCodeRefactoringSelection(state, range);
+ await TaskScheduler.Default;
+
+ // If we have a selection, kick off the work to get refactorings concurrently with the above work to get errors.
+ var refactoringTask = selection != null
+ ? TryGetRefactoringSuggestedActionCategoryAsync(selection)
+ : SpecializedTasks.Null();
// If we happen to get the result of the error task before the refactoring task,
// and that result is non-null, we can just cancel the refactoring task.
@@ -357,6 +207,79 @@ private void OnTextViewClosed(object sender, EventArgs e)
return result == null
? null
: _suggestedActionCategoryRegistry.CreateSuggestedActionCategorySet(result);
+
+ async Task GetFixLevelAsync()
+ {
+ // Ensure we yield the thread that called into us, allowing it to continue onwards.
+ await TaskScheduler.Default.SwitchTo(alwaysYield: true);
+ var lowPriorityAnalyzers = new ConcurrentSet();
+
+ foreach (var order in Orderings)
+ {
+ var priority = TryGetPriority(order);
+ Contract.ThrowIfNull(priority);
+ var priorityProvider = new SuggestedActionPriorityProvider(priority.Value, lowPriorityAnalyzers);
+
+ var result = await GetFixCategoryAsync(priorityProvider).ConfigureAwait(false);
+ if (result != null)
+ return result;
+ }
+
+ return null;
+ }
+
+ async Task GetFixCategoryAsync(ICodeActionRequestPriorityProvider priorityProvider)
+ {
+ if (state.Target.Owner._codeFixService != null &&
+ state.Target.SubjectBuffer.SupportsCodeFixes())
+ {
+ var result = await state.Target.Owner._codeFixService.GetMostSevereFixAsync(
+ document, range.Span.ToTextSpan(), priorityProvider, fallbackOptions, cancellationToken).ConfigureAwait(false);
+
+ if (result.HasFix)
+ {
+ Logger.Log(FunctionId.SuggestedActions_HasSuggestedActionsAsync);
+ return result.CodeFixCollection.FirstDiagnostic.Severity switch
+ {
+
+ DiagnosticSeverity.Hidden or DiagnosticSeverity.Info or DiagnosticSeverity.Warning => PredefinedSuggestedActionCategoryNames.CodeFix,
+ DiagnosticSeverity.Error => PredefinedSuggestedActionCategoryNames.ErrorFix,
+ _ => throw ExceptionUtilities.Unreachable(),
+ };
+ }
+
+ if (!result.UpToDate)
+ return null;
+ }
+
+ return null;
+ }
+
+ async Task TryGetRefactoringSuggestedActionCategoryAsync(TextSpan? selection)
+ {
+ // Ensure we yield the thread that called into us, allowing it to continue onwards.
+ await TaskScheduler.Default.SwitchTo(alwaysYield: true);
+
+ if (!selection.HasValue)
+ {
+ // this is here to fail test and see why it is failed.
+ Trace.WriteLine("given range is not current");
+ return null;
+ }
+
+ if (GlobalOptions.GetOption(EditorComponentOnOffOptions.CodeRefactorings) &&
+ state.Target.Owner._codeRefactoringService != null &&
+ state.Target.SubjectBuffer.SupportsRefactorings())
+ {
+ if (await state.Target.Owner._codeRefactoringService.HasRefactoringsAsync(
+ document, selection.Value, fallbackOptions, cancellationToken).ConfigureAwait(false))
+ {
+ return PredefinedSuggestedActionCategoryNames.Refactoring;
+ }
+ }
+
+ return null;
+ }
}
}
}
diff --git a/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSource_Async.cs b/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSource_Async.cs
index 1a78c33ae59e2..8745781c048a2 100644
--- a/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSource_Async.cs
+++ b/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSource_Async.cs
@@ -70,7 +70,7 @@ private async Task GetSuggestedActionsWorkerAsync(
CancellationToken cancellationToken)
{
_threadingContext.ThrowIfNotOnUIThread();
- using var state = SourceState.TryAddReference();
+ using var state = _state.TryAddReference();
if (state is null)
return;
diff --git a/src/EditorFeatures/Core/CommentSelection/AbstractToggleBlockCommentBase.cs b/src/EditorFeatures/Core/CommentSelection/AbstractToggleBlockCommentBase.cs
index c8c5859d075d5..f025bbca1dd3d 100644
--- a/src/EditorFeatures/Core/CommentSelection/AbstractToggleBlockCommentBase.cs
+++ b/src/EditorFeatures/Core/CommentSelection/AbstractToggleBlockCommentBase.cs
@@ -436,7 +436,7 @@ private ImmutableArray GetUncommentedSpansInSelection()
}
}
- return uncommentedSpans.ToImmutableArray();
+ return [.. uncommentedSpans];
}
}
}
diff --git a/src/EditorFeatures/Core/Editor/TextEditApplication.cs b/src/EditorFeatures/Core/Editor/TextEditApplication.cs
index c4bf5575e8f83..c0acaa4266745 100644
--- a/src/EditorFeatures/Core/Editor/TextEditApplication.cs
+++ b/src/EditorFeatures/Core/Editor/TextEditApplication.cs
@@ -17,7 +17,7 @@ internal static void UpdateText(SourceText newText, ITextBuffer buffer, EditOpti
var oldSnapshot = buffer.CurrentSnapshot;
var oldText = oldSnapshot.AsText();
var changes = newText.GetTextChanges(oldText);
- UpdateText(changes.ToImmutableArray(), buffer, oldSnapshot, oldText, options);
+ UpdateText([.. changes], buffer, oldSnapshot, oldText, options);
}
public static void UpdateText(ImmutableArray textChanges, ITextBuffer buffer, EditOptions options)
diff --git a/src/EditorFeatures/Core/EditorConfigSettings/Aggregator/SettingsAggregator.cs b/src/EditorFeatures/Core/EditorConfigSettings/Aggregator/SettingsAggregator.cs
index ead1708f6bec9..0395dfb45c7fc 100644
--- a/src/EditorFeatures/Core/EditorConfigSettings/Aggregator/SettingsAggregator.cs
+++ b/src/EditorFeatures/Core/EditorConfigSettings/Aggregator/SettingsAggregator.cs
@@ -93,7 +93,7 @@ private static ISettingsProviderFactory GetOptionsProviderFactory(Workspac
TryAddProviderForLanguage(LanguageNames.VisualBasic, workspace, providers);
}
- return new CombinedOptionsProviderFactory(providers.ToImmutableArray());
+ return new CombinedOptionsProviderFactory([.. providers]);
static void TryAddProviderForLanguage(string language, Workspace workspace, List> providers)
{
diff --git a/src/EditorFeatures/Core/EditorConfigSettings/DataProvider/SettingsProviderBase.cs b/src/EditorFeatures/Core/EditorConfigSettings/DataProvider/SettingsProviderBase.cs
index fb310e0fc78f7..b1a04b9621a9f 100644
--- a/src/EditorFeatures/Core/EditorConfigSettings/DataProvider/SettingsProviderBase.cs
+++ b/src/EditorFeatures/Core/EditorConfigSettings/DataProvider/SettingsProviderBase.cs
@@ -88,7 +88,7 @@ public ImmutableArray GetCurrentDataSnapshot()
{
lock (s_gate)
{
- return _snapshot.ToImmutableArray();
+ return [.. _snapshot];
}
}
diff --git a/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/VSTypeScriptInProcLanguageClient.cs b/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/VSTypeScriptInProcLanguageClient.cs
index 78d641cebbfc2..cfc295a276a4d 100644
--- a/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/VSTypeScriptInProcLanguageClient.cs
+++ b/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/VSTypeScriptInProcLanguageClient.cs
@@ -12,6 +12,7 @@
using Microsoft.CodeAnalysis.ExternalAccess.VSTypeScript.Api;
using Microsoft.CodeAnalysis.Host.Mef;
using Microsoft.CodeAnalysis.LanguageServer;
+using Microsoft.CodeAnalysis.LanguageServer.Handler.Diagnostics;
using Microsoft.CodeAnalysis.Options;
using Microsoft.VisualStudio.Composition;
using Microsoft.VisualStudio.LanguageServer.Client;
@@ -57,6 +58,18 @@ public override ServerCapabilities GetCapabilities(ClientCapabilities clientCapa
serverCapabilities.ProjectContextProvider = true;
serverCapabilities.SupportsDiagnosticRequests = true;
+ serverCapabilities.DiagnosticProvider = new()
+ {
+ SupportsMultipleContextsDiagnostics = true,
+ DiagnosticKinds =
+ [
+ new(PullDiagnosticCategories.Task),
+ new(PullDiagnosticCategories.WorkspaceDocumentsAndProject),
+ new(PullDiagnosticCategories.DocumentAnalyzerSyntax),
+ new(PullDiagnosticCategories.DocumentAnalyzerSemantic),
+ ]
+ };
+
return serverCapabilities;
}
diff --git a/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/VSTypeScriptPullDiagnosticHandlerProvider.cs b/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/VSTypeScriptPullDiagnosticHandlerProvider.cs
index da2e663f06bfd..b5527e89596a0 100644
--- a/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/VSTypeScriptPullDiagnosticHandlerProvider.cs
+++ b/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/VSTypeScriptPullDiagnosticHandlerProvider.cs
@@ -8,6 +8,7 @@
using Microsoft.CodeAnalysis.Host.Mef;
using Microsoft.CodeAnalysis.LanguageServer;
using Microsoft.CodeAnalysis.LanguageServer.Handler.Diagnostics;
+using Microsoft.CodeAnalysis.LanguageServer.Handler.Diagnostics.DiagnosticSources;
using Microsoft.CodeAnalysis.Options;
namespace Microsoft.CodeAnalysis.ExternalAccess.VSTypeScript;
@@ -17,8 +18,9 @@ namespace Microsoft.CodeAnalysis.ExternalAccess.VSTypeScript;
[method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)]
internal class VSTypeScriptDocumentPullDiagnosticHandlerFactory(
IDiagnosticAnalyzerService analyzerService,
+ IDiagnosticSourceManager diagnosticSourceManager,
IDiagnosticsRefresher diagnosticsRefresher,
- IGlobalOptionService globalOptions) : DocumentPullDiagnosticHandlerFactory(analyzerService, diagnosticsRefresher, globalOptions)
+ IGlobalOptionService globalOptions) : DocumentPullDiagnosticHandlerFactory(analyzerService, diagnosticSourceManager, diagnosticsRefresher, globalOptions)
{
}
@@ -28,7 +30,8 @@ internal class VSTypeScriptDocumentPullDiagnosticHandlerFactory(
internal class VSTypeScriptWorkspacePullDiagnosticHandler(
LspWorkspaceRegistrationService registrationService,
IDiagnosticAnalyzerService analyzerService,
+ IDiagnosticSourceManager diagnosticSourceManager,
IDiagnosticsRefresher diagnosticsRefresher,
- IGlobalOptionService globalOptions) : WorkspacePullDiagnosticHandlerFactory(registrationService, analyzerService, diagnosticsRefresher, globalOptions)
+ IGlobalOptionService globalOptions) : WorkspacePullDiagnosticHandlerFactory(registrationService, analyzerService, diagnosticSourceManager, diagnosticsRefresher, globalOptions)
{
}
diff --git a/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs b/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs
index fe13da5eaac87..4f30186d98c73 100644
--- a/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs
+++ b/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs
@@ -319,7 +319,7 @@ private void UpdateReferenceLocationsTask()
// https://github.com/dotnet/roslyn/issues/40890
await _threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(alwaysYield: true, cancellationToken);
- RaiseSessionSpansUpdated(inlineRenameLocations.Locations.ToImmutableArray());
+ RaiseSessionSpansUpdated([.. inlineRenameLocations.Locations]);
return inlineRenameLocations;
});
diff --git a/src/EditorFeatures/Core/IntelliSense/AsyncCompletion/CompletionSource.cs b/src/EditorFeatures/Core/IntelliSense/AsyncCompletion/CompletionSource.cs
index 2f738faae61df..df4f024f6bedc 100644
--- a/src/EditorFeatures/Core/IntelliSense/AsyncCompletion/CompletionSource.cs
+++ b/src/EditorFeatures/Core/IntelliSense/AsyncCompletion/CompletionSource.cs
@@ -82,7 +82,7 @@ internal CompletionSource(
_asyncListener = asyncListener;
_editorOptionsService = editorOptionsService;
_isDebuggerTextView = textView is IDebuggerTextView;
- _roles = textView.Roles.ToImmutableHashSet();
+ _roles = [.. textView.Roles];
}
public AsyncCompletionData.CompletionStartData InitializeCompletion(
diff --git a/src/EditorFeatures/Core/LanguageServer/AlwaysActivateInProcLanguageClient.cs b/src/EditorFeatures/Core/LanguageServer/AlwaysActivateInProcLanguageClient.cs
index e4ce2a8eacb29..dacbc7633a275 100644
--- a/src/EditorFeatures/Core/LanguageServer/AlwaysActivateInProcLanguageClient.cs
+++ b/src/EditorFeatures/Core/LanguageServer/AlwaysActivateInProcLanguageClient.cs
@@ -12,6 +12,7 @@
using Microsoft.CodeAnalysis.Host.Mef;
using Microsoft.CodeAnalysis.LanguageServer;
using Microsoft.CodeAnalysis.LanguageServer.Handler.Diagnostics;
+using Microsoft.CodeAnalysis.LanguageServer.Handler.Diagnostics.DiagnosticSources;
using Microsoft.CodeAnalysis.LanguageServer.Handler.SemanticTokens;
using Microsoft.CodeAnalysis.Options;
using Microsoft.VisualStudio.Composition;
@@ -40,9 +41,11 @@ internal class AlwaysActivateInProcLanguageClient(
ILspServiceLoggerFactory lspLoggerFactory,
IThreadingContext threadingContext,
ExportProvider exportProvider,
+ IDiagnosticSourceManager diagnosticSourceManager,
[ImportMany] IEnumerable> buildOnlyDiagnostics) : AbstractInProcLanguageClient(lspServiceProvider, globalOptions, lspLoggerFactory, threadingContext, exportProvider)
{
private readonly ExperimentalCapabilitiesProvider _experimentalCapabilitiesProvider = defaultCapabilitiesProvider;
+ private readonly IDiagnosticSourceManager _diagnosticSourceManager = diagnosticSourceManager;
private readonly IEnumerable> _buildOnlyDiagnostics = buildOnlyDiagnostics;
protected override ImmutableArray SupportedLanguages => ProtocolConstants.RoslynLspLanguages;
@@ -69,28 +72,15 @@ public override ServerCapabilities GetCapabilities(ClientCapabilities clientCapa
serverCapabilities.SupportsDiagnosticRequests = true;
serverCapabilities.DiagnosticProvider ??= new();
+
+ // VS does not distinguish between document and workspace diagnostics, so we need to merge them.
+ var diagnosticSourceNames = _diagnosticSourceManager.GetDocumentSourceProviderNames()
+ .Concat(_diagnosticSourceManager.GetWorkspaceSourceProviderNames())
+ .Distinct();
serverCapabilities.DiagnosticProvider = serverCapabilities.DiagnosticProvider with
{
SupportsMultipleContextsDiagnostics = true,
- DiagnosticKinds =
- [
- // Support a specialized requests dedicated to task-list items. This way the client can ask just
- // for these, independently of other diagnostics. They can also throttle themselves to not ask if
- // the task list would not be visible.
- new(PullDiagnosticCategories.Task),
- new(PullDiagnosticCategories.EditAndContinue),
- // Dedicated request for workspace-diagnostics only. We will only respond to these if FSA is on.
- new(PullDiagnosticCategories.WorkspaceDocumentsAndProject),
- // Fine-grained diagnostics requests. Importantly, this separates out syntactic vs semantic
- // requests, allowing the former to quickly reach the user without blocking on the latter. In a
- // similar vein, compiler diagnostics are explicitly distinct from analyzer-diagnostics, allowing
- // the former to appear as soon as possible as they are much more critical for the user and should
- // not be delayed by a slow analyzer.
- new(PullDiagnosticCategories.DocumentCompilerSyntax),
- new(PullDiagnosticCategories.DocumentCompilerSemantic),
- new(PullDiagnosticCategories.DocumentAnalyzerSyntax),
- new(PullDiagnosticCategories.DocumentAnalyzerSemantic),
- ],
+ DiagnosticKinds = diagnosticSourceNames.Select(n => new VSInternalDiagnosticKind(n)).ToArray(),
BuildOnlyDiagnosticIds = _buildOnlyDiagnostics
.SelectMany(lazy => lazy.Metadata.BuildOnlyDiagnostics)
.Distinct()
@@ -118,7 +108,7 @@ public override ServerCapabilities GetCapabilities(ClientCapabilities clientCapa
Range = true,
Legend = new SemanticTokensLegend
{
- TokenTypes = SemanticTokensSchema.GetSchema(clientCapabilities.HasVisualStudioLspCapability()).AllTokenTypes.ToArray(),
+ TokenTypes = [.. SemanticTokensSchema.GetSchema(clientCapabilities.HasVisualStudioLspCapability()).AllTokenTypes],
TokenModifiers = SemanticTokensSchema.TokenModifiers
}
};
diff --git a/src/EditorFeatures/Core/NavigationBar/NavigationBarController.cs b/src/EditorFeatures/Core/NavigationBar/NavigationBarController.cs
index abce7a9ad1c88..385423e295bc6 100644
--- a/src/EditorFeatures/Core/NavigationBar/NavigationBarController.cs
+++ b/src/EditorFeatures/Core/NavigationBar/NavigationBarController.cs
@@ -215,13 +215,13 @@ private void GetProjectItems(out ImmutableArray projec
return;
}
- projectItems = documents.Select(d =>
+ projectItems = [.. documents.Select(d =>
new NavigationBarProjectItem(
d.Project.Name,
d.Project.GetGlyph(),
workspace: d.Project.Solution.Workspace,
documentId: d.Id,
- language: d.Project.Language)).OrderBy(projectItem => projectItem.Text).ToImmutableArray();
+ language: d.Project.Language)).OrderBy(projectItem => projectItem.Text)];
var document = _subjectBuffer.AsTextContainer().GetOpenDocumentInCurrentContext();
selectedProjectItem = document != null
diff --git a/src/EditorFeatures/Core/Preview/AbstractPreviewFactoryService.cs b/src/EditorFeatures/Core/Preview/AbstractPreviewFactoryService.cs
index 75a264060fcc5..fae0c03b08895 100644
--- a/src/EditorFeatures/Core/Preview/AbstractPreviewFactoryService.cs
+++ b/src/EditorFeatures/Core/Preview/AbstractPreviewFactoryService.cs
@@ -589,7 +589,7 @@ public Task> CreateRemovedAnalyzerCo
oldBuffer.CurrentSnapshot,
"...",
description,
- originalSpans.ToArray());
+ [.. originalSpans]);
var changedBuffer = _projectionBufferFactoryService.CreateProjectionBufferWithoutIndentation(
_contentTypeRegistryService,
@@ -597,7 +597,7 @@ public Task> CreateRemovedAnalyzerCo
newBuffer.CurrentSnapshot,
"...",
description,
- changedSpans.ToArray());
+ [.. changedSpans]);
#pragma warning disable CA2007 // Consider calling ConfigureAwait on the awaited task (containing method uses JTF)
return await CreateNewDifferenceViewerAsync(leftWorkspace, rightWorkspace, originalBuffer, changedBuffer, zoomLevel, cancellationToken);
diff --git a/src/EditorFeatures/Core/Remote/SolutionChecksumUpdater.cs b/src/EditorFeatures/Core/Remote/SolutionChecksumUpdater.cs
index 92187c42e3748..805117ccedac8 100644
--- a/src/EditorFeatures/Core/Remote/SolutionChecksumUpdater.cs
+++ b/src/EditorFeatures/Core/Remote/SolutionChecksumUpdater.cs
@@ -28,18 +28,25 @@ internal sealed class SolutionChecksumUpdater
///
private readonly IGlobalOperationNotificationService? _globalOperationService;
+ private readonly IDocumentTrackingService _documentTrackingService;
+
///
/// Queue to push out text changes in a batched fashion when we hear about them. Because these should be short
/// operations (only syncing text changes) we don't cancel this when we enter the paused state. We simply don't
/// start queuing more requests into this until we become unpaused.
///
- private readonly AsyncBatchingWorkQueue<(Document? oldDocument, Document? newDocument)> _textChangeQueue;
+ private readonly AsyncBatchingWorkQueue<(Document oldDocument, Document newDocument)> _textChangeQueue;
///
/// Queue for kicking off the work to synchronize the primary workspace's solution.
///
private readonly AsyncBatchingWorkQueue _synchronizeWorkspaceQueue;
+ ///
+ /// Queue for kicking off the work to synchronize the active document to the remote process.
+ ///
+ private readonly AsyncBatchingWorkQueue _synchronizeActiveDocumentQueue;
+
private readonly object _gate = new();
private bool _isPaused;
@@ -53,8 +60,9 @@ public SolutionChecksumUpdater(
_globalOperationService = workspace.Services.SolutionServices.ExportProvider.GetExports().FirstOrDefault()?.Value;
_workspace = workspace;
+ _documentTrackingService = workspace.Services.GetRequiredService();
- _textChangeQueue = new AsyncBatchingWorkQueue<(Document? oldDocument, Document? newDocument)>(
+ _textChangeQueue = new AsyncBatchingWorkQueue<(Document oldDocument, Document newDocument)>(
DelayTimeSpan.NearImmediate,
SynchronizeTextChangesAsync,
listener,
@@ -66,8 +74,15 @@ public SolutionChecksumUpdater(
listener,
shutdownToken);
+ _synchronizeActiveDocumentQueue = new AsyncBatchingWorkQueue(
+ DelayTimeSpan.NearImmediate,
+ SynchronizeActiveDocumentAsync,
+ listener,
+ shutdownToken);
+
// start listening workspace change event
_workspace.WorkspaceChanged += OnWorkspaceChanged;
+ _documentTrackingService.ActiveDocumentChanged += OnActiveDocumentChanged;
if (_globalOperationService != null)
{
@@ -84,6 +99,7 @@ public void Shutdown()
// Try to stop any work that is in progress.
PauseWork();
+ _documentTrackingService.ActiveDocumentChanged -= OnActiveDocumentChanged;
_workspace.WorkspaceChanged -= OnWorkspaceChanged;
if (_globalOperationService != null)
@@ -106,6 +122,7 @@ private void PauseWork()
lock (_gate)
{
_synchronizeWorkspaceQueue.CancelExistingWork();
+ _synchronizeActiveDocumentQueue.CancelExistingWork();
_isPaused = true;
}
}
@@ -115,6 +132,7 @@ private void ResumeWork()
lock (_gate)
{
_isPaused = false;
+ _synchronizeActiveDocumentQueue.AddWork();
_synchronizeWorkspaceQueue.AddWork();
}
}
@@ -131,12 +149,18 @@ private void OnWorkspaceChanged(object? sender, WorkspaceChangeEventArgs e)
if (e.Kind == WorkspaceChangeKind.DocumentChanged)
{
- _textChangeQueue.AddWork((e.OldSolution.GetDocument(e.DocumentId), e.NewSolution.GetDocument(e.DocumentId)));
+ var oldDocument = e.OldSolution.GetDocument(e.DocumentId);
+ var newDocument = e.NewSolution.GetDocument(e.DocumentId);
+ if (oldDocument != null && newDocument != null)
+ _textChangeQueue.AddWork((oldDocument, newDocument));
}
_synchronizeWorkspaceQueue.AddWork();
}
+ private void OnActiveDocumentChanged(object? sender, DocumentId? e)
+ => _synchronizeActiveDocumentQueue.AddWork();
+
private async ValueTask SynchronizePrimaryWorkspaceAsync(CancellationToken cancellationToken)
{
var solution = _workspace.CurrentSolution;
@@ -153,15 +177,26 @@ await client.TryInvokeAsync(
}
}
+ private async ValueTask SynchronizeActiveDocumentAsync(CancellationToken cancellationToken)
+ {
+ var activeDocument = _documentTrackingService.TryGetActiveDocument();
+
+ var client = await RemoteHostClient.TryGetClientAsync(_workspace, cancellationToken).ConfigureAwait(false);
+ if (client == null)
+ return;
+
+ var solution = _workspace.CurrentSolution;
+ await client.TryInvokeAsync(
+ (service, cancellationToken) => service.SynchronizeActiveDocumentAsync(activeDocument, cancellationToken),
+ cancellationToken).ConfigureAwait(false);
+ }
+
private async ValueTask SynchronizeTextChangesAsync(
- ImmutableSegmentedList<(Document? oldDocument, Document? newDocument)> values,
+ ImmutableSegmentedList<(Document oldDocument, Document newDocument)> values,
CancellationToken cancellationToken)
{
foreach (var (oldDocument, newDocument) in values)
{
- if (oldDocument is null || newDocument is null)
- continue;
-
cancellationToken.ThrowIfCancellationRequested();
await SynchronizeTextChangesAsync(oldDocument, newDocument, cancellationToken).ConfigureAwait(false);
}
@@ -194,15 +229,15 @@ async ValueTask SynchronizeTextChangesAsync(Document oldDocument, Document newDo
}
// get text changes
- var textChanges = newText.GetTextChanges(oldText);
- if (textChanges.Count == 0)
+ var textChanges = newText.GetTextChanges(oldText).AsImmutable();
+ if (textChanges.Length == 0)
{
// no changes
return;
}
// whole document case
- if (textChanges.Count == 1 && textChanges[0].Span.Length == oldText.Length)
+ if (textChanges.Length == 1 && textChanges[0].Span.Length == oldText.Length)
{
// no benefit here. pulling from remote host is more efficient
return;
diff --git a/src/EditorFeatures/Core/Shared/Utilities/IThreadingContextExtensions.cs b/src/EditorFeatures/Core/Shared/Utilities/IThreadingContextExtensions.cs
deleted file mode 100644
index 069816e08b4e7..0000000000000
--- a/src/EditorFeatures/Core/Shared/Utilities/IThreadingContextExtensions.cs
+++ /dev/null
@@ -1,57 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System;
-using System.Diagnostics;
-using System.Threading;
-using System.Threading.Tasks;
-using Roslyn.Utilities;
-
-namespace Microsoft.CodeAnalysis.Editor.Shared.Utilities;
-
-internal static class IThreadingContextExtensions
-{
- ///
- /// Returns true if any keyboard or mouse button input is pending on the message queue.
- ///
- public static bool IsInputPending()
- {
- // The code below invokes into user32.dll, which is not available in non-Windows.
- if (PlatformInformation.IsUnix)
- {
- return false;
- }
-
- // The return value of GetQueueStatus is HIWORD:LOWORD.
- // A non-zero value in HIWORD indicates some input message in the queue.
- var result = NativeMethods.GetQueueStatus(NativeMethods.QS_INPUT);
-
- const uint InputMask = NativeMethods.QS_INPUT | (NativeMethods.QS_INPUT << 16);
- return (result & InputMask) != 0;
- }
-
- public static Task InvokeBelowInputPriorityAsync(this IThreadingContext threadingContext, Action action, CancellationToken cancellationToken = default)
- {
- if (threadingContext.JoinableTaskContext.IsOnMainThread && !IsInputPending())
- {
- // Optimize to inline the action if we're already on the foreground thread
- // and there's no pending user input.
- action();
-
- return Task.CompletedTask;
- }
- else
- {
- return Task.Factory.SafeStartNewFromAsync(
- async () =>
- {
- await threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken);
-
- action();
- },
- cancellationToken,
- TaskScheduler.Default);
- }
- }
-}
diff --git a/src/EditorFeatures/Core/Shared/Utilities/IUIContextActivationService.cs b/src/EditorFeatures/Core/Shared/Utilities/IUIContextActivationService.cs
new file mode 100644
index 0000000000000..a68e544abd1b4
--- /dev/null
+++ b/src/EditorFeatures/Core/Shared/Utilities/IUIContextActivationService.cs
@@ -0,0 +1,15 @@
+// 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;
+
+namespace Microsoft.CodeAnalysis.Editor.Shared.Utilities;
+
+internal interface IUIContextActivationService
+{
+ ///
+ /// Executes the specified action when the UIContext first becomes active, or immediately if it is already active
+ ///
+ void ExecuteWhenActivated(Guid uiContext, Action action);
+}
diff --git a/src/EditorFeatures/Test/CodeFixes/CodeFixServiceTests.cs b/src/EditorFeatures/Test/CodeFixes/CodeFixServiceTests.cs
index 7cafd90ce14eb..0594aa086c502 100644
--- a/src/EditorFeatures/Test/CodeFixes/CodeFixServiceTests.cs
+++ b/src/EditorFeatures/Test/CodeFixes/CodeFixServiceTests.cs
@@ -1079,8 +1079,9 @@ void M()
? root.DescendantNodes().OfType().First().Span
: root.DescendantNodes().OfType().First().Span;
- await diagnosticIncrementalAnalyzer.GetDiagnosticsAsync(
- sourceDocument.Project.Solution, sourceDocument.Project.Id, sourceDocument.Id, includeSuppressedDiagnostics: true, includeNonLocalDocumentDiagnostics: true, CancellationToken.None);
+ await diagnosticIncrementalAnalyzer.GetDiagnosticsForIdsAsync(
+ sourceDocument.Project.Solution, sourceDocument.Project.Id, sourceDocument.Id, diagnosticIds: null, shouldIncludeAnalyzer: null, getDocuments: null,
+ includeSuppressedDiagnostics: true, includeLocalDocumentDiagnostics: true, includeNonLocalDocumentDiagnostics: true, CancellationToken.None);
await diagnosticIncrementalAnalyzer.GetTestAccessor().TextDocumentOpenAsync(sourceDocument);
var lowPriorityAnalyzers = new ConcurrentSet();
diff --git a/src/EditorFeatures/Test/CodeFixes/ExtensionOrderingTests.cs b/src/EditorFeatures/Test/CodeFixes/ExtensionOrderingTests.cs
index 687c123b63ba3..8541cd06e00ff 100644
--- a/src/EditorFeatures/Test/CodeFixes/ExtensionOrderingTests.cs
+++ b/src/EditorFeatures/Test/CodeFixes/ExtensionOrderingTests.cs
@@ -48,7 +48,7 @@ public void TestNoCyclesInFixProviders()
var vbProviders = providersPerLanguage[LanguageNames.VisualBasic];
ExtensionOrderer.TestAccessor.CheckForCycles(vbProviders);
- actualOrder = ExtensionOrderer.Order(vbProviders).ToArray();
+ actualOrder = [.. ExtensionOrderer.Order(vbProviders)];
Assert.True(actualOrder.Length > 0);
Assert.True(actualOrder.IndexOf(p => p.Metadata.Name == PredefinedCodeFixProviderNames.AddImport) <
actualOrder.IndexOf(p => p.Metadata.Name == PredefinedCodeFixProviderNames.FullyQualify));
@@ -106,7 +106,7 @@ public void TestNoCyclesInRefactoringProviders()
var vbProviders = providersPerLanguage[LanguageNames.VisualBasic];
ExtensionOrderer.TestAccessor.CheckForCycles(vbProviders);
- actualOrder = ExtensionOrderer.Order(vbProviders).ToArray();
+ actualOrder = [.. ExtensionOrderer.Order(vbProviders)];
Assert.True(actualOrder.Length > 0);
}
diff --git a/src/EditorFeatures/Test/Diagnostics/DiagnosticAnalyzerServiceTests.cs b/src/EditorFeatures/Test/Diagnostics/DiagnosticAnalyzerServiceTests.cs
index 9fb93970e27cf..2c7e97f9e7084 100644
--- a/src/EditorFeatures/Test/Diagnostics/DiagnosticAnalyzerServiceTests.cs
+++ b/src/EditorFeatures/Test/Diagnostics/DiagnosticAnalyzerServiceTests.cs
@@ -12,20 +12,16 @@
using Microsoft.CodeAnalysis.CSharp.RemoveUnnecessarySuppressions;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Diagnostics.CSharp;
-using Microsoft.CodeAnalysis.Diagnostics.EngineV2;
using Microsoft.CodeAnalysis.Editor.Test;
-using Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces;
using Microsoft.CodeAnalysis.Options;
using Microsoft.CodeAnalysis.PooledObjects;
using Microsoft.CodeAnalysis.Remote.Diagnostics;
using Microsoft.CodeAnalysis.Remote.Testing;
using Microsoft.CodeAnalysis.Shared.Extensions;
-using Microsoft.CodeAnalysis.Shared.TestHooks;
using Microsoft.CodeAnalysis.Simplification;
using Microsoft.CodeAnalysis.SolutionCrawler;
using Microsoft.CodeAnalysis.Test.Utilities;
using Microsoft.CodeAnalysis.Text;
-using Microsoft.CodeAnalysis.UnitTests;
using Roslyn.Test.Utilities;
using Roslyn.Test.Utilities.TestGenerators;
using Roslyn.Utilities;
@@ -71,8 +67,9 @@ public async Task TestHasSuccessfullyLoadedBeingFalse()
var analyzer = service.CreateIncrementalAnalyzer(workspace);
var globalOptions = exportProvider.GetExportedValue();
- var diagnostics = await analyzer.GetDiagnosticsAsync(
- workspace.CurrentSolution, projectId: null, documentId: null, includeSuppressedDiagnostics: false, includeNonLocalDocumentDiagnostics: false, CancellationToken.None);
+ var diagnostics = await analyzer.GetDiagnosticsForIdsAsync(
+ workspace.CurrentSolution, projectId: null, documentId: null, diagnosticIds: null, shouldIncludeAnalyzer: null, getDocuments: null,
+ includeSuppressedDiagnostics: false, includeLocalDocumentDiagnostics: true, includeNonLocalDocumentDiagnostics: false, CancellationToken.None);
Assert.NotEmpty(diagnostics);
}
diff --git a/src/EditorFeatures/Test/Emit/CompilationOutputsTests.cs b/src/EditorFeatures/Test/Emit/CompilationOutputsTests.cs
index ca2b47721d8d9..434fcf3f2cd69 100644
--- a/src/EditorFeatures/Test/Emit/CompilationOutputsTests.cs
+++ b/src/EditorFeatures/Test/Emit/CompilationOutputsTests.cs
@@ -61,7 +61,7 @@ public void AssemblyAndPdb(DebugInformationFormat format)
Stream? currentPdbStream = null;
var outputs = new TestCompilationOutputs(
- openAssemblyStream: () => currentPEStream = new MemoryStream(peImage.ToArray()),
+ openAssemblyStream: () => currentPEStream = new MemoryStream([.. peImage]),
openPdbStream: () =>
{
if (pdbStream == null)
diff --git a/src/EditorFeatures/Test/Structure/StructureTaggerTests.cs b/src/EditorFeatures/Test/Structure/StructureTaggerTests.cs
index 793df59acf65f..00ceef681f06d 100644
--- a/src/EditorFeatures/Test/Structure/StructureTaggerTests.cs
+++ b/src/EditorFeatures/Test/Structure/StructureTaggerTests.cs
@@ -339,7 +339,7 @@ private static async Task> GetTagsFromWorkspaceAsyn
var context = new TaggerContext(document, view.TextSnapshot, frozenPartialSemantics: false);
await provider.GetTestAccessor().ProduceTagsAsync(context);
- return context.TagSpans.Select(x => x.Tag).OrderBy(t => t.OutliningSpan.Value.Start).ToList();
+ return [.. context.TagSpans.Select(x => x.Tag).OrderBy(t => t.OutliningSpan.Value.Start)];
}
#pragma warning restore CS0618 // Type or member is obsolete
diff --git a/src/EditorFeatures/Test/Utilities/AsynchronousOperationListenerTests.cs b/src/EditorFeatures/Test/Utilities/AsynchronousOperationListenerTests.cs
index 09da0aa6cb580..c364f5a0ffd40 100644
--- a/src/EditorFeatures/Test/Utilities/AsynchronousOperationListenerTests.cs
+++ b/src/EditorFeatures/Test/Utilities/AsynchronousOperationListenerTests.cs
@@ -35,7 +35,7 @@ public void Dispose()
lock (_tasks)
{
_tokenSource.Cancel();
- tasks = _tasks.ToArray();
+ tasks = [.. _tasks];
}
try
diff --git a/src/EditorFeatures/Test/Utilities/BloomFilterTests.cs b/src/EditorFeatures/Test/Utilities/BloomFilterTests.cs
index d8fd33a73fc2c..33bff5542e174 100644
--- a/src/EditorFeatures/Test/Utilities/BloomFilterTests.cs
+++ b/src/EditorFeatures/Test/Utilities/BloomFilterTests.cs
@@ -41,7 +41,8 @@ private static string GenerateString(int value)
return builder.ToString();
}
- private static void Test(bool isCaseSensitive)
+ [Theory, CombinatorialData]
+ public void Test(bool isCaseSensitive)
{
var comparer = isCaseSensitive ? StringComparer.Ordinal : StringComparer.OrdinalIgnoreCase;
var strings = new HashSet(GenerateStrings(2000).Skip(500).Take(1000), comparer);
@@ -79,14 +80,6 @@ private static void Test(bool isCaseSensitive)
}
}
- [Fact]
- public void Test1()
- => Test(isCaseSensitive: true);
-
- [Fact]
- public void TestInsensitive()
- => Test(isCaseSensitive: false);
-
[Fact]
public void TestEmpty()
{
@@ -106,6 +99,33 @@ public void TestEmpty()
}
}
+ [Fact]
+ public void TestCacheWhenEmpty()
+ {
+ BloomFilter.BloomFilterHash.ResetCachedEntry();
+
+ _ = new BloomFilter(falsePositiveProbability: 0.0001, isCaseSensitive: false, []);
+
+ Assert.False(BloomFilter.BloomFilterHash.TryGetCachedEntry(out _, out _));
+ }
+
+ [Fact]
+ public void TestCacheAfterCalls()
+ {
+ var filter1 = new BloomFilter(falsePositiveProbability: 0.0001, isCaseSensitive: false, []);
+ var filter2 = new BloomFilter(falsePositiveProbability: 0.0001, isCaseSensitive: true, []);
+
+ _ = filter1.ProbablyContains("test1");
+ Assert.True(BloomFilter.BloomFilterHash.TryGetCachedEntry(out var isCaseSensitive, out var value));
+ Assert.True(!isCaseSensitive);
+ Assert.Equal("test1", value);
+
+ _ = filter2.ProbablyContains("test2");
+ Assert.True(BloomFilter.BloomFilterHash.TryGetCachedEntry(out isCaseSensitive, out value));
+ Assert.True(isCaseSensitive);
+ Assert.Equal("test2", value);
+ }
+
[Fact]
public void TestSerialization()
{
@@ -180,6 +200,78 @@ public void TestInt64()
}
}
+ [Theory, CombinatorialData]
+ public void TestCacheCorrectness(bool isCaseSensitive, bool reverse)
+ {
+ var allStringsToTest = GenerateStrings(100_000);
+
+ var comparer = isCaseSensitive ? StringComparer.Ordinal : StringComparer.OrdinalIgnoreCase;
+ var allHashSets = new List>
+ {
+ new HashSet(GenerateStrings(1_000), comparer),
+ new HashSet(GenerateStrings(1_000).Where((s, i) => i % 1 == 0), comparer),
+ new HashSet(GenerateStrings(1_000).Where((s, i) => i % 1 == 1), comparer),
+ new HashSet(GenerateStrings(10_000), comparer),
+ new HashSet(GenerateStrings(10_000).Where((s, i) => i % 1 == 0), comparer),
+ new HashSet(GenerateStrings(10_000).Where((s, i) => i % 1 == 1), comparer),
+ new HashSet(GenerateStrings(100_000), comparer),
+ new HashSet(GenerateStrings(100_000).Where((s, i) => i % 1 == 0), comparer),
+ new HashSet(GenerateStrings(100_000).Where((s, i) => i % 1 == 1), comparer),
+ };
+
+ // Try the patterns where we're searching smaller filters then larger ones. Then the pattern of larger ones then smaller ones.
+ if (reverse)
+ allHashSets.Reverse();
+
+ // Try several different probability levels to ensure we maintain the correct false positive rate. We
+ // must always preserve the true 0 negative rate.
+ for (var d = 0.1; d >= 0.0001; d /= 10)
+ {
+ // Get a bloom filter for each set of strings.
+ var allFilters = allHashSets.Select(s => new BloomFilter(d, isCaseSensitive, s)).ToArray();
+
+ // The double array stores the correct/incorrect count per run.
+ var allCounts = allHashSets.Select(_ => new double[2]).ToArray();
+
+ // We want to take each string, and test it against each bloom filter. This will ensure that the caches
+ // we have when computing against one bloom filter don't infect the results of the other bloom filters.
+ foreach (var test in allStringsToTest)
+ {
+ for (var i = 0; i < allHashSets.Count; i++)
+ {
+ var strings = allHashSets[i];
+ var filter = allFilters[i];
+ var counts = allCounts[i];
+ var actualContains = strings.Contains(test);
+ var filterContains = filter.ProbablyContains(test);
+
+ // if the filter says no, then it can't be in the real set.
+ if (!filterContains)
+ Assert.False(actualContains);
+
+ if (actualContains == filterContains)
+ {
+ counts[0]++;
+ }
+ else
+ {
+ counts[1]++;
+ }
+ }
+ }
+
+ // Now validate for this set of bloom filters, and this particular probability level, that all the
+ // rates remain correct for each bloom filter.
+ foreach (var counts in allCounts)
+ {
+ var correctCount = counts[0];
+ var incorrectCount = counts[1];
+ var falsePositivePercentage = incorrectCount / (correctCount + incorrectCount);
+ Assert.True(falsePositivePercentage < (d * 1.5), string.Format("falsePositivePercentage={0}, d={1}", falsePositivePercentage, d));
+ }
+ }
+ }
+
private static HashSet CreateLongs(List ints)
{
var result = new HashSet();
diff --git a/src/EditorFeatures/Test/Workspaces/TextFactoryTests.cs b/src/EditorFeatures/Test/Workspaces/TextFactoryTests.cs
index 6ebfbc1b253d4..377d303f6a210 100644
--- a/src/EditorFeatures/Test/Workspaces/TextFactoryTests.cs
+++ b/src/EditorFeatures/Test/Workspaces/TextFactoryTests.cs
@@ -68,7 +68,10 @@ public void TestCreateTextUsesByteOrderMarkIfPresent()
TestCreateTextInferredEncoding(
textFactoryService,
- Encoding.UTF8.GetPreamble().Concat(new UTF8Encoding(encoderShouldEmitUTF8Identifier: false, throwOnInvalidBytes: true).GetBytes("Test")).ToArray(),
+ [
+ .. Encoding.UTF8.GetPreamble(),
+ .. new UTF8Encoding(encoderShouldEmitUTF8Identifier: false, throwOnInvalidBytes: true).GetBytes("Test"),
+ ],
defaultEncoding: Encoding.GetEncoding(1254),
expectedEncoding: Encoding.UTF8);
}
@@ -82,13 +85,11 @@ public async Task TestCreateFromTemporaryStorage()
var text = SourceText.From("Hello, World!");
- // Create a temporary storage location
- using var temporaryStorage = temporaryStorageService.CreateTemporaryTextStorage();
// Write text into it
- await temporaryStorage.WriteTextAsync(text);
+ var handle = await temporaryStorageService.WriteToTemporaryStorageAsync(text, CancellationToken.None);
// Read text back from it
- var text2 = await temporaryStorage.ReadTextAsync();
+ var text2 = await handle.ReadFromTemporaryStorageAsync(CancellationToken.None);
Assert.NotSame(text, text2);
Assert.Equal(text.ToString(), text2.ToString());
@@ -104,13 +105,11 @@ public async Task TestCreateFromTemporaryStorageWithEncoding()
var text = SourceText.From("Hello, World!", Encoding.ASCII);
- // Create a temporary storage location
- using var temporaryStorage = temporaryStorageService.CreateTemporaryTextStorage();
// Write text into it
- await temporaryStorage.WriteTextAsync(text);
+ var handle = await temporaryStorageService.WriteToTemporaryStorageAsync(text, CancellationToken.None);
// Read text back from it
- var text2 = await temporaryStorage.ReadTextAsync();
+ var text2 = await handle.ReadFromTemporaryStorageAsync(CancellationToken.None);
Assert.NotSame(text, text2);
Assert.Equal(text.ToString(), text2.ToString());
diff --git a/src/EditorFeatures/Test2/Diagnostics/DiagnosticProviderTests.vb b/src/EditorFeatures/Test2/Diagnostics/DiagnosticProviderTests.vb
index 479f3b4014a6b..19a9f764f34be 100644
--- a/src/EditorFeatures/Test2/Diagnostics/DiagnosticProviderTests.vb
+++ b/src/EditorFeatures/Test2/Diagnostics/DiagnosticProviderTests.vb
@@ -261,11 +261,9 @@ Namespace Microsoft.CodeAnalysis.Editor.Implementation.Diagnostics.UnitTests
Next
Dim diagnosticProvider = GetDiagnosticProvider(workspace)
- Dim actualDiagnostics = diagnosticProvider.GetDiagnosticsAsync(
- workspace.CurrentSolution, projectId:=Nothing, documentId:=Nothing,
- includeSuppressedDiagnostics:=False,
- includeNonLocalDocumentDiagnostics:=True,
- CancellationToken.None).Result
+ Dim actualDiagnostics = diagnosticProvider.GetDiagnosticsForIdsAsync(
+ workspace.CurrentSolution, projectId:=Nothing, documentId:=Nothing, diagnosticIds:=Nothing, shouldIncludeAnalyzer:=Nothing,
+ includeSuppressedDiagnostics:=False, includeLocalDocumentDiagnostics:=True, includeNonLocalDocumentDiagnostics:=True, CancellationToken.None).Result
If diagnostics Is Nothing Then
Assert.Equal(0, actualDiagnostics.Length)
diff --git a/src/EditorFeatures/Test2/Diagnostics/DiagnosticServiceTests.vb b/src/EditorFeatures/Test2/Diagnostics/DiagnosticServiceTests.vb
index 1f9aec9da2ced..d6722a2eee3cf 100644
--- a/src/EditorFeatures/Test2/Diagnostics/DiagnosticServiceTests.vb
+++ b/src/EditorFeatures/Test2/Diagnostics/DiagnosticServiceTests.vb
@@ -536,10 +536,9 @@ Namespace Microsoft.CodeAnalysis.Editor.Implementation.Diagnostics.UnitTests
Dim diagnostics = Await GetDiagnosticsForSpanAsync(diagnosticService, document, root.FullSpan)
Assert.Equal(0, diagnostics.Count())
- diagnostics = Await diagnosticService.GetDiagnosticsAsync(project.Solution, projectId:=Nothing, documentId:=Nothing,
- includeSuppressedDiagnostics:=False,
- includeNonLocalDocumentDiagnostics:=True,
- CancellationToken.None).ConfigureAwait(False)
+ diagnostics = Await diagnosticService.GetDiagnosticsForIdsAsync(
+ project.Solution, projectId:=Nothing, documentId:=Nothing, diagnosticIds:=Nothing, shouldIncludeAnalyzer:=Nothing,
+ includeSuppressedDiagnostics:=False, includeLocalDocumentDiagnostics:=True, includeNonLocalDocumentDiagnostics:=True, CancellationToken.None)
Dim diagnostic = diagnostics.First()
Assert.True(diagnostic.Id = "AD0001")
Assert.Contains("CodeBlockStartedAnalyzer", diagnostic.Message, StringComparison.Ordinal)
@@ -608,10 +607,9 @@ Namespace Microsoft.CodeAnalysis.Editor.Implementation.Diagnostics.UnitTests
Assert.Equal(1, descriptorsMap.Count)
Dim document = project.Documents.Single()
- Dim diagnostics = Await diagnosticService.GetDiagnosticsAsync(project.Solution, project.Id, documentId:=Nothing,
- includeSuppressedDiagnostics:=False,
- includeNonLocalDocumentDiagnostics:=True,
- CancellationToken.None)
+ Dim diagnostics = Await diagnosticService.GetDiagnosticsForIdsAsync(
+ project.Solution, project.Id, documentId:=Nothing, diagnosticIds:=Nothing, shouldIncludeAnalyzer:=Nothing,
+ includeSuppressedDiagnostics:=False, includeLocalDocumentDiagnostics:=True, includeNonLocalDocumentDiagnostics:=True, CancellationToken.None)
Assert.Equal(1, diagnostics.Count())
Dim diagnostic = diagnostics.First()
Assert.Equal(OperationAnalyzer.Descriptor.Id, diagnostic.Id)
@@ -951,10 +949,9 @@ class AnonymousFunctions
' Verify no duplicate analysis/diagnostics.
Dim document = project.Documents.Single()
- Dim diagnostics = (Await diagnosticService.GetDiagnosticsAsync(project.Solution, project.Id, documentId:=Nothing,
- includeSuppressedDiagnostics:=False,
- includeNonLocalDocumentDiagnostics:=True,
- CancellationToken.None)).
+ Dim diagnostics = (Await diagnosticService.GetDiagnosticsForIdsAsync(
+ project.Solution, project.Id, documentId:=Nothing, diagnosticIds:=Nothing, shouldIncludeAnalyzer:=Nothing,
+ includeSuppressedDiagnostics:=False, includeLocalDocumentDiagnostics:=True, includeNonLocalDocumentDiagnostics:=True, CancellationToken.None)).
Select(Function(d) d.Id = NamedTypeAnalyzer.DiagDescriptor.Id)
Assert.Equal(1, diagnostics.Count)
@@ -1047,10 +1044,9 @@ class AnonymousFunctions
' Verify project diagnostics contains diagnostics reported on both partial definitions.
Dim incrementalAnalyzer = diagnosticService.CreateIncrementalAnalyzer(workspace)
- Dim diagnostics = Await diagnosticService.GetDiagnosticsAsync(project.Solution, project.Id, documentId:=Nothing,
- includeSuppressedDiagnostics:=False,
- includeNonLocalDocumentDiagnostics:=True,
- CancellationToken.None)
+ Dim diagnostics = Await diagnosticService.GetDiagnosticsForIdsAsync(
+ project.Solution, project.Id, documentId:=Nothing, diagnosticIds:=Nothing, shouldIncludeAnalyzer:=Nothing,
+ includeSuppressedDiagnostics:=False, includeLocalDocumentDiagnostics:=True, includeNonLocalDocumentDiagnostics:=True, CancellationToken.None)
Assert.Equal(2, diagnostics.Count())
Dim file1HasDiag = False, file2HasDiag = False
For Each diagnostic In diagnostics
@@ -2151,10 +2147,9 @@ class MyClass
Assert.Equal(expectedCount, diagnostics.Count())
' Get diagnostics explicitly
- Dim hiddenDiagnostics = Await diagnosticService.GetDiagnosticsAsync(project.Solution, project.Id, documentId:=Nothing,
- includeSuppressedDiagnostics:=False,
- includeNonLocalDocumentDiagnostics:=True,
- CancellationToken.None)
+ Dim hiddenDiagnostics = Await diagnosticService.GetDiagnosticsForIdsAsync(
+ project.Solution, project.Id, documentId:=Nothing, diagnosticIds:=Nothing, shouldIncludeAnalyzer:=Nothing,
+ includeSuppressedDiagnostics:=False, includeLocalDocumentDiagnostics:=True, includeNonLocalDocumentDiagnostics:=True, CancellationToken.None)
Assert.Equal(1, hiddenDiagnostics.Count())
Assert.Equal(analyzer.Descriptor.Id, hiddenDiagnostics.Single().Id)
End Using
@@ -2239,10 +2234,9 @@ class C
Assert.Equal(1, descriptorsMap.Count)
Dim incrementalAnalyzer = diagnosticService.CreateIncrementalAnalyzer(workspace)
- Dim diagnostics = Await diagnosticService.GetDiagnosticsAsync(project.Solution, project.Id, documentId:=Nothing,
- includeSuppressedDiagnostics:=False,
- includeNonLocalDocumentDiagnostics:=True,
- CancellationToken.None)
+ Dim diagnostics = Await diagnosticService.GetDiagnosticsForIdsAsync(
+ project.Solution, project.Id, documentId:=Nothing, diagnosticIds:=Nothing, shouldIncludeAnalyzer:=Nothing,
+ includeSuppressedDiagnostics:=False, includeLocalDocumentDiagnostics:=True, includeNonLocalDocumentDiagnostics:=True, CancellationToken.None)
Assert.Equal(0, diagnostics.Count())
End Using
End Function
diff --git a/src/EditorFeatures/TestUtilities/Diagnostics/MockDiagnosticAnalyzerService.cs b/src/EditorFeatures/TestUtilities/Diagnostics/MockDiagnosticAnalyzerService.cs
index 6bd490efea2e5..424a6876218c1 100644
--- a/src/EditorFeatures/TestUtilities/Diagnostics/MockDiagnosticAnalyzerService.cs
+++ b/src/EditorFeatures/TestUtilities/Diagnostics/MockDiagnosticAnalyzerService.cs
@@ -61,7 +61,7 @@ public Task> GetCachedDiagnosticsAsync(Workspace
public Task> GetDiagnosticsAsync(Solution solution, ProjectId? projectId, DocumentId? documentId, bool includeSuppressedDiagnostics, bool includeNonLocalDocumentDiagnostics, CancellationToken cancellationToken)
=> throw new NotImplementedException();
- public Task> GetDiagnosticsForIdsAsync(Solution solution, ProjectId? projectId, DocumentId? documentId, ImmutableHashSet? diagnosticIds, Func? shouldIncludeAnalyzer, bool includeSuppressedDiagnostics, bool includeLocalDocumentDiagnostics, bool includeNonLocalDocumentDiagnostics, CancellationToken cancellationToken)
+ public Task> GetDiagnosticsForIdsAsync(Solution solution, ProjectId? projectId, DocumentId? documentId, ImmutableHashSet? diagnosticIds, Func? shouldIncludeAnalyzer, Func>? getDocuments, bool includeSuppressedDiagnostics, bool includeLocalDocumentDiagnostics, bool includeNonLocalDocumentDiagnostics, CancellationToken cancellationToken)
=> throw new NotImplementedException();
public Task> GetDiagnosticsForSpanAsync(TextDocument document, TextSpan? range, Func? shouldIncludeDiagnostic, bool includeCompilerDiagnostics, bool includeSuppressedDiagnostics, ICodeActionRequestPriorityProvider priorityProvider, Func? addOperationScope, DiagnosticKind diagnosticKind, bool isExplicit, CancellationToken cancellationToken)
diff --git a/src/EditorFeatures/TestUtilities/NavigateTo/FirstDocIsActiveAndVisibleDocumentTrackingService.cs b/src/EditorFeatures/TestUtilities/DocumentTracking/FirstDocumentIsActiveAndVisibleDocumentTrackingService.cs
similarity index 72%
rename from src/EditorFeatures/TestUtilities/NavigateTo/FirstDocIsActiveAndVisibleDocumentTrackingService.cs
rename to src/EditorFeatures/TestUtilities/DocumentTracking/FirstDocumentIsActiveAndVisibleDocumentTrackingService.cs
index 7a02c1defd780..4f8ccd9d7cdc6 100644
--- a/src/EditorFeatures/TestUtilities/NavigateTo/FirstDocIsActiveAndVisibleDocumentTrackingService.cs
+++ b/src/EditorFeatures/TestUtilities/DocumentTracking/FirstDocumentIsActiveAndVisibleDocumentTrackingService.cs
@@ -10,25 +10,23 @@
using Microsoft.CodeAnalysis.Host.Mef;
using Roslyn.Utilities;
-namespace Microsoft.CodeAnalysis.Editor.UnitTests.NavigateTo;
+namespace Microsoft.CodeAnalysis.Editor.Test;
-internal sealed class FirstDocIsActiveAndVisibleDocumentTrackingService : IDocumentTrackingService
+internal sealed class FirstDocumentIsActiveAndVisibleDocumentTrackingService : IDocumentTrackingService
{
private readonly Workspace _workspace;
[Obsolete(MefConstruction.FactoryMethodMessage, error: true)]
- private FirstDocIsActiveAndVisibleDocumentTrackingService(Workspace workspace)
+ private FirstDocumentIsActiveAndVisibleDocumentTrackingService(Workspace workspace)
=> _workspace = workspace;
- public bool SupportsDocumentTracking => true;
-
public event EventHandler ActiveDocumentChanged { add { } remove { } }
public DocumentId TryGetActiveDocument()
=> _workspace.CurrentSolution.Projects.First().DocumentIds.First();
public ImmutableArray GetVisibleDocuments()
- => ImmutableArray.Create(_workspace.CurrentSolution.Projects.First().DocumentIds.First());
+ => [TryGetActiveDocument()];
[ExportWorkspaceServiceFactory(typeof(IDocumentTrackingService), ServiceLayer.Test), Shared, PartNotDiscoverable]
public class Factory : IWorkspaceServiceFactory
@@ -41,6 +39,6 @@ public Factory()
[Obsolete(MefConstruction.FactoryMethodMessage, error: true)]
public IWorkspaceService CreateService(HostWorkspaceServices workspaceServices)
- => new FirstDocIsActiveAndVisibleDocumentTrackingService(workspaceServices.Workspace);
+ => new FirstDocumentIsActiveAndVisibleDocumentTrackingService(workspaceServices.Workspace);
}
}
diff --git a/src/EditorFeatures/TestUtilities/DocumentTracking/TestDocumentTrackingService.cs b/src/EditorFeatures/TestUtilities/DocumentTracking/TestDocumentTrackingService.cs
new file mode 100644
index 0000000000000..ec01c8c69affc
--- /dev/null
+++ b/src/EditorFeatures/TestUtilities/DocumentTracking/TestDocumentTrackingService.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 System;
+using System.Collections.Immutable;
+using System.Composition;
+using Microsoft.CodeAnalysis.Host.Mef;
+
+namespace Microsoft.CodeAnalysis.Editor.Test;
+
+[ExportWorkspaceService(typeof(IDocumentTrackingService), ServiceLayer.Test), Shared, PartNotDiscoverable]
+[method: ImportingConstructor]
+[method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)]
+internal sealed class TestDocumentTrackingService() : IDocumentTrackingService
+{
+ private DocumentId? _activeDocumentId;
+
+ public event EventHandler? ActiveDocumentChanged;
+
+ public void SetActiveDocument(DocumentId? newActiveDocumentId)
+ {
+ _activeDocumentId = newActiveDocumentId;
+ ActiveDocumentChanged?.Invoke(this, newActiveDocumentId);
+ }
+
+ public DocumentId? TryGetActiveDocument()
+ => _activeDocumentId;
+
+ public ImmutableArray GetVisibleDocuments()
+ => _activeDocumentId != null ? [_activeDocumentId] : [];
+}
diff --git a/src/EditorFeatures/TestUtilities/NavigateTo/AbstractNavigateToTests.cs b/src/EditorFeatures/TestUtilities/NavigateTo/AbstractNavigateToTests.cs
index 619033a76de5a..22b76a49786d6 100644
--- a/src/EditorFeatures/TestUtilities/NavigateTo/AbstractNavigateToTests.cs
+++ b/src/EditorFeatures/TestUtilities/NavigateTo/AbstractNavigateToTests.cs
@@ -17,6 +17,7 @@
using Microsoft.CodeAnalysis.Editor.Implementation.NavigateTo;
using Microsoft.CodeAnalysis.Editor.Shared.Extensions;
using Microsoft.CodeAnalysis.Editor.Shared.Utilities;
+using Microsoft.CodeAnalysis.Editor.Test;
using Microsoft.CodeAnalysis.Editor.Wpf;
using Microsoft.CodeAnalysis.Host;
using Microsoft.CodeAnalysis.Host.Mef;
@@ -41,7 +42,7 @@ public abstract partial class AbstractNavigateToTests
{
protected static readonly TestComposition DefaultComposition = EditorTestCompositions.EditorFeatures.AddParts(typeof(TestWorkspaceNavigateToSearchHostService));
protected static readonly TestComposition FirstVisibleComposition = EditorTestCompositions.EditorFeatures.AddParts(typeof(TestWorkspaceNavigateToSearchHostService), typeof(FirstDocIsVisibleDocumentTrackingService.Factory));
- protected static readonly TestComposition FirstActiveAndVisibleComposition = EditorTestCompositions.EditorFeatures.AddParts(typeof(TestWorkspaceNavigateToSearchHostService), typeof(FirstDocIsActiveAndVisibleDocumentTrackingService.Factory));
+ protected static readonly TestComposition FirstActiveAndVisibleComposition = EditorTestCompositions.EditorFeatures.AddParts(typeof(TestWorkspaceNavigateToSearchHostService), typeof(FirstDocumentIsActiveAndVisibleDocumentTrackingService.Factory));
protected INavigateToItemProvider _provider;
protected NavigateToTestAggregator _aggregator;
@@ -162,7 +163,7 @@ internal void InitializeWorkspace(EditorTestWorkspace workspace)
protected static void VerifyNavigateToResultItems(
List expecteditems, IEnumerable items)
{
- expecteditems = expecteditems.OrderBy(i => i.Name).ToList();
+ expecteditems = [.. expecteditems.OrderBy(i => i.Name)];
items = items.OrderBy(i => i.Name).ToList();
Assert.Equal(expecteditems.Count(), items.Count());
@@ -237,8 +238,6 @@ private class FirstDocIsVisibleDocumentTrackingService : IDocumentTrackingServic
private FirstDocIsVisibleDocumentTrackingService(Workspace workspace)
=> _workspace = workspace;
- public bool SupportsDocumentTracking => true;
-
public event EventHandler ActiveDocumentChanged { add { } remove { } }
public DocumentId TryGetActiveDocument()
diff --git a/src/EditorFeatures/TestUtilities/SolutionCrawler/TestDocumentTrackingService.cs b/src/EditorFeatures/TestUtilities/SolutionCrawler/TestDocumentTrackingService.cs
deleted file mode 100644
index de2466aa68453..0000000000000
--- a/src/EditorFeatures/TestUtilities/SolutionCrawler/TestDocumentTrackingService.cs
+++ /dev/null
@@ -1,39 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System;
-using System.Collections.Immutable;
-using System.Composition;
-using Microsoft.CodeAnalysis.Host.Mef;
-
-namespace Microsoft.CodeAnalysis.Editor.Test
-{
- [ExportWorkspaceService(typeof(IDocumentTrackingService), ServiceLayer.Test), Shared, PartNotDiscoverable]
- internal sealed class TestDocumentTrackingService : IDocumentTrackingService
- {
- private DocumentId? _activeDocumentId;
-
- [ImportingConstructor]
- [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)]
- public TestDocumentTrackingService()
- {
- }
-
- public bool SupportsDocumentTracking => true;
-
- public event EventHandler? ActiveDocumentChanged;
-
- public void SetActiveDocument(DocumentId? newActiveDocumentId)
- {
- _activeDocumentId = newActiveDocumentId;
- ActiveDocumentChanged?.Invoke(this, newActiveDocumentId);
- }
-
- public DocumentId? TryGetActiveDocument()
- => _activeDocumentId;
-
- public ImmutableArray GetVisibleDocuments()
- => _activeDocumentId != null ? ImmutableArray.Create(_activeDocumentId) : ImmutableArray.Empty;
- }
-}
diff --git a/src/EditorFeatures/TestUtilities/Squiggles/SquiggleUtilities.cs b/src/EditorFeatures/TestUtilities/Squiggles/SquiggleUtilities.cs
index 1a76d41a4f352..90ed3e6ea22e0 100644
--- a/src/EditorFeatures/TestUtilities/Squiggles/SquiggleUtilities.cs
+++ b/src/EditorFeatures/TestUtilities/Squiggles/SquiggleUtilities.cs
@@ -28,7 +28,7 @@ public static class SquiggleUtilities
internal static TestComposition WpfCompositionWithSolutionCrawler = EditorTestCompositions.EditorFeaturesWpf
.RemoveParts(typeof(MockWorkspaceEventListenerProvider));
- internal static async Task<(ImmutableArray, ImmutableArray>)> GetDiagnosticsAndErrorSpansAsync(
+ internal static async Task>> GetTagSpansAsync(
EditorTestWorkspace workspace,
IReadOnlyDictionary> analyzerMap = null)
where TProvider : AbstractDiagnosticsTaggerProvider
@@ -43,14 +43,10 @@ public static class SquiggleUtilities
using var disposable = tagger as IDisposable;
await wrapper.WaitForTags();
- var service = (DiagnosticAnalyzerService)workspace.ExportProvider.GetExportedValue();
- var analyzerDiagnostics = await service.GetDiagnosticsAsync(workspace.CurrentSolution,
- projectId: null, documentId: null, includeSuppressedDiagnostics: false, includeNonLocalDocumentDiagnostics: true, CancellationToken.None);
-
var snapshot = textBuffer.CurrentSnapshot;
var spans = tagger.GetTags(snapshot.GetSnapshotSpanCollection()).ToImmutableArray();
- return (analyzerDiagnostics, spans);
+ return spans;
}
}
}
diff --git a/src/EditorFeatures/TestUtilities/Squiggles/TestDiagnosticTagProducer.cs b/src/EditorFeatures/TestUtilities/Squiggles/TestDiagnosticTagProducer.cs
index 79108121d640b..d42a8b5abcc4d 100644
--- a/src/EditorFeatures/TestUtilities/Squiggles/TestDiagnosticTagProducer.cs
+++ b/src/EditorFeatures/TestUtilities/Squiggles/TestDiagnosticTagProducer.cs
@@ -18,11 +18,11 @@ internal sealed class TestDiagnosticTagProducer
where TProvider : AbstractDiagnosticsTaggerProvider
where TTag : class, ITag
{
- internal static Task<(ImmutableArray, ImmutableArray>)> GetDiagnosticsAndErrorSpans(
+ internal static Task>> GetTagSpansAsync(
EditorTestWorkspace workspace,
IReadOnlyDictionary>? analyzerMap = null)
{
- return SquiggleUtilities.GetDiagnosticsAndErrorSpansAsync(workspace, analyzerMap);
+ return SquiggleUtilities.GetTagSpansAsync(workspace, analyzerMap);
}
internal static DiagnosticData CreateDiagnosticData(EditorTestHostDocument document, TextSpan span)
diff --git a/src/Features/CSharp/Portable/Completion/CompletionProviders/DeclarationName/DeclarationNameCompletionProvider.cs b/src/Features/CSharp/Portable/Completion/CompletionProviders/DeclarationName/DeclarationNameCompletionProvider.cs
index e6f199978569a..60ebe77ff745b 100644
--- a/src/Features/CSharp/Portable/Completion/CompletionProviders/DeclarationName/DeclarationNameCompletionProvider.cs
+++ b/src/Features/CSharp/Portable/Completion/CompletionProviders/DeclarationName/DeclarationNameCompletionProvider.cs
@@ -30,7 +30,7 @@ namespace Microsoft.CodeAnalysis.CSharp.Completion.Providers;
[method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)]
internal partial class DeclarationNameCompletionProvider([ImportMany] IEnumerable> recommenders) : LSPCompletionProvider
{
- private ImmutableArray> Recommenders { get; } = ExtensionOrderer.Order(recommenders).ToImmutableArray();
+ private ImmutableArray> Recommenders { get; } = [.. ExtensionOrderer.Order(recommenders)];
internal override string Language => LanguageNames.CSharp;
diff --git a/src/Features/CSharp/Portable/ConvertLinq/CSharpConvertLinqQueryToForEachProvider.cs b/src/Features/CSharp/Portable/ConvertLinq/CSharpConvertLinqQueryToForEachProvider.cs
index edfc5c4e75f64..ea9130d85ec3a 100644
--- a/src/Features/CSharp/Portable/ConvertLinq/CSharpConvertLinqQueryToForEachProvider.cs
+++ b/src/Features/CSharp/Portable/ConvertLinq/CSharpConvertLinqQueryToForEachProvider.cs
@@ -827,7 +827,7 @@ private StatementSyntax[] GenerateStatements(
// The stack was processed in the reverse order, but the extra statements should be provided in the direct order.
statements.Reverse();
statements.Add(statement.WithAdditionalAnnotations(Simplifier.Annotation));
- return statements.ToArray();
+ return [.. statements];
}
private bool TryProcessQueryBody(QueryBodySyntax queryBody, QueryExpressionProcessingInfo queryExpressionProcessingInfo)
diff --git a/src/Features/CSharp/Portable/ConvertLinq/ConvertForEachToLinqQuery/AbstractToMethodConverter.cs b/src/Features/CSharp/Portable/ConvertLinq/ConvertForEachToLinqQuery/AbstractToMethodConverter.cs
index ea8ae8a8da756..61f9cf84c86fe 100644
--- a/src/Features/CSharp/Portable/ConvertLinq/ConvertForEachToLinqQuery/AbstractToMethodConverter.cs
+++ b/src/Features/CSharp/Portable/ConvertLinq/ConvertForEachToLinqQuery/AbstractToMethodConverter.cs
@@ -124,8 +124,7 @@ void Convert(ExpressionSyntax replacingExpression, SyntaxNode nodeToRemoveIfFoll
// Output:
// return queryGenerated.ToList(); or return queryGenerated.Count();
replacingExpression = returnStatement.Expression;
- leadingTrivia = GetTriviaFromNode(nodeToRemoveIfFollowedByReturn)
- .Concat(SyntaxNodeOrTokenExtensions.GetTrivia(replacingExpression)).ToArray();
+ leadingTrivia = [.. GetTriviaFromNode(nodeToRemoveIfFollowedByReturn), .. SyntaxNodeOrTokenExtensions.GetTrivia(replacingExpression)];
editor.RemoveNode(nodeToRemoveIfFollowedByReturn);
}
else
diff --git a/src/Features/CSharp/Portable/ConvertPrimaryToRegularConstructor/ConvertPrimaryToRegularConstructorCodeRefactoringProvider.cs b/src/Features/CSharp/Portable/ConvertPrimaryToRegularConstructor/ConvertPrimaryToRegularConstructorCodeRefactoringProvider.cs
index 6cedb5812a4f7..617ca5843708c 100644
--- a/src/Features/CSharp/Portable/ConvertPrimaryToRegularConstructor/ConvertPrimaryToRegularConstructorCodeRefactoringProvider.cs
+++ b/src/Features/CSharp/Portable/ConvertPrimaryToRegularConstructor/ConvertPrimaryToRegularConstructorCodeRefactoringProvider.cs
@@ -240,7 +240,7 @@ ImmutableDictionary CreateSynthesizedFields()
}
}
- return result.ToImmutableHashSet();
+ return [.. result];
}
void RemovePrimaryConstructorParameterList()
diff --git a/src/Features/CSharp/Portable/DocumentHighlighting/CSharpDocumentHighlightsService.cs b/src/Features/CSharp/Portable/DocumentHighlighting/CSharpDocumentHighlightsService.cs
index c8a48212c6e61..e472dfb91502e 100644
--- a/src/Features/CSharp/Portable/DocumentHighlighting/CSharpDocumentHighlightsService.cs
+++ b/src/Features/CSharp/Portable/DocumentHighlighting/CSharpDocumentHighlightsService.cs
@@ -24,10 +24,12 @@ namespace Microsoft.CodeAnalysis.CSharp.DocumentHighlighting;
[method: ImportingConstructor]
[method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)]
internal class CSharpDocumentHighlightsService(
- [ImportMany] IEnumerable> services) : AbstractDocumentHighlightsService(LanguageNames.CSharp,
- CSharpEmbeddedLanguagesProvider.Info,
- CSharpSyntaxKinds.Instance,
- services)
+ [ImportMany] IEnumerable> services)
+ : AbstractDocumentHighlightsService(
+ LanguageNames.CSharp,
+ CSharpEmbeddedLanguagesProvider.Info,
+ CSharpSyntaxKinds.Instance,
+ services)
{
protected override async Task> GetAdditionalReferencesAsync(
Document document, ISymbol symbol, CancellationToken cancellationToken)
@@ -56,7 +58,9 @@ protected override async Task> GetAdditionalReferencesA
if (type.IsVar)
{
- semanticModel ??= await document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false);
+ // Document highlights are not impacted by nullable analysis. Get a semantic model with nullability
+ // disabled to lower the amount of work we need to do here.
+ semanticModel ??= await document.GetRequiredNullableDisabledSemanticModelAsync(cancellationToken).ConfigureAwait(false);
var boundSymbol = semanticModel.GetSymbolInfo(type, cancellationToken).Symbol;
boundSymbol = boundSymbol?.OriginalDefinition;
diff --git a/src/Features/CSharp/Portable/EditAndContinue/CSharpEditAndContinueAnalyzer.cs b/src/Features/CSharp/Portable/EditAndContinue/CSharpEditAndContinueAnalyzer.cs
index dddf059963c97..991287eeaeeaf 100644
--- a/src/Features/CSharp/Portable/EditAndContinue/CSharpEditAndContinueAnalyzer.cs
+++ b/src/Features/CSharp/Portable/EditAndContinue/CSharpEditAndContinueAnalyzer.cs
@@ -921,7 +921,7 @@ private static bool AreSimilarActiveStatements(CommonForEachStatementSyntax oldN
RoslynDebug.Assert(oldTokens != null);
RoslynDebug.Assert(newTokens != null);
- return DeclareSameIdentifiers(oldTokens.ToArray(), newTokens.ToArray());
+ return DeclareSameIdentifiers([.. oldTokens], [.. newTokens]);
}
protected override bool AreEquivalentImpl(SyntaxToken oldToken, SyntaxToken newToken)
diff --git a/src/Features/CSharp/Portable/GenerateMember/GenerateParameterizedMember/CSharpGenerateParameterizedMemberService.cs b/src/Features/CSharp/Portable/GenerateMember/GenerateParameterizedMember/CSharpGenerateParameterizedMemberService.cs
index 6bab88b6f96d8..3a5e3e9a9d8dd 100644
--- a/src/Features/CSharp/Portable/GenerateMember/GenerateParameterizedMember/CSharpGenerateParameterizedMemberService.cs
+++ b/src/Features/CSharp/Portable/GenerateMember/GenerateParameterizedMember/CSharpGenerateParameterizedMemberService.cs
@@ -59,7 +59,7 @@ protected override ImmutableArray GetCapturedTypeParameter
type.GetReferencedTypeParameters(result);
}
- return result.ToImmutableArray();
+ return [.. result];
}
protected override ImmutableArray GenerateTypeParameters(CancellationToken cancellationToken)
diff --git a/src/Features/CSharp/Portable/QuickInfo/CSharpDiagnosticAnalyzerQuickInfoProvider.cs b/src/Features/CSharp/Portable/QuickInfo/CSharpDiagnosticAnalyzerQuickInfoProvider.cs
index 2c06e936fc06a..3e439cc5f6b4e 100644
--- a/src/Features/CSharp/Portable/QuickInfo/CSharpDiagnosticAnalyzerQuickInfoProvider.cs
+++ b/src/Features/CSharp/Portable/QuickInfo/CSharpDiagnosticAnalyzerQuickInfoProvider.cs
@@ -156,15 +156,15 @@ private static QuickInfoItem CreateQuickInfo(TextSpan location, DiagnosticDescri
var idTag = !string.IsNullOrWhiteSpace(descriptor.HelpLinkUri)
? new TaggedText(TextTags.Text, descriptor.Id, TaggedTextStyle.None, descriptor.HelpLinkUri, descriptor.HelpLinkUri)
: new TaggedText(TextTags.Text, descriptor.Id);
- return QuickInfoItem.Create(location, sections: new[]
- {
- QuickInfoSection.Create(QuickInfoSectionKinds.Description, new[]
- {
+ return QuickInfoItem.Create(location, sections:
+ [
+ QuickInfoSection.Create(QuickInfoSectionKinds.Description,
+ [
idTag,
new TaggedText(TextTags.Punctuation, ":"),
new TaggedText(TextTags.Space, " "),
new TaggedText(TextTags.Text, description)
- }.ToImmutableArray())
- }.ToImmutableArray(), relatedSpans: relatedSpans.ToImmutableArray());
+ ])
+ ], relatedSpans: [.. relatedSpans]);
}
}
diff --git a/src/Features/CSharpTest/EditAndContinue/Helpers/EditAndContinueValidation.cs b/src/Features/CSharpTest/EditAndContinue/Helpers/EditAndContinueValidation.cs
index 7d9e4f7c66ec5..9e42352af2e27 100644
--- a/src/Features/CSharpTest/EditAndContinue/Helpers/EditAndContinueValidation.cs
+++ b/src/Features/CSharpTest/EditAndContinue/Helpers/EditAndContinueValidation.cs
@@ -27,7 +27,7 @@ internal static void VerifyLineEdits(
VerifyLineEdits(
editScript,
- new[] { new SequencePointUpdates(editScript.Match.OldRoot.SyntaxTree.FilePath, lineEdits.ToImmutableArray()) },
+ new[] { new SequencePointUpdates(editScript.Match.OldRoot.SyntaxTree.FilePath, [.. lineEdits]) },
semanticEdits,
diagnostics,
capabilities);
diff --git a/src/Features/CSharpTest/EditAndContinue/TopLevelEditingTests.cs b/src/Features/CSharpTest/EditAndContinue/TopLevelEditingTests.cs
index 1eac532fdd3bb..7967d1f73cb8a 100644
--- a/src/Features/CSharpTest/EditAndContinue/TopLevelEditingTests.cs
+++ b/src/Features/CSharpTest/EditAndContinue/TopLevelEditingTests.cs
@@ -3679,7 +3679,7 @@ public void Record_Property_Delete_ReplacingCustomWithSynthesized_WithBodyAndMet
expectedEdits.Add(SemanticEdit(SemanticEditKind.Update, c => c.GetPrimaryConstructor("C"), preserveLocalVariables: true));
edits.VerifySemantics(
- expectedEdits.ToArray(),
+ [.. expectedEdits],
capabilities: EditAndContinueCapabilities.AddInstanceFieldToExistingType);
}
diff --git a/src/Features/Core/Portable/AddImport/AbstractAddImportFeatureService.cs b/src/Features/Core/Portable/AddImport/AbstractAddImportFeatureService.cs
index ca3f102bcfc9a..84a7d0ffe9b66 100644
--- a/src/Features/Core/Portable/AddImport/AbstractAddImportFeatureService.cs
+++ b/src/Features/Core/Portable/AddImport/AbstractAddImportFeatureService.cs
@@ -192,7 +192,7 @@ await FindResultsInAllSymbolsInStartingProjectAsync(
}
}
- return allReferences.ToImmutableArray();
+ return [.. allReferences];
}
private static async Task FindResultsInAllSymbolsInStartingProjectAsync(
diff --git a/src/Features/Core/Portable/AddImport/SymbolReferenceFinder.cs b/src/Features/Core/Portable/AddImport/SymbolReferenceFinder.cs
index 4850d08d7fd1b..945aa8594c7ff 100644
--- a/src/Features/Core/Portable/AddImport/SymbolReferenceFinder.cs
+++ b/src/Features/Core/Portable/AddImport/SymbolReferenceFinder.cs
@@ -138,12 +138,11 @@ private async Task> DoAsync(SearchScope searchSc
private ImmutableArray DeDupeAndSortReferences(ImmutableArray allReferences)
{
- return allReferences
+ return [.. allReferences
.Distinct()
.Where(NotNull)
.Where(NotGlobalNamespace)
- .OrderBy((r1, r2) => r1.CompareTo(_document, r2))
- .ToImmutableArray();
+ .OrderBy((r1, r2) => r1.CompareTo(_document, r2))];
}
private static void CalculateContext(
diff --git a/src/Features/Core/Portable/ChangeSignature/DelegateInvokeMethodReferenceFinder.cs b/src/Features/Core/Portable/ChangeSignature/DelegateInvokeMethodReferenceFinder.cs
index 023fb637ee227..fab481046098c 100644
--- a/src/Features/Core/Portable/ChangeSignature/DelegateInvokeMethodReferenceFinder.cs
+++ b/src/Features/Core/Portable/ChangeSignature/DelegateInvokeMethodReferenceFinder.cs
@@ -2,6 +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.
+using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
@@ -59,20 +60,27 @@ protected override async ValueTask> DetermineCascadedSym
return result.ToImmutableAndClear();
}
- protected override Task> DetermineDocumentsToSearchAsync(
+ protected override Task DetermineDocumentsToSearchAsync(
IMethodSymbol symbol,
HashSet? globalAliases,
Project project,
IImmutableSet? documents,
+ Action processResult,
+ TData processResultData,
FindReferencesSearchOptions options,
CancellationToken cancellationToken)
{
- return Task.FromResult(project.Documents.ToImmutableArray());
+ foreach (var document in project.Documents)
+ processResult(document, processResultData);
+
+ return Task.CompletedTask;
}
- protected override async ValueTask> FindReferencesInDocumentAsync(
+ protected override async ValueTask FindReferencesInDocumentAsync(
IMethodSymbol methodSymbol,
FindReferencesDocumentState state,
+ Action processResult,
+ TData processResultData,
FindReferencesSearchOptions options,
CancellationToken cancellationToken)
{
@@ -83,7 +91,12 @@ protected override async ValueTask> FindReference
var root = state.Root;
var nodes = root.DescendantNodes();
- using var _ = ArrayBuilder.GetInstance(out var convertedAnonymousFunctions);
+ var invocations = nodes.Where(syntaxFacts.IsInvocationExpression)
+ .Where(e => state.SemanticModel.GetSymbolInfo(e, cancellationToken).Symbol?.OriginalDefinition == methodSymbol);
+
+ foreach (var node in invocations)
+ processResult(CreateFinderLocation(node, state, cancellationToken), processResultData);
+
foreach (var node in nodes)
{
if (!syntaxFacts.IsAnonymousFunctionExpression(node))
@@ -97,14 +110,17 @@ protected override async ValueTask> FindReference
}
if (convertedType == methodSymbol.ContainingType)
- convertedAnonymousFunctions.Add(node);
+ {
+ var finderLocation = CreateFinderLocation(node, state, cancellationToken);
+ processResult(finderLocation, processResultData);
+ }
}
- var invocations = nodes.Where(syntaxFacts.IsInvocationExpression)
- .Where(e => state.SemanticModel.GetSymbolInfo(e, cancellationToken).Symbol?.OriginalDefinition == methodSymbol);
+ return;
- return invocations.Concat(convertedAnonymousFunctions).SelectAsArray(
- node => new FinderLocation(
+ static FinderLocation CreateFinderLocation(SyntaxNode node, FindReferencesDocumentState state, CancellationToken cancellationToken)
+ {
+ return new FinderLocation(
node,
new ReferenceLocation(
state.Document,
@@ -113,6 +129,7 @@ protected override async ValueTask> FindReference
isImplicit: false,
GetSymbolUsageInfo(node, state, cancellationToken),
GetAdditionalFindUsagesProperties(node, state),
- CandidateReason.None)));
+ CandidateReason.None));
+ }
}
}
diff --git a/src/Features/Core/Portable/CodeFixes/Configuration/ConfigurationUpdater.cs b/src/Features/Core/Portable/CodeFixes/Configuration/ConfigurationUpdater.cs
index a9d1b96663ade..2d332d593df81 100644
--- a/src/Features/Core/Portable/CodeFixes/Configuration/ConfigurationUpdater.cs
+++ b/src/Features/Core/Portable/CodeFixes/Configuration/ConfigurationUpdater.cs
@@ -385,10 +385,10 @@ internal static ImmutableArray GetCodeStyleOptionsForDiagnostic(Diagno
{
if (IDEDiagnosticIdToOptionMappingHelper.TryGetMappedOptions(diagnostic.Id, project.Language, out var options))
{
- return (from option in options
- where option.DefaultValue is ICodeStyleOption
- orderby option.Definition.ConfigName
- select option).ToImmutableArray();
+ return [.. from option in options
+ where option.DefaultValue is ICodeStyleOption
+ orderby option.Definition.ConfigName
+ select option];
}
return [];
diff --git a/src/Features/Core/Portable/CodeFixes/Suppression/AbstractSuppressionBatchFixAllProvider.cs b/src/Features/Core/Portable/CodeFixes/Suppression/AbstractSuppressionBatchFixAllProvider.cs
index fd9d7e160d41c..5b0a56aaff0be 100644
--- a/src/Features/Core/Portable/CodeFixes/Suppression/AbstractSuppressionBatchFixAllProvider.cs
+++ b/src/Features/Core/Portable/CodeFixes/Suppression/AbstractSuppressionBatchFixAllProvider.cs
@@ -110,7 +110,7 @@ internal abstract class AbstractSuppressionBatchFixAllProvider : FixAllProvider
await Task.WhenAll(tasks).ConfigureAwait(false);
}
- return fixesBag.ToImmutableArray();
+ return [.. fixesBag];
}
private async Task AddDocumentFixesAsync(
diff --git a/src/Features/Core/Portable/CodeFixes/Suppression/AbstractSuppressionCodeFixProvider.PragmaHelpers.cs b/src/Features/Core/Portable/CodeFixes/Suppression/AbstractSuppressionCodeFixProvider.PragmaHelpers.cs
index c748295d4eabb..e0c7a073532e0 100644
--- a/src/Features/Core/Portable/CodeFixes/Suppression/AbstractSuppressionCodeFixProvider.PragmaHelpers.cs
+++ b/src/Features/Core/Portable/CodeFixes/Suppression/AbstractSuppressionCodeFixProvider.PragmaHelpers.cs
@@ -164,11 +164,11 @@ internal static SyntaxToken GetNewEndTokenWithAddedPragma(
var isEOF = fixer.IsEndOfFileToken(endToken);
if (isEOF)
{
- trivia = endToken.LeadingTrivia.ToImmutableArray();
+ trivia = [.. endToken.LeadingTrivia];
}
else
{
- trivia = endToken.TrailingTrivia.ToImmutableArray();
+ trivia = [.. endToken.TrailingTrivia];
}
var index = GetPositionForPragmaInsertion(trivia, currentDiagnosticSpan, fixer, isStartToken: false, triviaAtIndex: out var insertBeforeTrivia);
diff --git a/src/Features/Core/Portable/CodeFixes/Suppression/AbstractSuppressionCodeFixProvider.RemoveSuppressionCodeAction.BatchFixer.cs b/src/Features/Core/Portable/CodeFixes/Suppression/AbstractSuppressionCodeFixProvider.RemoveSuppressionCodeAction.BatchFixer.cs
index 44d0ae9e5e5a5..a52525a81854c 100644
--- a/src/Features/Core/Portable/CodeFixes/Suppression/AbstractSuppressionCodeFixProvider.RemoveSuppressionCodeAction.BatchFixer.cs
+++ b/src/Features/Core/Portable/CodeFixes/Suppression/AbstractSuppressionCodeFixProvider.RemoveSuppressionCodeAction.BatchFixer.cs
@@ -153,7 +153,7 @@ public override async Task TryGetMergedFixAsync(
}
return await base.TryGetMergedFixAsync(
- newBatchOfFixes.ToImmutableArray(), fixAllState, progressTracker, cancellationToken).ConfigureAwait(false);
+ [.. newBatchOfFixes], fixAllState, progressTracker, cancellationToken).ConfigureAwait(false);
}
private static async Task> GetAttributeNodesToFixAsync(ImmutableArray attributeRemoveFixes, CancellationToken cancellationToken)
diff --git a/src/Features/Core/Portable/CodeLens/CodeLensFindReferenceProgress.cs b/src/Features/Core/Portable/CodeLens/CodeLensFindReferenceProgress.cs
index 076e4ddaabbdb..5a0a535ac915c 100644
--- a/src/Features/Core/Portable/CodeLens/CodeLensFindReferenceProgress.cs
+++ b/src/Features/Core/Portable/CodeLens/CodeLensFindReferenceProgress.cs
@@ -48,7 +48,7 @@ internal sealed class CodeLensFindReferencesProgress(
public int ReferencesCount => _locations.Count;
- public ImmutableArray Locations => _locations.ToImmutableArray();
+ public ImmutableArray Locations => [.. _locations];
public void OnStarted()
{
diff --git a/src/Features/Core/Portable/CodeRefactorings/CodeRefactoringService.cs b/src/Features/Core/Portable/CodeRefactorings/CodeRefactoringService.cs
index d0326a24686fe..49dd3e0320e36 100644
--- a/src/Features/Core/Portable/CodeRefactorings/CodeRefactoringService.cs
+++ b/src/Features/Core/Portable/CodeRefactorings/CodeRefactoringService.cs
@@ -212,7 +212,7 @@ private class ProjectCodeRefactoringProvider
: AbstractProjectExtensionProvider
{
protected override ImmutableArray GetLanguages(ExportCodeRefactoringProviderAttribute exportAttribute)
- => exportAttribute.Languages.ToImmutableArray();
+ => [.. exportAttribute.Languages];
protected override bool TryGetExtensionsFromReference(AnalyzerReference reference, out ImmutableArray extensions)
{
diff --git a/src/Features/Core/Portable/CodeRefactorings/SyncNamespace/AbstractChangeNamespaceService.cs b/src/Features/Core/Portable/CodeRefactorings/SyncNamespace/AbstractChangeNamespaceService.cs
index a67552e29dedd..b9dd43e57681d 100644
--- a/src/Features/Core/Portable/CodeRefactorings/SyncNamespace/AbstractChangeNamespaceService.cs
+++ b/src/Features/Core/Portable/CodeRefactorings/SyncNamespace/AbstractChangeNamespaceService.cs
@@ -259,7 +259,7 @@ await ChangeNamespaceInSingleDocumentAsync(solutionAfterNamespaceChange, documen
solutionAfterImportsRemoved = await RemoveUnnecessaryImportsAsync(
solutionAfterImportsRemoved,
- referenceDocuments.ToImmutableArray(),
+ [.. referenceDocuments],
[declaredNamespace, targetNamespace],
fallbackOptions,
cancellationToken).ConfigureAwait(false);
diff --git a/src/Features/Core/Portable/CodeRefactorings/SyncNamespace/AbstractSyncNamespaceCodeRefactoringProvider.State.cs b/src/Features/Core/Portable/CodeRefactorings/SyncNamespace/AbstractSyncNamespaceCodeRefactoringProvider.State.cs
index 9f9afa686ebeb..5a7dbf9fb95b9 100644
--- a/src/Features/Core/Portable/CodeRefactorings/SyncNamespace/AbstractSyncNamespaceCodeRefactoringProvider.State.cs
+++ b/src/Features/Core/Portable/CodeRefactorings/SyncNamespace/AbstractSyncNamespaceCodeRefactoringProvider.State.cs
@@ -158,7 +158,7 @@ private static bool IsDocumentPathRootedInProjectFolder(Document document)
if (projectRoot is null)
return false;
- var folderPath = Path.Combine(document.Folders.ToArray());
+ var folderPath = Path.Combine([.. document.Folders]);
var logicalDirectoryPath = PathUtilities.CombineAbsoluteAndRelativePaths(projectRoot, folderPath);
if (logicalDirectoryPath is null)
return false;
diff --git a/src/Features/Core/Portable/Completion/CharacterSetModificationRule.cs b/src/Features/Core/Portable/Completion/CharacterSetModificationRule.cs
index 9115fa8976a73..b05169033da52 100644
--- a/src/Features/Core/Portable/Completion/CharacterSetModificationRule.cs
+++ b/src/Features/Core/Portable/Completion/CharacterSetModificationRule.cs
@@ -43,5 +43,5 @@ public static CharacterSetModificationRule Create(CharacterSetModificationKind k
/// One or more characters. These are typically punctuation characters.
///
public static CharacterSetModificationRule Create(CharacterSetModificationKind kind, params char[] characters)
- => new(kind, characters.ToImmutableArray());
+ => new(kind, [.. characters]);
}
diff --git a/src/Features/Core/Portable/Completion/CompletionService_GetCompletions.cs b/src/Features/Core/Portable/Completion/CompletionService_GetCompletions.cs
index 9c707d7f8cb70..5095803afa12f 100644
--- a/src/Features/Core/Portable/Completion/CompletionService_GetCompletions.cs
+++ b/src/Features/Core/Portable/Completion/CompletionService_GetCompletions.cs
@@ -137,13 +137,13 @@ ImmutableArray GetTriggeredProviders(
var triggeredProviders = providers.Where(p => p.ShouldTriggerCompletion(document.Project.Services, text, caretPosition, trigger, options, passThroughOptions)).ToImmutableArrayOrEmpty();
Debug.Assert(ValidatePossibleTriggerCharacterSet(trigger.Kind, triggeredProviders, document, text, caretPosition, options));
- return triggeredProviders.IsEmpty ? providers.ToImmutableArray() : triggeredProviders;
+ return triggeredProviders.IsEmpty ? [.. providers] : triggeredProviders;
}
return [];
default:
- return providers.ToImmutableArray();
+ return [.. providers];
}
}
diff --git a/src/Features/Core/Portable/Completion/Providers/AbstractSymbolCompletionProvider.cs b/src/Features/Core/Portable/Completion/Providers/AbstractSymbolCompletionProvider.cs
index ace71a736df3c..8f7035e04710f 100644
--- a/src/Features/Core/Portable/Completion/Providers/AbstractSymbolCompletionProvider.cs
+++ b/src/Features/Core/Portable/Completion/Providers/AbstractSymbolCompletionProvider.cs
@@ -277,7 +277,7 @@ private async Task> GetItemsAsync(
var totalProjects = contextAndSymbolLists.Select(t => t.documentId.ProjectId).ToList();
return CreateItems(
- completionContext, symbolToContextMap.Keys.ToImmutableArray(), symbol => symbolToContextMap[symbol], missingSymbolsMap, totalProjects);
+ completionContext, [.. symbolToContextMap.Keys], symbol => symbolToContextMap[symbol], missingSymbolsMap, totalProjects);
}
protected virtual bool IsExclusive()
diff --git a/src/Features/Core/Portable/Completion/Providers/ImportCompletionProvider/ExtensionMethodImportCompletionHelper.SymbolComputer.cs b/src/Features/Core/Portable/Completion/Providers/ImportCompletionProvider/ExtensionMethodImportCompletionHelper.SymbolComputer.cs
index e3472e4604f61..979bed9aade96 100644
--- a/src/Features/Core/Portable/Completion/Providers/ImportCompletionProvider/ExtensionMethodImportCompletionHelper.SymbolComputer.cs
+++ b/src/Features/Core/Portable/Completion/Providers/ImportCompletionProvider/ExtensionMethodImportCompletionHelper.SymbolComputer.cs
@@ -482,7 +482,7 @@ private static ImmutableArray GetReceiverTypeNames(ITypeSymbol receiverT
{
using var _ = PooledHashSet.GetInstance(out var allTypeNamesBuilder);
AddNamesForTypeWorker(receiverTypeSymbol, allTypeNamesBuilder);
- return allTypeNamesBuilder.ToImmutableArray();
+ return [.. allTypeNamesBuilder];
static void AddNamesForTypeWorker(ITypeSymbol receiverTypeSymbol, PooledHashSet builder)
{
diff --git a/src/Features/Core/Portable/Completion/Providers/ImportCompletionProvider/ExtensionMethodImportCompletionHelper.cs b/src/Features/Core/Portable/Completion/Providers/ImportCompletionProvider/ExtensionMethodImportCompletionHelper.cs
index d63813efdca06..13273cb105550 100644
--- a/src/Features/Core/Portable/Completion/Providers/ImportCompletionProvider/ExtensionMethodImportCompletionHelper.cs
+++ b/src/Features/Core/Portable/Completion/Providers/ImportCompletionProvider/ExtensionMethodImportCompletionHelper.cs
@@ -72,7 +72,7 @@ public static void WarmUpCacheInCurrentProcess(Project project)
var remoteResult = await client.TryInvokeAsync(
project,
(service, solutionInfo, cancellationToken) => service.GetUnimportedExtensionMethodsAsync(
- solutionInfo, document.Id, position, receiverTypeSymbolKeyData, namespaceInScope.ToImmutableArray(),
+ solutionInfo, document.Id, position, receiverTypeSymbolKeyData, [.. namespaceInScope],
targetTypesSymbolKeyData, forceCacheCreation, hideAdvancedMembers, cancellationToken),
cancellationToken).ConfigureAwait(false);
diff --git a/src/Features/Core/Portable/Completion/Providers/RecommendedKeyword.cs b/src/Features/Core/Portable/Completion/Providers/RecommendedKeyword.cs
index 869ffdd646947..a4739b0a46790 100644
--- a/src/Features/Core/Portable/Completion/Providers/RecommendedKeyword.cs
+++ b/src/Features/Core/Portable/Completion/Providers/RecommendedKeyword.cs
@@ -40,6 +40,6 @@ internal static ImmutableArray CreateDisplayParts(string keyw
textContentBuilder.AddText(toolTip);
}
- return textContentBuilder.ToImmutableArray();
+ return [.. textContentBuilder];
}
}
diff --git a/src/Features/Core/Portable/Debugging/AbstractBreakpointResolver.cs b/src/Features/Core/Portable/Debugging/AbstractBreakpointResolver.cs
index 1bdb4ab26c64d..7e41ac5d80b2f 100644
--- a/src/Features/Core/Portable/Debugging/AbstractBreakpointResolver.cs
+++ b/src/Features/Core/Portable/Debugging/AbstractBreakpointResolver.cs
@@ -147,7 +147,7 @@ private async Task> FindMembersAsync(
default:
// They have a namespace or nested type qualified name. Walk up to the root namespace trying to match.
var containers = await _solution.GetGlobalNamespacesAsync(cancellationToken).ConfigureAwait(false);
- return FindMembers(containers, nameParts.ToArray());
+ return FindMembers(containers, [.. nameParts]);
}
}
catch (Exception e) when (FatalError.ReportAndCatchUnlessCanceled(e, cancellationToken))
diff --git a/src/Features/Core/Portable/Diagnostics/IDiagnosticAnalyzerService.cs b/src/Features/Core/Portable/Diagnostics/IDiagnosticAnalyzerService.cs
index a1521848a186c..6ac5f90bcae97 100644
--- a/src/Features/Core/Portable/Diagnostics/IDiagnosticAnalyzerService.cs
+++ b/src/Features/Core/Portable/Diagnostics/IDiagnosticAnalyzerService.cs
@@ -3,6 +3,7 @@
// See the LICENSE file in the project root for more information.
using System;
+using System.Collections.Generic;
using System.Collections.Immutable;
using System.Threading;
using System.Threading.Tasks;
@@ -47,22 +48,6 @@ internal interface IDiagnosticAnalyzerService
/// Cancellation token.
Task> GetCachedDiagnosticsAsync(Workspace workspace, ProjectId? projectId, DocumentId? documentId, bool includeSuppressedDiagnostics, bool includeLocalDocumentDiagnostics, bool includeNonLocalDocumentDiagnostics, CancellationToken cancellationToken);
- ///
- /// Get diagnostics for the given solution. all diagnostics returned should be up-to-date with respect to the given solution.
- ///
- /// Solution to fetch diagnostics for.
- /// Optional project to scope the returned diagnostics.
- /// Optional document to scope the returned diagnostics.
- /// Indicates if diagnostics suppressed in source via pragmas and SuppressMessageAttributes should be returned.
- ///
- /// Indicates if non-local document diagnostics must be returned.
- /// Non-local diagnostics are the ones reported by analyzers either at compilation end callback OR
- /// in a different file from which the callback was made. Entire project must be analyzed to get the
- /// complete set of non-local document diagnostics.
- ///
- /// Cancellation token.
- Task> GetDiagnosticsAsync(Solution solution, ProjectId? projectId, DocumentId? documentId, bool includeSuppressedDiagnostics, bool includeNonLocalDocumentDiagnostics, CancellationToken cancellationToken);
-
///
/// Force analyzes the given project by running all applicable analyzers on the project and caching the reported analyzer diagnostics.
///
@@ -91,11 +76,13 @@ internal interface IDiagnosticAnalyzerService
/// complete set of non-local document diagnostics.
///
/// Cancellation token.
- Task> GetDiagnosticsForIdsAsync(Solution solution, ProjectId? projectId, DocumentId? documentId, ImmutableHashSet? diagnosticIds, Func? shouldIncludeAnalyzer, bool includeSuppressedDiagnostics, bool includeLocalDocumentDiagnostics, bool includeNonLocalDocumentDiagnostics, CancellationToken cancellationToken);
+ Task> GetDiagnosticsForIdsAsync(Solution solution, ProjectId? projectId, DocumentId? documentId, ImmutableHashSet? diagnosticIds, Func? shouldIncludeAnalyzer, Func>? getDocumentIds, bool includeSuppressedDiagnostics, bool includeLocalDocumentDiagnostics, bool includeNonLocalDocumentDiagnostics, CancellationToken cancellationToken);
///
- /// Get project diagnostics (diagnostics with no source location) of the given diagnostic ids and/or analyzers from the given solution. all diagnostics returned should be up-to-date with respect to the given solution.
- /// Note that this method doesn't return any document diagnostics. Use to also fetch those.
+ /// Get project diagnostics (diagnostics with no source location) of the given diagnostic ids and/or analyzers from
+ /// the given solution. all diagnostics returned should be up-to-date with respect to the given solution. Note that
+ /// this method doesn't return any document diagnostics. Use to also fetch
+ /// those.
///
/// Solution to fetch the diagnostics for.
/// Optional project to scope the returned diagnostics.
@@ -197,4 +184,12 @@ public static Task> GetDiagnosticsForSpanAsync(th
includeCompilerDiagnostics: true, includeSuppressedDiagnostics, priorityProvider,
addOperationScope, diagnosticKind, isExplicit, cancellationToken);
}
+
+ public static Task> GetDiagnosticsForIdsAsync(
+ this IDiagnosticAnalyzerService service, Solution solution, ProjectId? projectId, DocumentId? documentId, ImmutableHashSet? diagnosticIds, Func? shouldIncludeAnalyzer, bool includeSuppressedDiagnostics, bool includeLocalDocumentDiagnostics, bool includeNonLocalDocumentDiagnostics, CancellationToken cancellationToken)
+ {
+ return service.GetDiagnosticsForIdsAsync(
+ solution, projectId, documentId, diagnosticIds, shouldIncludeAnalyzer, getDocumentIds: null,
+ includeSuppressedDiagnostics, includeLocalDocumentDiagnostics, includeNonLocalDocumentDiagnostics, cancellationToken);
+ }
}
diff --git a/src/Features/Core/Portable/DocumentHighlighting/AbstractDocumentHighlightsService.cs b/src/Features/Core/Portable/DocumentHighlighting/AbstractDocumentHighlightsService.cs
index 1671cca3ac7fd..f4075ce374447 100644
--- a/src/Features/Core/Portable/DocumentHighlighting/AbstractDocumentHighlightsService.cs
+++ b/src/Features/Core/Portable/DocumentHighlighting/AbstractDocumentHighlightsService.cs
@@ -63,7 +63,9 @@ public async Task> GetDocumentHighlightsAsync
private async Task> GetDocumentHighlightsInCurrentProcessAsync(
Document document, int position, IImmutableSet documentsToSearch, HighlightingOptions options, CancellationToken cancellationToken)
{
- var semanticModel = await document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false);
+ // Document highlights are not impacted by nullable analysis. Get a semantic model with nullability disabled to
+ // lower the amount of work we need to do here.
+ var semanticModel = await document.GetRequiredNullableDisabledSemanticModelAsync(cancellationToken).ConfigureAwait(false);
var result = TryGetEmbeddedLanguageHighlights(document, semanticModel, position, options, cancellationToken);
if (!result.IsDefaultOrEmpty)
return result;
diff --git a/src/Features/Core/Portable/EditAndContinue/DebuggingSession.cs b/src/Features/Core/Portable/EditAndContinue/DebuggingSession.cs
index ff5a2ce294130..62ba99219f3af 100644
--- a/src/Features/Core/Portable/EditAndContinue/DebuggingSession.cs
+++ b/src/Features/Core/Portable/EditAndContinue/DebuggingSession.cs
@@ -433,7 +433,7 @@ private static ImmutableDictionary> GroupToImmutableDiction
foreach (var item in items)
{
- builder.Add(item.Key, item.ToImmutableArray());
+ builder.Add(item.Key, [.. item]);
}
return builder.ToImmutable();
@@ -836,7 +836,7 @@ public ImmutableHashSet GetModulesPreparedForUpdate()
{
lock (_instance._modulesPreparedForUpdateGuard)
{
- return _instance._modulesPreparedForUpdate.ToImmutableHashSet();
+ return [.. _instance._modulesPreparedForUpdate];
}
}
diff --git a/src/Features/Core/Portable/EditAndContinue/DebuggingSessionTelemetry.cs b/src/Features/Core/Portable/EditAndContinue/DebuggingSessionTelemetry.cs
index 2b3d5186583d6..2a9b478b6a437 100644
--- a/src/Features/Core/Portable/EditAndContinue/DebuggingSessionTelemetry.cs
+++ b/src/Features/Core/Portable/EditAndContinue/DebuggingSessionTelemetry.cs
@@ -15,7 +15,7 @@ internal sealed class DebuggingSessionTelemetry(Guid solutionSessionId)
internal readonly struct Data(DebuggingSessionTelemetry telemetry)
{
public readonly Guid SolutionSessionId = telemetry._solutionSessionId;
- public readonly ImmutableArray EditSessionData = telemetry._editSessionData.ToImmutableArray();
+ public readonly ImmutableArray EditSessionData = [.. telemetry._editSessionData];
public readonly int EmptyEditSessionCount = telemetry._emptyEditSessionCount;
public readonly int EmptyHotReloadEditSessionCount = telemetry._emptyHotReloadEditSessionCount;
}
diff --git a/src/Features/Core/Portable/EditAndContinue/EditAndContinueDocumentAnalysesCache.cs b/src/Features/Core/Portable/EditAndContinue/EditAndContinueDocumentAnalysesCache.cs
index 9e5ec07398c1c..2812e10592465 100644
--- a/src/Features/Core/Portable/EditAndContinue/EditAndContinueDocumentAnalysesCache.cs
+++ b/src/Features/Core/Portable/EditAndContinue/EditAndContinueDocumentAnalysesCache.cs
@@ -45,7 +45,7 @@ public async ValueTask> GetDocumentAnaly
var tasks = documents.Select(document => Task.Run(() => GetDocumentAnalysisAsync(oldSolution, document.oldDocument, document.newDocument, activeStatementSpanProvider, cancellationToken).AsTask(), cancellationToken));
var allResults = await Task.WhenAll(tasks).ConfigureAwait(false);
- return allResults.ToImmutableArray();
+ return [.. allResults];
}
catch (Exception e) when (FatalError.ReportAndPropagateUnlessCanceled(e, cancellationToken))
{
diff --git a/src/Features/Core/Portable/EditAndContinue/EditAndContinueMethodDebugInfoReader.cs b/src/Features/Core/Portable/EditAndContinue/EditAndContinueMethodDebugInfoReader.cs
index 1d69bf53c5dd6..c62f2c83f7ef4 100644
--- a/src/Features/Core/Portable/EditAndContinue/EditAndContinueMethodDebugInfoReader.cs
+++ b/src/Features/Core/Portable/EditAndContinue/EditAndContinueMethodDebugInfoReader.cs
@@ -236,7 +236,7 @@ internal static bool TryGetDocumentChecksum(ISymUnmanagedReader5 symReader, stri
}
algorithmId = symDocument.GetHashAlgorithm();
- checksum = symDocument.GetChecksum().ToImmutableArray();
+ checksum = [.. symDocument.GetChecksum()];
return true;
}
}
diff --git a/src/Features/Core/Portable/EditAndContinue/EditAndContinueService.cs b/src/Features/Core/Portable/EditAndContinue/EditAndContinueService.cs
index c950c64aafaf5..010063ad16ddb 100644
--- a/src/Features/Core/Portable/EditAndContinue/EditAndContinueService.cs
+++ b/src/Features/Core/Portable/EditAndContinue/EditAndContinueService.cs
@@ -120,7 +120,7 @@ private ImmutableArray GetActiveDebuggingSessions()
{
lock (_debuggingSessions)
{
- return _debuggingSessions.ToImmutableArray();
+ return [.. _debuggingSessions];
}
}
diff --git a/src/Features/Core/Portable/EditAndContinue/EditSession.cs b/src/Features/Core/Portable/EditAndContinue/EditSession.cs
index a44f2e9cad3b1..51057d7b7bcef 100644
--- a/src/Features/Core/Portable/EditAndContinue/EditSession.cs
+++ b/src/Features/Core/Portable/EditAndContinue/EditSession.cs
@@ -726,7 +726,7 @@ internal static void MergePartialEdits(
if (edits.Count == mergedEditsBuilder.Count)
{
mergedEdits = mergedEditsBuilder.ToImmutable();
- addedSymbols = addedSymbolsBuilder.ToImmutableHashSet();
+ addedSymbols = [.. addedSymbolsBuilder];
return;
}
@@ -780,7 +780,7 @@ internal static void MergePartialEdits(
}
mergedEdits = mergedEditsBuilder.ToImmutable();
- addedSymbols = addedSymbolsBuilder.ToImmutableHashSet();
+ addedSymbols = [.. addedSymbolsBuilder];
}
public async ValueTask EmitSolutionUpdateAsync(Solution solution, ActiveStatementSpanProvider solutionActiveStatementSpanProvider, UpdateId updateId, CancellationToken cancellationToken)
diff --git a/src/Features/Core/Portable/EditAndContinue/TraceLog.cs b/src/Features/Core/Portable/EditAndContinue/TraceLog.cs
index 8c0afaf35a6fd..a96471c54ad53 100644
--- a/src/Features/Core/Portable/EditAndContinue/TraceLog.cs
+++ b/src/Features/Core/Portable/EditAndContinue/TraceLog.cs
@@ -159,7 +159,7 @@ public void Write(DebuggingSessionId sessionId, ImmutableArray bytes, stri
try
{
path = Path.Combine(CreateSessionDirectory(sessionId, directory), fileName);
- File.WriteAllBytes(path, bytes.ToArray());
+ File.WriteAllBytes(path, [.. bytes]);
}
catch (Exception e)
{
diff --git a/src/Features/Core/Portable/ExternalAccess/Watch/Api/WatchHotReloadService.cs b/src/Features/Core/Portable/ExternalAccess/Watch/Api/WatchHotReloadService.cs
index d13938a57c7ad..31a5509f51e6f 100644
--- a/src/Features/Core/Portable/ExternalAccess/Watch/Api/WatchHotReloadService.cs
+++ b/src/Features/Core/Portable/ExternalAccess/Watch/Api/WatchHotReloadService.cs
@@ -4,7 +4,6 @@
using System;
using System.Collections.Immutable;
-using System.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.EditAndContinue;
@@ -14,12 +13,10 @@
namespace Microsoft.CodeAnalysis.ExternalAccess.Watch.Api;
-internal sealed class WatchHotReloadService
+internal sealed class WatchHotReloadService(SolutionServices services, Func>> capabilitiesProvider)
{
- private sealed class DebuggerService(ImmutableArray capabilities) : IManagedHotReloadService
+ private sealed class DebuggerService(Func>> capabilitiesProvider) : IManagedHotReloadService
{
- private readonly ImmutableArray _capabilities = capabilities;
-
public ValueTask> GetActiveStatementsAsync(CancellationToken cancellationToken)
=> ValueTaskFactory.FromResult(ImmutableArray.Empty);
@@ -27,41 +24,39 @@ public ValueTask GetAvailabilityAsync(Guid module,
=> ValueTaskFactory.FromResult(new ManagedHotReloadAvailability(ManagedHotReloadAvailabilityStatus.Available));
public ValueTask> GetCapabilitiesAsync(CancellationToken cancellationToken)
- => ValueTaskFactory.FromResult(_capabilities);
+ => capabilitiesProvider();
public ValueTask PrepareModuleForUpdateAsync(Guid module, CancellationToken cancellationToken)
=> ValueTaskFactory.CompletedTask;
}
- public readonly struct Update
+ public readonly struct Update(
+ Guid moduleId,
+ ImmutableArray ilDelta,
+ ImmutableArray metadataDelta,
+ ImmutableArray pdbDelta,
+ ImmutableArray updatedTypes,
+ ImmutableArray requiredCapabilities)
{
- public readonly Guid ModuleId;
- public readonly ImmutableArray ILDelta;
- public readonly ImmutableArray MetadataDelta;
- public readonly ImmutableArray PdbDelta;
- public readonly ImmutableArray UpdatedTypes;
- public readonly ImmutableArray RequiredCapabilities;
-
- internal Update(Guid moduleId, ImmutableArray ilDelta, ImmutableArray metadataDelta, ImmutableArray pdbDelta, ImmutableArray updatedTypes, ImmutableArray requiredCapabilities)
- {
- ModuleId = moduleId;
- ILDelta = ilDelta;
- MetadataDelta = metadataDelta;
- PdbDelta = pdbDelta;
- UpdatedTypes = updatedTypes;
- RequiredCapabilities = requiredCapabilities;
- }
+ public readonly Guid ModuleId = moduleId;
+ public readonly ImmutableArray ILDelta = ilDelta;
+ public readonly ImmutableArray MetadataDelta = metadataDelta;
+ public readonly ImmutableArray PdbDelta = pdbDelta;
+ public readonly ImmutableArray UpdatedTypes = updatedTypes;
+ public readonly ImmutableArray RequiredCapabilities = requiredCapabilities;
}
private static readonly ActiveStatementSpanProvider s_solutionActiveStatementSpanProvider =
(_, _, _) => ValueTaskFactory.FromResult(ImmutableArray.Empty);
- private readonly IEditAndContinueService _encService;
+ private readonly IEditAndContinueService _encService = services.GetRequiredService().Service;
+
private DebuggingSessionId _sessionId;
- private readonly ImmutableArray _capabilities;
public WatchHotReloadService(HostWorkspaceServices services, ImmutableArray capabilities)
- => (_encService, _capabilities) = (services.GetRequiredService().Service, capabilities);
+ : this(services.SolutionServices, () => ValueTaskFactory.FromResult(capabilities))
+ {
+ }
///
/// Starts the watcher.
@@ -72,7 +67,7 @@ public async Task StartSessionAsync(Solution solution, CancellationToken cancell
{
var newSessionId = await _encService.StartDebuggingSessionAsync(
solution,
- new DebuggerService(_capabilities),
+ new DebuggerService(capabilitiesProvider),
NullPdbMatchingSourceTextProvider.Instance,
captureMatchingDocuments: [],
captureAllMatchingDocuments: true,
@@ -82,6 +77,17 @@ public async Task StartSessionAsync(Solution solution, CancellationToken cancell
_sessionId = newSessionId;
}
+ ///
+ /// Invoke when capabilities have changed.
+ ///
+ public void CapabilitiesChanged()
+ {
+ var sessionId = _sessionId;
+ Contract.ThrowIfFalse(sessionId != default, "Session has not started");
+
+ _encService.BreakStateOrCapabilitiesChanged(sessionId, inBreakState: null);
+ }
+
///
/// Emits updates for all projects that differ between the given snapshot and the one given to the previous successful call or
/// the one passed to for the first invocation.
@@ -115,6 +121,7 @@ public void EndSession()
{
Contract.ThrowIfFalse(_sessionId != default, "Session has not started");
_encService.EndDebuggingSession(_sessionId);
+ _sessionId = default;
}
internal TestAccessor GetTestAccessor()
diff --git a/src/Features/Core/Portable/ExtractMethod/MethodExtractor.cs b/src/Features/Core/Portable/ExtractMethod/MethodExtractor.cs
index af01a2f0785ee..349b799dcf13d 100644
--- a/src/Features/Core/Portable/ExtractMethod/MethodExtractor.cs
+++ b/src/Features/Core/Portable/ExtractMethod/MethodExtractor.cs
@@ -214,7 +214,7 @@ private static async Task ExpandAsync(TSelectionResult selecti
}
private ImmutableArray GetFormattingRules(Document document)
- => ImmutableArray.Create(GetCustomFormattingRule(document)).AddRange(Formatter.GetDefaultFormattingRules(document));
+ => [GetCustomFormattingRule(document), .. Formatter.GetDefaultFormattingRules(document)];
private OperationStatus CheckVariableTypes(
OperationStatus status,
diff --git a/src/Features/Core/Portable/FindUsages/AbstractFindUsagesService.DefinitionTrackingContext.cs b/src/Features/Core/Portable/FindUsages/AbstractFindUsagesService.DefinitionTrackingContext.cs
index b5c8b72f60d31..30c8390088926 100644
--- a/src/Features/Core/Portable/FindUsages/AbstractFindUsagesService.DefinitionTrackingContext.cs
+++ b/src/Features/Core/Portable/FindUsages/AbstractFindUsagesService.DefinitionTrackingContext.cs
@@ -59,7 +59,7 @@ public ImmutableArray GetDefinitions()
{
lock (_gate)
{
- return _definitions.ToImmutableArray();
+ return [.. _definitions];
}
}
}
diff --git a/src/Features/Core/Portable/FindUsages/AbstractFindUsagesService_FindImplementations.cs b/src/Features/Core/Portable/FindUsages/AbstractFindUsagesService_FindImplementations.cs
index 18ef1f1dd5451..9e2ff048580f5 100644
--- a/src/Features/Core/Portable/FindUsages/AbstractFindUsagesService_FindImplementations.cs
+++ b/src/Features/Core/Portable/FindUsages/AbstractFindUsagesService_FindImplementations.cs
@@ -120,7 +120,7 @@ private static async Task> FindSourceImplementationsAsyn
}
}
- return builder.ToImmutableArray();
+ return [.. builder];
static bool AddedAllLocations(ISymbol implementation, HashSet<(string filePath, TextSpan span)> seenLocations)
{
@@ -153,7 +153,7 @@ private static async Task> FindImplementationsWorkerAsyn
}
}
- return result.ToImmutableArray();
+ return [.. result];
}
private static async Task> FindSourceAndMetadataImplementationsAsync(
@@ -189,7 +189,7 @@ private static async Task> FindSourceAndMetadataImplemen
implementationsAndOverrides.Add(symbol);
}
- return implementationsAndOverrides.ToImmutableArray();
+ return [.. implementationsAndOverrides];
}
else if (symbol is INamedTypeSymbol { TypeKind: TypeKind.Class } namedType)
{
diff --git a/src/Features/Core/Portable/GenerateEqualsAndGetHashCodeFromMembers/GenerateEqualsAndGetHashCodeFromMembersCodeRefactoringProvider.cs b/src/Features/Core/Portable/GenerateEqualsAndGetHashCodeFromMembers/GenerateEqualsAndGetHashCodeFromMembersCodeRefactoringProvider.cs
index 5ed4e014de204..590f45b35393c 100644
--- a/src/Features/Core/Portable/GenerateEqualsAndGetHashCodeFromMembers/GenerateEqualsAndGetHashCodeFromMembersCodeRefactoringProvider.cs
+++ b/src/Features/Core/Portable/GenerateEqualsAndGetHashCodeFromMembers/GenerateEqualsAndGetHashCodeFromMembersCodeRefactoringProvider.cs
@@ -236,7 +236,7 @@ private async Task> CreateActionsAsync(
}
var codeActions = await Task.WhenAll(tasks).ConfigureAwait(false);
- return codeActions.ToImmutableArray();
+ return [.. codeActions];
}
diff --git a/src/Features/Core/Portable/GenerateMember/GenerateParameterizedMember/AbstractGenerateParameterizedMemberService.AbstractInvocationInfo.cs b/src/Features/Core/Portable/GenerateMember/GenerateParameterizedMember/AbstractGenerateParameterizedMemberService.AbstractInvocationInfo.cs
index 8ffdab80fa802..7cd296978ce7b 100644
--- a/src/Features/Core/Portable/GenerateMember/GenerateParameterizedMember/AbstractGenerateParameterizedMemberService.AbstractInvocationInfo.cs
+++ b/src/Features/Core/Portable/GenerateMember/GenerateParameterizedMember/AbstractGenerateParameterizedMemberService.AbstractInvocationInfo.cs
@@ -62,7 +62,7 @@ private ITypeParameterSymbol MassageTypeParameter(
var nonClassTypes = constraints.Where(ts => ts.TypeKind != TypeKind.Class).ToList();
classTypes = MergeClassTypes(classTypes);
- constraints = classTypes.Concat(nonClassTypes).ToList();
+ constraints = [.. classTypes, .. nonClassTypes];
if (constraints.SequenceEqual(typeParameter.ConstraintTypes))
{
return typeParameter;
diff --git a/src/Features/Core/Portable/GenerateType/AbstractGenerateTypeService.Editor.cs b/src/Features/Core/Portable/GenerateType/AbstractGenerateTypeService.Editor.cs
index 48d4dfc643a5f..8adaaeda55199 100644
--- a/src/Features/Core/Portable/GenerateType/AbstractGenerateTypeService.Editor.cs
+++ b/src/Features/Core/Portable/GenerateType/AbstractGenerateTypeService.Editor.cs
@@ -313,7 +313,7 @@ private async Task> GetGenerateInNewFileOper
? folders
: _state.SimpleName != _state.NameOrMemberAccessExpression
? containers.ToList()
- : _semanticDocument.Document.Folders.ToList();
+ : [.. _semanticDocument.Document.Folders];
if (newDocument.Project.Language == _semanticDocument.Document.Project.Language)
{
@@ -524,8 +524,8 @@ private async Task> GetGenerateIntoExistingD
// Populate the ContainerList
AddFoldersToNamespaceContainers(containerList, folders);
- containers = containerList.ToArray();
- includeUsingsOrImports = string.Join(".", containerList.ToArray());
+ containers = [.. containerList];
+ includeUsingsOrImports = string.Join(".", [.. containerList]);
}
// Case 4 : If the type is generated into the same VB project or
@@ -538,8 +538,8 @@ private async Task> GetGenerateIntoExistingD
{
// Populate the ContainerList
AddFoldersToNamespaceContainers(containerList, folders);
- containers = containerList.ToArray();
- includeUsingsOrImports = string.Join(".", containerList.ToArray());
+ containers = [.. containerList];
+ includeUsingsOrImports = string.Join(".", [.. containerList]);
if (!string.IsNullOrWhiteSpace(rootNamespaceOfTheProjectGeneratedInto))
{
includeUsingsOrImports = string.IsNullOrEmpty(includeUsingsOrImports)
diff --git a/src/Features/Core/Portable/InheritanceMargin/InheritanceMarginItem.cs b/src/Features/Core/Portable/InheritanceMargin/InheritanceMarginItem.cs
index e5fe8ea9ea5f1..4e17a45b3c04e 100644
--- a/src/Features/Core/Portable/InheritanceMargin/InheritanceMarginItem.cs
+++ b/src/Features/Core/Portable/InheritanceMargin/InheritanceMarginItem.cs
@@ -71,5 +71,5 @@ public bool Equals(InheritanceMarginItem other)
=> targetItems.IsEmpty ? null : new(lineNumber, topLevelDisplayText, displayTexts, glyph, Order(targetItems));
public static ImmutableArray Order(ImmutableArray targetItems)
- => targetItems.OrderBy(t => t.DisplayName).ThenByDescending(t => t.LanguageGlyph).ThenBy(t => t.ProjectName ?? "").ToImmutableArray();
+ => [.. targetItems.OrderBy(t => t.DisplayName).ThenByDescending(t => t.LanguageGlyph).ThenBy(t => t.ProjectName ?? "")];
}
diff --git a/src/Features/Core/Portable/InlineHints/InlineHintHelpers.cs b/src/Features/Core/Portable/InlineHints/InlineHintHelpers.cs
index 1848fe2b0847d..3f7c1c32c7e43 100644
--- a/src/Features/Core/Portable/InlineHints/InlineHintHelpers.cs
+++ b/src/Features/Core/Portable/InlineHints/InlineHintHelpers.cs
@@ -54,7 +54,7 @@ private static async Task