diff --git a/.gitignore b/.gitignore index 496f18e070dfe..a450984adaab6 100644 --- a/.gitignore +++ b/.gitignore @@ -49,7 +49,7 @@ UnitTestResults.html *.nuget.props *.nuget.targets project.lock.json -msbuild.binlog +*.binlog *.project.lock.json *_i.c diff --git a/Roslyn.sln b/Roslyn.sln index a87d22b5bb0a8..5d80ffa648886 100644 --- a/Roslyn.sln +++ b/Roslyn.sln @@ -539,8 +539,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CodeAnalysis.Exte EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CodeAnalysis.ExternalAccess.EditorConfigGenerator", "src\VisualStudio\ExternalAccess\EditorConfigGenerator\Microsoft.CodeAnalysis.ExternalAccess.EditorConfigGenerator.csproj", "{09AEDEE4-6358-47C9-8022-3BD37A518070}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IntegrationTestBuildProject", "src\VisualStudio\IntegrationTest\IntegrationTestBuildProject.csproj", "{4D9D7A28-BB44-4F3F-81DA-14F39B853718}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CodeAnalysis.Features.DiagnosticsTests.Utilities", "src\Features\DiagnosticsTestUtilities\Microsoft.CodeAnalysis.Features.DiagnosticsTests.Utilities.csproj", "{5BABC440-4F1B-46E8-9068-DD7F02ED25D3}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CodeAnalysis.Features.Test.Utilities", "src\Features\TestUtilities\Microsoft.CodeAnalysis.Features.Test.Utilities.csproj", "{5762E483-75CE-4328-A410-511F30737712}" @@ -1365,10 +1363,6 @@ Global {09AEDEE4-6358-47C9-8022-3BD37A518070}.Debug|Any CPU.Build.0 = Debug|Any CPU {09AEDEE4-6358-47C9-8022-3BD37A518070}.Release|Any CPU.ActiveCfg = Release|Any CPU {09AEDEE4-6358-47C9-8022-3BD37A518070}.Release|Any CPU.Build.0 = Release|Any CPU - {4D9D7A28-BB44-4F3F-81DA-14F39B853718}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {4D9D7A28-BB44-4F3F-81DA-14F39B853718}.Debug|Any CPU.Build.0 = Debug|Any CPU - {4D9D7A28-BB44-4F3F-81DA-14F39B853718}.Release|Any CPU.ActiveCfg = Release|Any CPU - {4D9D7A28-BB44-4F3F-81DA-14F39B853718}.Release|Any CPU.Build.0 = Release|Any CPU {5BABC440-4F1B-46E8-9068-DD7F02ED25D3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {5BABC440-4F1B-46E8-9068-DD7F02ED25D3}.Debug|Any CPU.Build.0 = Debug|Any CPU {5BABC440-4F1B-46E8-9068-DD7F02ED25D3}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -1652,7 +1646,6 @@ Global {B1481D94-682E-46EC-ADBE-A16EB46FEEE9} = {55A62CFA-1155-46F1-ADF3-BEEE51B58AB5} {5E8FB6D6-6C5C-42E6-9220-1EAA7ED9BCAD} = {1AE9182D-B03E-4B00-B32E-37AE01715F57} {09AEDEE4-6358-47C9-8022-3BD37A518070} = {5880FECB-91F1-4AB8-8726-75EAFA8A918E} - {4D9D7A28-BB44-4F3F-81DA-14F39B853718} = {CC126D03-7EAC-493F-B187-DCDEE1EF6A70} {5BABC440-4F1B-46E8-9068-DD7F02ED25D3} = {3E5FE3DB-45F7-4D83-9097-8F05D3B3AEC6} {5762E483-75CE-4328-A410-511F30737712} = {3E5FE3DB-45F7-4D83-9097-8F05D3B3AEC6} {6D819E80-BA2F-4317-8368-37F8F4434D3A} = {806F0C6F-3640-4C92-8D55-6767B1535467} diff --git a/azure-pipelines-pr-validation.yml b/azure-pipelines-pr-validation.yml index 8373362545bc1..2b8394f1b5d82 100644 --- a/azure-pipelines-pr-validation.yml +++ b/azure-pipelines-pr-validation.yml @@ -33,6 +33,8 @@ variables: value: false - name: Codeql.SkipTaskAutoInjection value: true + - name: SignType + value: '' # To retrieve OptProf data we need to authenticate to the VS drop storage. # If the pipeline is running in DevDiv, the account has access to the VS drop storage. @@ -339,5 +341,6 @@ extends: # Symbol validation is not entirely reliable as of yet, so should be turned off until # https://github.com/dotnet/arcade/issues/2871 is resolved. enableSymbolValidation: false + enableSigningValidation: false enableSourceLinkValidation: false SDLValidationParameters: false diff --git a/docs/Language Feature Status.md b/docs/Language Feature Status.md index 6375ddd575789..6c6411a70f2d2 100644 --- a/docs/Language Feature Status.md +++ b/docs/Language Feature Status.md @@ -10,20 +10,22 @@ efforts behind them. | Feature | Branch | State | Developer | Reviewer | IDE Buddy | LDM Champ | | ------- | ------ | ----- | --------- | -------- | --------- | --------- | -| [Default in deconstruction](https://github.com/dotnet/roslyn/pull/25562) | [decon-default](https://github.com/dotnet/roslyn/tree/features/decon-default) | [In Progress](https://github.com/dotnet/roslyn/issues/25559) | [jcouv](https://github.com/jcouv) | [gafter](https://github.com/gafter) | | [jcouv](https://github.com/jcouv) | -| [Roles/Extensions](https://github.com/dotnet/csharplang/issues/5497) | [roles](https://github.com/dotnet/roslyn/tree/features/roles) | [In Progress](https://github.com/dotnet/roslyn/issues/66722) | [jcouv](https://github.com/jcouv) | [AlekseyTs](https://github.com/AlekseyTs), [jjonescz](https://github.com/jjonescz) | [CyrusNajmabadi](https://github.com/CyrusNajmabadi) | [MadsTorgersen](https://github.com/MadsTorgersen) | +| String literals in data section as UTF8 | [PR](https://github.com/dotnet/roslyn/pull/76036) | [In Progress](https://github.com/dotnet/roslyn/issues/76234) | [jjonescz](https://github.com/jjonescz) | [AlekseyTs](https://github.com/AlekseyTs), [jcouv](https://github.com/jcouv) | N/A | N/A | +| Runtime Async | [features/runtime-async](https://github.com/dotnet/roslyn/tree/features/runtime-async) | [In Progress](https://github.com/dotnet/roslyn/issues/75960) | [333fred](https://github.com/333fred) | [jcouv](https://github.com/jcouv), [RikkiGibson](https://github.com/RikkiGibson) | | | +| [Simple lambda parameters with modifiers](https://github.com/dotnet/csharplang/blob/main/proposals/simple-lambda-parameters-with-modifiers.md) | [PR](https://github.com/dotnet/roslyn/pull/75400) | [In Progress](https://github.com/dotnet/roslyn/issues/76298) | [CyrusNajmabadi](https://github.com/CyrusNajmabadi) | [jjonescz](https://github.com/jjonescz), [cston](https://github.com/cston) | [CyrusNajmabadi](https://github.com/CyrusNajmabadi) | [CyrusNajmabadi](https://github.com/CyrusNajmabadi) | | [Null-conditional assignment](https://github.com/dotnet/csharplang/issues/6045) | [null-conditional-assignment](https://github.com/dotnet/roslyn/tree/features/null-conditional-assignment) | [In Progress](https://github.com/dotnet/roslyn/issues/75554) | [RikkiGibson](https://github.com/RikkiGibson) | [cston](https://github.com/cston), [jjonescz](https://github.com/jjonescz) | TBD | [RikkiGibson](https://github.com/RikkiGibson) | +| [Extensions](https://github.com/dotnet/csharplang/issues/8697) | [extensions](https://github.com/dotnet/roslyn/tree/features/extensions) | [In Progress](https://github.com/dotnet/roslyn/issues/76130) | [jcouv](https://github.com/jcouv), [AlekseyTs](https://github.com/AlekseyTs) | [jjonescz](https://github.com/jjonescz), TBD | [CyrusNajmabadi](https://github.com/CyrusNajmabadi) | [MadsTorgersen](https://github.com/MadsTorgersen) | +| [Dictionary expressions](https://github.com/dotnet/csharplang/issues/8659) | [dictionary-expressions](https://github.com/dotnet/roslyn/tree/features/dictionary-expressions) | [In Progress](https://github.com/dotnet/roslyn/issues/76310) | [cston](https://github.com/cston), [CyrusNajmabadi](https://github.com/CyrusNajmabadi) | [333fred](https://github.com/333fred), [jcouv](https://github.com/jcouv) | [CyrusNajmabadi](https://github.com/CyrusNajmabadi) | [CyrusNajmabadi](https://github.com/CyrusNajmabadi) | | [`field` keyword in properties](https://github.com/dotnet/csharplang/issues/140) | [field-keyword](https://github.com/dotnet/roslyn/tree/features/field-keyword) | [Merged into 17.12p3](https://github.com/dotnet/roslyn/issues/57012) | [Youssef1313](https://github.com/Youssef1313), [cston](https://github.com/cston) | [333fred](https://github.com/333fred), [RikkiGibson](https://github.com/RikkiGibson) | [CyrusNajmabadi](https://github.com/CyrusNajmabadi) | [CyrusNajmabadi](https://github.com/CyrusNajmabadi) | | [First-class Span Types](https://github.com/dotnet/csharplang/issues/7905) | [FirstClassSpan](https://github.com/dotnet/roslyn/tree/features/FirstClassSpan) | [Merged into 17.13p1](https://github.com/dotnet/roslyn/issues/73445) | [jjonescz](https://github.com/jjonescz) | [cston](https://github.com/cston), [333fred](https://github.com/333fred) | | [333fred](https://github.com/333fred), [stephentoub](https://github.com/stephentoub) | -| [Unbound generic types in `nameof`](https://github.com/dotnet/csharplang/issues/8480) | [PR](https://github.com/dotnet/roslyn/pull/75368) | [In Progress](https://github.com/dotnet/roslyn/pull/75368) | [CyrusNajmabadi](https://github.com/CyrusNajmabadi) | [jcouv](https://github.com/jcouv) | [CyrusNajmabadi](https://github.com/CyrusNajmabadi) | [CyrusNajmabadi](https://github.com/CyrusNajmabadi) | -| Runtime Async | [features/runtime-async](https://github.com/dotnet/roslyn/tree/features/runtime-async) | [In Progress](https://github.com/dotnet/roslyn/issues/75960) | [333fred](https://github.com/333fred) | [jcouv](https://github.com/jcouv), [RikkiGibson](https://github.com/RikkiGibson) | | | +| [Unbound generic types in `nameof`](https://github.com/dotnet/csharplang/issues/8480) | [PR](https://github.com/dotnet/roslyn/pull/75368) | [Merged into 17.13p2](https://github.com/dotnet/roslyn/pull/75368) | [CyrusNajmabadi](https://github.com/CyrusNajmabadi) | [jcouv](https://github.com/jcouv), [AlekseyTs](https://github.com/AlekseyTs) | [CyrusNajmabadi](https://github.com/CyrusNajmabadi) | [CyrusNajmabadi](https://github.com/CyrusNajmabadi) | # Working Set VB | Feature | Branch | State | Developer | Reviewer | IDE Buddy | LDM Champ | | ------- | ------ | ----- | --------- | -------- | --------- | --------- | | Recognizing 'unmanaged' constraint | main | [Merged into 17.13 P2](https://github.com/dotnet/roslyn/pull/75665) | [AlekseyTs](https://github.com/AlekseyTs) | [cston](https://github.com/cston), [333fred](https://github.com/333fred) | (no IDE impact) | [jaredpar](https://github.com/jaredpar) | -| Overload Resolution Priority | [features/VBOverloadResolutionPriority](https://github.com/dotnet/roslyn/tree/features/VBOverloadResolutionPriority) | In Progress | [AlekseyTs](https://github.com/AlekseyTs) | [333fred](https://github.com/333fred), [cston](https://github.com/cston) | (no IDE impact) | [333fred](https://github.com/333fred) | +| Overload Resolution Priority | main | [Merged into 17.13 P3](https://github.com/dotnet/roslyn/pull/76419) | [AlekseyTs](https://github.com/AlekseyTs) | [333fred](https://github.com/333fred), [cston](https://github.com/cston) | (no IDE impact) | [333fred](https://github.com/333fred) | # C# 13.0 diff --git a/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 10.md b/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 10.md index b1f6e72765761..1d315df482f1a 100644 --- a/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 10.md +++ b/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 10.md @@ -19,7 +19,7 @@ Assert.Equal([2], x); // previously Assert.Equal(T[], T[]), now ambiguous wit Assert.Equal([2], x.AsSpan()); // workaround var y = new int[] { 1, 2 }; -var s = new ArraySegment(x, 1, 1); +var s = new ArraySegment(y, 1, 1); Assert.Equal(y, s); // previously Assert.Equal(T, T), now ambiguous with Assert.Equal(Span, Span) Assert.Equal(y.AsSpan(), s); // workaround ``` @@ -39,11 +39,26 @@ static class C public static void R(IEnumerable e) => Console.Write(1); public static void R(Span s) => Console.Write(2); // another workaround: - [OverloadResolutionPriority(1)] public static void R(ReadOnlySpan s) => Console.Write(3); } ``` +For that reason, `ReadOnlySpan` is generally preferred over `Span` by overload resolution in C# 14. +In some cases, that might lead to compilation breaks, +for example when there are overloads for both `Span` and `ReadOnlySpan`, both taking and returning the same span type: + +```cs +double[] x = new double[0]; +Span y = MemoryMarshal.Cast(x); // previously worked, now compilation error +Span z = MemoryMarshal.Cast(x.AsSpan()); // workaround + +static class MemoryMarshal +{ + public static ReadOnlySpan Cast(ReadOnlySpan span) => default; + public static Span Cast(Span span) => default; +} +``` + When using C# 14 or newer and targeting a .NET older than `net10.0` or .NET Framework with `System.Memory` reference, there is a breaking change with `Enumerable.Reverse` and arrays: @@ -89,3 +104,126 @@ class C } } ``` + +## Set state of enumerator object to "after" during disposal + +***Introduced in Visual Studio 2022 version 17.13*** + +The state machine for enumerators incorrectly allowed resuming execution after the enumerator was disposed. +Now, `MoveNext()` on a disposed enumerator properly returns `false` without executing any more user code. + +```csharp +var enumerator = C.GetEnumerator(); + +Console.Write(enumerator.MoveNext()); // prints True +Console.Write(enumerator.Current); // prints 1 + +enumerator.Dispose(); + +Console.Write(enumerator.MoveNext()); // now prints False + +class C +{ + public static IEnumerator GetEnumerator() + { + yield return 1; + Console.Write("not executed after disposal") + yield return 2; + } +} +``` + +## `UnscopedRefAttribute` cannot be used with old ref safety rules + +***Introduced in Visual Studio 2022 version 17.13*** + +The `UnscopedRefAttribute` unintentionally affected code compiled by new Roslyn compiler versions +even when the code was compiled in the context of the earlier ref safety rules +(i.e., targeting C# 10 or earlier with net6.0 or earlier). +However, the attribute should not have an effect in that context, and that is now fixed. + +Code that previously did not report any errors in C# 10 or earlier with net6.0 or earlier can now fail to compile: + +```cs +using System.Diagnostics.CodeAnalysis; +struct S +{ + public int F; + + // previously allowed in C# 10 with net6.0 + // now fails with the same error as if the [UnscopedRef] wasn't there: + // error CS8170: Struct members cannot return 'this' or other instance members by reference + [UnscopedRef] public ref int Ref() => ref F; +} +``` + +To prevent misunderstanding (thinking the attribute has an effect +but it actually does not because your code is compiled with the earlier ref safety rules), +a warning is reported when the attribute is used in C# 10 or earlier with net6.0 or earlier: + +```cs +using System.Diagnostics.CodeAnalysis; +struct S +{ + // both are errors in C# 10 with net6.0: + // warning CS9269: UnscopedRefAttribute is only valid in C# 11 or later or when targeting net7.0 or later. + [UnscopedRef] public ref int Ref() => throw null!; + public static void M([UnscopedRef] ref int x) { } +} +``` + +## Variance of `scoped` and `[UnscopedRef]` is more strict + +***Introduced in Visual Studio 2022 version 17.13*** + +Scope can be changed when overriding a method, implementing an interface, or converting a lambda/method to a delegate under +[some conditions](https://github.com/dotnet/csharplang/blob/05064c2a9567b7a58a07e526dff403ece1866541/proposals/csharp-11.0/low-level-struct-improvements.md#scoped-mismatch) +(roughly, `scoped` can be added and `[UnscopedRef]` can be removed). +Previously, the compiler did not report an error/warning for such mismatch under some circumstances, but it is now always reported. +Note that the error is downgraded to a warning in `unsafe` contexts and also (in scenarios where it would be a breaking change) with LangVersion 12 or lower. + +```cs +D1 d1 = (ref int i) => { }; // previously no mismatch error reported, now: + // error CS8986: The 'scoped' modifier of parameter 'i' doesn't match target 'D1'. + +D2 d2 = (ref int i) => ref i; // an error was and continues to be reported: + // error CS8986: The 'scoped' modifier of parameter 'i' doesn't match target 'D2'. + +delegate void D1(scoped ref int x); +delegate ref int D2(scoped ref int x); +``` + +```cs +using System.Diagnostics.CodeAnalysis; + +D1 d1 = ([UnscopedRef] ref int i) => { }; // previously no mismatch error reported, now: + // error CS8986: The 'scoped' modifier of parameter 'i' doesn't match target 'D1'. + +D2 d2 = ([UnscopedRef] ref int i) => ref i; // an error was and continues to be reported: + // error CS8986: The 'scoped' modifier of parameter 'i' doesn't match target 'D2'. + +delegate void D1(ref int x); +delegate ref int D2(ref int x); +``` + +## `Microsoft.CodeAnalysis.EmbeddedAttribute` is validated on declaration + +***Introduced in Visual Studio 2022 version 17.13*** + +The compiler now validates the shape of `Microsoft.CodeAnalysis.EmbeddedAttribute` when declared in source. Previously, the compiler +would allow user-defined declarations of this attribute, but only when it didn't need to generate one itself. We now validate that: + +1. It must be internal +2. It must be a class +3. It must be sealed +4. It must be non-static +5. It must have an internal or public parameterless constructor +6. It must inherit from System.Attribute. +7. It must be allowed on any type declaration (class, struct, interface, enum, or delegate) + +```cs +namespace Microsoft.CodeAnalysis; + +// Previously, sometimes allowed. Now, CS9271 +public class EmbeddedAttribute : Attribute {} +``` diff --git a/docs/compilers/CSharp/Runtime Async Design.md b/docs/compilers/CSharp/Runtime Async Design.md index ba218eaceb8db..e577604505e9f 100644 --- a/docs/compilers/CSharp/Runtime Async Design.md +++ b/docs/compilers/CSharp/Runtime Async Design.md @@ -40,15 +40,22 @@ public static class RuntimeHelpers } ``` -Additionally, we use the following helper attributes to indicate information to the runtime. If these attributes are not present in the reference assemblies, we will generate them; the runtime matches by full -name, not by type identity, so we do not need to care about using the "canonical" versions. +We presume the following `MethodImplOptions` bit is present. This is used to indicate to the JIT that it should generate an async state machine for the method. ```cs namespace System.Runtime.CompilerServices; -// Used to tell the runtime to generate the async state machinery for this method -[AttributeUsage(AttributeTargets.Method)] -public class RuntimeAsyncMethodAttribute() : Attribute(); +public enum MethodImplOptions +{ + Async = 1024 +} +``` + +Additionally, we use the following helper type to indicate information to the runtime. If this type is not present in the reference assemblies, we will generate it; the runtime matches by full +name, not by type identity, so we do not need to care about using the "canonical" version. + +```cs +namespace System.Runtime.CompilerServices; // Used to mark locals that should be hoisted to the generated async closure. Note that the runtime does not guarantee that all locals marked with this modreq will be hoisted; if it can prove that it // doesn't need to hoist a variable, it may avoid doing so. @@ -67,7 +74,7 @@ public class RuntimeAsyncMethodGenerationAttribute(bool runtimeAsync) : Attribut ## Transformation strategy -As mentioned previously, we try to expose as little of this to initial binding as possible. The one major exception to this is our handling of the `RuntimeAsyncMethodAttribute`; we do not let this be applied to +As mentioned previously, we try to expose as little of this to initial binding as possible. The one major exception to this is our handling of the `MethodImplOption.Async`; we do not let this be applied to user code, and will issue an error if a user tries to do this by hand. Compiler generated async state machines and runtime generated async share some of the same building blocks. Both need to have `await`s with in `catch` and `finally` blocks rewritten to pend the exceptions, @@ -98,7 +105,7 @@ async Task M() ``` ```cs -[RuntimeAsyncMethod, Experimental] +[MethodImpl(MethodImplOptions.Async), Experimental] Task M() { // ... see lowering strategy for each kind of await below ... diff --git a/docs/compilers/Visual Basic/Compiler Breaking Changes - DotNet 10.md b/docs/compilers/Visual Basic/Compiler Breaking Changes - DotNet 10.md new file mode 100644 index 0000000000000..da5f38b19a035 --- /dev/null +++ b/docs/compilers/Visual Basic/Compiler Breaking Changes - DotNet 10.md @@ -0,0 +1,61 @@ +# Breaking changes in Roslyn after .NET 9.0.100 through .NET 10.0.100 + +This document lists known breaking changes in Roslyn after .NET 9 general release (.NET SDK version 9.0.100) through .NET 10 general release (.NET SDK version 10.0.100). + +## Set state of enumerator object to "after" during disposal + +***Introduced in Visual Studio 2022 version 17.13*** + +The state machine for enumerators incorrectly allowed resuming execution after the enumerator was disposed. +Now, `MoveNext()` on a disposed enumerator properly returns `false` without executing any more user code. + +```vb +Imports System +Imports System.Collections.Generic + +Module Program + Sub Main() + Dim enumerator = C.GetEnumerator() + + Console.Write(enumerator.MoveNext()) ' prints True + Console.Write(enumerator.Current) ' prints 1 + + enumerator.Dispose() + + Console.Write(enumerator.MoveNext()) ' now prints False + End Sub +End Module + +Class C + Public Shared Iterator Function GetEnumerator() As IEnumerator(Of Integer) + Yield 1 + Console.Write("not executed after disposal") + Yield 2 + End Function +End Class +``` + +## `Microsoft.CodeAnalysis.EmbeddedAttribute` is validated on declaration + +***Introduced in Visual Studio 2022 version 17.13*** + +The compiler now validates the shape of `Microsoft.CodeAnalysis.EmbeddedAttribute` when declared in source. Previously, the compiler +would allow user-defined declarations of this attribute with any shape. We now validate that: + +1. It must be Friend +2. It must be a Class +3. It must be NotInheritable +4. It must not be a Module +5. It must have a Public parameterless constructor +6. It must inherit from System.Attribute. +7. It must be allowed on any type declaration (Class, Structure, Interface, Enum, or Delegate) + +```vb +Namespace Microsoft.CodeAnalysis + + ' Previously allowed. Now, BC37335 + Public Class EmbeddedAttribute + Inherits Attribute + End Class +End Namespace +``` diff --git a/docs/contributing/Bootstrap Builds.md b/docs/contributing/Bootstrap Builds.md index 128a4d59fe740..a51992681abfe 100644 --- a/docs/contributing/Bootstrap Builds.md +++ b/docs/contributing/Bootstrap Builds.md @@ -1,108 +1 @@ -# Bootstrap Builds - -The build correctness leg ensures that the latest code in dotnet/roslyn can be used to build dotnet/roslyn. Essentially our compiler can bootstrap itself. - -## Why? - -The reason we go through so much effort is failures of this nature are incredibly hard to track down after the fact. The compiler is a complex tool and dotnet/roslyn is a large code base. It can take significant time to work out which of the ~300 commits since the last successful bootstrap is causing the current one to fail. - -In the past we used to run a bootstrap exercise roughly once a month. Every time there was a failure to build dotnet/roslyn with the latest compiler and it often took weeks for us to understand what change caused the failure. That resulted in a **lot** of wasted time and almost caused us to slip several releases. - -The build correctness jobs was introduced to solve this problem. The compiler verifies it can bootstrap on every change which means we find the failures immediately. - -## Process - -The build correctness job works by first building the Microsoft.Net.Compilers.Toolset package. This gives us a functioning compiler with the latest changes. This build occurs using the `/define:BOOTSTRAP` which allows the compiler to make failures more actionable. This is primarily leveraged in the following ways: - -- Inserts a [ExitingTraceListener](https://github.com/dotnet/roslyn/blob/main/src/Compilers/Shared/ExitingTraceListener.cs) into the process trace listeners. This means any `Debug.Assert` failure will result in the compilation failing with an actionable stack trace. -- Defines a [ValidateBootstrap](https://github.com/dotnet/roslyn/blob/main/src/Compilers/Core/MSBuildTask/ValidateBootstrap.cs). This lets us validate that the compiler used in the bootstrap build is actually the one we built vs. the default. This helps protect against build authoring changes which could inadvertently cause the default compiler to be used in a bootstrap build. - -The job then cleans out all of the artifacts from the build and starts a normal build of Roslyn.sln but specifies `/p:BootstrapBuildPath=...`. This causes two files to be loaded: - -- [Bootstrap.props](https://github.com/dotnet/roslyn/blob/main/eng/targets/Bootstrap.props): loads the bootstrap compiler over the default one -- [Bootstrap.targets](https://github.com/dotnet/roslyn/blob/main/eng/targets/Bootstrap.targets): verifies the bootstrap compiler was actually used - -This leg also ensures that the binary log and the build server log are captured in the set of published artifacts to allow for easy investigations. - -## Investigating - -The first step for investigating a correctness build failure is downloading the log files. These are available in the published artifacts - -![Published Artifacts](images/bootstrap-logs.png) - -The two most interesting files are: - -1. Build.Server.log: this is the text log of the compilation process. All stack traces and server error messages will be present in this file -1. Build.binlog: this is the binary log that results from building dotnet/roslyn with a bootstrap compiler. - -The build server log file will contain the reason why the particular request to the compiler failed. In most cases searching for one of two terms will take you straight to the failure. - -The first term to search for is `"Debug.Assert"` (no quotes). The most common cause of a bootstrap failure is a `Debug.Assert` call failing during compilation. This will result in an exception being added to the log with the full stack trace. For example: - -```txt -ID=VBCSCompiler TID=33: Debug.Assert failed with message: Fail: -Stack Trace - at Microsoft.CodeAnalysis.CommandLine.ExitingTraceListener.Exit(String originalMessage) - at Microsoft.CodeAnalysis.CommandLine.ExitingTraceListener.WriteLine(String message) - at System.Diagnostics.TraceInternal.Fail(String message) - at System.Diagnostics.Debug.Assert(Boolean condition) - at Microsoft.CodeAnalysis.GeneratorDriver..ctor(GeneratorDriverState state) - at Microsoft.CodeAnalysis.CSharp.CSharpGeneratorDriver..ctor(GeneratorDriverState state) - at Microsoft.CodeAnalysis.CSharp.CSharpGeneratorDriver.FromState(GeneratorDriverState state) - at Microsoft.CodeAnalysis.GeneratorDriver.RunGeneratorsAndUpdateCompilation(Compilation compilation, Compilation& outputCompilation, ImmutableArray`1& diagnostics, CancellationToken cancellationToken) - at Microsoft.CodeAnalysis.CommonCompiler.RunGenerators(Compilation input, ParseOptions parseOptions, ImmutableArray`1 generators, AnalyzerConfigOptionsProvider analyzerConfigOptionsProvider, ImmutableArray`1 additionalTexts, DiagnosticBag generatorDiagnostics) - at Microsoft.CodeAnalysis.CommonCompiler.CompileAndEmit(TouchedFileLogger touchedFilesLogger, Compilation& compilation, ImmutableArray`1 analyzers, ImmutableArray`1 generators, ImmutableArray`1 additionalTextFiles, AnalyzerConfigSet analyzerConfigSet, ImmutableArray`1 sourceFileAnalyzerConfigOptions, ImmutableArray`1 embeddedTexts, DiagnosticBag diagnostics, CancellationToken cancellationToken, CancellationTokenSource& analyzerCts, AnalyzerDriver& analyzerDriver, Nullable`1& generatorTimingInfo) - at Microsoft.CodeAnalysis.CommonCompiler.RunCore(TextWriter consoleOutput, ErrorLogger errorLogger, CancellationToken cancellationToken) - at Microsoft.CodeAnalysis.CommonCompiler.Run(TextWriter consoleOutput, CancellationToken cancellationToken) - at Microsoft.CodeAnalysis.CompilerServer.CompilerServerHost.RunCompilation(RunRequest& request, CancellationToken cancellationToken) - at Microsoft.CodeAnalysis.CompilerServer.CompilerServerHost.Microsoft.CodeAnalysis.CompilerServer.ICompilerServerHost.RunCompilation(RunRequest& request, CancellationToken cancellationToken) - at Microsoft.CodeAnalysis.CompilerServer.ClientConnectionHandler.<>c__DisplayClass8_0.b__1() - at System.Threading.Tasks.Task`1.InnerInvoke() - at System.Threading.Tasks.Task.Execute() - at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx) - at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx) - at System.Threading.Tasks.Task.ExecuteWithThreadLocal(Task& currentTaskSlot) - at System.Threading.Tasks.Task.ExecuteEntry(Boolean bPreventDoubleExecution) - at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx) - at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx) - at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state) - at System.Threading.ThreadHelper.ThreadStart(Object obj) - ``` - -These failures are almost always due to changes being tested. Essentially the change updated compiler logic in such a way that it caused an `Assert` to fail. On occasion this will also fail because an IDE change introduces a coding pattern that sets of a latent bug in the compiler or analyzer but this is certainly the rare case. - -The next term to search for is `"Error "` (no quotes but keep the space). This will be added to the log every the server hits an error and needs to shut down. - -```txt -ID=MSBuild 60300 TID=3: Error Error: 'EndOfStreamException' 'Reached end of stream before end of read.' occurred during 'Reading response for d2c3aeac-bd8a-4251-bde0-2e11bbc57d13' -Stack trace: - at Microsoft.CodeAnalysis.CommandLine.BuildProtocolConstants.d__4.MoveNext() in C:\Users\jaredpar\code\wt\ros2\src\Compilers\Core\CommandLine\BuildProtocol.cs:line 641 ---- End of stack trace from previous location where exception was thrown --- - at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) - at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) - at System.Runtime.CompilerServices.ConfiguredTaskAwaitable.ConfiguredTaskAwaiter.GetResult() - at Microsoft.CodeAnalysis.CommandLine.BuildResponse.d__5.MoveNext() in C:\Users\jaredpar\code\wt\ros2\src\Compilers\Core\CommandLine\BuildProtocol.cs:line 342 ---- End of stack trace from previous location where exception was thrown --- - at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) - at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) - at System.Runtime.CompilerServices.ConfiguredTaskAwaitable`1.ConfiguredTaskAwaiter.GetResult() - at Microsoft.CodeAnalysis.CommandLine.BuildServerConnection.<g__tryRunRequestAsync|7_1>d.MoveNext() in C:\Users\jaredpar\code\wt\ros2\src\Compilers\Shared\BuildServerConnection.cs:line 288 -``` - -These type of errors, when not paired with a `Debug.Assert` failure, are almost always bugs in the compiler server. Please contact the compiler team to help track down such failures. - -Note: when you encounter a case where the log file does not have an actionable description of why a build failed, strongly consider sending a PR that fixes this. This approach is why the log is such a valuable tool for tracking down bootstrap failures. - -## Debugging - -To debug a bootstrap build failure locally do the following. - -The first step is disabling the `ExitingTraceListener`. This is important for CI where the compiler needs to crash on a `Debug.Assert` failure vs. popping up a dialog that would hang CI. When debugging locally though developers want the `Debug.Assert` pops up a dialog behavior. To disable the `ExitingTraceListener` comment out the following line: - -https://github.com/dotnet/roslyn/blob/d73d31cbccb9aa850f3582afb464b709fef88fd7/src/Compilers/Server/VBCSCompiler/VBCSCompiler.cs#L22 - -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 -``` +Moved to [bootstrap-builds.md](docs/contributing/bootstrap-builds.md) \ No newline at end of file diff --git a/docs/contributing/Compiler Test Plan.md b/docs/contributing/Compiler Test Plan.md index ec87b5569012d..138e9cc6e197f 100644 --- a/docs/contributing/Compiler Test Plan.md +++ b/docs/contributing/Compiler Test Plan.md @@ -34,6 +34,7 @@ This document provides guidance for thinking about language interactions and tes - Performance and stress testing - Can build VS - Check that `Obsolete` is honored for members used in binding/lowering +- LangVersion # Type and members - Access modifiers (public, protected, internal, protected internal, private protected, private), static, ref @@ -51,6 +52,9 @@ This document provides guidance for thinking about language interactions and tes - events (including add/remove accessors) - Parameter modifiers: ref, out, in, ref readonly, params (for array, for non-array) - Attributes (including generic attributes and security attributes) + - Compiler-recognized attributes should not have any effect in earlier LangVersions, + except a LangVersion error should be reported when functionality depending on the attribute is used + (for example, InlineArray conversion to Span). - Generics (type arguments, variance, constraints including `class`, `struct`, `new()`, `unmanaged`, `notnull`, types and interfaces with nullability) - Default and constant values - Partial classes diff --git a/docs/contributing/Powershell Guidelines.md b/docs/contributing/Powershell Guidelines.md index 9a1852178a291..987e87216f0c9 100644 --- a/docs/contributing/Powershell Guidelines.md +++ b/docs/contributing/Powershell Guidelines.md @@ -106,3 +106,22 @@ in source and unified build. Until that moves to `pwsh` our scripts need to stay The exception is that our VS Code helper scripts should use `pwsh`. That is not a part of our infrastructure and needs to run cross platform hence `pwsh` is appropriate. + +### Supporting .cmd file + +Consider adding a `.cmd` file that calls the `.ps1` file. This is to support users who are not +running a powershell shell. It also helps with ensuring the script is run locally the same it is +run in CI by controlling the powershell used to invoke the script. + +test.cmd + +```cmd +@echo off +set PSMODULEPATH= +powershell -noprofile -ExecutionPolicy Unrestricted -file "%~dp0\test.ps1" %* +``` + +Note: the `PSMODULEPATH` is cleared to ensure a pwsh shell [does not interfere][psmodulepath] +with launching powershell. + +[psmodulepath]: https://github.com/PowerShell/PowerShell/discussions/24630 \ No newline at end of file diff --git a/docs/contributing/README.md b/docs/contributing/README.md index e709034cfcac6..409f48cc9d819 100644 --- a/docs/contributing/README.md +++ b/docs/contributing/README.md @@ -8,8 +8,8 @@ Guides for contributing to this project - [Windows](Building%2C%20Debugging%2C%20and%20Testing%20on%20Windows.md) - [Localization in tests](Localization%20In%20Compiler%20Tests.md) - [Nullable Annotations](Nullable%20Annotations.md) -- [Target Framework Strategy](Target%20Framework%20Strategy.md) -- [Bootstrap Builds](Bootstrap%20Builds.md) +- [Target Framework Strategy](target-framework-strategy.md) +- [Bootstrap Builds](bootstrap-builds.md) - [API Review Process](API%20Review%20Process.md) - [Developing a Language Feature](Developing%20a%20Language%20Feature.md) - [Documentation for IDE CodeStyle analyzers](Documentation%20for%20IDE%20CodeStyle%20analyzers.md) diff --git a/docs/contributing/Target Framework Strategy.md b/docs/contributing/Target Framework Strategy.md index 1fc5b952daef1..b752dedf51f52 100644 --- a/docs/contributing/Target Framework Strategy.md +++ b/docs/contributing/Target Framework Strategy.md @@ -1,122 +1 @@ -# Target Framework Strategy - -## Layers - -The roslyn repository produces components for a number of different products that push varying ship and TFM constraints on us. A summary of some of our dependencies are : - -- Build Tools: requires us to ship compilers on `net472` -- .NET SDK: requires us to ship compilers on current servicing target framework (presently `net8.0`) -- Source build: requires us to ship `$(NetCurrent)` and `$(NetPrevious)` in workspaces and below (presently `net9.0` and `net8.0` respectively) -- Visual Studio: requires us to ship `net472` for base IDE components and `$(NetVisualStudio)` (presently `net8.0`) for private runtime components. -- Visual Studio Code: expects us to ship against the same runtime as DevKit (presently `net7.0`) to avoid two runtime downloads. -- MSBuildWorkspace: requires to ship a process that must be usable on the lowest supported SDK (presently `net6.0`) - -It is not reasonable for us to take the union of all TFM and multi-target every single project to them. That would add several hundred compilations to any build operation which would in turn negatively impact our developer throughput. Instead we attempt to use the TFM where needed. That keeps our builds smaller but increases complexity a bit as we end up shipping a mix of TFM for binaries across our layers. - -## Picking the right TargetFramework - -Projects in our repository should include the following values in `` based on the rules below: - -1. `$(NetRoslynSourceBuild)`: code that needs to be part of source build. This property will change based on whether the code is building in a source build context or official builds. - a. In official builds this will include the TFMs for `$(NetVSShared)` - b. In source builds this will include `$(NetRoslyn)` -2. `$(NetVS)`: code that needs to execute on the private runtime of Visual Studio. -3. `$(NetVSCode)`: code that needs to execute in DevKit host -4. `$(NetVSShared)`: code that needs to execute in both Visual Studio and VS Code but does not need to be source built. -5. `$(NetRoslyn)`: code that needs to execute on .NET but does not have any specific product deployment requirements. For example utilities that are used by our infra, compiler unit tests, etc ... This property also controls which of the frameworks the compiler builds against are shipped in the toolset packages. This value will potentially change in source builds. -6. `$(NetRoslynAll)`: code, generally test utilities, that need to build for all .NET runtimes that we support. -7. `$(NetRoslynBuildHostNetCoreVersion)`: the target used for the .NET Core BuildHost process used by MSBuildWorkspace. -8. `$(NetRoslynNext)`: code that needs to run on the next .NET Core version. This is used during the transition to a new .NET Core version where we need to move forward but don't want to hard code a .NET Core TFM into the build files. - -This properties `$(NetCurrent)`, `$(NetPrevious)` and `$(NetMinimum)` are not used in our project files because they change in ways that make it hard for us to maintain corect product deployments. Our product ships on VS and VS Code which are not captured by arcade `$(Net...)` macros. Further as the arcade properties change it's very easy for us to end up with duplicate entries in a `` setting. Instead our repo uses the above values and when inside source build or VMR our properties are initialized with arcade properties. - -**DO NOT** hard code .NET Core TFMs in project files. Instead use the properties above as that lets us centrally manage them and structure the properties to avoid duplication. It is fine to hard code other TFMs like `netstandard2.0` or `net472` as those are not expected to change. - -**DO NOT** use `$(NetCurrent)` or `$(NetPrevious)` in project files. These should only be used inside of `TargetFrameworks.props` to initialize the above values in certain configurations. - -## Require consistent API across Target Frameworks - -It is important that our shipping APIs maintain consistent API surface area across target frameworks. That is true whether the API is `public` or `internal`. - -The reason for `public` is standard design pattern. The reason for `internal` is a combination of the following problems: - -- Our repository makes use of `InternalsVisibleTo` which allows other assemblies to directly reference signatures of `internal` members. -- Our repository ships a mix of target frameworks. Typically workspaces and below will ship more recent TFMs than the layers above it. Compiler has to ship newer TFM for source build while IDE is constrained by Visual Studio's private runtime hence adopts newer TFM slower. -- Our repository invests in polyfill APIs to make compiling against multiple TFMs in the same project a seamless experience. - -Taken together though this means that our `internal` surface area in many cases is effectively `public` when it comes to binary compatibility. For example a consuming project can end up with `net7.0` binaries from workspaces layer and `net6.0` binaries from IDE layer. Because there is `InternalsVisibleTo` between these binaries the `internal` API surface area is effectively `public`. This requires us to have a consistent strategy for achieving binary compatibility across TFM combinations. - -Consider a specific example of what goes wrong when our `internal` APIs are not consistent across TFM: - -- Workspaces today targets `net6.0` and `net7.0` and it contains our `EnumerableExtensions.cs` which polyfills many extensions methods on `IEnumerable`. In `net7.0` the `Order` extension method is not needed because it was put into the .NET core libraries. -- Language Server Protocol targets `net6.0` and consumes the `Order` polyfill from Workspaces - -Let's assume for a second that we `#if` the `Order` method such that it's not present in `net7.0`. Locally this all builds because we compile the `net6.0` versions against each other so they're consistent. However if an external project which targets `net7.0` and consumes both Workspaces and Language Server Protocol then it will be in a broken state. The Protocol binary is expecting Workspaces to contain a polyfill method for `Order` but it does not since it's at `net7.0` and it was `#if` out. As a result this will fail at runtime with missing method exceptions. - -This problem primarily comes from our use of polyfill APIs. To avoid this we employ the following rule: - -> When there is a `#if` directive that matches the regex `#if !?NET.*` that declares a non-private member, there must be an `#else` that defines an equivalent binary compatible symbol - -This comes up in two forms: - -### Pattern for types - -When creating a polyfill for a type use the `#if !NET...` to declare the type and in the `#else` use a `TypeForwardedTo` for the actual type. - -Example: - -```csharp -#if NET6_0_OR_GREATER - -using System.Runtime.CompilerServices; - -#pragma warning disable RS0016 // Add public types and members to the declared API (this is a supporting forwarder for an internal polyfill API) -[assembly: TypeForwardedTo(typeof(IsExternalInit))] -#pragma warning restore RS0016 // Add public types and members to the declared API - -#else - -using System.ComponentModel; - -namespace System.Runtime.CompilerServices -{ - internal static class IsExternalInit - { - } -} - -#endif -``` - -### Pattern for extension methods - -When creating a polyfill for an extension use the `#if NET...` to declare the extension method and the `#else` to declare the same method without `this`. That will put a method with the expected signature in the binary but avoids it appearing as an extension method within that target framework. - -```csharp -#if NET7_0_OR_GREATER - public static IOrderedEnumerable Order(IEnumerable source) where T : IComparable -#else - public static IOrderedEnumerable Order(this IEnumerable source) where T : IComparable -#endif -``` - -## Transitioning to new .NET SDK - -As the .NET team approaches releasing a new .NET SDK the Roslyn team will begin using preview versions of that SDK in our build. This will often lead to test failures in our CI system due to underlying behavior changes in the runtime. These failures will often not show up when running in Visual Studio due to the way the runtime for the test runner is chosen. - -To ensure we have a simple developer environment such project should be moved to to the `$(NetRoslynNext)` target framework. That ensures the new runtime is loaded when running tests locally. - -When the .NET SDK RTMs and Roslyn adopts it all occurrences of `$(NetRoslynNext)` will be moved to simply `$(NetRoslyn)`. - -**DO NOT** include both `$(NetRoslyn)` and `$(NetRoslynNext)` in the same project unless there is a very specific reason that both tests are adding value. The most common case is that the runtime has changed behavior and we simply need to update our baselines to match it. Adding extra TFMs for this just increases test time for very little gain. - -## Checklist for updating TFMs (once a year) - -- Update `TargetFrameworks.props`. - - Ensure we have the correct TFM for VS / VSCode (usually not the latest TFM). -- Might need updating `MicrosoftNetCompilersToolsetVersion` in `eng\Versions.props` to consume latest compiler features. -- Change `$(NetRoslynNext)` references to `$(NetRoslyn)` in project files. -- Update TFMs in code/scripts/pipelines (search for the old `netX.0` and replace with the new `netY.0`). -- Replace `#if NET7_0_OR_GREATER` corresponding to the no longer used TFM (`net7.0` in this example) with the lowest used TFM (e.g., `net8.0`: `#if NET8_0_OR_GREATER`) and similarly the negated variant `#if !NET7_0_OR_GREATER` with `#if !NET8_0_OR_GREATER`. See https://github.com/dotnet/roslyn/issues/75453#issuecomment-2405500584. -- Check that the same number of tests still run in CI (they are not unintentionally filtered out by TFM). -- Try an official build, a VS insertion. +Moved to [target-framework-strategy.md](docs/contributing/target-framework-strategy.md) \ No newline at end of file diff --git a/docs/contributing/bootstrap-builds.md b/docs/contributing/bootstrap-builds.md new file mode 100644 index 0000000000000..128a4d59fe740 --- /dev/null +++ b/docs/contributing/bootstrap-builds.md @@ -0,0 +1,108 @@ +# Bootstrap Builds + +The build correctness leg ensures that the latest code in dotnet/roslyn can be used to build dotnet/roslyn. Essentially our compiler can bootstrap itself. + +## Why? + +The reason we go through so much effort is failures of this nature are incredibly hard to track down after the fact. The compiler is a complex tool and dotnet/roslyn is a large code base. It can take significant time to work out which of the ~300 commits since the last successful bootstrap is causing the current one to fail. + +In the past we used to run a bootstrap exercise roughly once a month. Every time there was a failure to build dotnet/roslyn with the latest compiler and it often took weeks for us to understand what change caused the failure. That resulted in a **lot** of wasted time and almost caused us to slip several releases. + +The build correctness jobs was introduced to solve this problem. The compiler verifies it can bootstrap on every change which means we find the failures immediately. + +## Process + +The build correctness job works by first building the Microsoft.Net.Compilers.Toolset package. This gives us a functioning compiler with the latest changes. This build occurs using the `/define:BOOTSTRAP` which allows the compiler to make failures more actionable. This is primarily leveraged in the following ways: + +- Inserts a [ExitingTraceListener](https://github.com/dotnet/roslyn/blob/main/src/Compilers/Shared/ExitingTraceListener.cs) into the process trace listeners. This means any `Debug.Assert` failure will result in the compilation failing with an actionable stack trace. +- Defines a [ValidateBootstrap](https://github.com/dotnet/roslyn/blob/main/src/Compilers/Core/MSBuildTask/ValidateBootstrap.cs). This lets us validate that the compiler used in the bootstrap build is actually the one we built vs. the default. This helps protect against build authoring changes which could inadvertently cause the default compiler to be used in a bootstrap build. + +The job then cleans out all of the artifacts from the build and starts a normal build of Roslyn.sln but specifies `/p:BootstrapBuildPath=...`. This causes two files to be loaded: + +- [Bootstrap.props](https://github.com/dotnet/roslyn/blob/main/eng/targets/Bootstrap.props): loads the bootstrap compiler over the default one +- [Bootstrap.targets](https://github.com/dotnet/roslyn/blob/main/eng/targets/Bootstrap.targets): verifies the bootstrap compiler was actually used + +This leg also ensures that the binary log and the build server log are captured in the set of published artifacts to allow for easy investigations. + +## Investigating + +The first step for investigating a correctness build failure is downloading the log files. These are available in the published artifacts + +![Published Artifacts](images/bootstrap-logs.png) + +The two most interesting files are: + +1. Build.Server.log: this is the text log of the compilation process. All stack traces and server error messages will be present in this file +1. Build.binlog: this is the binary log that results from building dotnet/roslyn with a bootstrap compiler. + +The build server log file will contain the reason why the particular request to the compiler failed. In most cases searching for one of two terms will take you straight to the failure. + +The first term to search for is `"Debug.Assert"` (no quotes). The most common cause of a bootstrap failure is a `Debug.Assert` call failing during compilation. This will result in an exception being added to the log with the full stack trace. For example: + +```txt +ID=VBCSCompiler TID=33: Debug.Assert failed with message: Fail: +Stack Trace + at Microsoft.CodeAnalysis.CommandLine.ExitingTraceListener.Exit(String originalMessage) + at Microsoft.CodeAnalysis.CommandLine.ExitingTraceListener.WriteLine(String message) + at System.Diagnostics.TraceInternal.Fail(String message) + at System.Diagnostics.Debug.Assert(Boolean condition) + at Microsoft.CodeAnalysis.GeneratorDriver..ctor(GeneratorDriverState state) + at Microsoft.CodeAnalysis.CSharp.CSharpGeneratorDriver..ctor(GeneratorDriverState state) + at Microsoft.CodeAnalysis.CSharp.CSharpGeneratorDriver.FromState(GeneratorDriverState state) + at Microsoft.CodeAnalysis.GeneratorDriver.RunGeneratorsAndUpdateCompilation(Compilation compilation, Compilation& outputCompilation, ImmutableArray`1& diagnostics, CancellationToken cancellationToken) + at Microsoft.CodeAnalysis.CommonCompiler.RunGenerators(Compilation input, ParseOptions parseOptions, ImmutableArray`1 generators, AnalyzerConfigOptionsProvider analyzerConfigOptionsProvider, ImmutableArray`1 additionalTexts, DiagnosticBag generatorDiagnostics) + at Microsoft.CodeAnalysis.CommonCompiler.CompileAndEmit(TouchedFileLogger touchedFilesLogger, Compilation& compilation, ImmutableArray`1 analyzers, ImmutableArray`1 generators, ImmutableArray`1 additionalTextFiles, AnalyzerConfigSet analyzerConfigSet, ImmutableArray`1 sourceFileAnalyzerConfigOptions, ImmutableArray`1 embeddedTexts, DiagnosticBag diagnostics, CancellationToken cancellationToken, CancellationTokenSource& analyzerCts, AnalyzerDriver& analyzerDriver, Nullable`1& generatorTimingInfo) + at Microsoft.CodeAnalysis.CommonCompiler.RunCore(TextWriter consoleOutput, ErrorLogger errorLogger, CancellationToken cancellationToken) + at Microsoft.CodeAnalysis.CommonCompiler.Run(TextWriter consoleOutput, CancellationToken cancellationToken) + at Microsoft.CodeAnalysis.CompilerServer.CompilerServerHost.RunCompilation(RunRequest& request, CancellationToken cancellationToken) + at Microsoft.CodeAnalysis.CompilerServer.CompilerServerHost.Microsoft.CodeAnalysis.CompilerServer.ICompilerServerHost.RunCompilation(RunRequest& request, CancellationToken cancellationToken) + at Microsoft.CodeAnalysis.CompilerServer.ClientConnectionHandler.<>c__DisplayClass8_0.b__1() + at System.Threading.Tasks.Task`1.InnerInvoke() + at System.Threading.Tasks.Task.Execute() + at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx) + at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx) + at System.Threading.Tasks.Task.ExecuteWithThreadLocal(Task& currentTaskSlot) + at System.Threading.Tasks.Task.ExecuteEntry(Boolean bPreventDoubleExecution) + at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx) + at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx) + at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state) + at System.Threading.ThreadHelper.ThreadStart(Object obj) + ``` + +These failures are almost always due to changes being tested. Essentially the change updated compiler logic in such a way that it caused an `Assert` to fail. On occasion this will also fail because an IDE change introduces a coding pattern that sets of a latent bug in the compiler or analyzer but this is certainly the rare case. + +The next term to search for is `"Error "` (no quotes but keep the space). This will be added to the log every the server hits an error and needs to shut down. + +```txt +ID=MSBuild 60300 TID=3: Error Error: 'EndOfStreamException' 'Reached end of stream before end of read.' occurred during 'Reading response for d2c3aeac-bd8a-4251-bde0-2e11bbc57d13' +Stack trace: + at Microsoft.CodeAnalysis.CommandLine.BuildProtocolConstants.d__4.MoveNext() in C:\Users\jaredpar\code\wt\ros2\src\Compilers\Core\CommandLine\BuildProtocol.cs:line 641 +--- End of stack trace from previous location where exception was thrown --- + at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) + at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) + at System.Runtime.CompilerServices.ConfiguredTaskAwaitable.ConfiguredTaskAwaiter.GetResult() + at Microsoft.CodeAnalysis.CommandLine.BuildResponse.d__5.MoveNext() in C:\Users\jaredpar\code\wt\ros2\src\Compilers\Core\CommandLine\BuildProtocol.cs:line 342 +--- End of stack trace from previous location where exception was thrown --- + at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) + at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) + at System.Runtime.CompilerServices.ConfiguredTaskAwaitable`1.ConfiguredTaskAwaiter.GetResult() + at Microsoft.CodeAnalysis.CommandLine.BuildServerConnection.<g__tryRunRequestAsync|7_1>d.MoveNext() in C:\Users\jaredpar\code\wt\ros2\src\Compilers\Shared\BuildServerConnection.cs:line 288 +``` + +These type of errors, when not paired with a `Debug.Assert` failure, are almost always bugs in the compiler server. Please contact the compiler team to help track down such failures. + +Note: when you encounter a case where the log file does not have an actionable description of why a build failed, strongly consider sending a PR that fixes this. This approach is why the log is such a valuable tool for tracking down bootstrap failures. + +## Debugging + +To debug a bootstrap build failure locally do the following. + +The first step is disabling the `ExitingTraceListener`. This is important for CI where the compiler needs to crash on a `Debug.Assert` failure vs. popping up a dialog that would hang CI. When debugging locally though developers want the `Debug.Assert` pops up a dialog behavior. To disable the `ExitingTraceListener` comment out the following line: + +https://github.com/dotnet/roslyn/blob/d73d31cbccb9aa850f3582afb464b709fef88fd7/src/Compilers/Server/VBCSCompiler/VBCSCompiler.cs#L22 + +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 +``` diff --git a/docs/contributing/target-framework-strategy.md b/docs/contributing/target-framework-strategy.md new file mode 100644 index 0000000000000..fcc02683d5cd5 --- /dev/null +++ b/docs/contributing/target-framework-strategy.md @@ -0,0 +1,123 @@ +# Target Framework Strategy + +## Layers + +The roslyn repository produces components for a number of different products that push varying ship and TFM constraints on us. A summary of some of our dependencies are : + +- Build Tools: requires us to ship compilers on `net472` +- .NET SDK: requires us to ship compilers on current servicing target framework (presently `net9.0`) +- Repository Source build: requires us to ship `$(NetCurrent)` and `$(NetPrevious)` in workspaces and below (presently `net10.0` and `net9.0` respectively). This is because the output of repository source build is an input to other repository source build and those could be targeting either `$(NetCurrent)` or `$(NetPrevious)`. +- Full Source build: requires us to ship `$(NetCurrent)` +- Visual Studio: requires us to ship `net472` for base IDE components and `$(NetVisualStudio)` (presently `net8.0`) for private runtime components. +- Visual Studio Code: expects us to ship against the same runtime as DevKit (presently `net7.0`) to avoid two runtime downloads. +- MSBuildWorkspace: requires to ship a process that must be usable on the lowest supported SDK (presently `net6.0`) + +It is not reasonable for us to take the union of all TFM and multi-target every single project to them. That would add several hundred compilations to any build operation which would in turn negatively impact our developer throughput. Instead we attempt to use the TFM where needed. That keeps our builds smaller but increases complexity a bit as we end up shipping a mix of TFM for binaries across our layers. + +## Picking the right TargetFramework + +Projects in our repository should include the following values in `` based on the rules below: + +1. `$(NetRoslynSourceBuild)`: code that needs to be part of source build. This property will change based on whether the code is building in a source build context or official builds. + a. In official builds this will include the TFMs for `$(NetVSShared)` + b. In source builds this will include `$(NetRoslyn)` +2. `$(NetVS)`: code that needs to execute on the private runtime of Visual Studio. +3. `$(NetVSCode)`: code that needs to execute in DevKit host +4. `$(NetVSShared)`: code that needs to execute in both Visual Studio and VS Code but does not need to be source built. +5. `$(NetRoslyn)`: code that needs to execute on .NET but does not have any specific product deployment requirements. For example utilities that are used by our infra, compiler unit tests, etc ... This property also controls which of the frameworks the compiler builds against are shipped in the toolset packages. This value will potentially change in source builds. +6. `$(NetRoslynAll)`: code, generally test utilities, that need to build for all .NET runtimes that we support. +7. `$(NetRoslynBuildHostNetCoreVersion)`: the target used for the .NET Core BuildHost process used by MSBuildWorkspace. +8. `$(NetRoslynNext)`: code that needs to run on the next .NET Core version. This is used during the transition to a new .NET Core version where we need to move forward but don't want to hard code a .NET Core TFM into the build files. + +This properties `$(NetCurrent)`, `$(NetPrevious)` and `$(NetMinimum)` are not used in our project files because they change in ways that make it hard for us to maintain corect product deployments. Our product ships on VS and VS Code which are not captured by arcade `$(Net...)` macros. Further as the arcade properties change it's very easy for us to end up with duplicate entries in a `` setting. Instead our repo uses the above values and when inside source build or VMR our properties are initialized with arcade properties. + +**DO NOT** hard code .NET Core TFMs in project files. Instead use the properties above as that lets us centrally manage them and structure the properties to avoid duplication. It is fine to hard code other TFMs like `netstandard2.0` or `net472` as those are not expected to change. + +**DO NOT** use `$(NetCurrent)` or `$(NetPrevious)` in project files. These should only be used inside of `TargetFrameworks.props` to initialize the above values in certain configurations. + +## Require consistent API across Target Frameworks + +It is important that our shipping APIs maintain consistent API surface area across target frameworks. That is true whether the API is `public` or `internal`. + +The reason for `public` is standard design pattern. The reason for `internal` is a combination of the following problems: + +- Our repository makes use of `InternalsVisibleTo` which allows other assemblies to directly reference signatures of `internal` members. +- Our repository ships a mix of target frameworks. Typically workspaces and below will ship more recent TFMs than the layers above it. Compiler has to ship newer TFM for source build while IDE is constrained by Visual Studio's private runtime hence adopts newer TFM slower. +- Our repository invests in polyfill APIs to make compiling against multiple TFMs in the same project a seamless experience. + +Taken together though this means that our `internal` surface area in many cases is effectively `public` when it comes to binary compatibility. For example a consuming project can end up with `net7.0` binaries from workspaces layer and `net6.0` binaries from IDE layer. Because there is `InternalsVisibleTo` between these binaries the `internal` API surface area is effectively `public`. This requires us to have a consistent strategy for achieving binary compatibility across TFM combinations. + +Consider a specific example of what goes wrong when our `internal` APIs are not consistent across TFM: + +- Workspaces today targets `net6.0` and `net7.0` and it contains our `EnumerableExtensions.cs` which polyfills many extensions methods on `IEnumerable`. In `net7.0` the `Order` extension method is not needed because it was put into the .NET core libraries. +- Language Server Protocol targets `net6.0` and consumes the `Order` polyfill from Workspaces + +Let's assume for a second that we `#if` the `Order` method such that it's not present in `net7.0`. Locally this all builds because we compile the `net6.0` versions against each other so they're consistent. However if an external project which targets `net7.0` and consumes both Workspaces and Language Server Protocol then it will be in a broken state. The Protocol binary is expecting Workspaces to contain a polyfill method for `Order` but it does not since it's at `net7.0` and it was `#if` out. As a result this will fail at runtime with missing method exceptions. + +This problem primarily comes from our use of polyfill APIs. To avoid this we employ the following rule: + +> When there is a `#if` directive that matches the regex `#if !?NET.*` that declares a non-private member, there must be an `#else` that defines an equivalent binary compatible symbol + +This comes up in two forms: + +### Pattern for types + +When creating a polyfill for a type use the `#if !NET...` to declare the type and in the `#else` use a `TypeForwardedTo` for the actual type. + +Example: + +```csharp +#if NET6_0_OR_GREATER + +using System.Runtime.CompilerServices; + +#pragma warning disable RS0016 // Add public types and members to the declared API (this is a supporting forwarder for an internal polyfill API) +[assembly: TypeForwardedTo(typeof(IsExternalInit))] +#pragma warning restore RS0016 // Add public types and members to the declared API + +#else + +using System.ComponentModel; + +namespace System.Runtime.CompilerServices +{ + internal static class IsExternalInit + { + } +} + +#endif +``` + +### Pattern for extension methods + +When creating a polyfill for an extension use the `#if NET...` to declare the extension method and the `#else` to declare the same method without `this`. That will put a method with the expected signature in the binary but avoids it appearing as an extension method within that target framework. + +```csharp +#if NET7_0_OR_GREATER + public static IOrderedEnumerable Order(IEnumerable source) where T : IComparable +#else + public static IOrderedEnumerable Order(this IEnumerable source) where T : IComparable +#endif +``` + +## Transitioning to new .NET SDK + +As the .NET team approaches releasing a new .NET SDK the Roslyn team will begin using preview versions of that SDK in our build. This will often lead to test failures in our CI system due to underlying behavior changes in the runtime. These failures will often not show up when running in Visual Studio due to the way the runtime for the test runner is chosen. + +To ensure we have a simple developer environment such project should be moved to to the `$(NetRoslynNext)` target framework. That ensures the new runtime is loaded when running tests locally. + +When the .NET SDK RTMs and Roslyn adopts it all occurrences of `$(NetRoslynNext)` will be moved to simply `$(NetRoslyn)`. + +**DO NOT** include both `$(NetRoslyn)` and `$(NetRoslynNext)` in the same project unless there is a very specific reason that both tests are adding value. The most common case is that the runtime has changed behavior and we simply need to update our baselines to match it. Adding extra TFMs for this just increases test time for very little gain. + +## Checklist for updating TFMs (once a year) + +- Update `TargetFrameworks.props`. + - Ensure we have the correct TFM for VS / VSCode (usually not the latest TFM). +- Might need updating `MicrosoftNetCompilersToolsetVersion` in `eng\Versions.props` to consume latest compiler features. +- Change `$(NetRoslynNext)` references to `$(NetRoslyn)` in project files. +- Update TFMs in code/scripts/pipelines (search for the old `netX.0` and replace with the new `netY.0`). +- Replace `#if NET7_0_OR_GREATER` corresponding to the no longer used TFM (`net7.0` in this example) with the lowest used TFM (e.g., `net8.0`: `#if NET8_0_OR_GREATER`) and similarly the negated variant `#if !NET7_0_OR_GREATER` with `#if !NET8_0_OR_GREATER`. See https://github.com/dotnet/roslyn/issues/75453#issuecomment-2405500584. +- Check that the same number of tests still run in CI (they are not unintentionally filtered out by TFM). +- Try an official build, a VS insertion. diff --git a/docs/features/incremental-generators.cookbook.md b/docs/features/incremental-generators.cookbook.md index 93995068d71b8..88afe55a9e69c 100644 --- a/docs/features/incremental-generators.cookbook.md +++ b/docs/features/incremental-generators.cookbook.md @@ -208,6 +208,15 @@ public class FileTransformGenerator : IIncrementalGenerator } ``` +Items need to be included in your csproj files by using the `AdditionalFiles` ItemGroup: + +```xml + + + + +``` + ### Augment user code **User scenario:** As a generator author I want to be able to inspect and augment a user's code with new functionality. diff --git a/docs/features/interceptors.md b/docs/features/interceptors.md index c34d5294446b0..33870c212df86 100644 --- a/docs/features/interceptors.md +++ b/docs/features/interceptors.md @@ -3,7 +3,7 @@ ## Summary [summary]: #summary -*Interceptors* are an experimental compiler feature planned to ship in .NET 8 (with support for C# only). The feature may be subject to breaking changes or removal in a future release. +*Interceptors* is a C# compiler feature, first shipped experimentally in .NET 8, with stable support in .NET 9.0.2xx SDK and later. An *interceptor* is a method which can declaratively substitute a call to an *interceptable* method with a call to itself at compile time. This substitution occurs by having the interceptor declare the source locations of the calls that it intercepts. This provides a limited facility to change the semantics of existing code by adding new code to a compilation (e.g. in a source generator). @@ -68,8 +68,6 @@ In addition to "ordinary" forms `M()` and `receiver.M()`, a call within a condit File-local declarations of this type (`file class InterceptsLocationAttribute`) are valid and usages are recognized by the compiler when they are within the same file and compilation. A generator which needs to declare this attribute should use a file-local declaration to ensure it doesn't conflict with other generators that need to do the same thing. -In prior experimental releases of the feature, a well-known constructor signature `InterceptsLocation(string path, int line, int column)]` was also supported. Support for this constructor will be **dropped** prior to stable release of the feature. - #### Location encoding The arguments to `[InterceptsLocation]` are: @@ -212,9 +210,9 @@ The reason we permit implicit receiver capture for the above intercepted call is ### Editor experience -Interceptors are treated like a post-compilation step in this design. Diagnostics are given for misuse of interceptors, but some diagnostics are only given in the command-line build and not in the IDE. There is limited traceability in the editor for which calls in a compilation are actually being intercepted. If this feature is brought forward past the experimental stage, this limitation will need to be re-examined. +Interceptors are treated like a post-compilation step in this design. Diagnostics are given for misuse of interceptors, but some diagnostics are only given in the command-line build and not in the IDE. There is limited traceability in the editor for which calls in a compilation are actually being intercepted. -There is an experimental public API `GetInterceptorMethod(this SemanticModel, InvocationExpressionSyntax, CancellationToken)` which enables analyzers to determine if a call is being intercepted, and if so, which method is intercepting the call. See https://github.com/dotnet/roslyn/issues/72093 for further details. +`GetInterceptorMethod(this SemanticModel, InvocationExpressionSyntax, CancellationToken)` enables analyzers to determine if a call is being intercepted, and if so, which method is intercepting the call. See https://github.com/dotnet/roslyn/issues/72093 for further details. ### User opt-in diff --git a/docs/wiki/Analyzer-Runner.md b/docs/wiki/Analyzer-Runner.md new file mode 100644 index 0000000000000..bd15fd560f15c --- /dev/null +++ b/docs/wiki/Analyzer-Runner.md @@ -0,0 +1,17 @@ +Analyzer Runner +------------- + +AnalyzerRunner currently exists as part of the Roslyn source code. + +## Steps to run: + +1. Check out the latest main branch from dotnet/roslyn +2. Run Restore.cmd to restore NuGet packages +3. Build Roslyn.sln in the Release configuration, either within Visual Studio or by running Build.cmd -release +4. Set AnalyzerRunner as the startup project +5. Select the launch configuration (several are specified in launchProperties.json but you can create a new one or modify an existing one) +6. Run AnalyzerRunner with Ctrl+F5 or on the command line + + + + diff --git a/docs/wiki/NuGet-packages.md b/docs/wiki/NuGet-packages.md index d7791e2277305..3caad8005c828 100644 --- a/docs/wiki/NuGet-packages.md +++ b/docs/wiki/NuGet-packages.md @@ -49,6 +49,8 @@ Below are the versions of the language available in the NuGet packages. Remember - Version `4.8` includes C# 12.0 (Visual Studio 2022 version 17.8, .NET 8) - Version `4.9.2` includes C# 12.0 (Visual Studio 2022 version 17.9, .NET 8) - Version `4.10` includes C# 12.0 (Visual Studio 2022 version 17.10, .NET 8) +- Version `4.11` includes C# 12.0 (Visual Studio 2022 version 17.11, .NET 8) +- Version `4.12` includes C# 13.0 (Visual Studio 2022 version 17.12, .NET 9) See the [history of C# language features](https://github.com/dotnet/csharplang/blob/main/Language-Version-History.md) for more details. diff --git a/eng/Directory.Packages.props b/eng/Directory.Packages.props index 1466d9260850b..7114e22690ff4 100644 --- a/eng/Directory.Packages.props +++ b/eng/Directory.Packages.props @@ -20,7 +20,7 @@ --> 8.0.10 8.0.10 - <_xunitVersion>2.6.6 + <_xunitVersion>2.9.2 2.1.0 @@ -106,14 +106,14 @@ - + - + @@ -184,7 +184,7 @@ - + @@ -194,18 +194,15 @@ - - - - + + + - - - + @@ -221,19 +218,9 @@ - - - - - - + @@ -266,8 +253,6 @@ - - @@ -277,7 +262,7 @@ - + @@ -307,11 +292,7 @@ - - + diff --git a/eng/Signing.props b/eng/Signing.props index f1d94e766f317..0bda27d7aa9f1 100644 --- a/eng/Signing.props +++ b/eng/Signing.props @@ -61,4 +61,19 @@ + + + + + + + + + + true + + + diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index cb4f6fbbb104e..6b57465082be0 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -2,15 +2,15 @@ - + https://github.com/dotnet/source-build-externals - c65b1c1affed1f4847f9c3f81623dfa929d21e1a + ab469606a3e6b026dcac301e2dab96117c94faeb - + https://github.com/dotnet/source-build-reference-packages - df6fdaf26c24fa7c897ca8062227aa28e76e2339 + 94798e07efab2663f2d1a71862780bc365d2e3ab @@ -122,14 +122,14 @@ - + https://github.com/dotnet/arcade - 1c7e09a8d9c9c9b15ba574cd6a496553505559de + b41381d5cd633471265e9cd72e933a7048e03062 - + https://github.com/dotnet/arcade - 1c7e09a8d9c9c9b15ba574cd6a496553505559de + b41381d5cd633471265e9cd72e933a7048e03062 @@ -156,9 +156,9 @@ https://github.com/dotnet/roslyn 5d10d428050c0d6afef30a072c4ae68776621877 - + https://github.com/dotnet/arcade - 1c7e09a8d9c9c9b15ba574cd6a496553505559de + b41381d5cd633471265e9cd72e933a7048e03062 https://github.com/dotnet/roslyn-analyzers diff --git a/eng/Versions.props b/eng/Versions.props index 5ce59ad87b5fb..c043223d028c7 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -8,7 +8,7 @@ 4 13 0 - 2 + 3 $(MajorVersion).$(MinorVersion).$(PatchVersion) $(MajorVersion).$(MinorVersion).0.0 + + + 6.1.0 + 4.6.0 + 4.9.0 + 4.6.0 + 4.6.0 + 6.1.0 + 4.6.0 + + + 6.0.1 + 4.5.1 + + 4.8.6 + 4.5.5 + 4.5.0 + 6.0.0 + 4.5.4 + @@ -33,9 +59,9 @@ 8.0.0 8.0.0 8.0.0 - 8.0.0 - 8.0.4 + + 8.0.5 8.0.0 8.0.0 8.0.0 diff --git a/eng/common/sdk-task.ps1 b/eng/common/sdk-task.ps1 index aab40de3fd9ac..4f0546dce1208 100644 --- a/eng/common/sdk-task.ps1 +++ b/eng/common/sdk-task.ps1 @@ -64,7 +64,7 @@ try { $GlobalJson.tools | Add-Member -Name "vs" -Value (ConvertFrom-Json "{ `"version`": `"16.5`" }") -MemberType NoteProperty } if( -not ($GlobalJson.tools.PSObject.Properties.Name -match "xcopy-msbuild" )) { - $GlobalJson.tools | Add-Member -Name "xcopy-msbuild" -Value "17.10.0-pre.4.0" -MemberType NoteProperty + $GlobalJson.tools | Add-Member -Name "xcopy-msbuild" -Value "17.12.0" -MemberType NoteProperty } if ($GlobalJson.tools."xcopy-msbuild".Trim() -ine "none") { $xcopyMSBuildToolsFolder = InitializeXCopyMSBuild $GlobalJson.tools."xcopy-msbuild" -install $true diff --git a/eng/common/tools.ps1 b/eng/common/tools.ps1 index 22954477a5747..aa94fb1745965 100644 --- a/eng/common/tools.ps1 +++ b/eng/common/tools.ps1 @@ -383,8 +383,8 @@ function InitializeVisualStudioMSBuild([bool]$install, [object]$vsRequirements = # If the version of msbuild is going to be xcopied, # use this version. Version matches a package here: - # https://dev.azure.com/dnceng/public/_artifacts/feed/dotnet-eng/NuGet/Microsoft.DotNet.Arcade.MSBuild.Xcopy/versions/17.10.0-pre.4.0 - $defaultXCopyMSBuildVersion = '17.10.0-pre.4.0' + # https://dev.azure.com/dnceng/public/_artifacts/feed/dotnet-eng/NuGet/Microsoft.DotNet.Arcade.MSBuild.Xcopy/versions/17.12.0 + $defaultXCopyMSBuildVersion = '17.12.0' if (!$vsRequirements) { if (Get-Member -InputObject $GlobalJson.tools -Name 'vs') { diff --git a/eng/config/PublishData.json b/eng/config/PublishData.json index a621e8447545d..9e0b87df0ca62 100644 --- a/eng/config/PublishData.json +++ b/eng/config/PublishData.json @@ -215,6 +215,15 @@ "vsMajorVersion": 17, "insertionTitlePrefix": "[d17.12]" }, + "release/dev17.12-telmet": { + "nugetKind": [ + "Shipping", + "NonShipping" + ], + "vsBranch": "rel/d17.12telmet", + "vsMajorVersion": 17, + "insertionTitlePrefix": "[d17.12]" + }, "release/dev17.13": { "nugetKind": [ "Shipping", @@ -222,7 +231,16 @@ ], "vsBranch": "rel/d17.13", "vsMajorVersion": 17, - "insertionTitlePrefix": "[d17.13 P1]" + "insertionTitlePrefix": "[d17.13 P2]" + }, + "release/dev17.13-preview2.1": { + "nugetKind": [ + "Shipping", + "NonShipping" + ], + "vsBranch": "rel/d17.13", + "vsMajorVersion": 17, + "insertionTitlePrefix": "[d17.13 P2]" }, "main": { "nugetKind": [ @@ -232,7 +250,7 @@ "vsBranch": "main", "vsMajorVersion": 17, "insertionCreateDraftPR": false, - "insertionTitlePrefix": "[d17.13 P2]" + "insertionTitlePrefix": "[d17.13 P3]" }, "dev/andrha/telemetry": { "nugetKind": [ diff --git a/eng/config/globalconfigs/Common.globalconfig b/eng/config/globalconfigs/Common.globalconfig index 028d94a89350e..f073601eac363 100644 --- a/eng/config/globalconfigs/Common.globalconfig +++ b/eng/config/globalconfigs/Common.globalconfig @@ -7,6 +7,9 @@ dotnet_diagnostic.CA1821.severity = warning dotnet_diagnostic.CA1868.severity = warning dotnet_diagnostic.CA2009.severity = warning +# CA1052: Static holder types should be Static or NotInheritable +dotnet_diagnostic.CA1052.severity = warning + # CA2012: Use ValueTasks correctly dotnet_diagnostic.CA2012.severity = warning diff --git a/eng/generate-compiler-code.cmd b/eng/generate-compiler-code.cmd index 808137ef77cb7..60a78f0589889 100644 --- a/eng/generate-compiler-code.cmd +++ b/eng/generate-compiler-code.cmd @@ -1,3 +1,4 @@ @echo off -powershell -noprofile -executionPolicy RemoteSigned -file "%~dp0\generate-compiler-code.ps1" %* +set PSMODULEPATH= +powershell -noprofile -executionPolicy Unrestricted -file "%~dp0\generate-compiler-code.ps1" %* diff --git a/eng/make-bootstrap.cmd b/eng/make-bootstrap.cmd index fe6cae0b6e9f9..612ae9b362fa5 100644 --- a/eng/make-bootstrap.cmd +++ b/eng/make-bootstrap.cmd @@ -1,2 +1,3 @@ @echo off -powershell -noprofile -file "%~dp0\make-bootstrap.ps1" %* \ No newline at end of file +set PSMODULEPATH= +powershell -noprofile -executionPolicy Unrestricted -file "%~dp0\make-bootstrap.ps1" %* \ No newline at end of file diff --git a/eng/make-bootstrap.ps1 b/eng/make-bootstrap.ps1 index 64100d029cdfa..ab01f47766db1 100644 --- a/eng/make-bootstrap.ps1 +++ b/eng/make-bootstrap.ps1 @@ -46,6 +46,8 @@ try { throw "Unsupported bootstrap toolset $toolset" } + $projectPath = Join-Path $RepoRoot $projectPath + $name = Split-Path -Leaf $output $binaryLogFilePath = Join-Path $LogDir "bootstrap-$($name).binlog" diff --git a/eng/pipelines/test-integration-helix.yml b/eng/pipelines/test-integration-helix.yml index 9cb3fefdfaa33..606d675c72751 100644 --- a/eng/pipelines/test-integration-helix.yml +++ b/eng/pipelines/test-integration-helix.yml @@ -83,6 +83,14 @@ stages: env: HELIX_CORRELATION_PAYLOAD: '$(Build.SourcesDirectory)\.duplicate' + - task: UseDotNet@2 + displayName: 'Install .NET 9 Runtime' + inputs: + packageType: runtime + version: '9.0.0' + includePreviewVersions: true + installationPath: '$(Build.SourcesDirectory)/.dotnet' + - task: PowerShell@2 displayName: Run Integration Tests inputs: diff --git a/eng/pipelines/test-windows-job-single-machine.yml b/eng/pipelines/test-windows-job-single-machine.yml index 975bdb744f2f0..25561e2dbd37b 100644 --- a/eng/pipelines/test-windows-job-single-machine.yml +++ b/eng/pipelines/test-windows-job-single-machine.yml @@ -33,7 +33,7 @@ jobs: displayName: 'Install .NET 9 Runtime' inputs: packageType: runtime - version: 9.0.0-rc.2.24473.5 + version: '9.0.0' includePreviewVersions: true installationPath: '$(Build.SourcesDirectory)/.dotnet' diff --git a/eng/targets/TargetFrameworks.props b/eng/targets/TargetFrameworks.props index 728de8b627db9..58f90114f4d1e 100644 --- a/eng/targets/TargetFrameworks.props +++ b/eng/targets/TargetFrameworks.props @@ -3,7 +3,7 @@ @@ -2386,12 +2389,14 @@ - + + - + + @@ -2408,12 +2413,14 @@ - + + - + + @@ -2421,6 +2428,7 @@ + @@ -2439,6 +2447,7 @@ + @@ -2455,7 +2464,8 @@ - + + @@ -2479,22 +2489,37 @@ - + + - + + - + + - + + diff --git a/src/Compilers/CSharp/Portable/BoundTree/BoundRecursivePattern.cs b/src/Compilers/CSharp/Portable/BoundTree/BoundRecursivePattern.cs new file mode 100644 index 0000000000000..dfc478df4d92e --- /dev/null +++ b/src/Compilers/CSharp/Portable/BoundTree/BoundRecursivePattern.cs @@ -0,0 +1,19 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Diagnostics; +using Microsoft.CodeAnalysis.CSharp.Symbols; + +namespace Microsoft.CodeAnalysis.CSharp +{ + internal partial class BoundRecursivePattern + { + private partial void Validate() + { + Debug.Assert(DeclaredType is null ? + NarrowedType.Equals(InputType.StrippedType(), TypeCompareKind.AllIgnoreOptions) : + NarrowedType.Equals(DeclaredType.Type, TypeCompareKind.AllIgnoreOptions)); + } + } +} diff --git a/src/Compilers/CSharp/Portable/BoundTree/BoundRelationalPattern.cs b/src/Compilers/CSharp/Portable/BoundTree/BoundRelationalPattern.cs new file mode 100644 index 0000000000000..955782d1edbe9 --- /dev/null +++ b/src/Compilers/CSharp/Portable/BoundTree/BoundRelationalPattern.cs @@ -0,0 +1,17 @@ +// 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.Diagnostics; + +namespace Microsoft.CodeAnalysis.CSharp +{ + internal partial class BoundRelationalPattern + { + private partial void Validate() + { + Debug.Assert(NarrowedType.Equals(InputType, TypeCompareKind.AllIgnoreOptions) || + NarrowedType.Equals(Value.Type, TypeCompareKind.AllIgnoreOptions)); + } + } +} diff --git a/src/Compilers/CSharp/Portable/BoundTree/BoundSlicePattern.cs b/src/Compilers/CSharp/Portable/BoundTree/BoundSlicePattern.cs index c1434c854ca58..a26c3928daaa7 100644 --- a/src/Compilers/CSharp/Portable/BoundTree/BoundSlicePattern.cs +++ b/src/Compilers/CSharp/Portable/BoundTree/BoundSlicePattern.cs @@ -12,6 +12,7 @@ private partial void Validate() { Debug.Assert(IndexerAccess is null or BoundIndexerAccess or BoundImplicitIndexerAccess or BoundArrayAccess or BoundBadExpression or BoundDynamicIndexerAccess); Debug.Assert(Binder.GetIndexerOrImplicitIndexerSymbol(IndexerAccess) is var _); + Debug.Assert(NarrowedType.Equals(InputType, TypeCompareKind.AllIgnoreOptions)); } } } diff --git a/src/Compilers/CSharp/Portable/BoundTree/BoundTypePattern.cs b/src/Compilers/CSharp/Portable/BoundTree/BoundTypePattern.cs new file mode 100644 index 0000000000000..349a82f28047c --- /dev/null +++ b/src/Compilers/CSharp/Portable/BoundTree/BoundTypePattern.cs @@ -0,0 +1,16 @@ +// 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.Diagnostics; + +namespace Microsoft.CodeAnalysis.CSharp +{ + internal partial class BoundTypePattern + { + private partial void Validate() + { + Debug.Assert(NarrowedType.Equals(DeclaredType.Type, TypeCompareKind.AllIgnoreOptions)); + } + } +} diff --git a/src/Compilers/CSharp/Portable/BoundTree/UnboundLambda.cs b/src/Compilers/CSharp/Portable/BoundTree/UnboundLambda.cs index a3a7d38e23a5b..f0666b06cb720 100644 --- a/src/Compilers/CSharp/Portable/BoundTree/UnboundLambda.cs +++ b/src/Compilers/CSharp/Portable/BoundTree/UnboundLambda.cs @@ -766,7 +766,7 @@ private static TypeWithAnnotations DelegateReturnTypeWithAnnotations(MethodSymbo lambdaSymbol, hasParams: OverloadResolution.IsValidParams(Binder, lambdaSymbol, disallowExpandedNonArrayParams: false, out _), parameterScopesBuilder.ToImmutableAndFree(), - lambdaSymbol.Parameters.SelectAsArray(p => p.HasUnscopedRefAttribute), + lambdaSymbol.Parameters.SelectAsArray(p => p.HasUnscopedRefAttribute && p.UseUpdatedEscapeRules), returnRefKind, returnType); } diff --git a/src/Compilers/CSharp/Portable/CSharpExtensions.cs b/src/Compilers/CSharp/Portable/CSharpExtensions.cs index 745c036c18d99..25b14e8e90174 100644 --- a/src/Compilers/CSharp/Portable/CSharpExtensions.cs +++ b/src/Compilers/CSharp/Portable/CSharpExtensions.cs @@ -1632,7 +1632,8 @@ public static Conversion ClassifyConversion(this SemanticModel? semanticModel, i } /// If the call represented by is referenced in an InterceptsLocationAttribute, returns the original definition symbol which is decorated with that attribute. Otherwise, returns null. - [Experimental(RoslynExperiments.Interceptors, UrlFormat = RoslynExperiments.Interceptors_Url)] + /// + /// public static IMethodSymbol? GetInterceptorMethod(this SemanticModel? semanticModel, InvocationExpressionSyntax node, CancellationToken cancellationToken = default) { var csModel = semanticModel as CSharpSemanticModel; @@ -1643,7 +1644,8 @@ public static Conversion ClassifyConversion(this SemanticModel? semanticModel, i /// If cannot be intercepted syntactically, returns null. /// Otherwise, returns an instance which can be used to intercept the call denoted by . /// - [Experimental(RoslynExperiments.Interceptors, UrlFormat = RoslynExperiments.Interceptors_Url)] + /// + /// public static InterceptableLocation? GetInterceptableLocation(this SemanticModel? semanticModel, InvocationExpressionSyntax node, CancellationToken cancellationToken = default) { var csModel = semanticModel as CSharpSemanticModel; @@ -1653,7 +1655,8 @@ public static Conversion ClassifyConversion(this SemanticModel? semanticModel, i /// /// Gets an attribute list syntax consisting of an InterceptsLocationAttribute, which intercepts the call referenced by parameter . /// - [Experimental(RoslynExperiments.Interceptors, UrlFormat = RoslynExperiments.Interceptors_Url)] + /// + /// public static string GetInterceptsLocationAttributeSyntax(this InterceptableLocation location) { return $"""[global::System.Runtime.CompilerServices.InterceptsLocationAttribute({location.Version}, "{location.Data}")]"""; diff --git a/src/Compilers/CSharp/Portable/CSharpResources.resx b/src/Compilers/CSharp/Portable/CSharpResources.resx index 85dd758873c3f..372af3bb5bc41 100644 --- a/src/Compilers/CSharp/Portable/CSharpResources.resx +++ b/src/Compilers/CSharp/Portable/CSharpResources.resx @@ -5536,6 +5536,12 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. + + '{0}' is for evaluation purposes only and is subject to change or removal in future updates: '{1}'. Suppress this diagnostic to proceed. + + + Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. + Compiler version: '{0}'. Language version: {1}. @@ -5902,6 +5908,9 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ The type name '{0}' is reserved to be used by the compiler. + + The type 'Microsoft.CodeAnalysis.EmbeddedAttribute' must be non-generic, internal, sealed, non-static, have a parameterless constructor, inherit from System.Attribute, and be able to be applied to any type. + The first 'in' or 'ref readonly' parameter of the extension method '{0}' must be a concrete (non-generic) value type. @@ -7995,7 +8004,7 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ Cannot use 'OverloadResolutionPriorityAttribute' on this member. - + overload resolution priority @@ -8020,4 +8029,16 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ Element type of an iterator may not be a ref struct or a type parameter allowing ref structs + + UnscopedRefAttribute is only valid in C# 11 or later or when targeting net7.0 or later. + + + UnscopedRefAttribute is only valid in C# 11 or later or when targeting net7.0 or later. + + + 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) + + + 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) + diff --git a/src/Compilers/CSharp/Portable/CommandLine/CSharpCommandLineParser.cs b/src/Compilers/CSharp/Portable/CommandLine/CSharpCommandLineParser.cs index 108c348aa4427..2e9e88d8df1ed 100644 --- a/src/Compilers/CSharp/Portable/CommandLine/CSharpCommandLineParser.cs +++ b/src/Compilers/CSharp/Portable/CommandLine/CSharpCommandLineParser.cs @@ -1816,6 +1816,8 @@ private static Platform ParsePlatform(string value, IList diagnostic case "arm64": return Platform.Arm64; default: + // This switch supports architectures that .NET Framework runs on Windows only. + // Non-Windows architectures that .NET runs on are intentionally not supported here. AddDiagnostic(diagnostics, ErrorCode.ERR_BadPlatformType, value); return Platform.AnyCpu; } diff --git a/src/Compilers/CSharp/Portable/Compilation/CSharpCompilation.cs b/src/Compilers/CSharp/Portable/Compilation/CSharpCompilation.cs index c253ffacec43c..d5fee9089cef0 100644 --- a/src/Compilers/CSharp/Portable/Compilation/CSharpCompilation.cs +++ b/src/Compilers/CSharp/Portable/Compilation/CSharpCompilation.cs @@ -2427,16 +2427,36 @@ internal void AddModuleInitializerMethod(MethodSymbol method) internal bool InterceptorsDiscoveryComplete; + /// Equals and GetHashCode on this type intentionally resemble corresponding methods on . + private sealed class InterceptorKeyComparer : IEqualityComparer<(ImmutableArray ContentHash, int Position)> + { + private InterceptorKeyComparer() { } + public static readonly InterceptorKeyComparer Instance = new InterceptorKeyComparer(); + + public bool Equals((ImmutableArray ContentHash, int Position) x, (ImmutableArray ContentHash, int Position) y) + { + return x.ContentHash.SequenceEqual(y.ContentHash) && x.Position == y.Position; + } + + public int GetHashCode((ImmutableArray ContentHash, int Position) obj) + { + return Hash.Combine( + BinaryPrimitives.ReadInt32LittleEndian(obj.ContentHash.AsSpan()), + obj.Position); + } + } + // NB: the 'Many' case for these dictionary values means there are duplicates. An error is reported for this after binding. - private ConcurrentDictionary<(string FilePath, int Position), OneOrMany<(Location AttributeLocation, MethodSymbol Interceptor)>>? _interceptions; + private ConcurrentDictionary<(ImmutableArray ContentHash, int Position), OneOrMany<(Location AttributeLocation, MethodSymbol Interceptor)>>? _interceptions; - internal void AddInterception(string filePath, int position, Location attributeLocation, MethodSymbol interceptor) + internal void AddInterception(ImmutableArray contentHash, int position, Location attributeLocation, MethodSymbol interceptor) { Debug.Assert(!_declarationDiagnosticsFrozen); Debug.Assert(!InterceptorsDiscoveryComplete); - var dictionary = LazyInitializer.EnsureInitialized(ref _interceptions); - dictionary.AddOrUpdate((filePath, position), + var dictionary = LazyInitializer.EnsureInitialized(ref _interceptions, + () => new ConcurrentDictionary<(ImmutableArray ContentHash, int Position), OneOrMany<(Location AttributeLocation, MethodSymbol Interceptor)>>(comparer: InterceptorKeyComparer.Instance)); + dictionary.AddOrUpdate((contentHash, position), addValueFactory: static (key, newValue) => OneOrMany.Create(newValue), updateValueFactory: static (key, existingValues, newValue) => { @@ -2469,7 +2489,7 @@ internal void AddInterception(string filePath, int position, Location attributeL return null; } - var key = (node.SyntaxTree.FilePath, node.Position); + var key = (node.SyntaxTree.GetText().GetContentHash(), node.Position); if (_interceptions.TryGetValue(key, out var interceptionsAtAGivenLocation) && interceptionsAtAGivenLocation is [var oneInterception]) { return oneInterception; diff --git a/src/Compilers/CSharp/Portable/Compilation/CSharpDiagnosticFilter.cs b/src/Compilers/CSharp/Portable/Compilation/CSharpDiagnosticFilter.cs index 453aa43211b3a..1845650c064e5 100644 --- a/src/Compilers/CSharp/Portable/Compilation/CSharpDiagnosticFilter.cs +++ b/src/Compilers/CSharp/Portable/Compilation/CSharpDiagnosticFilter.cs @@ -319,7 +319,7 @@ internal static ReportDiagnostic GetDiagnosticReport( } } - if (!isSpecified && errorCode == (int)ErrorCode.WRN_Experimental) + if (!isSpecified && errorCode is (int)ErrorCode.WRN_Experimental or (int)ErrorCode.WRN_ExperimentalWithMessage) { // Special handling for [Experimental] warning (treat as error severity by default) Debug.Assert(isEnabledByDefault); diff --git a/src/Compilers/CSharp/Portable/Compilation/CSharpSemanticModel.cs b/src/Compilers/CSharp/Portable/Compilation/CSharpSemanticModel.cs index 4ab3ceaa48867..33c4e8adad8b9 100644 --- a/src/Compilers/CSharp/Portable/Compilation/CSharpSemanticModel.cs +++ b/src/Compilers/CSharp/Portable/Compilation/CSharpSemanticModel.cs @@ -5229,7 +5229,7 @@ internal InterceptableLocation GetInterceptableLocationInternal(SyntaxNode nameS var lineNumberOneIndexed = lineSpan.Line + 1; var characterNumberOneIndexed = lineSpan.Character + 1; - return new InterceptableLocation1(checksum, path, nameSyntax.Position, lineNumberOneIndexed, characterNumberOneIndexed); + return new InterceptableLocation1(checksum, path, Compilation.Options.SourceReferenceResolver, nameSyntax.Position, lineNumberOneIndexed, characterNumberOneIndexed); } #nullable disable diff --git a/src/Compilers/CSharp/Portable/Emitter/Model/MethodSymbolAdapter.cs b/src/Compilers/CSharp/Portable/Emitter/Model/MethodSymbolAdapter.cs index 349edede8b243..5ec5fde9c5af4 100644 --- a/src/Compilers/CSharp/Portable/Emitter/Model/MethodSymbolAdapter.cs +++ b/src/Compilers/CSharp/Portable/Emitter/Model/MethodSymbolAdapter.cs @@ -510,7 +510,7 @@ bool Cci.IMethodDefinition.RequiresSecurityObject CheckDefinitionInvariant(); ImmutableArray userDefined = AdaptedMethodSymbol.GetReturnTypeAttributes(); - ArrayBuilder synthesized = null; + ArrayBuilder synthesized = null; AdaptedMethodSymbol.AddSynthesizedReturnTypeAttributes((PEModuleBuilder)context.Module, ref synthesized); // Note that callers of this method (CCI and ReflectionEmitter) have to enumerate diff --git a/src/Compilers/CSharp/Portable/Emitter/Model/PEAssemblyBuilder.cs b/src/Compilers/CSharp/Portable/Emitter/Model/PEAssemblyBuilder.cs index b3a8ca9e082d4..5244d968826cc 100644 --- a/src/Compilers/CSharp/Portable/Emitter/Model/PEAssemblyBuilder.cs +++ b/src/Compilers/CSharp/Portable/Emitter/Model/PEAssemblyBuilder.cs @@ -10,6 +10,7 @@ using System.Diagnostics; using System.Linq; using System.Reflection; +using System.Threading; using Microsoft.CodeAnalysis.CSharp.Symbols; using Microsoft.CodeAnalysis.Emit; using Microsoft.CodeAnalysis.PooledObjects; @@ -32,7 +33,7 @@ internal abstract class PEAssemblyBuilderBase : PEModuleBuilder, Cci.IAssemblyRe /// This is a cache of a subset of . We don't include manifest resources in ref assemblies private ImmutableArray _lazyFilesWithoutManifestResources; - private SynthesizedEmbeddedAttributeSymbol _lazyEmbeddedAttribute; + private NamedTypeSymbol _lazyEmbeddedAttribute; private SynthesizedEmbeddedAttributeSymbol _lazyIsReadOnlyAttribute; private SynthesizedEmbeddedAttributeSymbol _lazyRequiresLocationAttribute; private SynthesizedEmbeddedAttributeSymbol _lazyParamCollectionAttribute; @@ -94,7 +95,11 @@ internal sealed override ImmutableArray GetEmbeddedTypes(Bindin CreateEmbeddedAttributesIfNeeded(diagnostics); - builder.AddIfNotNull(_lazyEmbeddedAttribute); + if (_lazyEmbeddedAttribute is SynthesizedEmbeddedAttributeSymbol) + { + builder.Add(_lazyEmbeddedAttribute); + } + builder.AddIfNotNull(_lazyIsReadOnlyAttribute); builder.AddIfNotNull(_lazyRequiresLocationAttribute); builder.AddIfNotNull(_lazyParamCollectionAttribute); @@ -387,7 +392,8 @@ private void CreateEmbeddedAttributesIfNeeded(BindingDiagnosticBag diagnostics) ref _lazyEmbeddedAttribute, diagnostics, AttributeDescription.CodeAnalysisEmbeddedAttribute, - createParameterlessEmbeddedAttributeSymbol); + createParameterlessEmbeddedAttributeSymbol, + allowUserDefinedAttribute: true); if ((needsAttributes & EmbeddableAttributes.IsReadOnlyAttribute) != 0) { @@ -544,16 +550,32 @@ private SynthesizedEmbeddedRefSafetyRulesAttributeSymbol CreateRefSafetyRulesAtt GetWellKnownType(WellKnownType.System_Attribute, diagnostics), GetSpecialType(SpecialType.System_Int32, diagnostics)); +#nullable enable private void CreateAttributeIfNeeded( ref T symbol, BindingDiagnosticBag diagnostics, AttributeDescription description, - Func factory) - where T : SynthesizedEmbeddedAttributeSymbolBase + Func factory, + bool allowUserDefinedAttribute = false) + where T : NamedTypeSymbol { + Debug.Assert(!allowUserDefinedAttribute || typeof(T) == typeof(NamedTypeSymbol)); if (symbol is null) { - AddDiagnosticsForExistingAttribute(description, diagnostics); + var userDefinedAttribute = getExistingType(description); + + if (userDefinedAttribute is not null) + { + if (allowUserDefinedAttribute) + { + symbol = (T)userDefinedAttribute; + return; + } + else + { + diagnostics.Add(ErrorCode.ERR_TypeReserved, userDefinedAttribute.GetFirstLocation(), description.FullName); + } + } var containingNamespace = GetOrSynthesizeNamespace(description.Namespace); @@ -567,23 +589,17 @@ private void CreateAttributeIfNeeded( AddSynthesizedDefinition(containingNamespace, symbol); } - } - -#nullable enable - private void AddDiagnosticsForExistingAttribute(AttributeDescription description, BindingDiagnosticBag diagnostics) - { - var attributeMetadataName = MetadataTypeName.FromFullName(description.FullName); - var userDefinedAttribute = _sourceAssembly.SourceModule.LookupTopLevelMetadataType(ref attributeMetadataName); - Debug.Assert(userDefinedAttribute is null || (object)userDefinedAttribute.ContainingModule == _sourceAssembly.SourceModule); - Debug.Assert(userDefinedAttribute?.IsErrorType() != true); - - if (userDefinedAttribute is not null) + NamedTypeSymbol? getExistingType(AttributeDescription description) { - diagnostics.Add(ErrorCode.ERR_TypeReserved, userDefinedAttribute.GetFirstLocation(), description.FullName); + var attributeMetadataName = MetadataTypeName.FromFullName(description.FullName); + var userDefinedAttribute = _sourceAssembly.SourceModule.LookupTopLevelMetadataType(ref attributeMetadataName); + Debug.Assert(userDefinedAttribute is null || (object)userDefinedAttribute.ContainingModule == _sourceAssembly.SourceModule); + Debug.Assert(userDefinedAttribute?.IsErrorType() != true); + + return userDefinedAttribute; } } - #nullable disable protected NamespaceSymbol GetOrSynthesizeNamespace(string namespaceFullName) diff --git a/src/Compilers/CSharp/Portable/Emitter/Model/PEModuleBuilder.cs b/src/Compilers/CSharp/Portable/Emitter/Model/PEModuleBuilder.cs index fa2c9743ddc21..f19d7f8e9f6dd 100644 --- a/src/Compilers/CSharp/Portable/Emitter/Model/PEModuleBuilder.cs +++ b/src/Compilers/CSharp/Portable/Emitter/Model/PEModuleBuilder.cs @@ -613,9 +613,9 @@ private static void GetExportedTypes(NamespaceOrTypeSymbol symbol, int parentInd if (_lazyExportedTypes.IsDefault) { - _lazyExportedTypes = CalculateExportedTypes(); + var initialized = ImmutableInterlocked.InterlockedInitialize(ref _lazyExportedTypes, CalculateExportedTypes()); - if (_lazyExportedTypes.Length > 0) + if (initialized && _lazyExportedTypes.Length > 0) { ReportExportedTypeNameCollisions(_lazyExportedTypes, diagnostics); } diff --git a/src/Compilers/CSharp/Portable/Emitter/Model/SourceAssemblySymbolAdapter.cs b/src/Compilers/CSharp/Portable/Emitter/Model/SourceAssemblySymbolAdapter.cs index 66d7ad7888bef..a6e4bb2edeae3 100644 --- a/src/Compilers/CSharp/Portable/Emitter/Model/SourceAssemblySymbolAdapter.cs +++ b/src/Compilers/CSharp/Portable/Emitter/Model/SourceAssemblySymbolAdapter.cs @@ -18,7 +18,7 @@ internal IEnumerable GetCustomAttributesToEmit(PEModuleBuil CheckDefinitionInvariant(); ImmutableArray userDefined = this.GetAttributes(); - ArrayBuilder synthesized = null; + ArrayBuilder synthesized = null; this.AddSynthesizedAttributes(moduleBuilder, ref synthesized); if (emittingRefAssembly && !HasReferenceAssemblyAttribute) diff --git a/src/Compilers/CSharp/Portable/Emitter/Model/SymbolAdapter.cs b/src/Compilers/CSharp/Portable/Emitter/Model/SymbolAdapter.cs index 3f6099ccbc6b8..afd34feab5b3c 100644 --- a/src/Compilers/CSharp/Portable/Emitter/Model/SymbolAdapter.cs +++ b/src/Compilers/CSharp/Portable/Emitter/Model/SymbolAdapter.cs @@ -95,7 +95,7 @@ internal IEnumerable GetCustomAttributesToEmit(PEModuleBuil Debug.Assert(this.Kind != SymbolKind.Assembly); ImmutableArray userDefined; - ArrayBuilder synthesized = null; + ArrayBuilder synthesized = null; userDefined = this.GetAttributes(); this.AddSynthesizedAttributes(moduleBuilder, ref synthesized); @@ -110,7 +110,7 @@ internal IEnumerable GetCustomAttributesToEmit(PEModuleBuil /// internal IEnumerable GetCustomAttributesToEmit( ImmutableArray userDefined, - ArrayBuilder synthesized, + ArrayBuilder synthesized, bool isReturnType, bool emittingAssemblyAttributesInNetModule) { @@ -127,7 +127,7 @@ internal IEnumerable GetCustomAttributesToEmit( private IEnumerable GetCustomAttributesToEmitIterator( ImmutableArray userDefined, - ArrayBuilder synthesized, + ArrayBuilder synthesized, bool isReturnType, bool emittingAssemblyAttributesInNetModule) { diff --git a/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs b/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs index 90e45ee89de30..5faced88ed48b 100644 --- a/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs +++ b/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs @@ -2351,6 +2351,13 @@ internal enum ErrorCode ERR_IteratorRefLikeElementType = 9267, + WRN_ExperimentalWithMessage = 9268, + + WRN_UnscopedRefAttributeOldRules = 9269, + WRN_InterceptsLocationAttributeUnsupportedSignature = 9270, + + ERR_EmbeddedAttributeMustFollowPattern = 9271, + // Note: you will need to do the following after adding errors: // 1) Update ErrorFacts.IsBuildOnlyDiagnostic (src/Compilers/CSharp/Portable/Errors/ErrorFacts.cs) diff --git a/src/Compilers/CSharp/Portable/Errors/ErrorFacts.cs b/src/Compilers/CSharp/Portable/Errors/ErrorFacts.cs index b3c03386122fa..c07e760e77bbc 100644 --- a/src/Compilers/CSharp/Portable/Errors/ErrorFacts.cs +++ b/src/Compilers/CSharp/Portable/Errors/ErrorFacts.cs @@ -214,6 +214,10 @@ internal static int GetWarningLevel(ErrorCode code) // Warning level 10 is exclusively for warnings introduced in the compiler // shipped with dotnet 10 (C# 14) and that can be reported for pre-existing code. return 10; + case ErrorCode.WRN_InterceptsLocationAttributeUnsupportedSignature: + // Warning level 9 is exclusively for warnings introduced in the compiler + // shipped with dotnet 9 (C# 13) and that can be reported for pre-existing code. + return 9; case ErrorCode.WRN_AddressOfInAsync: case ErrorCode.WRN_ByValArraySizeConstRequired: // Warning level 8 is exclusively for warnings introduced in the compiler @@ -558,6 +562,7 @@ internal static int GetWarningLevel(ErrorCode code) case ErrorCode.WRN_RefReadonlyParameterDefaultValue: case ErrorCode.WRN_UseDefViolationRefField: case ErrorCode.WRN_Experimental: + case ErrorCode.WRN_ExperimentalWithMessage: case ErrorCode.WRN_CollectionExpressionRefStructMayAllocate: case ErrorCode.WRN_CollectionExpressionRefStructSpreadMayAllocate: case ErrorCode.WRN_ConvertingLock: @@ -565,6 +570,7 @@ internal static int GetWarningLevel(ErrorCode code) case ErrorCode.WRN_FieldIsAmbiguous: case ErrorCode.WRN_UninitializedNonNullableBackingField: case ErrorCode.WRN_AccessorDoesNotUseBackingField: + case ErrorCode.WRN_UnscopedRefAttributeOldRules: return 1; default: return 0; @@ -1841,6 +1847,7 @@ or ErrorCode.ERR_RefReturnReadonlyNotField or ErrorCode.ERR_RefReturnReadonlyNotField2 or ErrorCode.ERR_ExplicitReservedAttr or ErrorCode.ERR_TypeReserved + or ErrorCode.ERR_EmbeddedAttributeMustFollowPattern or ErrorCode.ERR_RefExtensionMustBeValueTypeOrConstrainedToOne or ErrorCode.ERR_InExtensionMustBeValueType or ErrorCode.ERR_FieldsInRoStruct @@ -2410,6 +2417,7 @@ or ErrorCode.WRN_UseDefViolationRefField or ErrorCode.ERR_FeatureNotAvailableInVersion12 or ErrorCode.ERR_CollectionExpressionEscape or ErrorCode.WRN_Experimental + or ErrorCode.WRN_ExperimentalWithMessage or ErrorCode.ERR_ExpectedInterpolatedString or ErrorCode.ERR_InterceptorGlobalNamespace or ErrorCode.WRN_CollectionExpressionRefStructMayAllocate @@ -2467,6 +2475,8 @@ or ErrorCode.WRN_UninitializedNonNullableBackingField or ErrorCode.WRN_UnassignedInternalRefField or ErrorCode.WRN_AccessorDoesNotUseBackingField or ErrorCode.ERR_IteratorRefLikeElementType + or ErrorCode.WRN_UnscopedRefAttributeOldRules + or ErrorCode.WRN_InterceptsLocationAttributeUnsupportedSignature => false, }; #pragma warning restore CS8524 // The switch expression does not handle some values of its input type (it is not exhaustive) involving an unnamed enum value. diff --git a/src/Compilers/CSharp/Portable/Errors/MessageID.cs b/src/Compilers/CSharp/Portable/Errors/MessageID.cs index 0783ddd7a7a0f..2a7703792fc84 100644 --- a/src/Compilers/CSharp/Portable/Errors/MessageID.cs +++ b/src/Compilers/CSharp/Portable/Errors/MessageID.cs @@ -291,7 +291,7 @@ internal enum MessageID IDS_FeatureFieldKeyword = MessageBase + 12846, IDS_FeatureAllowsRefStructConstraint = MessageBase + 12847, - IDS_OverloadResolutionPriority = MessageBase + 12848, + IDS_FeatureOverloadResolutionPriority = MessageBase + 12848, IDS_FeatureFirstClassSpan = MessageBase + 12849, IDS_FeatureUnboundGenericTypesInNameof = MessageBase + 12850, @@ -489,7 +489,7 @@ internal static LanguageVersion RequiredVersion(this MessageID feature) case MessageID.IDS_FeatureRefStructInterfaces: case MessageID.IDS_FeatureAllowsRefStructConstraint: case MessageID.IDS_FeaturePartialProperties: - case MessageID.IDS_OverloadResolutionPriority: + case MessageID.IDS_FeatureOverloadResolutionPriority: return LanguageVersion.CSharp13; // C# 12.0 features. diff --git a/src/Compilers/CSharp/Portable/FlowAnalysis/AbstractFlowPass.cs b/src/Compilers/CSharp/Portable/FlowAnalysis/AbstractFlowPass.cs index fb8ad0ddae840..9331dab2b5c2e 100644 --- a/src/Compilers/CSharp/Portable/FlowAnalysis/AbstractFlowPass.cs +++ b/src/Compilers/CSharp/Portable/FlowAnalysis/AbstractFlowPass.cs @@ -2541,6 +2541,7 @@ private void VisitBinaryOperatorChildren(BoundBinaryOperator node) do { stack.Push(binary); + EnterRegionIfNeeded(binary); binary = binary.Left as BoundBinaryOperator; } while (binary != null && !binary.OperatorKind.IsLogical() && binary.InterpolatedStringHandlerData is null); @@ -2550,6 +2551,7 @@ private void VisitBinaryOperatorChildren(BoundBinaryOperator node) } #nullable enable + /// Nested left-associative binary operators, pushed on from outermost to innermost. protected virtual void VisitBinaryOperatorChildren(ArrayBuilder stack) { var binary = stack.Pop(); @@ -2592,6 +2594,7 @@ protected virtual void VisitBinaryOperatorChildren(ArrayBuilder membersToBeInitialized(NamedTypeSymbol containingT => ImmutableArray.Empty, (includeAllMembers: false, includeCurrentTypeRequiredMembers: true, includeBaseRequiredMembers: false) - => containingType.GetMembersUnordered().SelectManyAsArray(predicate: SymbolExtensions.IsRequired, selector: getAllMembersToBeDefaulted), + => containingType.GetMembersUnordered().SelectManyAsArray( + predicate: SymbolExtensions.IsRequired, + selector: symbol => getAllMembersToBeDefaulted(symbol, filterOverridingProperties: true)), (includeAllMembers: false, includeCurrentTypeRequiredMembers: true, includeBaseRequiredMembers: true) - => containingType.AllRequiredMembers.SelectManyAsArray(static kvp => getAllMembersToBeDefaulted(kvp.Value)), + => containingType.AllRequiredMembers.SelectManyAsArray(static kvp => getAllMembersToBeDefaulted(kvp.Value, filterOverridingProperties: true)), (includeAllMembers: true, includeCurrentTypeRequiredMembers: _, includeBaseRequiredMembers: false) - => containingType.GetMembersUnordered().SelectAsArray(getFieldSymbolToBeInitialized), + => containingType.GetMembersUnordered().SelectManyAsArray( + selector: symbol => + { + var symbolToInitialize = getFieldSymbolToBeInitialized(symbol); + var prop = symbolToInitialize as PropertySymbol ?? (symbolToInitialize as FieldSymbol)?.AssociatedSymbol as PropertySymbol; + if (prop is not null && isFilterableOverrideOfAbstractProperty(prop)) + { + return OneOrMany.Empty; + } + else + { + return OneOrMany.Create(symbolToInitialize); + } + }), (includeAllMembers: true, includeCurrentTypeRequiredMembers: true, includeBaseRequiredMembers: true) => getAllTypeAndRequiredMembers(containingType), @@ -928,50 +944,95 @@ static ImmutableArray membersToBeInitialized(NamedTypeSymbol containingT static ImmutableArray getAllTypeAndRequiredMembers(TypeSymbol containingType) { var members = containingType.GetMembersUnordered(); - var requiredMembers = containingType.BaseTypeNoUseSiteDiagnostics?.AllRequiredMembers ?? ImmutableSegmentedDictionary.Empty; + var baseRequiredMembers = containingType.BaseTypeNoUseSiteDiagnostics?.AllRequiredMembers ?? ImmutableSegmentedDictionary.Empty; - if (requiredMembers.IsEmpty) + if (baseRequiredMembers.IsEmpty) { return members; } - var builder = ArrayBuilder.GetInstance(members.Length + requiredMembers.Count); + var builder = ArrayBuilder.GetInstance(members.Length + baseRequiredMembers.Count); builder.AddRange(members); - foreach (var (_, requiredMember) in requiredMembers) + foreach (var (_, requiredMember) in baseRequiredMembers) { // We want to assume that all required members were _not_ set by the chained constructor - builder.AddRange(getAllMembersToBeDefaulted(requiredMember)); + + // We exclude any members that are abstract and have an implementation in the current type, when that implementation passes the same heuristics + // we use in the other other cases (annotations match up across overrides). This is because the chained constructor, which as SetsRequiredMembers as well, + // will have already set the abstract member to non-null, and there isn't a separate slot for that abstract member. + if (requiredMember is PropertySymbol { IsAbstract: true } abstractProperty) + { + if (members.FirstOrDefault(static (thisMember, baseMember) => thisMember.IsOverride && (object)thisMember.GetOverriddenMember() == baseMember, requiredMember) is { } overridingMember + && isFilterableOverrideOfAbstractProperty((PropertySymbol)overridingMember)) + { + continue; + } + } + + builder.AddRange(getAllMembersToBeDefaulted(requiredMember, filterOverridingProperties: false)); } return builder.ToImmutableAndFree(); } - static IEnumerable getAllMembersToBeDefaulted(Symbol requiredMember) + static OneOrMany getAllMembersToBeDefaulted(Symbol requiredMember, bool filterOverridingProperties) { Debug.Assert(requiredMember.IsRequired()); if (requiredMember is FieldSymbol) { - yield return requiredMember; + return OneOrMany.Create(requiredMember); } else { var property = (PropertySymbol)requiredMember; - yield return getFieldSymbolToBeInitialized(property); + + if (filterOverridingProperties && isFilterableOverrideOfAbstractProperty(property)) + { + return OneOrMany.Empty; + } + + var @return = OneOrMany.Create(getFieldSymbolToBeInitialized(property)); // If the set method is null (ie missing), that's an error, but we'll recover as best we can foreach (var notNullMemberName in (property.SetMethod?.NotNullMembers ?? property.NotNullMembers)) { foreach (var member in property.ContainingType.GetMembers(notNullMemberName)) { - yield return getFieldSymbolToBeInitialized(member); + @return = @return.Add(getFieldSymbolToBeInitialized(member)); } } + + return @return; } } static Symbol getFieldSymbolToBeInitialized(Symbol requiredMember) => requiredMember is SourcePropertySymbolBase { BackingField: { } backingField } ? backingField : requiredMember; + + static bool isFilterableOverrideOfAbstractProperty(PropertySymbol property) + { + // If this is an override of an abstract property, and the overridden property has the same nullable + // annotation as us, we can skip default-initializing the property because the chained constructor + // will have done so + if (property.OverriddenProperty is not { IsAbstract: true } overriddenProperty) + { + return false; + } + + var symbolAnnotations = property is SourcePropertySymbolBase { UsesFieldKeyword: true, BackingField: { } field } + ? field!.FlowAnalysisAnnotations + : property.GetFlowAnalysisAnnotations(); + var symbolType = ApplyUnconditionalAnnotations(property.TypeWithAnnotations, symbolAnnotations); + if (!symbolType.NullableAnnotation.IsNotAnnotated()) + { + return false; + } + + var overriddenAnnotations = overriddenProperty.GetFlowAnalysisAnnotations(); + var overriddenType = ApplyUnconditionalAnnotations(overriddenProperty.TypeWithAnnotations, overriddenAnnotations); + return overriddenType.NullableAnnotation == symbolType.NullableAnnotation; + } } } } diff --git a/src/Compilers/CSharp/Portable/Generated/BoundNodes.xml.Generated.cs b/src/Compilers/CSharp/Portable/Generated/BoundNodes.xml.Generated.cs index 595e5105ae73c..228ce05213251 100644 --- a/src/Compilers/CSharp/Portable/Generated/BoundNodes.xml.Generated.cs +++ b/src/Compilers/CSharp/Portable/Generated/BoundNodes.xml.Generated.cs @@ -8026,8 +8026,12 @@ public BoundConstantPattern(SyntaxNode syntax, BoundExpression value, ConstantVa this.Value = value; this.ConstantValue = constantValue; + Validate(); } + [Conditional("DEBUG")] + private partial void Validate(); + public BoundExpression Value { get; } public ConstantValue ConstantValue { get; } @@ -8055,8 +8059,12 @@ public BoundDiscardPattern(SyntaxNode syntax, TypeSymbol inputType, TypeSymbol n RoslynDebug.Assert(inputType is object, "Field 'inputType' cannot be null (make the type nullable in BoundNodes.xml to remove this check)"); RoslynDebug.Assert(narrowedType is object, "Field 'narrowedType' cannot be null (make the type nullable in BoundNodes.xml to remove this check)"); + Validate(); } + [Conditional("DEBUG")] + private partial void Validate(); + public BoundDiscardPattern(SyntaxNode syntax, TypeSymbol inputType, TypeSymbol narrowedType) : base(BoundKind.DiscardPattern, syntax, inputType, narrowedType) { @@ -8111,8 +8119,12 @@ public BoundDeclarationPattern(SyntaxNode syntax, BoundTypeExpression declaredTy this.DeclaredType = declaredType; this.IsVar = isVar; + Validate(); } + [Conditional("DEBUG")] + private partial void Validate(); + public BoundTypeExpression DeclaredType { get; } public bool IsVar { get; } @@ -8145,8 +8157,12 @@ public BoundRecursivePattern(SyntaxNode syntax, BoundTypeExpression? declaredTyp this.Deconstruction = deconstruction; this.Properties = properties; this.IsExplicitNotNullTest = isExplicitNotNullTest; + Validate(); } + [Conditional("DEBUG")] + private partial void Validate(); + public BoundTypeExpression? DeclaredType { get; } public MethodSymbol? DeconstructMethod { get; } public ImmutableArray Deconstruction { get; } @@ -8266,8 +8282,12 @@ public BoundITuplePattern(SyntaxNode syntax, MethodSymbol getLengthMethod, Metho this.GetLengthMethod = getLengthMethod; this.GetItemMethod = getItemMethod; this.Subpatterns = subpatterns; + Validate(); } + [Conditional("DEBUG")] + private partial void Validate(); + public MethodSymbol GetLengthMethod { get; } public MethodSymbol GetItemMethod { get; } public ImmutableArray Subpatterns { get; } @@ -8403,8 +8423,12 @@ public BoundTypePattern(SyntaxNode syntax, BoundTypeExpression declaredType, boo this.DeclaredType = declaredType; this.IsExplicitNotNullTest = isExplicitNotNullTest; + Validate(); } + [Conditional("DEBUG")] + private partial void Validate(); + public BoundTypeExpression DeclaredType { get; } public bool IsExplicitNotNullTest { get; } @@ -8437,8 +8461,12 @@ public BoundBinaryPattern(SyntaxNode syntax, bool disjunction, BoundPattern left this.Disjunction = disjunction; this.Left = left; this.Right = right; + Validate(); } + [Conditional("DEBUG")] + private partial void Validate(); + public bool Disjunction { get; } public BoundPattern Left { get; } public BoundPattern Right { get; } @@ -8469,8 +8497,12 @@ public BoundNegatedPattern(SyntaxNode syntax, BoundPattern negated, TypeSymbol i RoslynDebug.Assert(narrowedType is object, "Field 'narrowedType' cannot be null (make the type nullable in BoundNodes.xml to remove this check)"); this.Negated = negated; + Validate(); } + [Conditional("DEBUG")] + private partial void Validate(); + public BoundPattern Negated { get; } [DebuggerStepThrough] @@ -8502,8 +8534,12 @@ public BoundRelationalPattern(SyntaxNode syntax, BinaryOperatorKind relation, Bo this.Relation = relation; this.Value = value; this.ConstantValue = constantValue; + Validate(); } + [Conditional("DEBUG")] + private partial void Validate(); + public BinaryOperatorKind Relation { get; } public BoundExpression Value { get; } public ConstantValue ConstantValue { get; } diff --git a/src/Compilers/CSharp/Portable/Generated/ErrorFacts.Generated.cs b/src/Compilers/CSharp/Portable/Generated/ErrorFacts.Generated.cs index a937cb51196b8..266ea28e686ca 100644 --- a/src/Compilers/CSharp/Portable/Generated/ErrorFacts.Generated.cs +++ b/src/Compilers/CSharp/Portable/Generated/ErrorFacts.Generated.cs @@ -343,6 +343,9 @@ public static bool IsWarning(ErrorCode code) case ErrorCode.WRN_UninitializedNonNullableBackingField: case ErrorCode.WRN_UnassignedInternalRefField: case ErrorCode.WRN_AccessorDoesNotUseBackingField: + case ErrorCode.WRN_ExperimentalWithMessage: + case ErrorCode.WRN_UnscopedRefAttributeOldRules: + case ErrorCode.WRN_InterceptsLocationAttributeUnsupportedSignature: return true; default: return false; diff --git a/src/Compilers/CSharp/Portable/Lowering/ClosureConversion/LambdaCapturedVariable.cs b/src/Compilers/CSharp/Portable/Lowering/ClosureConversion/LambdaCapturedVariable.cs index 66c567bc3a8f4..d58fe6b7886d0 100644 --- a/src/Compilers/CSharp/Portable/Lowering/ClosureConversion/LambdaCapturedVariable.cs +++ b/src/Compilers/CSharp/Portable/Lowering/ClosureConversion/LambdaCapturedVariable.cs @@ -10,18 +10,20 @@ using Roslyn.Utilities; using System.Collections.Immutable; using Microsoft.CodeAnalysis.Symbols; +using Microsoft.CodeAnalysis.CSharp.Emit; +using Microsoft.CodeAnalysis.PooledObjects; namespace Microsoft.CodeAnalysis.CSharp { /// /// A field of a frame class that represents a variable that has been captured in a lambda. /// - internal sealed class LambdaCapturedVariable : SynthesizedFieldSymbolBase, ISynthesizedMethodBodyImplementationSymbol + internal class LambdaCapturedVariable : SynthesizedFieldSymbolBase, ISynthesizedMethodBodyImplementationSymbol { private readonly TypeWithAnnotations _type; private readonly bool _isThis; - private LambdaCapturedVariable(SynthesizedClosureEnvironment frame, TypeWithAnnotations type, string fieldName, bool isThisParameter) + protected LambdaCapturedVariable(SynthesizedClosureEnvironment frame, TypeWithAnnotations type, string fieldName, bool isThisParameter) : base(frame, fieldName, isPublic: true, @@ -39,21 +41,38 @@ private LambdaCapturedVariable(SynthesizedClosureEnvironment frame, TypeWithAnno public SynthesizedClosureEnvironment Frame => (SynthesizedClosureEnvironment)ContainingType; +#nullable enable + public static LambdaCapturedVariable Create(SynthesizedClosureEnvironment frame, Symbol captured, ref int uniqueId) { Debug.Assert(captured is LocalSymbol || captured is ParameterSymbol); string fieldName = GetCapturedVariableFieldName(captured, ref uniqueId); TypeSymbol type = GetCapturedVariableFieldType(frame, captured); - return new LambdaCapturedVariable(frame, TypeWithAnnotations.Create(type), fieldName, IsThis(captured)); + bool isThis = IsThis(captured, out ParameterSymbol? parameter); + return parameter is not null && !isThis ? + new LambdaCapturedVariableForRegularParameter(frame, TypeWithAnnotations.Create(type), fieldName, parameter) : + new LambdaCapturedVariable(frame, TypeWithAnnotations.Create(type), fieldName, isThis); } private static bool IsThis(Symbol captured) { - var parameter = captured as ParameterSymbol; - return (object)parameter != null && parameter.IsThis; + return IsThis(captured, out _); + } + + /// + /// + /// Is assigned to when it is a , + /// null otherwise. Note, the value is not correlated with returned boolean. + /// + private static bool IsThis(Symbol captured, out ParameterSymbol? parameter) + { + parameter = captured as ParameterSymbol; + return (object?)parameter != null && parameter.IsThis; } +#nullable disable + private static string GetCapturedVariableFieldName(Symbol variable, ref int uniqueId) { if (IsThis(variable)) @@ -151,4 +170,34 @@ public IMethodSymbolInternal Method public bool HasMethodBodyDependency => false; } + + internal sealed class LambdaCapturedVariableForRegularParameter : LambdaCapturedVariable + { + private readonly ParameterSymbol _parameter; + + public LambdaCapturedVariableForRegularParameter(SynthesizedClosureEnvironment frame, TypeWithAnnotations type, string fieldName, ParameterSymbol parameter) + : base(frame, type, fieldName, isThisParameter: false) + { + Debug.Assert(parameter is { IsThis: false }); + _parameter = parameter; + } + + internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, ref ArrayBuilder attributes) + { + if (_parameter.OriginalDefinition is SourceParameterSymbolBase definition && + ContainingModule == definition.ContainingModule) + { + foreach (CSharpAttributeData attr in definition.GetAttributes()) + { + if (attr.AttributeClass is { HasCompilerLoweringPreserveAttribute: true } attributeType && + (attributeType.GetAttributeUsageInfo().ValidTargets & System.AttributeTargets.Field) != 0) + { + AddSynthesizedAttribute(ref attributes, attr); + } + } + } + + base.AddSynthesizedAttributes(moduleBuilder, ref attributes); + } + } } diff --git a/src/Compilers/CSharp/Portable/Lowering/IteratorRewriter/IteratorConstructor.cs b/src/Compilers/CSharp/Portable/Lowering/IteratorRewriter/IteratorConstructor.cs index 78ed7749163e1..20a1202c90f0d 100644 --- a/src/Compilers/CSharp/Portable/Lowering/IteratorRewriter/IteratorConstructor.cs +++ b/src/Compilers/CSharp/Portable/Lowering/IteratorRewriter/IteratorConstructor.cs @@ -28,7 +28,7 @@ internal IteratorConstructor(StateMachineTypeSymbol container) SynthesizedParameterSymbol.Create(this, TypeWithAnnotations.Create(intType), 0, RefKind.None, GeneratedNames.MakeStateMachineStateFieldName())); } - internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, ref ArrayBuilder attributes) + internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, ref ArrayBuilder attributes) { base.AddSynthesizedAttributes(moduleBuilder, ref attributes); diff --git a/src/Compilers/CSharp/Portable/Lowering/IteratorRewriter/IteratorMethodToStateMachineRewriter.cs b/src/Compilers/CSharp/Portable/Lowering/IteratorRewriter/IteratorMethodToStateMachineRewriter.cs index f022c87dd9e40..04cb1a691e333 100644 --- a/src/Compilers/CSharp/Portable/Lowering/IteratorRewriter/IteratorMethodToStateMachineRewriter.cs +++ b/src/Compilers/CSharp/Portable/Lowering/IteratorRewriter/IteratorMethodToStateMachineRewriter.cs @@ -163,6 +163,7 @@ internal void GenerateMoveNextAndDispose(BoundStatement body, SynthesizedImpleme // nothing to finalize var disposeBody = F.Block( GenerateAllHoistedLocalsCleanup(), + F.Assignment(F.Field(F.This(), stateField), F.Literal(StateMachineState.FinishedState)), F.Return()); F.CloseMethod(disposeBody); @@ -177,6 +178,7 @@ internal void GenerateMoveNextAndDispose(BoundStatement body, SynthesizedImpleme F.Assignment(F.Local(stateLocal), F.Field(F.This(), stateField)), EmitFinallyFrame(rootFrame, state), GenerateAllHoistedLocalsCleanup(), + F.Assignment(F.Field(F.This(), stateField), F.Literal(StateMachineState.FinishedState)), F.Return()); F.CloseMethod(disposeBody); diff --git a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter.cs b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter.cs index 9a81320dfef8c..8e73de6531706 100644 --- a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter.cs +++ b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter.cs @@ -404,7 +404,7 @@ public override BoundNode VisitLocalFunctionStatement(BoundLocalFunctionStatemen if (_factory.CompilationState.Compilation.ShouldEmitNullableAttributes(localFunction)) { bool constraintsNeedNullableAttribute = typeParameters.Any( - static typeParameter => ((SourceTypeParameterSymbolBase)typeParameter).ConstraintsNeedNullableAttribute()); + static typeParameter => ((SourceTypeParameterSymbol)typeParameter).ConstraintsNeedNullableAttribute()); if (constraintsNeedNullableAttribute || hasReturnTypeOrParameter(localFunction, static t => t.NeedsNullableAttribute())) { diff --git a/src/Compilers/CSharp/Portable/Lowering/MethodToClassRewriter.cs b/src/Compilers/CSharp/Portable/Lowering/MethodToClassRewriter.cs index 1f2fa70219430..de13dc92deff2 100644 --- a/src/Compilers/CSharp/Portable/Lowering/MethodToClassRewriter.cs +++ b/src/Compilers/CSharp/Portable/Lowering/MethodToClassRewriter.cs @@ -757,7 +757,7 @@ internal BaseMethodWrapperSymbol(NamedTypeSymbol containingType, MethodSymbol me AssignTypeMapAndTypeParameters(typeMap, typeParameters); } - internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, ref ArrayBuilder attributes) + internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, ref ArrayBuilder attributes) { base.AddSynthesizedAttributes(moduleBuilder, ref attributes); diff --git a/src/Compilers/CSharp/Portable/Lowering/StateMachineRewriter/StateMachineFieldSymbol.cs b/src/Compilers/CSharp/Portable/Lowering/StateMachineRewriter/StateMachineFieldSymbol.cs index c1215c815324c..fc2554073473d 100644 --- a/src/Compilers/CSharp/Portable/Lowering/StateMachineRewriter/StateMachineFieldSymbol.cs +++ b/src/Compilers/CSharp/Portable/Lowering/StateMachineRewriter/StateMachineFieldSymbol.cs @@ -7,7 +7,9 @@ using System.Collections.Immutable; using System.Diagnostics; using Microsoft.CodeAnalysis.CodeGen; +using Microsoft.CodeAnalysis.CSharp.Emit; using Microsoft.CodeAnalysis.CSharp.Symbols; +using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Symbols; using Roslyn.Utilities; @@ -16,7 +18,7 @@ namespace Microsoft.CodeAnalysis.CSharp /// /// Represents a synthesized state machine field. /// - internal sealed class StateMachineFieldSymbol : SynthesizedFieldSymbolBase, ISynthesizedMethodBodyImplementationSymbol + internal class StateMachineFieldSymbol : SynthesizedFieldSymbolBase, ISynthesizedMethodBodyImplementationSymbol { private readonly TypeWithAnnotations _type; private readonly bool _isThis; @@ -83,4 +85,34 @@ internal override bool IsCapturedFrame get { return _isThis; } } } + + internal sealed class StateMachineFieldSymbolForRegularParameter : StateMachineFieldSymbol + { + private readonly ParameterSymbol _parameter; + + public StateMachineFieldSymbolForRegularParameter(NamedTypeSymbol stateMachineType, TypeWithAnnotations type, string name, ParameterSymbol parameter, bool isPublic) + : base(stateMachineType, type, name, isPublic, isThis: false) + { + Debug.Assert(parameter is { IsThis: false }); + _parameter = parameter; + } + + internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, ref ArrayBuilder attributes) + { + if (_parameter.OriginalDefinition is SourceParameterSymbolBase definition && + ContainingModule == definition.ContainingModule) + { + foreach (CSharpAttributeData attr in definition.GetAttributes()) + { + if (attr.AttributeClass is { HasCompilerLoweringPreserveAttribute: true } attributeType && + (attributeType.GetAttributeUsageInfo().ValidTargets & System.AttributeTargets.Field) != 0) + { + AddSynthesizedAttribute(ref attributes, attr); + } + } + } + + base.AddSynthesizedAttributes(moduleBuilder, ref attributes); + } + } } diff --git a/src/Compilers/CSharp/Portable/Lowering/StateMachineRewriter/StateMachineRewriter.cs b/src/Compilers/CSharp/Portable/Lowering/StateMachineRewriter/StateMachineRewriter.cs index a6911a94549f4..1d30a0ecd01ed 100644 --- a/src/Compilers/CSharp/Portable/Lowering/StateMachineRewriter/StateMachineRewriter.cs +++ b/src/Compilers/CSharp/Portable/Lowering/StateMachineRewriter/StateMachineRewriter.cs @@ -252,12 +252,12 @@ private void CreateNonReusableLocalProxies( { // The field needs to be public iff it is initialized directly from the kickoff method // (i.e. not for IEnumerable which loads the values from parameter proxies). - var proxyField = F.StateMachineField(typeMap.SubstituteType(parameter.Type).Type, parameter.Name, isPublic: !PreserveInitialParameterValuesAndThreadId); + var proxyField = F.StateMachineFieldForRegularParameter(typeMap.SubstituteType(parameter.Type).Type, parameter.Name, parameter, isPublic: !PreserveInitialParameterValuesAndThreadId); proxiesBuilder.Add(parameter, new CapturedToStateMachineFieldReplacement(proxyField, isReusable: false)); if (PreserveInitialParameterValuesAndThreadId) { - var field = F.StateMachineField(typeMap.SubstituteType(parameter.Type).Type, GeneratedNames.StateMachineParameterProxyFieldName(parameter.Name), isPublic: true); + var field = F.StateMachineFieldForRegularParameter(typeMap.SubstituteType(parameter.Type).Type, GeneratedNames.StateMachineParameterProxyFieldName(parameter.Name), parameter, isPublic: true); initialParameters.Add(parameter, new CapturedToStateMachineFieldReplacement(field, isReusable: false)); } } diff --git a/src/Compilers/CSharp/Portable/Lowering/StateMachineRewriter/StateMachineTypeSymbol.cs b/src/Compilers/CSharp/Portable/Lowering/StateMachineRewriter/StateMachineTypeSymbol.cs index 28f84d6e89cfe..1dbc00cef4295 100644 --- a/src/Compilers/CSharp/Portable/Lowering/StateMachineRewriter/StateMachineTypeSymbol.cs +++ b/src/Compilers/CSharp/Portable/Lowering/StateMachineRewriter/StateMachineTypeSymbol.cs @@ -85,5 +85,7 @@ public sealed override ImmutableArray GetAttributes() public sealed override bool AreLocalsZeroed => KickoffMethod.AreLocalsZeroed; internal override bool HasCodeAnalysisEmbeddedAttribute => false; + + internal override bool HasCompilerLoweringPreserveAttribute => false; } } diff --git a/src/Compilers/CSharp/Portable/Lowering/StateMachineRewriter/SynthesizedStateMachineMethod.cs b/src/Compilers/CSharp/Portable/Lowering/StateMachineRewriter/SynthesizedStateMachineMethod.cs index 1ee69d7210055..880f9759d86a2 100644 --- a/src/Compilers/CSharp/Portable/Lowering/StateMachineRewriter/SynthesizedStateMachineMethod.cs +++ b/src/Compilers/CSharp/Portable/Lowering/StateMachineRewriter/SynthesizedStateMachineMethod.cs @@ -118,7 +118,7 @@ public SynthesizedStateMachineDebuggerHiddenMethod( { } - internal sealed override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, ref ArrayBuilder attributes) + internal sealed override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, ref ArrayBuilder attributes) { var compilation = this.DeclaringCompilation; AddSynthesizedAttribute(ref attributes, compilation.TrySynthesizeAttribute(WellKnownMember.System_Diagnostics_DebuggerHiddenAttribute__ctor)); diff --git a/src/Compilers/CSharp/Portable/Lowering/SynthesizedMethodBaseSymbol.cs b/src/Compilers/CSharp/Portable/Lowering/SynthesizedMethodBaseSymbol.cs index 84656a69b0073..20589154af9bc 100644 --- a/src/Compilers/CSharp/Portable/Lowering/SynthesizedMethodBaseSymbol.cs +++ b/src/Compilers/CSharp/Portable/Lowering/SynthesizedMethodBaseSymbol.cs @@ -72,7 +72,7 @@ protected override void MethodChecks(BindingDiagnosticBag diagnostics) // TODO: move more functionality into here, making these symbols more lazy } - internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, ref ArrayBuilder attributes) + internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, ref ArrayBuilder attributes) { base.AddSynthesizedAttributes(moduleBuilder, ref attributes); diff --git a/src/Compilers/CSharp/Portable/Lowering/SyntheticBoundNodeFactory.cs b/src/Compilers/CSharp/Portable/Lowering/SyntheticBoundNodeFactory.cs index 637a3a8da0e85..58eb9d9a7c2d9 100644 --- a/src/Compilers/CSharp/Portable/Lowering/SyntheticBoundNodeFactory.cs +++ b/src/Compilers/CSharp/Portable/Lowering/SyntheticBoundNodeFactory.cs @@ -183,6 +183,14 @@ public StateMachineFieldSymbol StateMachineField(TypeSymbol type, string name, b return result; } + public StateMachineFieldSymbol StateMachineFieldForRegularParameter(TypeSymbol type, string name, ParameterSymbol parameter, bool isPublic) + { + Debug.Assert(CurrentType is { }); + var result = new StateMachineFieldSymbolForRegularParameter(CurrentType, TypeWithAnnotations.Create(type), name, parameter, isPublic); + AddField(CurrentType, result); + return result; + } + public StateMachineFieldSymbol StateMachineField(TypeSymbol type, string name, SynthesizedLocalKind synthesizedKind, int slotIndex) { Debug.Assert(CurrentType is { }); diff --git a/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs b/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs index 8ed96d2f9c71a..cfc1749fdef5e 100644 --- a/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs +++ b/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs @@ -2054,39 +2054,57 @@ private bool IsPossibleAggregateClauseStartOrStop() private BaseListSyntax ParseBaseList() { + // We are only called from ParseClassOrStructOrInterfaceDeclaration which unilaterally sets this. + Debug.Assert((_termState & TerminatorState.IsEndOfRecordOrClassOrStructOrInterfaceSignature) != 0); + var colon = this.TryEatToken(SyntaxKind.ColonToken); if (colon == null) return null; var list = _pool.AllocateSeparated(); - // first type + // Grammar requires at least one base type follow the colon. var firstType = this.ParseType(); - - var argumentList = this.CurrentToken.Kind == SyntaxKind.OpenParenToken - ? this.ParseParenthesizedArgumentList() - : null; - - list.Add(argumentList != null - ? _syntaxFactory.PrimaryConstructorBaseType(firstType, argumentList) + list.Add(this.CurrentToken.Kind == SyntaxKind.OpenParenToken + ? _syntaxFactory.PrimaryConstructorBaseType(firstType, this.ParseParenthesizedArgumentList()) : _syntaxFactory.SimpleBaseType(firstType)); - // any additional types + // Parse any optional base types that follow. while (true) { - if (this.CurrentToken.Kind == SyntaxKind.OpenBraceToken || - ((_termState & TerminatorState.IsEndOfRecordOrClassOrStructOrInterfaceSignature) != 0 && this.CurrentToken.Kind == SyntaxKind.SemicolonToken) || + if (this.CurrentToken.Kind is SyntaxKind.OpenBraceToken or SyntaxKind.SemicolonToken || this.IsCurrentTokenWhereOfConstraintClause()) { break; } - else if (this.CurrentToken.Kind == SyntaxKind.CommaToken || this.IsPossibleType()) + + if (this.CurrentToken.Kind == SyntaxKind.CommaToken) + { + list.AddSeparator(this.EatToken(SyntaxKind.CommaToken)); + list.Add(_syntaxFactory.SimpleBaseType(this.ParseType())); + continue; + } + + // Error recovery. Code had an element in the base list, but wasn't followed by a comma or the start of + // any production that normally follows in a type declaration. See if this is just a case of a missing + // comma between types in the base list. + // + // Note: if we see something that looks more like a modifier than a type (like 'file') do not try to + // consume it as a type here, as we want to use that to better determine what member is actually following + // this incomplete type declaration. + if (GetModifierExcludingScoped(this.CurrentToken) != DeclarationModifiers.None) + { + break; + } + + if (this.IsPossibleType()) { list.AddSeparator(this.EatToken(SyntaxKind.CommaToken)); list.Add(_syntaxFactory.SimpleBaseType(this.ParseType())); continue; } - else if (skipBadBaseListTokens(ref colon, list, SyntaxKind.CommaToken) == PostSkipAction.Abort) + + if (skipBadBaseListTokens(ref colon, list, SyntaxKind.CommaToken) == PostSkipAction.Abort) { break; } @@ -9162,24 +9180,30 @@ private ForStatementSyntax ParseForStatement(SyntaxList att var openParen = this.EatToken(SyntaxKind.OpenParenToken); var (variableDeclaration, initializers) = eatVariableDeclarationOrInitializers(); - // Pulled out as we need to track this when parsing incrementors to place skipped tokens. - SyntaxToken secondSemicolonToken; + var firstSemicolonToken = eatCommaOrSemicolon(); + var condition = this.CurrentToken.Kind is not SyntaxKind.SemicolonToken and not SyntaxKind.CommaToken + ? this.ParseExpressionCore() + : null; + + // Used to place skipped tokens we run into when parsing the incrementors list. + var secondSemicolonToken = eatCommaOrSemicolon(); + + // Do allow semicolons (with diagnostics) in the incrementors list. This allows us to consume + // accidental extra incrementors that should have been separated by commas. + var incrementors = this.CurrentToken.Kind != SyntaxKind.CloseParenToken + ? parseForStatementExpressionList(ref secondSemicolonToken, allowSemicolonAsSeparator: true) + : default; + var forStatement = _syntaxFactory.ForStatement( attributes, forToken, openParen, variableDeclaration, initializers, - firstSemicolonToken: eatCommaOrSemicolon(), - condition: this.CurrentToken.Kind is not SyntaxKind.SemicolonToken and not SyntaxKind.CommaToken - ? this.ParseExpressionCore() - : null, - secondSemicolonToken = eatCommaOrSemicolon(), - // Do allow semicolons (with diagnostics) in the incrementors list. This allows us to consume - // accidental extra incrementors that should have been separated by commas. - incrementors: this.CurrentToken.Kind != SyntaxKind.CloseParenToken - ? parseForStatementExpressionList(ref secondSemicolonToken, allowSemicolonAsSeparator: true) - : default, + firstSemicolonToken, + condition, + secondSemicolonToken, + incrementors, eatUnexpectedTokensAndCloseParenToken(), ParseEmbeddedStatement()); diff --git a/src/Compilers/CSharp/Portable/Parser/SyntaxParser.cs b/src/Compilers/CSharp/Portable/Parser/SyntaxParser.cs index 4c9e5502030c4..3934640cbcec9 100644 --- a/src/Compilers/CSharp/Portable/Parser/SyntaxParser.cs +++ b/src/Compilers/CSharp/Portable/Parser/SyntaxParser.cs @@ -35,8 +35,8 @@ internal abstract partial class SyntaxParser : IDisposable private int _resetCount; private int _resetStart; - private static readonly ObjectPool s_blendedNodesPool = new ObjectPool(() => new BlendedNode[32], 2); - private static readonly ObjectPool[]> s_lexedTokensPool = new ObjectPool[]>(() => new ArrayElement[CachedTokenArraySize], 2); + private static readonly ObjectPool s_blendedNodesPool = new ObjectPool(() => new BlendedNode[32]); + private static readonly ObjectPool[]> s_lexedTokensPool = new ObjectPool[]>(() => new ArrayElement[CachedTokenArraySize]); // Array size held in token pool. This should be large enough to prevent most allocations, but // not so large as to be wasteful when not in use. diff --git a/src/Compilers/CSharp/Portable/PublicAPI.Shipped.txt b/src/Compilers/CSharp/Portable/PublicAPI.Shipped.txt index ed7ab64420625..d5ea07698847c 100644 --- a/src/Compilers/CSharp/Portable/PublicAPI.Shipped.txt +++ b/src/Compilers/CSharp/Portable/PublicAPI.Shipped.txt @@ -1,6 +1,6 @@ #nullable enable [RSEXPERIMENTAL001]Microsoft.CodeAnalysis.CSharp.CSharpCompilation.GetSemanticModel(Microsoft.CodeAnalysis.SyntaxTree! syntaxTree, Microsoft.CodeAnalysis.SemanticModelOptions options) -> Microsoft.CodeAnalysis.SemanticModel! -[RSEXPERIMENTAL002]static Microsoft.CodeAnalysis.CSharp.CSharpExtensions.GetInterceptorMethod(this Microsoft.CodeAnalysis.SemanticModel? semanticModel, Microsoft.CodeAnalysis.CSharp.Syntax.InvocationExpressionSyntax! node, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> Microsoft.CodeAnalysis.IMethodSymbol? +static Microsoft.CodeAnalysis.CSharp.CSharpExtensions.GetInterceptorMethod(this Microsoft.CodeAnalysis.SemanticModel? semanticModel, Microsoft.CodeAnalysis.CSharp.Syntax.InvocationExpressionSyntax! node, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> Microsoft.CodeAnalysis.IMethodSymbol? ~Microsoft.CodeAnalysis.CSharp.Syntax.AnonymousMethodExpressionSyntax.Update(Microsoft.CodeAnalysis.SyntaxToken asyncKeyword, Microsoft.CodeAnalysis.SyntaxToken delegateKeyword, Microsoft.CodeAnalysis.CSharp.Syntax.ParameterListSyntax parameterList, Microsoft.CodeAnalysis.CSharp.CSharpSyntaxNode body) -> Microsoft.CodeAnalysis.CSharp.Syntax.AnonymousMethodExpressionSyntax ~Microsoft.CodeAnalysis.CSharp.Syntax.AnonymousMethodExpressionSyntax.Update(Microsoft.CodeAnalysis.SyntaxToken asyncKeyword, Microsoft.CodeAnalysis.SyntaxToken delegateKeyword, Microsoft.CodeAnalysis.CSharp.Syntax.ParameterListSyntax parameterList, Microsoft.CodeAnalysis.CSharp.Syntax.BlockSyntax block, Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax expressionBody) -> Microsoft.CodeAnalysis.CSharp.Syntax.AnonymousMethodExpressionSyntax ~Microsoft.CodeAnalysis.CSharp.Syntax.AnonymousMethodExpressionSyntax.WithAsyncKeyword(Microsoft.CodeAnalysis.SyntaxToken asyncKeyword) -> Microsoft.CodeAnalysis.CSharp.Syntax.AnonymousMethodExpressionSyntax diff --git a/src/Compilers/CSharp/Portable/PublicAPI.Unshipped.txt b/src/Compilers/CSharp/Portable/PublicAPI.Unshipped.txt index d1755de0d604a..0ebff1a371642 100644 --- a/src/Compilers/CSharp/Portable/PublicAPI.Unshipped.txt +++ b/src/Compilers/CSharp/Portable/PublicAPI.Unshipped.txt @@ -1,14 +1,14 @@ Microsoft.CodeAnalysis.CSharp.Conversion.IsSpan.get -> bool Microsoft.CodeAnalysis.CSharp.LanguageVersion.CSharp13 = 1300 -> Microsoft.CodeAnalysis.CSharp.LanguageVersion -[RSEXPERIMENTAL002]Microsoft.CodeAnalysis.CSharp.InterceptableLocation -[RSEXPERIMENTAL002]abstract Microsoft.CodeAnalysis.CSharp.InterceptableLocation.Data.get -> string! -[RSEXPERIMENTAL002]abstract Microsoft.CodeAnalysis.CSharp.InterceptableLocation.GetDisplayLocation() -> string! -[RSEXPERIMENTAL002]abstract Microsoft.CodeAnalysis.CSharp.InterceptableLocation.Version.get -> int +Microsoft.CodeAnalysis.CSharp.InterceptableLocation +abstract Microsoft.CodeAnalysis.CSharp.InterceptableLocation.Data.get -> string! +abstract Microsoft.CodeAnalysis.CSharp.InterceptableLocation.GetDisplayLocation() -> string! +abstract Microsoft.CodeAnalysis.CSharp.InterceptableLocation.Version.get -> int Microsoft.CodeAnalysis.CSharp.SyntaxKind.RazorContentToken = 8523 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind -[RSEXPERIMENTAL002]override abstract Microsoft.CodeAnalysis.CSharp.InterceptableLocation.Equals(object? obj) -> bool -[RSEXPERIMENTAL002]override abstract Microsoft.CodeAnalysis.CSharp.InterceptableLocation.GetHashCode() -> int -[RSEXPERIMENTAL002]static Microsoft.CodeAnalysis.CSharp.CSharpExtensions.GetInterceptableLocation(this Microsoft.CodeAnalysis.SemanticModel? semanticModel, Microsoft.CodeAnalysis.CSharp.Syntax.InvocationExpressionSyntax! node, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> Microsoft.CodeAnalysis.CSharp.InterceptableLocation? -[RSEXPERIMENTAL002]static Microsoft.CodeAnalysis.CSharp.CSharpExtensions.GetInterceptsLocationAttributeSyntax(this Microsoft.CodeAnalysis.CSharp.InterceptableLocation! location) -> string! +override abstract Microsoft.CodeAnalysis.CSharp.InterceptableLocation.Equals(object? obj) -> bool +override abstract Microsoft.CodeAnalysis.CSharp.InterceptableLocation.GetHashCode() -> int +static Microsoft.CodeAnalysis.CSharp.CSharpExtensions.GetInterceptableLocation(this Microsoft.CodeAnalysis.SemanticModel? semanticModel, Microsoft.CodeAnalysis.CSharp.Syntax.InvocationExpressionSyntax! node, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> Microsoft.CodeAnalysis.CSharp.InterceptableLocation? +static Microsoft.CodeAnalysis.CSharp.CSharpExtensions.GetInterceptsLocationAttributeSyntax(this Microsoft.CodeAnalysis.CSharp.InterceptableLocation! location) -> string! [RSEXPERIMENTAL003]Microsoft.CodeAnalysis.CSharp.SyntaxTokenParser [RSEXPERIMENTAL003]Microsoft.CodeAnalysis.CSharp.SyntaxTokenParser.Dispose() -> void [RSEXPERIMENTAL003]Microsoft.CodeAnalysis.CSharp.SyntaxTokenParser.ParseLeadingTrivia() -> Microsoft.CodeAnalysis.CSharp.SyntaxTokenParser.Result diff --git a/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/PublicSymbols/AnonymousManager.TypeOrDelegatePublicSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/PublicSymbols/AnonymousManager.TypeOrDelegatePublicSymbol.cs index e179edb4de88e..e2ed766e3be0e 100644 --- a/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/PublicSymbols/AnonymousManager.TypeOrDelegatePublicSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/PublicSymbols/AnonymousManager.TypeOrDelegatePublicSymbol.cs @@ -42,6 +42,8 @@ internal sealed override IEnumerable GetFieldsToEmit() internal sealed override bool HasCodeAnalysisEmbeddedAttribute => false; + internal sealed override bool HasCompilerLoweringPreserveAttribute => false; + internal sealed override bool IsInterpolatedStringHandlerType => false; internal sealed override ImmutableArray GetEarlyAttributeDecodingMembers() diff --git a/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType.DelegateTemplateSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType.DelegateTemplateSymbol.cs index b7749ddcd7867..9988175aaa0c5 100644 --- a/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType.DelegateTemplateSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType.DelegateTemplateSymbol.cs @@ -243,7 +243,7 @@ private static ImmutableArray CreateMembers(MethodSymbol constructor, Me public override ImmutableArray TypeParameters { get; } - internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, ref ArrayBuilder attributes) + internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, ref ArrayBuilder attributes) { base.AddSynthesizedAttributes(moduleBuilder, ref attributes); diff --git a/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType.FieldSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType.FieldSymbol.cs index 99541bb595a1d..d9bd6a604cebd 100644 --- a/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType.FieldSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType.FieldSymbol.cs @@ -143,7 +143,7 @@ public override bool IsImplicitlyDeclared get { return true; } } - internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, ref ArrayBuilder attributes) + internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, ref ArrayBuilder attributes) { base.AddSynthesizedAttributes(moduleBuilder, ref attributes); diff --git a/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType.PropertyAccessorSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType.PropertyAccessorSymbol.cs index afbca6b840301..a9f657366d425 100644 --- a/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType.PropertyAccessorSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType.PropertyAccessorSymbol.cs @@ -83,7 +83,7 @@ internal override bool IsMetadataFinal } } - internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, ref ArrayBuilder attributes) + internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, ref ArrayBuilder attributes) { // Do not call base.AddSynthesizedAttributes. // Dev11 does not emit DebuggerHiddenAttribute in property accessors diff --git a/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType.SynthesizedMethodBase.cs b/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType.SynthesizedMethodBase.cs index 1e4730727af7a..425d6a2a363cd 100644 --- a/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType.SynthesizedMethodBase.cs +++ b/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType.SynthesizedMethodBase.cs @@ -165,7 +165,7 @@ internal sealed override bool IsMetadataNewSlot(bool ignoreInterfaceImplementati return false; } - internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, ref ArrayBuilder attributes) + internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, ref ArrayBuilder attributes) { base.AddSynthesizedAttributes(moduleBuilder, ref attributes); diff --git a/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType.TemplateSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType.TemplateSymbol.cs index ce0f158b7a4a4..cf8174dac6733 100644 --- a/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType.TemplateSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType.TemplateSymbol.cs @@ -157,7 +157,7 @@ public override IEnumerable MemberNames get { return _nameToSymbols.Keys; } } - internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, ref ArrayBuilder attributes) + internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, ref ArrayBuilder attributes) { base.AddSynthesizedAttributes(moduleBuilder, ref attributes); diff --git a/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType.TypeOrDelegateTemplateSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType.TypeOrDelegateTemplateSymbol.cs index a0fd2af024250..9d601bda14ded 100644 --- a/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType.TypeOrDelegateTemplateSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType.TypeOrDelegateTemplateSymbol.cs @@ -120,6 +120,8 @@ internal override bool GetGuidString(out string? guidString) internal sealed override bool HasCodeAnalysisEmbeddedAttribute => false; + internal sealed override bool HasCompilerLoweringPreserveAttribute => false; + internal sealed override bool IsInterpolatedStringHandlerType => false; internal sealed override ImmutableArray GetEarlyAttributeDecodingMembers() diff --git a/src/Compilers/CSharp/Portable/Symbols/Attributes/PEAttributeData.cs b/src/Compilers/CSharp/Portable/Symbols/Attributes/PEAttributeData.cs index 2d48c11209ee0..0d53c1bfe761d 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Attributes/PEAttributeData.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Attributes/PEAttributeData.cs @@ -8,6 +8,7 @@ using System.Diagnostics.CodeAnalysis; using System.Reflection.Metadata; using System.Threading; +using Microsoft.CodeAnalysis.Collections; namespace Microsoft.CodeAnalysis.CSharp.Symbols.Metadata.PE { @@ -97,7 +98,7 @@ private void EnsureClassAndConstructorSymbolsAreLoaded() private void EnsureAttributeArgumentsAreLoaded() { - if (_lazyConstructorArguments.IsDefault || _lazyNamedArguments.IsDefault) + if (RoslynImmutableInterlocked.VolatileRead(in _lazyConstructorArguments).IsDefault || RoslynImmutableInterlocked.VolatileRead(in _lazyNamedArguments).IsDefault) { TypedConstant[]? lazyConstructorArguments = null; KeyValuePair[]? lazyNamedArguments = null; diff --git a/src/Compilers/CSharp/Portable/Symbols/ConstraintsHelper.cs b/src/Compilers/CSharp/Portable/Symbols/ConstraintsHelper.cs index 276d898f8a944..ab7001379184a 100644 --- a/src/Compilers/CSharp/Portable/Symbols/ConstraintsHelper.cs +++ b/src/Compilers/CSharp/Portable/Symbols/ConstraintsHelper.cs @@ -69,7 +69,7 @@ internal static class ConstraintsHelper /// generic method. In those cases, additional constraint checks are applied. /// public static TypeParameterBounds ResolveBounds( - this SourceTypeParameterSymbolBase typeParameter, + this SourceTypeParameterSymbol typeParameter, AssemblySymbol corLibrary, ConsList inProgress, ImmutableArray constraintTypes, diff --git a/src/Compilers/CSharp/Portable/Symbols/ErrorTypeSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/ErrorTypeSymbol.cs index 703f303fd2963..c6abc0310eddc 100644 --- a/src/Compilers/CSharp/Portable/Symbols/ErrorTypeSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/ErrorTypeSymbol.cs @@ -441,6 +441,8 @@ internal override bool GetGuidString(out string? guidString) internal override bool HasCodeAnalysisEmbeddedAttribute => false; + internal override bool HasCompilerLoweringPreserveAttribute => false; + internal override bool IsInterpolatedStringHandlerType => false; internal override ImmutableArray InterfacesNoUseSiteDiagnostics(ConsList? basesBeingResolved) diff --git a/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PEGlobalNamespaceSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PEGlobalNamespaceSymbol.cs index 427d4fb261044..05500ca014e0d 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PEGlobalNamespaceSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PEGlobalNamespaceSymbol.cs @@ -13,6 +13,7 @@ using System.Linq; using System.Reflection.Metadata; using System; +using System.Threading; namespace Microsoft.CodeAnalysis.CSharp.Symbols.Metadata.PE { @@ -81,7 +82,7 @@ internal override ModuleSymbol ContainingModule protected override void EnsureAllMembersLoaded() { - if (lazyTypes == null || lazyNamespaces == null) + if (Volatile.Read(ref lazyTypes) == null || Volatile.Read(ref lazyNamespaces) == null) { IEnumerable> groups; diff --git a/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PEMethodSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PEMethodSymbol.cs index 9629eda149760..7594549773a9b 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PEMethodSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PEMethodSymbol.cs @@ -131,24 +131,24 @@ public MethodKind MethodKind public bool IsExplicitFinalizerOverride => (_bits & IsExplicitFinalizerOverrideBit) != 0; public bool IsExplicitClassOverride => (_bits & IsExplicitClassOverrideBit) != 0; public bool IsExplicitOverrideIsPopulated => (_bits & IsExplicitOverrideIsPopulatedBit) != 0; - public bool IsObsoleteAttributePopulated => (_bits & IsObsoleteAttributePopulatedBit) != 0; - public bool IsCustomAttributesPopulated => (_bits & IsCustomAttributesPopulatedBit) != 0; - public bool IsUseSiteDiagnosticPopulated => (_bits & IsUseSiteDiagnosticPopulatedBit) != 0; - public bool IsConditionalPopulated => (_bits & IsConditionalPopulatedBit) != 0; - public bool IsOverriddenOrHiddenMembersPopulated => (_bits & IsOverriddenOrHiddenMembersPopulatedBit) != 0; + public bool IsObsoleteAttributePopulated => (Volatile.Read(ref _bits) & IsObsoleteAttributePopulatedBit) != 0; + public bool IsCustomAttributesPopulated => (Volatile.Read(ref _bits) & IsCustomAttributesPopulatedBit) != 0; + public bool IsUseSiteDiagnosticPopulated => (Volatile.Read(ref _bits) & IsUseSiteDiagnosticPopulatedBit) != 0; + public bool IsConditionalPopulated => (Volatile.Read(ref _bits) & IsConditionalPopulatedBit) != 0; + public bool IsOverriddenOrHiddenMembersPopulated => (Volatile.Read(ref _bits) & IsOverriddenOrHiddenMembersPopulatedBit) != 0; public bool IsReadOnly => (_bits & IsReadOnlyBit) != 0; public bool IsReadOnlyPopulated => (_bits & IsReadOnlyPopulatedBit) != 0; public bool DoesNotReturn => (_bits & DoesNotReturnBit) != 0; public bool IsDoesNotReturnPopulated => (_bits & IsDoesNotReturnPopulatedBit) != 0; - public bool IsMemberNotNullPopulated => (_bits & IsMemberNotNullPopulatedBit) != 0; + public bool IsMemberNotNullPopulated => (Volatile.Read(ref _bits) & IsMemberNotNullPopulatedBit) != 0; public bool IsInitOnly => (_bits & IsInitOnlyBit) != 0; public bool IsInitOnlyPopulated => (_bits & IsInitOnlyPopulatedBit) != 0; - public bool IsUnmanagedCallersOnlyAttributePopulated => (_bits & IsUnmanagedCallersOnlyAttributePopulatedBit) != 0; + public bool IsUnmanagedCallersOnlyAttributePopulated => (Volatile.Read(ref _bits) & IsUnmanagedCallersOnlyAttributePopulatedBit) != 0; public bool HasSetsRequiredMembers => (_bits & HasSetsRequiredMembersBit) != 0; public bool HasSetsRequiredMembersPopulated => (_bits & HasSetsRequiredMembersPopulatedBit) != 0; public bool IsUnscopedRef => (_bits & IsUnscopedRefBit) != 0; public bool IsUnscopedRefPopulated => (_bits & IsUnscopedRefPopulatedBit) != 0; - public bool IsOverloadResolutionPriorityPopulated => (_bits & OverloadResolutionPriorityPopulatedBit) != 0; + public bool IsOverloadResolutionPriorityPopulated => (Volatile.Read(ref _bits) & OverloadResolutionPriorityPopulatedBit) != 0; #if DEBUG static PackedFlags() @@ -1653,12 +1653,12 @@ internal override OverriddenOrHiddenMembersResult OverriddenOrHiddenMembers } } - internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, ref ArrayBuilder attributes) + internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, ref ArrayBuilder attributes) { throw ExceptionUtilities.Unreachable(); } - internal override void AddSynthesizedReturnTypeAttributes(PEModuleBuilder moduleBuilder, ref ArrayBuilder attributes) + internal override void AddSynthesizedReturnTypeAttributes(PEModuleBuilder moduleBuilder, ref ArrayBuilder attributes) { throw ExceptionUtilities.Unreachable(); } diff --git a/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PENamedTypeSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PENamedTypeSymbol.cs index ea2cd5b3dbaa5..60d770d5ad6b8 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PENamedTypeSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PENamedTypeSymbol.cs @@ -15,6 +15,7 @@ using System.Reflection.Metadata.Ecma335; using System.Runtime.InteropServices; using System.Threading; +using Microsoft.CodeAnalysis.Collections; using Microsoft.CodeAnalysis.CSharp.DocumentationComments; using Microsoft.CodeAnalysis.CSharp.Emit; using Microsoft.CodeAnalysis.PooledObjects; @@ -144,6 +145,7 @@ private sealed class UncommonProperties internal NamedTypeSymbol lazyComImportCoClassType = ErrorTypeSymbol.UnknownResultType; internal CollectionBuilderAttributeData lazyCollectionBuilderAttributeData = CollectionBuilderAttributeData.Uninitialized; internal ThreeState lazyHasEmbeddedAttribute = ThreeState.Unknown; + internal ThreeState lazyHasCompilerLoweringPreserveAttribute = ThreeState.Unknown; internal ThreeState lazyHasInterpolatedStringHandlerAttribute = ThreeState.Unknown; internal ThreeState lazyHasRequiredMembers = ThreeState.Unknown; @@ -467,6 +469,25 @@ internal override bool HasCodeAnalysisEmbeddedAttribute } } + internal override bool HasCompilerLoweringPreserveAttribute + { + get + { + var uncommon = GetUncommonProperties(); + if (uncommon == s_noUncommonProperties) + { + return false; + } + + if (!uncommon.lazyHasCompilerLoweringPreserveAttribute.HasValue()) + { + uncommon.lazyHasCompilerLoweringPreserveAttribute = ContainingPEModule.Module.HasCompilerLoweringPreserveAttribute(_handle).ToThreeState(); + } + + return uncommon.lazyHasCompilerLoweringPreserveAttribute.Value(); + } + } + internal override NamedTypeSymbol BaseTypeNoUseSiteDiagnostics { get @@ -1260,7 +1281,7 @@ private void EnsureEnumUnderlyingTypeIsLoaded(UncommonProperties uncommon) private void EnsureAllMembersAreLoaded() { - if (_lazyMembersByName == null) + if (Volatile.Read(ref _lazyMembersByName) == null) { LoadMembers(); } @@ -1270,7 +1291,7 @@ private void LoadMembers() { ArrayBuilder members = null; - if (_lazyMembersInDeclarationOrder.IsDefault) + if (RoslynImmutableInterlocked.VolatileRead(ref _lazyMembersInDeclarationOrder).IsDefault) { EnsureNestedTypesAreLoaded(); @@ -1440,7 +1461,7 @@ private void LoadMembers() } } - if (_lazyMembersByName == null) + if (Volatile.Read(ref _lazyMembersByName) == null) { if (members == null) { diff --git a/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PENestedNamespaceSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PENestedNamespaceSymbol.cs index 797c31a8e713f..926726b82aaa3 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PENestedNamespaceSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PENestedNamespaceSymbol.cs @@ -125,11 +125,14 @@ internal override ModuleSymbol ContainingModule protected override void EnsureAllMembersLoaded() { - var typesByNS = _typesByNS; + var typesByNS = Volatile.Read(ref _typesByNS); - if (lazyTypes == null || lazyNamespaces == null) + if (typesByNS == null) + { + Debug.Assert(lazyNamespaces != null && lazyTypes != null); + } + else { - System.Diagnostics.Debug.Assert(typesByNS != null); LoadAllMembers(typesByNS); Interlocked.Exchange(ref _typesByNS, null); } diff --git a/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PEPropertySymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PEPropertySymbol.cs index 0956462733b10..86e4c0dd8c549 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PEPropertySymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PEPropertySymbol.cs @@ -128,28 +128,28 @@ public void SetUseSiteDiagnosticPopulated() ThreadSafeFlagOperations.Set(ref _bits, IsUseSiteDiagnosticPopulatedBit); } - public readonly bool IsUseSiteDiagnosticPopulated => (_bits & IsUseSiteDiagnosticPopulatedBit) != 0; + public bool IsUseSiteDiagnosticPopulated => (Volatile.Read(ref _bits) & IsUseSiteDiagnosticPopulatedBit) != 0; public void SetObsoleteAttributePopulated() { ThreadSafeFlagOperations.Set(ref _bits, IsObsoleteAttributePopulatedBit); } - public readonly bool IsObsoleteAttributePopulated => (_bits & IsObsoleteAttributePopulatedBit) != 0; + public bool IsObsoleteAttributePopulated => (Volatile.Read(ref _bits) & IsObsoleteAttributePopulatedBit) != 0; public void SetCustomAttributesPopulated() { ThreadSafeFlagOperations.Set(ref _bits, IsCustomAttributesPopulatedBit); } - public readonly bool IsCustomAttributesPopulated => (_bits & IsCustomAttributesPopulatedBit) != 0; + public bool IsCustomAttributesPopulated => (Volatile.Read(ref _bits) & IsCustomAttributesPopulatedBit) != 0; public void SetOverloadResolutionPriorityPopulated() { ThreadSafeFlagOperations.Set(ref _bits, IsOverloadResolutionPriorityPopulatedBit); } - public readonly bool IsOverloadResolutionPriorityPopulated => (_bits & IsOverloadResolutionPriorityPopulatedBit) != 0; + public bool IsOverloadResolutionPriorityPopulated => (Volatile.Read(ref _bits) & IsOverloadResolutionPriorityPopulatedBit) != 0; } /// diff --git a/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PETypeParameterSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PETypeParameterSymbol.cs index ae6accbadf890..9a48e210bf529 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PETypeParameterSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PETypeParameterSymbol.cs @@ -12,6 +12,7 @@ using System.Reflection.Metadata; using System.Reflection.Metadata.Ecma335; using System.Threading; +using Microsoft.CodeAnalysis.Collections; using Microsoft.CodeAnalysis.PooledObjects; using Roslyn.Utilities; @@ -152,7 +153,7 @@ private ImmutableArray GetDeclaredConstraintTypes(ConsList< Debug.Assert(!inProgress.ContainsReference(this)); Debug.Assert(!inProgress.Any() || ReferenceEquals(inProgress.Head.ContainingSymbol, this.ContainingSymbol)); - if (_lazyDeclaredConstraintTypes.IsDefault) + if (RoslynImmutableInterlocked.VolatileRead(ref _lazyDeclaredConstraintTypes).IsDefault) { ImmutableArray declaredConstraintTypes; diff --git a/src/Compilers/CSharp/Portable/Symbols/MethodSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/MethodSymbol.cs index ac078acaa6101..163e0f8ffb927 100644 --- a/src/Compilers/CSharp/Portable/Symbols/MethodSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/MethodSymbol.cs @@ -1148,7 +1148,7 @@ internal virtual bool SynthesizesLoweredBoundBody /// /// Build and add synthesized return type attributes for this method symbol. /// - internal virtual void AddSynthesizedReturnTypeAttributes(PEModuleBuilder moduleBuilder, ref ArrayBuilder attributes) + internal virtual void AddSynthesizedReturnTypeAttributes(PEModuleBuilder moduleBuilder, ref ArrayBuilder attributes) { if (this.ReturnsByRefReadonly) { @@ -1266,7 +1266,7 @@ public override int GetHashCode() } #nullable enable - protected static void AddRequiredMembersMarkerAttributes(ref ArrayBuilder attributes, MethodSymbol methodToAttribute) + protected static void AddRequiredMembersMarkerAttributes(ref ArrayBuilder attributes, MethodSymbol methodToAttribute) { if (methodToAttribute.ShouldCheckRequiredMembers() && methodToAttribute.ContainingType.HasAnyRequiredMembers) { diff --git a/src/Compilers/CSharp/Portable/Symbols/NamedTypeSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/NamedTypeSymbol.cs index 9a2ffda20fc87..86bffaf57f12a 100644 --- a/src/Compilers/CSharp/Portable/Symbols/NamedTypeSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/NamedTypeSymbol.cs @@ -204,17 +204,14 @@ public MethodSymbol? DelegateInvokeMethod #nullable disable /// - /// Get the operators for this type by their metadata name + /// Adds the operators for this type by their metadata name to /// - internal ImmutableArray GetOperators(string name) + internal void AddOperators(string name, ArrayBuilder operators) { ImmutableArray candidates = GetSimpleNonTypeMembers(name); if (candidates.IsEmpty) - { - return ImmutableArray.Empty; - } + return; - var operators = ArrayBuilder.GetInstance(candidates.Length); foreach (var candidate in candidates) { if (candidate is MethodSymbol { MethodKind: MethodKind.UserDefinedOperator or MethodKind.Conversion } method) @@ -222,8 +219,6 @@ internal ImmutableArray GetOperators(string name) operators.Add(method); } } - - return operators.ToImmutableAndFree(); } /// @@ -1154,6 +1149,8 @@ internal NamedTypeSymbol GetUnboundGenericTypeOrSelf() internal abstract bool HasAsyncMethodBuilderAttribute(out TypeSymbol builderArgument); + internal abstract bool HasCompilerLoweringPreserveAttribute { get; } + /// /// Gets a value indicating whether this type has System.Runtime.CompilerServices.InterpolatedStringHandlerAttribute or not. /// diff --git a/src/Compilers/CSharp/Portable/Symbols/NativeIntegerTypeSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/NativeIntegerTypeSymbol.cs index 4bf3c91ad7608..b805e7b0319fb 100644 --- a/src/Compilers/CSharp/Portable/Symbols/NativeIntegerTypeSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/NativeIntegerTypeSymbol.cs @@ -205,6 +205,8 @@ internal override bool Equals(TypeSymbol? other, TypeCompareKind comparison) public override int GetHashCode() => _underlyingType.GetHashCode(); + internal override bool HasCompilerLoweringPreserveAttribute => false; + #if !DEBUG void Cci.IReference.Dispatch(Cci.MetadataVisitor visitor) { diff --git a/src/Compilers/CSharp/Portable/Symbols/ObsoleteAttributeHelpers.cs b/src/Compilers/CSharp/Portable/Symbols/ObsoleteAttributeHelpers.cs index 267bb314af447..9bbceb37356d6 100644 --- a/src/Compilers/CSharp/Portable/Symbols/ObsoleteAttributeHelpers.cs +++ b/src/Compilers/CSharp/Portable/Symbols/ObsoleteAttributeHelpers.cs @@ -186,12 +186,19 @@ static DiagnosticInfo createObsoleteDiagnostic(Symbol symbol, BinderFlags locati if (data.Kind == ObsoleteAttributeKind.Experimental) { - Debug.Assert(data.Message is null); Debug.Assert(!data.IsError); // Provide an explicit format for fully-qualified type names. - return new CustomObsoleteDiagnosticInfo(MessageProvider.Instance, (int)ErrorCode.WRN_Experimental, data, - new FormattedSymbol(symbol, SymbolDisplayFormat.CSharpErrorMessageFormat)); + if (string.IsNullOrEmpty(data.Message)) + { + return new CustomObsoleteDiagnosticInfo(MessageProvider.Instance, (int)ErrorCode.WRN_Experimental, data, + new FormattedSymbol(symbol, SymbolDisplayFormat.CSharpErrorMessageFormat)); + } + else + { + return new CustomObsoleteDiagnosticInfo(MessageProvider.Instance, (int)ErrorCode.WRN_ExperimentalWithMessage, data, + new FormattedSymbol(symbol, SymbolDisplayFormat.CSharpErrorMessageFormat), data.Message); + } } // Issue a specialized diagnostic for add methods of collection initializers @@ -219,7 +226,7 @@ static DiagnosticInfo createObsoleteDiagnostic(Symbol symbol, BinderFlags locati internal static bool IsObsoleteDiagnostic(this DiagnosticInfo diagnosticInfo) { return (ErrorCode)diagnosticInfo.Code is - (ErrorCode.WRN_Experimental or ErrorCode.WRN_WindowsExperimental or ErrorCode.WRN_DeprecatedCollectionInitAdd or + (ErrorCode.WRN_Experimental or ErrorCode.WRN_ExperimentalWithMessage or ErrorCode.WRN_WindowsExperimental or ErrorCode.WRN_DeprecatedCollectionInitAdd or ErrorCode.WRN_DeprecatedSymbol or ErrorCode.ERR_DeprecatedCollectionInitAddStr or ErrorCode.ERR_DeprecatedSymbolStr or ErrorCode.WRN_DeprecatedCollectionInitAddStr or ErrorCode.WRN_DeprecatedSymbolStr); diff --git a/src/Compilers/CSharp/Portable/Symbols/Retargeting/RetargetingNamedTypeSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Retargeting/RetargetingNamedTypeSymbol.cs index 006c1447cb8dc..32a375a6e2eed 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Retargeting/RetargetingNamedTypeSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Retargeting/RetargetingNamedTypeSymbol.cs @@ -436,5 +436,7 @@ internal sealed override bool HasAsyncMethodBuilderAttribute(out TypeSymbol? bui builderArgument = null; return false; } + + internal override bool HasCompilerLoweringPreserveAttribute => _underlyingType.HasCompilerLoweringPreserveAttribute; } } diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/FieldSymbolWithAttributesAndModifiers.cs b/src/Compilers/CSharp/Portable/Symbols/Source/FieldSymbolWithAttributesAndModifiers.cs index bfec737594640..23835977ee21b 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/FieldSymbolWithAttributesAndModifiers.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/FieldSymbolWithAttributesAndModifiers.cs @@ -385,7 +385,7 @@ internal sealed override int? TypeLayoutOffset } } - internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, ref ArrayBuilder attributes) + internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, ref ArrayBuilder attributes) { base.AddSynthesizedAttributes(moduleBuilder, ref attributes); diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/ImplicitNamedTypeSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/ImplicitNamedTypeSymbol.cs index b18d9cbf6d5a5..b370e6423052a 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/ImplicitNamedTypeSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/ImplicitNamedTypeSymbol.cs @@ -171,6 +171,8 @@ internal override ObsoleteAttributeData ObsoleteAttributeData internal override bool HasCodeAnalysisEmbeddedAttribute => false; + internal override bool HasCompilerLoweringPreserveAttribute => false; + internal override bool IsInterpolatedStringHandlerType => false; internal sealed override NamedTypeSymbol AsNativeInteger() => throw ExceptionUtilities.Unreachable(); diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/LambdaSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/LambdaSymbol.cs index 217699cef51bf..c35f8ca4b7677 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/LambdaSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/LambdaSymbol.cs @@ -12,7 +12,7 @@ namespace Microsoft.CodeAnalysis.CSharp.Symbols { - internal sealed class LambdaSymbol : SourceMethodSymbolWithAttributes + internal sealed class LambdaSymbol : SourceMethodSymbol { private readonly Binder _binder; private readonly Symbol _containingSymbol; diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/LocalFunctionOrSourceMemberMethodSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/LocalFunctionOrSourceMemberMethodSymbol.cs index a3565933cd8a5..b7a2d1a11cdb3 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/LocalFunctionOrSourceMemberMethodSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/LocalFunctionOrSourceMemberMethodSymbol.cs @@ -7,7 +7,7 @@ namespace Microsoft.CodeAnalysis.CSharp.Symbols { - internal abstract class LocalFunctionOrSourceMemberMethodSymbol : SourceMethodSymbolWithAttributes + internal abstract class LocalFunctionOrSourceMemberMethodSymbol : SourceMethodSymbol { private TypeWithAnnotations.Boxed? _lazyIteratorElementType; diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/LocalFunctionSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/LocalFunctionSymbol.cs index 3c962f0b90f64..81beddf885f99 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/LocalFunctionSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/LocalFunctionSymbol.cs @@ -7,6 +7,7 @@ using System.Diagnostics; using System.Threading; using Microsoft.Cci; +using Microsoft.CodeAnalysis.Collections; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.PooledObjects; using Roslyn.Utilities; @@ -181,7 +182,7 @@ public override ImmutableArray Parameters private void ComputeParameters() { - if (_lazyParameters != null) + if (!RoslynImmutableInterlocked.VolatileRead(in _lazyParameters).IsDefault) { return; } @@ -211,7 +212,7 @@ private void ComputeParameters() lock (_declarationDiagnostics) { - if (_lazyParameters != null) + if (!_lazyParameters.IsDefault) { diagnostics.Free(); return; @@ -221,7 +222,7 @@ private void ComputeParameters() _declarationDependencies.AddAll(diagnostics.DependenciesBag); diagnostics.Free(); _lazyIsVarArg = isVararg; - _lazyParameters = parameters; + RoslynImmutableInterlocked.VolatileWrite(ref _lazyParameters, parameters); } } @@ -451,7 +452,7 @@ private ImmutableArray MakeTypeParameters(Bindi diagnostics.Add(typeError, location, name, tpEnclosing.ContainingSymbol); } - var typeParameter = new SourceMethodTypeParameterSymbol( + var typeParameter = new SourceNotOverridingMethodTypeParameterSymbol( this, name, ordinal, diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceAssemblySymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceAssemblySymbol.cs index 916a8a348eac2..b6c467e7338a2 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceAssemblySymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceAssemblySymbol.cs @@ -1935,7 +1935,7 @@ internal override bool GetGuidString(out string guidString) return guidString != null; } - internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, ref ArrayBuilder attributes) + internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, ref ArrayBuilder attributes) { base.AddSynthesizedAttributes(moduleBuilder, ref attributes); diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceComplexParameterSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceComplexParameterSymbol.cs index fad54f4249416..cb35f330c2699 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceComplexParameterSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceComplexParameterSymbol.cs @@ -79,7 +79,7 @@ protected SourceComplexParameterSymbolBase( _lazyDefaultSyntaxValue = ConstantValue.Unset; } - private Binder WithTypeParametersBinderOpt => (ContainingSymbol as SourceMethodSymbolWithAttributes)?.WithTypeParametersBinder; + private Binder WithTypeParametersBinderOpt => (ContainingSymbol as SourceMethodSymbol)?.WithTypeParametersBinder; internal sealed override SyntaxReference SyntaxReference => _syntaxRef; @@ -210,7 +210,8 @@ internal sealed override ScopedKind EffectiveScope { var scope = CalculateEffectiveScopeIgnoringAttributes(); if (scope != ScopedKind.None && - HasUnscopedRefAttribute) + HasUnscopedRefAttribute && + UseUpdatedEscapeRules) { return ScopedKind.None; } @@ -865,6 +866,11 @@ protected override void DecodeWellKnownAttributeImpl(ref DecodeWellKnownAttribut } else if (attribute.IsTargetAttribute(AttributeDescription.UnscopedRefAttribute)) { + if (!this.UseUpdatedEscapeRules) + { + diagnostics.Add(ErrorCode.WRN_UnscopedRefAttributeOldRules, arguments.AttributeSyntaxOpt.Location); + } + if (!this.IsValidUnscopedRefAttributeTarget()) { diagnostics.Add(ErrorCode.ERR_UnscopedRefAttributeUnsupportedTarget, arguments.AttributeSyntaxOpt.Location); @@ -878,7 +884,7 @@ protected override void DecodeWellKnownAttributeImpl(ref DecodeWellKnownAttribut private bool IsValidUnscopedRefAttributeTarget() { - return UseUpdatedEscapeRules && (RefKind != RefKind.None || (HasParamsModifier && Type.IsRefLikeOrAllowsRefLikeType())); + return RefKind != RefKind.None || (HasParamsModifier && Type.IsRefLikeOrAllowsRefLikeType()); } private static bool? DecodeMaybeNullWhenOrNotNullWhenOrDoesNotReturnIfAttribute(CSharpAttributeData attribute) diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceConstructorSymbolBase.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceConstructorSymbolBase.cs index 33bf6d447922b..246b307c70ef8 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceConstructorSymbolBase.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceConstructorSymbolBase.cs @@ -260,7 +260,7 @@ internal override (CSharpAttributeData?, BoundAttribute?) EarlyDecodeWellKnownAt return base.EarlyDecodeWellKnownAttribute(ref arguments); } - internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, ref ArrayBuilder attributes) + internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, ref ArrayBuilder attributes) { base.AddSynthesizedAttributes(moduleBuilder, ref attributes); AddRequiredMembersMarkerAttributes(ref attributes, this); diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceEventFieldSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceEventFieldSymbol.cs index 6fbf7a12c38b4..b9ee725bb610f 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceEventFieldSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceEventFieldSymbol.cs @@ -56,7 +56,7 @@ public override Symbol AssociatedSymbol } } - internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, ref ArrayBuilder attributes) + internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, ref ArrayBuilder attributes) { base.AddSynthesizedAttributes(moduleBuilder, ref attributes); diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceEventSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceEventSymbol.cs index 0151e99ce3bab..f59aa15ba20fc 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceEventSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceEventSymbol.cs @@ -321,7 +321,7 @@ protected sealed override void DecodeWellKnownAttributeImpl(ref DecodeWellKnownA } } - internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, ref ArrayBuilder? attributes) + internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, ref ArrayBuilder? attributes) { base.AddSynthesizedAttributes(moduleBuilder, ref attributes); diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceFixedFieldSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceFixedFieldSymbol.cs index 9b8ba7104aaec..16402ae80cc81 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceFixedFieldSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceFixedFieldSymbol.cs @@ -37,7 +37,7 @@ internal SourceFixedFieldSymbol( Debug.Assert(this.IsFixedSizeBuffer); } - internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, ref ArrayBuilder attributes) + internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, ref ArrayBuilder attributes) { base.AddSynthesizedAttributes(moduleBuilder, ref attributes); @@ -153,7 +153,7 @@ internal sealed class FixedFieldImplementationType : SynthesizedContainer private readonly FieldSymbol _internalField; public FixedFieldImplementationType(SourceMemberFieldSymbol field) - : base(GeneratedNames.MakeFixedFieldImplementationName(field.Name), typeParameters: ImmutableArray.Empty, typeMap: TypeMap.Empty) + : base(GeneratedNames.MakeFixedFieldImplementationName(field.Name)) { _field = field; _constructor = new SynthesizedInstanceConstructor(this); @@ -203,7 +203,7 @@ internal override FieldSymbol FixedElementField get { return _internalField; } } - internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, ref ArrayBuilder attributes) + internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, ref ArrayBuilder attributes) { base.AddSynthesizedAttributes(moduleBuilder, ref attributes); var compilation = ContainingSymbol.DeclaringCompilation; diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberContainerSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberContainerSymbol.cs index f94f39639f149..bb3ec749a0ffc 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberContainerSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberContainerSymbol.cs @@ -2494,20 +2494,29 @@ private void CheckForUnmatchedOperators(BindingDiagnosticBag diagnostics) private void CheckForUnmatchedOperator(BindingDiagnosticBag diagnostics, string operatorName1, string operatorName2, bool symmetricCheck = true) { - ImmutableArray ops1 = this.GetOperators(operatorName1); + var ops1 = ArrayBuilder.GetInstance(); + this.AddOperators(operatorName1, ops1); if (symmetricCheck) { - var ops2 = this.GetOperators(operatorName2); + var ops2 = ArrayBuilder.GetInstance(); + this.AddOperators(operatorName2, ops2); CheckForUnmatchedOperator(diagnostics, ops1, ops2, operatorName2, reportOperatorNeedsMatch); CheckForUnmatchedOperator(diagnostics, ops2, ops1, operatorName1, reportOperatorNeedsMatch); + ops2.Free(); } else if (!ops1.IsEmpty) { - var ops2 = this.GetOperators(operatorName2); + var ops2 = ArrayBuilder.GetInstance(); + this.AddOperators(operatorName2, ops2); CheckForUnmatchedOperator(diagnostics, ops1, ops2, operatorName2, reportCheckedOperatorNeedsMatch); + ops2.Free(); } + ops1.Free(); + + return; + static void reportOperatorNeedsMatch(BindingDiagnosticBag diagnostics, string operatorName2, MethodSymbol op1) { // CS0216: The operator 'C.operator true(C)' requires a matching operator 'false' to also be defined @@ -2523,8 +2532,8 @@ static void reportCheckedOperatorNeedsMatch(BindingDiagnosticBag diagnostics, st private static void CheckForUnmatchedOperator( BindingDiagnosticBag diagnostics, - ImmutableArray ops1, - ImmutableArray ops2, + ArrayBuilder ops1, + ArrayBuilder ops2, string operatorName2, Action reportMatchNotFoundError) { @@ -2585,8 +2594,11 @@ private void CheckForEqualityAndGetHashCode(BindingDiagnosticBag diagnostics) return; } - bool hasOp = this.GetOperators(WellKnownMemberNames.EqualityOperatorName).Any() || - this.GetOperators(WellKnownMemberNames.InequalityOperatorName).Any(); + var ops = ArrayBuilder.GetInstance(); + this.AddOperators(WellKnownMemberNames.EqualityOperatorName, ops); + this.AddOperators(WellKnownMemberNames.InequalityOperatorName, ops); + + bool hasOp = ops.Any(); bool overridesEquals = this.TypeOverridesObjectMethod("Equals"); if (hasOp || overridesEquals) @@ -2610,6 +2622,8 @@ private void CheckForEqualityAndGetHashCode(BindingDiagnosticBag diagnostics) diagnostics.Add(ErrorCode.WRN_EqualityOpWithoutGetHashCode, this.GetFirstLocation(), this); } } + + ops.Free(); } private void CheckForRequiredMemberAttribute(BindingDiagnosticBag diagnostics) @@ -5313,7 +5327,7 @@ internal bool IsNullableEnabledForConstructorsAndInitializers(bool useStatic) membersAndInitializers.IsNullableEnabledForInstanceConstructorsAndFields; } - internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, ref ArrayBuilder attributes) + internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, ref ArrayBuilder attributes) { base.AddSynthesizedAttributes(moduleBuilder, ref attributes); diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberContainerSymbol_ImplementationChecks.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberContainerSymbol_ImplementationChecks.cs index 0f2216f4fef46..f767fe8561191 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberContainerSymbol_ImplementationChecks.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberContainerSymbol_ImplementationChecks.cs @@ -1149,25 +1149,22 @@ static void checkValidMethodOverride( MethodSymbol overridingMethod, BindingDiagnosticBag diagnostics) { - if (RequiresValidScopedOverrideForRefSafety(overriddenMethod)) - { - CheckValidScopedOverride( - overriddenMethod, - overridingMethod, - diagnostics, - static (diagnostics, overriddenMethod, overridingMethod, overridingParameter, _, location) => - { - diagnostics.Add( - ReportInvalidScopedOverrideAsError(overriddenMethod, overridingMethod) ? - ErrorCode.ERR_ScopedMismatchInParameterOfOverrideOrImplementation : - ErrorCode.WRN_ScopedMismatchInParameterOfOverrideOrImplementation, - location, - new FormattedSymbol(overridingParameter, SymbolDisplayFormat.ShortFormat)); - }, - overridingMemberLocation, - allowVariance: true, - invokedAsExtensionMethod: false); - } + CheckValidScopedOverride( + overriddenMethod, + overridingMethod, + diagnostics, + static (diagnostics, overriddenMethod, overridingMethod, overridingParameter, _, location) => + { + diagnostics.Add( + ReportInvalidScopedOverrideAsError(overriddenMethod, overridingMethod) ? + ErrorCode.ERR_ScopedMismatchInParameterOfOverrideOrImplementation : + ErrorCode.WRN_ScopedMismatchInParameterOfOverrideOrImplementation, + location, + new FormattedSymbol(overridingParameter, SymbolDisplayFormat.ShortFormat)); + }, + overridingMemberLocation, + allowVariance: true, + invokedAsExtensionMethod: false); CheckValidNullableMethodOverride(overridingMethod.DeclaringCompilation, overriddenMethod, overridingMethod, diagnostics, ReportBadReturn, @@ -1369,53 +1366,6 @@ static bool isValidNullableConversion( } #nullable enable - /// - /// Returns true if the method signature must match, with respect to scoped for ref safety, - /// in overrides, interface implementations, or delegate conversions. - /// - internal static bool RequiresValidScopedOverrideForRefSafety(MethodSymbol? method) - { - if (method is null) - { - return false; - } - - var parameters = method.Parameters; - - // https://github.com/dotnet/csharplang/blob/main/proposals/csharp-11.0/low-level-struct-improvements.md#scoped-mismatch - // The compiler will report a diagnostic for _unsafe scoped mismatches_ across overrides, interface implementations, and delegate conversions when: - // - The method returns a `ref struct` or returns a `ref` or `ref readonly`, or the method has a `ref` or `out` parameter of `ref struct` type, and - // ... - int nRefParametersRequired; - if (method.ReturnType.IsRefLikeOrAllowsRefLikeType() || - (method.RefKind is RefKind.Ref or RefKind.RefReadOnly)) - { - nRefParametersRequired = 1; - } - else if (parameters.Any(p => (p.RefKind is RefKind.Ref or RefKind.Out) && p.Type.IsRefLikeOrAllowsRefLikeType())) - { - nRefParametersRequired = 2; // including the parameter found above - } - else - { - return false; - } - - // ... - // - The method has at least one additional `ref`, `in`, `ref readonly`, or `out` parameter, or a parameter of `ref struct` type. - int nRefParameters = parameters.Count(p => p.RefKind is RefKind.Ref or RefKind.In or RefKind.RefReadOnlyParameter or RefKind.Out); - if (nRefParameters >= nRefParametersRequired) - { - return true; - } - else if (parameters.Any(p => p.RefKind == RefKind.None && p.Type.IsRefLikeOrAllowsRefLikeType())) - { - return true; - } - - return false; - } - /// /// Returns true if a scoped mismatch should be reported as an error rather than a warning. /// @@ -1423,7 +1373,49 @@ internal static bool ReportInvalidScopedOverrideAsError(MethodSymbol baseMethod, { // https://github.com/dotnet/csharplang/blob/main/proposals/csharp-11.0/low-level-struct-improvements.md#scoped-mismatch // The diagnostic is reported as an error if the mismatched signatures are both using C#11 ref safety rules; otherwise, the diagnostic is a warning. - return baseMethod.UseUpdatedEscapeRules && overrideMethod.UseUpdatedEscapeRules; + return baseMethod.UseUpdatedEscapeRules && overrideMethod.UseUpdatedEscapeRules && + // We have removed exceptions to the scoped mismatch error reporting, but to avoid breaks + // we report the new scenarios (previously exempted) as warnings in C# 12 and earlier. + // https://github.com/dotnet/roslyn/issues/76100 + (overrideMethod.DeclaringCompilation.LanguageVersion > LanguageVersion.CSharp12 || usedToBeReported(baseMethod)); + + static bool usedToBeReported(MethodSymbol method) + { + var parameters = method.Parameters; + + // https://github.com/dotnet/csharplang/blob/1f7f23f/proposals/csharp-11.0/low-level-struct-improvements.md#scoped-mismatch + // The compiler will report a diagnostic for _unsafe scoped mismatches_ across overrides, interface implementations, and delegate conversions when: + // - The method returns a `ref struct` or returns a `ref` or `ref readonly`, or the method has a `ref` or `out` parameter of `ref struct` type, and + // ... + int nRefParametersRequired; + if (method.ReturnType.IsRefLikeOrAllowsRefLikeType() || + (method.RefKind is RefKind.Ref or RefKind.RefReadOnly)) + { + nRefParametersRequired = 1; + } + else if (parameters.Any(p => (p.RefKind is RefKind.Ref or RefKind.Out) && p.Type.IsRefLikeOrAllowsRefLikeType())) + { + nRefParametersRequired = 2; // including the parameter found above + } + else + { + return false; + } + + // ... + // - The method has at least one additional `ref`, `in`, `ref readonly`, or `out` parameter, or a parameter of `ref struct` type. + int nRefParameters = parameters.Count(p => p.RefKind is RefKind.Ref or RefKind.In or RefKind.RefReadOnlyParameter or RefKind.Out); + if (nRefParameters >= nRefParametersRequired) + { + return true; + } + else if (parameters.Any(p => p.RefKind == RefKind.None && p.Type.IsRefLikeOrAllowsRefLikeType())) + { + return true; + } + + return false; + } } /// diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberFieldSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberFieldSymbol.cs index c5366989a30bc..7d5bf84d04031 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberFieldSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberFieldSymbol.cs @@ -100,7 +100,7 @@ protected void TypeChecks(TypeSymbol type, BindingDiagnosticBag diagnostics) public abstract bool HasInitializer { get; } - internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, ref ArrayBuilder attributes) + internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, ref ArrayBuilder attributes) { base.AddSynthesizedAttributes(moduleBuilder, ref attributes); diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberMethodSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberMethodSymbol.cs index 92424e5eaffa4..fc43f0601c28c 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberMethodSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberMethodSymbol.cs @@ -1005,7 +1005,7 @@ internal override bool IsNullableAnalysisEnabled() return flags.IsNullableAnalysisEnabled; } - internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, ref ArrayBuilder attributes) + internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, ref ArrayBuilder attributes) { base.AddSynthesizedAttributes(moduleBuilder, ref attributes); diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMethodSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMethodSymbol.cs index 8cce2057e5200..3f0597c402e65 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMethodSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMethodSymbol.cs @@ -14,7 +14,7 @@ namespace Microsoft.CodeAnalysis.CSharp.Symbols /// things like ordinary methods and constructors, and functions /// like lambdas and local functions. /// - internal abstract class SourceMethodSymbol : MethodSymbol + internal abstract partial class SourceMethodSymbol : MethodSymbol { /// /// If there are no constraints, returns an empty immutable array. Otherwise, returns an immutable diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMethodSymbolWithAttributes.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMethodSymbolWithAttributes.cs index 691df206c1abb..f50b7e3dab0a9 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMethodSymbolWithAttributes.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMethodSymbolWithAttributes.cs @@ -24,14 +24,14 @@ namespace Microsoft.CodeAnalysis.CSharp.Symbols /// /// A source method that can have attributes, including a member method, accessor, or local function. /// - internal abstract class SourceMethodSymbolWithAttributes : SourceMethodSymbol, IAttributeTargetSymbol + internal abstract partial class SourceMethodSymbol : IAttributeTargetSymbol { private CustomAttributesBag _lazyCustomAttributesBag; private CustomAttributesBag _lazyReturnTypeCustomAttributesBag; // some symbols may not have a syntax (e.g. lambdas, synthesized event accessors) protected readonly SyntaxReference syntaxReferenceOpt; - protected SourceMethodSymbolWithAttributes(SyntaxReference syntaxReferenceOpt) + protected SourceMethodSymbol(SyntaxReference syntaxReferenceOpt) { this.syntaxReferenceOpt = syntaxReferenceOpt; } @@ -614,6 +614,11 @@ private void DecodeWellKnownAttributeAppliedToMethod(ref DecodeWellKnownAttribut } else if (attribute.IsTargetAttribute(AttributeDescription.UnscopedRefAttribute)) { + if (!this.UseUpdatedEscapeRules) + { + diagnostics.Add(ErrorCode.WRN_UnscopedRefAttributeOldRules, arguments.AttributeSyntaxOpt.Location); + } + if (this.IsValidUnscopedRefAttributeTarget()) { arguments.GetOrCreateData().HasUnscopedRefAttribute = true; @@ -634,7 +639,7 @@ private void DecodeWellKnownAttributeAppliedToMethod(ref DecodeWellKnownAttribut } else if (attribute.IsTargetAttribute(AttributeDescription.OverloadResolutionPriorityAttribute)) { - MessageID.IDS_OverloadResolutionPriority.CheckFeatureAvailability(diagnostics, arguments.AttributeSyntaxOpt); + MessageID.IDS_FeatureOverloadResolutionPriority.CheckFeatureAvailability(diagnostics, arguments.AttributeSyntaxOpt); if (!CanHaveOverloadResolutionPriority) { @@ -1103,10 +1108,10 @@ private void DecodeInterceptsLocationChecksumBased(DecodeWellKnownAttributeArgum return; } - DeclaringCompilation.AddInterception(matchingTree.FilePath, position, attributeLocation, this); + DeclaringCompilation.AddInterception(matchingTree.GetText().GetContentHash(), position, attributeLocation, this); // Caller must free the returned builder. - static ArrayBuilder getNamespaceNames(SourceMethodSymbolWithAttributes @this) + static ArrayBuilder getNamespaceNames(SourceMethodSymbol @this) { var namespaceNames = ArrayBuilder.GetInstance(); for (var containingNamespace = @this.ContainingNamespace; containingNamespace?.IsGlobalNamespace == false; containingNamespace = containingNamespace.ContainingNamespace) @@ -1155,7 +1160,6 @@ static void reportFeatureNotEnabled(BindingDiagnosticBag diagnostics, Location a } } - // https://github.com/dotnet/roslyn/issues/72265: Remove support for path-based interceptors prior to stable release. private void DecodeInterceptsLocationAttributeExperimentalCompat( DecodeWellKnownAttributeArguments arguments, string? attributeFilePath, @@ -1166,6 +1170,8 @@ private void DecodeInterceptsLocationAttributeExperimentalCompat( var attributeSyntax = arguments.AttributeSyntaxOpt; Debug.Assert(attributeSyntax is object); var attributeLocation = attributeSyntax.Location; + diagnostics.Add(ErrorCode.WRN_InterceptsLocationAttributeUnsupportedSignature, attributeLocation); + const int filePathParameterIndex = 0; const int lineNumberParameterIndex = 1; const int characterNumberParameterIndex = 2; @@ -1316,7 +1322,7 @@ private void DecodeInterceptsLocationAttributeExperimentalCompat( return; } - DeclaringCompilation.AddInterception(matchingTree.FilePath, referencedToken.Position, attributeLocation, this); + DeclaringCompilation.AddInterception(matchingTree.GetText().GetContentHash(), referencedToken.Position, attributeLocation, this); // Caller must free the returned builder. ArrayBuilder getNamespaceNames() @@ -1424,7 +1430,7 @@ static void checkAndReportManagedTypes(TypeSymbol type, RefKind refKind, SyntaxN } } - static UnmanagedCallersOnlyAttributeData DecodeUnmanagedCallersOnlyAttributeData(SourceMethodSymbolWithAttributes @this, CSharpAttributeData attribute, Location location, BindingDiagnosticBag diagnostics) + static UnmanagedCallersOnlyAttributeData DecodeUnmanagedCallersOnlyAttributeData(SourceMethodSymbol @this, CSharpAttributeData attribute, Location location, BindingDiagnosticBag diagnostics) { Debug.Assert(attribute.AttributeClass is not null); ImmutableHashSet? callingConventionTypes = null; diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceModuleSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceModuleSymbol.cs index 11a59bf87bafd..1018ea9ba532b 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceModuleSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceModuleSymbol.cs @@ -621,7 +621,7 @@ static bool namespaceIncludesTypeDeclarations(NamespaceSymbol ns) } } - internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, ref ArrayBuilder attributes) + internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, ref ArrayBuilder attributes) { base.AddSynthesizedAttributes(moduleBuilder, ref attributes); diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceNamedTypeSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceNamedTypeSymbol.cs index 9e4cca64413c5..7fa6d895a89b5 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceNamedTypeSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceNamedTypeSymbol.cs @@ -4,6 +4,7 @@ #nullable disable +using System; using System.Collections.Generic; using System.Collections.Immutable; using System.Diagnostics; @@ -1217,6 +1218,10 @@ protected sealed override void DecodeWellKnownAttributeImpl(ref DecodeWellKnownA diagnostics.Add(ErrorCode.ERR_InlineArrayAttributeOnRecord, arguments.AttributeSyntaxOpt.Name.Location); } } + else if (attribute.IsTargetAttribute(AttributeDescription.CompilerLoweringPreserveAttribute)) + { + arguments.GetOrCreateData().HasCompilerLoweringPreserveAttribute = true; + } else { var compilation = this.DeclaringCompilation; @@ -1414,7 +1419,18 @@ internal override bool HasCodeAnalysisEmbeddedAttribute get { var data = GetEarlyDecodedWellKnownAttributeData(); - return data != null && data.HasCodeAnalysisEmbeddedAttribute; + return (data != null && data.HasCodeAnalysisEmbeddedAttribute) + // If this is Microsoft.CodeAnalysis.EmbeddedAttribute, we'll synthesize EmbeddedAttribute even if it's not applied. + || this.IsMicrosoftCodeAnalysisEmbeddedAttribute(); + } + } + + internal override bool HasCompilerLoweringPreserveAttribute + { + get + { + var data = GetDecodedWellKnownAttributeData(); + return data != null && data.HasCompilerLoweringPreserveAttribute; } } @@ -1659,7 +1675,7 @@ internal override bool HasInlineArrayAttribute(out int length) /// These won't be returned by GetAttributes on source methods, but they /// will be returned by GetAttributes on metadata symbols. /// - internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, ref ArrayBuilder attributes) + internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, ref ArrayBuilder attributes) { base.AddSynthesizedAttributes(moduleBuilder, ref attributes); @@ -1748,6 +1764,21 @@ internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, r ImmutableArray.Create(new TypedConstant(compilation.GetWellKnownType(WellKnownType.System_Type), TypedConstantKind.Type, originalType)), isOptionalUse: true)); } + + if (this.IsMicrosoftCodeAnalysisEmbeddedAttribute() && GetEarlyDecodedWellKnownAttributeData() is null or { HasCodeAnalysisEmbeddedAttribute: false }) + { + // This is Microsoft.CodeAnalysis.EmbeddedAttribute, and the user didn't manually apply this attribute to itself. Grab the parameterless constructor + // and apply it; if there isn't a parameterless constructor, there would have been a declaration diagnostic + + var parameterlessConstructor = InstanceConstructors.FirstOrDefault(c => c.ParameterCount == 0); + + if (parameterlessConstructor is not null) + { + AddSynthesizedAttribute( + ref attributes, + SynthesizedAttributeData.Create(DeclaringCompilation, parameterlessConstructor, arguments: [], namedArguments: [])); + } + } } #endregion @@ -1905,6 +1936,34 @@ protected override void AfterMembersCompletedChecks(BindingDiagnosticBag diagnos diagnostics.Add(ErrorCode.ERR_RuntimeDoesNotSupportInlineArrayTypes, GetFirstLocation()); } } + + if (this.IsMicrosoftCodeAnalysisEmbeddedAttribute()) + { + // This is a user-defined implementation of the special attribute Microsoft.CodeAnalysis.EmbeddedAttribute. It needs to follow specific rules: + // 1. It must be internal + // 2. It must be a class + // 3. It must be sealed + // 4. It must be non-static + // 5. It must have an internal or public parameterless constructor + // 6. It must inherit from System.Attribute + // 7. It must be allowed on any type declaration (class, struct, interface, enum, or delegate) + // 8. It must be non-generic (checked as part of IsMicrosoftCodeAnalysisEmbeddedAttribute, we don't error on this because both types can exist) + + const AttributeTargets expectedTargets = AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Interface | AttributeTargets.Enum | AttributeTargets.Delegate; + + if (DeclaredAccessibility != Accessibility.Internal + || TypeKind != TypeKind.Class + || !IsSealed + || IsStatic + || !InstanceConstructors.Any(c => c is { ParameterCount: 0, DeclaredAccessibility: Accessibility.Internal or Accessibility.Public }) + || !this.DeclaringCompilation.IsAttributeType(this) + || (GetAttributeUsageInfo().ValidTargets & expectedTargets) != expectedTargets) + { + // The type 'Microsoft.CodeAnalysis.EmbeddedAttribute' must be non-generic, internal, sealed, non-static, have a parameterless constructor, inherit from System.Attribute, and be able to be applied to any type. + diagnostics.Add(ErrorCode.ERR_EmbeddedAttributeMustFollowPattern, GetFirstLocation()); + } + + } } } } diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceOrdinaryMethodSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceOrdinaryMethodSymbol.cs index 2b14c397e27bf..c0df4ffcad913 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceOrdinaryMethodSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceOrdinaryMethodSymbol.cs @@ -1153,7 +1153,7 @@ private ImmutableArray MakeTypeParameters(MethodDeclaration ordinal, locations, syntaxRefs) : - new SourceMethodTypeParameterSymbol( + new SourceNotOverridingMethodTypeParameterSymbol( this, name, ordinal, diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceOrdinaryMethodSymbolBase.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceOrdinaryMethodSymbolBase.cs index 158419141cdeb..ade24d4dcfefe 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceOrdinaryMethodSymbolBase.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceOrdinaryMethodSymbolBase.cs @@ -92,7 +92,7 @@ public override string Name internal abstract override OneOrMany> GetAttributeDeclarations(); - internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, ref ArrayBuilder attributes) + internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, ref ArrayBuilder attributes) { base.AddSynthesizedAttributes(moduleBuilder, ref attributes); diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceParameterSymbolBase.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceParameterSymbolBase.cs index a8a1d2f81f362..dddd8387261ef 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceParameterSymbolBase.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceParameterSymbolBase.cs @@ -66,7 +66,7 @@ public sealed override AssemblySymbol ContainingAssembly internal abstract ConstantValue DefaultValueFromAttributes { get; } - internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, ref ArrayBuilder attributes) + internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, ref ArrayBuilder attributes) { base.AddSynthesizedAttributes(moduleBuilder, ref attributes); diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertyAccessorSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertyAccessorSymbol.cs index d57ad4859e972..4c7a1dd16a416 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertyAccessorSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertyAccessorSymbol.cs @@ -786,7 +786,7 @@ private ImmutableArray ComputeParameters() return parameters.ToImmutableAndFree(); } - internal sealed override void AddSynthesizedReturnTypeAttributes(PEModuleBuilder moduleBuilder, ref ArrayBuilder attributes) + internal sealed override void AddSynthesizedReturnTypeAttributes(PEModuleBuilder moduleBuilder, ref ArrayBuilder attributes) { base.AddSynthesizedReturnTypeAttributes(moduleBuilder, ref attributes); @@ -801,7 +801,7 @@ internal sealed override void AddSynthesizedReturnTypeAttributes(PEModuleBuilder } } - internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, ref ArrayBuilder attributes) + internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, ref ArrayBuilder attributes) { base.AddSynthesizedAttributes(moduleBuilder, ref attributes); diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbolBase.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbolBase.cs index 197f65d0fcc57..6ab9c97d1be7f 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbolBase.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbolBase.cs @@ -1255,7 +1255,7 @@ private SynthesizedSealedPropertyAccessor MakeSynthesizedSealedAccessor() /// /// Symbol to copy bound attributes from, or null if the attributes are not shared among multiple source property symbols. - /// Analogous to . + /// Analogous to . /// protected abstract SourcePropertySymbolBase BoundAttributesSource { get; } @@ -1360,7 +1360,7 @@ internal PropertyEarlyWellKnownAttributeData GetEarlyDecodedWellKnownAttributeDa return (PropertyEarlyWellKnownAttributeData)attributesBag.EarlyDecodedWellKnownAttributeData; } - internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, ref ArrayBuilder attributes) + internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, ref ArrayBuilder attributes) { base.AddSynthesizedAttributes(moduleBuilder, ref attributes); @@ -1568,6 +1568,11 @@ protected override void DecodeWellKnownAttributeImpl(ref DecodeWellKnownAttribut } else if (attribute.IsTargetAttribute(AttributeDescription.UnscopedRefAttribute)) { + if (!this.ContainingModule.UseUpdatedEscapeRules) + { + diagnostics.Add(ErrorCode.WRN_UnscopedRefAttributeOldRules, arguments.AttributeSyntaxOpt.Location); + } + if (this.IsValidUnscopedRefAttributeTarget()) { arguments.GetOrCreateData().HasUnscopedRefAttribute = true; @@ -1584,7 +1589,7 @@ protected override void DecodeWellKnownAttributeImpl(ref DecodeWellKnownAttribut } else if (attribute.IsTargetAttribute(AttributeDescription.OverloadResolutionPriorityAttribute)) { - MessageID.IDS_OverloadResolutionPriority.CheckFeatureAvailability(diagnostics, arguments.AttributeSyntaxOpt); + MessageID.IDS_FeatureOverloadResolutionPriority.CheckFeatureAvailability(diagnostics, arguments.AttributeSyntaxOpt); if (!CanHaveOverloadResolutionPriority) { diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceTypeParameterSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceTypeParameterSymbol.cs index b4f70d7b9dc34..76abe90229d18 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceTypeParameterSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceTypeParameterSymbol.cs @@ -20,7 +20,7 @@ namespace Microsoft.CodeAnalysis.CSharp.Symbols /// /// Base class for type and method type parameters. /// - internal abstract class SourceTypeParameterSymbolBase : TypeParameterSymbol, IAttributeTargetSymbol + internal abstract class SourceTypeParameterSymbol : TypeParameterSymbol, IAttributeTargetSymbol { private readonly ImmutableArray _syntaxRefs; private readonly ImmutableArray _locations; @@ -31,7 +31,7 @@ internal abstract class SourceTypeParameterSymbolBase : TypeParameterSymbol, IAt private CustomAttributesBag _lazyCustomAttributesBag; private TypeParameterBounds _lazyBounds = TypeParameterBounds.Unset; - protected SourceTypeParameterSymbolBase(string name, int ordinal, ImmutableArray locations, ImmutableArray syntaxRefs) + protected SourceTypeParameterSymbol(string name, int ordinal, ImmutableArray locations, ImmutableArray syntaxRefs) { Debug.Assert(!syntaxRefs.IsEmpty); @@ -131,7 +131,7 @@ internal ImmutableArray> MergedAttributeDeclarat var implementingPart = sourceMethod.SourcePartialImplementation; if ((object)implementingPart != null) { - var typeParameter = (SourceTypeParameterSymbolBase)implementingPart.TypeParameters[_ordinal]; + var typeParameter = (SourceTypeParameterSymbol)implementingPart.TypeParameters[_ordinal]; mergedAttributesBuilder.AddRange(typeParameter.MergedAttributeDeclarationSyntaxLists); } } @@ -190,7 +190,7 @@ internal virtual CustomAttributesBag GetAttributesBag() } else { - var typeParameter = (SourceTypeParameterSymbolBase)sourceMethod.SourcePartialDefinition.TypeParameters[_ordinal]; + var typeParameter = (SourceTypeParameterSymbol)sourceMethod.SourcePartialDefinition.TypeParameters[_ordinal]; CustomAttributesBag attributesBag = typeParameter.GetAttributesBag(); lazyAttributesStored = Interlocked.CompareExchange(ref _lazyCustomAttributesBag, attributesBag, null) == null; @@ -382,7 +382,7 @@ internal override void ForceComplete(SourceLocation locationOpt, Predicate attributes) + internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, ref ArrayBuilder attributes) { base.AddSynthesizedAttributes(moduleBuilder, ref attributes); @@ -456,12 +456,12 @@ protected sealed override void DecodeWellKnownAttributeImpl(ref DecodeWellKnownA } } - internal sealed class SourceTypeParameterSymbol : SourceTypeParameterSymbolBase + internal sealed class SourceTypeTypeParameterSymbol : SourceTypeParameterSymbol { private readonly SourceNamedTypeSymbol _owner; private readonly VarianceKind _varianceKind; - public SourceTypeParameterSymbol(SourceNamedTypeSymbol owner, string name, int ordinal, VarianceKind varianceKind, ImmutableArray locations, ImmutableArray syntaxRefs) + public SourceTypeTypeParameterSymbol(SourceNamedTypeSymbol owner, string name, int ordinal, VarianceKind varianceKind, ImmutableArray locations, ImmutableArray syntaxRefs) : base(name, ordinal, locations, syntaxRefs) { _owner = owner; @@ -602,20 +602,19 @@ private TypeParameterConstraintKind GetConstraintKinds() } } - internal sealed class SourceMethodTypeParameterSymbol : SourceTypeParameterSymbolBase + internal abstract class SourceMethodTypeParameterSymbol : SourceTypeParameterSymbol { - private readonly SourceMethodSymbol _owner; - - public SourceMethodTypeParameterSymbol(SourceMethodSymbol owner, string name, int ordinal, ImmutableArray locations, ImmutableArray syntaxRefs) + protected SourceMethodTypeParameterSymbol(string name, int ordinal, ImmutableArray locations, ImmutableArray syntaxRefs) : base(name, ordinal, locations, syntaxRefs) { - _owner = owner; } - internal override void AddDeclarationDiagnostics(BindingDiagnosticBag diagnostics) - => _owner.AddDeclarationDiagnostics(diagnostics); + public abstract SourceMethodSymbol Owner { get; } - public override TypeParameterKind TypeParameterKind + internal sealed override void AddDeclarationDiagnostics(BindingDiagnosticBag diagnostics) + => Owner.AddDeclarationDiagnostics(diagnostics); + + public sealed override TypeParameterKind TypeParameterKind { get { @@ -623,11 +622,51 @@ public override TypeParameterKind TypeParameterKind } } - public override Symbol ContainingSymbol + public sealed override Symbol ContainingSymbol { - get { return _owner; } + get { return Owner; } + } + + public abstract override bool HasConstructorConstraint { get; } + + public abstract override bool HasValueTypeConstraint { get; } + + public abstract override bool AllowsRefLikeType { get; } + + public abstract override bool IsValueTypeFromConstraintTypes { get; } + + public abstract override bool HasReferenceTypeConstraint { get; } + + public abstract override bool IsReferenceTypeFromConstraintTypes { get; } + + public abstract override bool HasNotNullConstraint { get; } + + internal abstract override bool? ReferenceTypeConstraintIsNullable { get; } + + internal abstract override bool? IsNotNullable { get; } + + public abstract override bool HasUnmanagedTypeConstraint { get; } + + protected sealed override ImmutableArray ContainerTypeParameters + { + get { return Owner.TypeParameters; } + } + + protected abstract override TypeParameterBounds ResolveBounds(ConsList inProgress, BindingDiagnosticBag diagnostics); + } + + internal sealed class SourceNotOverridingMethodTypeParameterSymbol : SourceMethodTypeParameterSymbol + { + private readonly SourceMethodSymbol _owner; + + public SourceNotOverridingMethodTypeParameterSymbol(SourceMethodSymbol owner, string name, int ordinal, ImmutableArray locations, ImmutableArray syntaxRefs) + : base(name, ordinal, locations, syntaxRefs) + { + _owner = owner; } + public override SourceMethodSymbol Owner => _owner; + public override bool HasConstructorConstraint { get @@ -722,11 +761,6 @@ public override bool HasUnmanagedTypeConstraint } } - protected override ImmutableArray ContainerTypeParameters - { - get { return _owner.TypeParameters; } - } - protected override TypeParameterBounds ResolveBounds(ConsList inProgress, BindingDiagnosticBag diagnostics) { var constraints = _owner.GetTypeParameterConstraintTypes(); @@ -863,7 +897,7 @@ protected override MethodSymbol GetOverriddenMethod(SourceOrdinaryMethodSymbol o /// /// Exists to copy constraints from the corresponding type parameter of an overridden method. /// - internal sealed class SourceOverridingMethodTypeParameterSymbol : SourceTypeParameterSymbolBase + internal sealed class SourceOverridingMethodTypeParameterSymbol : SourceMethodTypeParameterSymbol { private readonly OverriddenMethodTypeParameterMapBase _map; @@ -873,24 +907,11 @@ public SourceOverridingMethodTypeParameterSymbol(OverriddenMethodTypeParameterMa _map = map; } - public SourceOrdinaryMethodSymbol Owner + public override SourceMethodSymbol Owner { get { return _map.OverridingMethod; } } - public override TypeParameterKind TypeParameterKind - { - get - { - return TypeParameterKind.Method; - } - } - - public override Symbol ContainingSymbol - { - get { return this.Owner; } - } - public override bool HasConstructorConstraint { get @@ -979,11 +1000,6 @@ public override bool HasUnmanagedTypeConstraint } } - protected override ImmutableArray ContainerTypeParameters - { - get { return this.Owner.TypeParameters; } - } - protected override TypeParameterBounds ResolveBounds(ConsList inProgress, BindingDiagnosticBag diagnostics) { var typeParameter = this.OverriddenTypeParameter; diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/ThisParameterSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/ThisParameterSymbol.cs index beba4aa633cfb..0ba8707bea744 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/ThisParameterSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/ThisParameterSymbol.cs @@ -179,7 +179,8 @@ internal override ScopedKind EffectiveScope { var scope = _containingType.IsStructType() ? ScopedKind.ScopedRef : ScopedKind.None; if (scope != ScopedKind.None && - HasUnscopedRefAttribute) + HasUnscopedRefAttribute && + UseUpdatedEscapeRules) { return ScopedKind.None; } diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/TypeParameterBuilder.cs b/src/Compilers/CSharp/Portable/Symbols/Source/TypeParameterBuilder.cs index c76e5abe74503..9c262cf2c23a5 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/TypeParameterBuilder.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/TypeParameterBuilder.cs @@ -34,7 +34,7 @@ internal TypeParameterBuilder(SyntaxReference syntaxRef, SourceNamedTypeSymbol o internal TypeParameterSymbol MakeSymbol(int ordinal, IList builders, BindingDiagnosticBag diagnostics) { var syntaxNode = (TypeParameterSyntax)_syntaxRef.GetSyntax(); - var result = new SourceTypeParameterSymbol( + var result = new SourceTypeTypeParameterSymbol( _owner, syntaxNode.Identifier.ValueText, ordinal, diff --git a/src/Compilers/CSharp/Portable/Symbols/SubstitutedMethodSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/SubstitutedMethodSymbol.cs index 45b0527c8d466..8887c4520419b 100644 --- a/src/Compilers/CSharp/Portable/Symbols/SubstitutedMethodSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/SubstitutedMethodSymbol.cs @@ -7,6 +7,7 @@ using System.Collections.Immutable; using System.Diagnostics; using System.Threading; +using Microsoft.CodeAnalysis.Collections; using Microsoft.CodeAnalysis.PooledObjects; using Roslyn.Utilities; @@ -99,7 +100,7 @@ public sealed override ImmutableArray TypeParameters private void EnsureMapAndTypeParameters() { - if (!_lazyTypeParameters.IsDefault) + if (!RoslynImmutableInterlocked.VolatileRead(ref _lazyTypeParameters).IsDefault) { return; } diff --git a/src/Compilers/CSharp/Portable/Symbols/SubstitutedNamedTypeSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/SubstitutedNamedTypeSymbol.cs index d22f7e120c75b..379aae474eb7e 100644 --- a/src/Compilers/CSharp/Portable/Symbols/SubstitutedNamedTypeSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/SubstitutedNamedTypeSymbol.cs @@ -10,6 +10,7 @@ using System.Diagnostics; using System.Linq; using System.Threading; +using Microsoft.CodeAnalysis.Collections; using Microsoft.CodeAnalysis.CSharp.Emit; using Microsoft.CodeAnalysis.PooledObjects; using Roslyn.Utilities; @@ -96,7 +97,7 @@ public sealed override ImmutableArray TypeParameters private void EnsureMapAndTypeParameters() { - if (!_lazyTypeParameters.IsDefault) + if (!RoslynImmutableInterlocked.VolatileRead(ref _lazyTypeParameters).IsDefault) { return; } @@ -484,5 +485,7 @@ internal sealed override bool HasInlineArrayAttribute(out int length) { return _underlyingType.HasInlineArrayAttribute(out length); } + + internal sealed override bool HasCompilerLoweringPreserveAttribute => _underlyingType.HasCompilerLoweringPreserveAttribute; } } diff --git a/src/Compilers/CSharp/Portable/Symbols/Symbol.cs b/src/Compilers/CSharp/Portable/Symbols/Symbol.cs index 3af10fed130ca..216b61f6d68ae 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Symbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Symbol.cs @@ -870,20 +870,20 @@ internal Symbol() /// /// Build and add synthesized attributes for this symbol. /// - internal virtual void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, ref ArrayBuilder attributes) + internal virtual void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, ref ArrayBuilder attributes) { } /// /// Convenience helper called by subclasses to add a synthesized attribute to a collection of attributes. /// - internal static void AddSynthesizedAttribute(ref ArrayBuilder attributes, SynthesizedAttributeData attribute) + internal static void AddSynthesizedAttribute(ref ArrayBuilder attributes, CSharpAttributeData attribute) { if (attribute != null) { if (attributes == null) { - attributes = new ArrayBuilder(1); + attributes = new ArrayBuilder(1); } attributes.Add(attribute); @@ -1668,7 +1668,7 @@ internal void GetCommonNullableValues(CSharpCompilation compilation, ref MostCom builder.AddValue(((ParameterSymbol)this).TypeWithAnnotations); break; case SymbolKind.TypeParameter: - if (this is SourceTypeParameterSymbolBase typeParameter) + if (this is SourceTypeParameterSymbol typeParameter) { builder.AddValue(typeParameter.GetSynthesizedNullableAttributeValue()); foreach (var constraintType in typeParameter.ConstraintTypesNoUseSiteDiagnostics) diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/ReadOnlyListType/SynthesizedReadOnlyListEnumeratorTypeSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/ReadOnlyListType/SynthesizedReadOnlyListEnumeratorTypeSymbol.cs index a52e934731662..927c1d23d5931 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/ReadOnlyListType/SynthesizedReadOnlyListEnumeratorTypeSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/ReadOnlyListType/SynthesizedReadOnlyListEnumeratorTypeSymbol.cs @@ -169,6 +169,8 @@ static void addProperty(ArrayBuilder builder, PropertySymbol property) internal override bool HasCodeAnalysisEmbeddedAttribute => false; + internal override bool HasCompilerLoweringPreserveAttribute => false; + internal override bool IsInterpolatedStringHandlerType => false; internal override bool HasSpecialName => false; diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/ReadOnlyListType/SynthesizedReadOnlyListTypeSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/ReadOnlyListType/SynthesizedReadOnlyListTypeSymbol.cs index 3b55781ebc14a..43b5765ed7076 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/ReadOnlyListType/SynthesizedReadOnlyListTypeSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/ReadOnlyListType/SynthesizedReadOnlyListTypeSymbol.cs @@ -846,6 +846,8 @@ public static bool CanCreateSingleElement(CSharpCompilation compilation) internal override bool HasCodeAnalysisEmbeddedAttribute => false; + internal override bool HasCompilerLoweringPreserveAttribute => false; + internal override bool IsInterpolatedStringHandlerType => false; internal override bool HasSpecialName => false; @@ -917,7 +919,7 @@ internal override bool GetGuidString(out string? guidString) return false; } - internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, ref ArrayBuilder attributes) + internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, ref ArrayBuilder attributes) { base.AddSynthesizedAttributes(moduleBuilder, ref attributes); AddSynthesizedAttribute(ref attributes, DeclaringCompilation.TrySynthesizeAttribute(WellKnownMember.System_Runtime_CompilerServices_CompilerGeneratedAttribute__ctor)); diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/Records/SynthesizedPrimaryConstructorParameterBackingFieldSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/Records/SynthesizedPrimaryConstructorParameterBackingFieldSymbol.cs index 5f3d127451425..f373c80aade14 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/Records/SynthesizedPrimaryConstructorParameterBackingFieldSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/Records/SynthesizedPrimaryConstructorParameterBackingFieldSymbol.cs @@ -4,7 +4,9 @@ using System.Collections.Immutable; using System.Linq; +using Microsoft.CodeAnalysis.CSharp.Emit; using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.PooledObjects; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CSharp.Symbols @@ -64,5 +66,19 @@ public override Symbol ContainingSymbol public override NamedTypeSymbol ContainingType => ParameterSymbol.ContainingSymbol.ContainingType; + + internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, ref ArrayBuilder attributes) + { + foreach (CSharpAttributeData attr in ParameterSymbol.GetAttributes()) + { + if (attr.AttributeClass is { HasCompilerLoweringPreserveAttribute: true } attributeType && + (attributeType.GetAttributeUsageInfo().ValidTargets & System.AttributeTargets.Field) != 0) + { + AddSynthesizedAttribute(ref attributes, attr); + } + } + + base.AddSynthesizedAttributes(moduleBuilder, ref attributes); + } } } diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/Records/SynthesizedRecordCopyCtor.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/Records/SynthesizedRecordCopyCtor.cs index 382f69fbb0e21..6b355c31c0d4c 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/Records/SynthesizedRecordCopyCtor.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/Records/SynthesizedRecordCopyCtor.cs @@ -72,7 +72,7 @@ internal override void GenerateMethodBodyStatements(SyntheticBoundNodeFactory F, TextSpan.FromBounds(recordDeclaration.Identifier.Span.Start, recordDeclaration.TypeParameterList.Span.End))); } - internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, ref ArrayBuilder attributes) + internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, ref ArrayBuilder attributes) { base.AddSynthesizedAttributes(moduleBuilder, ref attributes); Debug.Assert(IsImplicitlyDeclared); diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/Records/SynthesizedRecordEqualityContractProperty.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/Records/SynthesizedRecordEqualityContractProperty.cs index 260dc11f240ce..b99b4283207fc 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/Records/SynthesizedRecordEqualityContractProperty.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/Records/SynthesizedRecordEqualityContractProperty.cs @@ -89,7 +89,7 @@ protected override void ValidatePropertyType(BindingDiagnosticBag diagnostics) VerifyOverridesEqualityContractFromBase(this, diagnostics); } - internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, ref ArrayBuilder attributes) + internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, ref ArrayBuilder attributes) { base.AddSynthesizedAttributes(moduleBuilder, ref attributes); @@ -155,7 +155,7 @@ internal GetAccessorSymbol( { } - internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, ref ArrayBuilder attributes) + internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, ref ArrayBuilder attributes) { base.AddSynthesizedAttributes(moduleBuilder, ref attributes); diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/Records/SynthesizedRecordEqualityOperatorBase.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/Records/SynthesizedRecordEqualityOperatorBase.cs index 3a0ec1fa8abe8..9b1f67f53bcd3 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/Records/SynthesizedRecordEqualityOperatorBase.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/Records/SynthesizedRecordEqualityOperatorBase.cs @@ -78,7 +78,7 @@ protected sealed override (TypeWithAnnotations ReturnType, ImmutableArray 2; - internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, ref ArrayBuilder attributes) + internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, ref ArrayBuilder attributes) { base.AddSynthesizedAttributes(moduleBuilder, ref attributes); Debug.Assert(IsImplicitlyDeclared); diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/Records/SynthesizedRecordOrdinaryMethod.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/Records/SynthesizedRecordOrdinaryMethod.cs index 3bcc164df94a6..404ed77cadab1 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/Records/SynthesizedRecordOrdinaryMethod.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/Records/SynthesizedRecordOrdinaryMethod.cs @@ -72,7 +72,7 @@ protected sealed override void CheckConstraintsForExplicitInterfaceType(Conversi { } - internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, ref ArrayBuilder attributes) + internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, ref ArrayBuilder attributes) { base.AddSynthesizedAttributes(moduleBuilder, ref attributes); Debug.Assert(IsImplicitlyDeclared); diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedAccessorValueParameterSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedAccessorValueParameterSymbol.cs index 7252c0fee9068..4e606bf4edcbe 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedAccessorValueParameterSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedAccessorValueParameterSymbol.cs @@ -77,7 +77,7 @@ internal override OneOrMany> GetAttributeDeclara return accessor.GetAttributeDeclarations(); } - internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, ref ArrayBuilder attributes) + internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, ref ArrayBuilder attributes) { base.AddSynthesizedAttributes(moduleBuilder, ref attributes); diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedBackingFieldSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedBackingFieldSymbol.cs index ba0d9afc70e4b..851b7d1f214d2 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedBackingFieldSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedBackingFieldSymbol.cs @@ -37,7 +37,7 @@ public SynthesizedBackingFieldSymbolBase( (isStatic ? DeclarationModifiers.Static : DeclarationModifiers.None); } - internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, ref ArrayBuilder attributes) + internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, ref ArrayBuilder attributes) { base.AddSynthesizedAttributes(moduleBuilder, ref attributes); diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedContainer.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedContainer.cs index cf72b7d487782..f6e73c27ebbe0 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedContainer.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedContainer.cs @@ -38,15 +38,13 @@ protected SynthesizedContainer(string name, MethodSymbol containingMethod) } } - protected SynthesizedContainer(string name, ImmutableArray typeParameters, TypeMap typeMap) + protected SynthesizedContainer(string name) { Debug.Assert(name != null); - Debug.Assert(!typeParameters.IsDefault); - Debug.Assert(typeMap != null); Name = name; - _typeParameters = typeParameters; - TypeMap = typeMap; + _typeParameters = ImmutableArray.Empty; + TypeMap = TypeMap.Empty; } internal TypeMap TypeMap { get; } @@ -55,7 +53,7 @@ protected SynthesizedContainer(string name, ImmutableArray internal sealed override bool IsInterface => this.TypeKind == TypeKind.Interface; - internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, ref ArrayBuilder attributes) + internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, ref ArrayBuilder attributes) { base.AddSynthesizedAttributes(moduleBuilder, ref attributes); @@ -102,6 +100,8 @@ internal override ImmutableArray TypeArgumentsWithAnnotatio internal override bool HasCodeAnalysisEmbeddedAttribute => false; + internal override bool HasCompilerLoweringPreserveAttribute => false; + internal sealed override bool IsInterpolatedStringHandlerType => false; internal sealed override bool HasDeclaredRequiredMembers => false; diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedEmbeddedAttributeSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedEmbeddedAttributeSymbol.cs index f753cfbdbec6d..b3a57c3c7e1c7 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedEmbeddedAttributeSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedEmbeddedAttributeSymbol.cs @@ -110,6 +110,8 @@ internal override bool GetGuidString(out string guidString) internal override bool HasCodeAnalysisEmbeddedAttribute => true; + internal override bool HasCompilerLoweringPreserveAttribute => false; + internal override bool IsInterpolatedStringHandlerType => false; internal override bool HasSpecialName => false; @@ -172,7 +174,7 @@ internal override bool GetGuidString(out string guidString) internal sealed override bool IsRecordStruct => false; internal sealed override bool HasPossibleWellKnownCloneMethod() => false; - internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, ref ArrayBuilder attributes) + internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, ref ArrayBuilder attributes) { base.AddSynthesizedAttributes(moduleBuilder, ref attributes); diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedEntryPointSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedEntryPointSymbol.cs index 62f5a6a4969a3..fc86c841ab206 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedEntryPointSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedEntryPointSymbol.cs @@ -378,7 +378,7 @@ internal AsyncForwardEntryPoint(CSharpCompilation compilation, NamedTypeSymbol c ReturnType.SpecialType == SpecialType.System_Int32); } - internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, ref ArrayBuilder attributes) + internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, ref ArrayBuilder attributes) { base.AddSynthesizedAttributes(moduleBuilder, ref attributes); diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedEnumValueFieldSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedEnumValueFieldSymbol.cs index 1d123c6be164d..ab2d76a36fdf8 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedEnumValueFieldSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedEnumValueFieldSymbol.cs @@ -35,7 +35,7 @@ internal override TypeWithAnnotations GetFieldType(ConsList fieldsB return TypeWithAnnotations.Create(((SourceNamedTypeSymbol)ContainingType).EnumUnderlyingType); } - internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, ref ArrayBuilder attributes) + internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, ref ArrayBuilder attributes) { // no attributes should be emitted } diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedEventAccessorSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedEventAccessorSymbol.cs index 3c5407381199a..9c37841206071 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedEventAccessorSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedEventAccessorSymbol.cs @@ -70,7 +70,7 @@ internal override OneOrMany> GetAttributeDeclara return OneOrMany.Create(this.AssociatedEvent.AttributeDeclarationSyntaxList); } - internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, ref ArrayBuilder attributes) + internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, ref ArrayBuilder attributes) { base.AddSynthesizedAttributes(moduleBuilder, ref attributes); diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedFieldSymbolBase.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedFieldSymbolBase.cs index 09a9100ffbd56..99833d8908a80 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedFieldSymbolBase.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedFieldSymbolBase.cs @@ -43,7 +43,7 @@ internal abstract bool SuppressDynamicAttribute get; } - internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, ref ArrayBuilder attributes) + internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, ref ArrayBuilder attributes) { base.AddSynthesizedAttributes(moduleBuilder, ref attributes); diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedHotReloadExceptionSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedHotReloadExceptionSymbol.cs index c98708ef4cd6a..30bcbb683b475 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedHotReloadExceptionSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedHotReloadExceptionSymbol.cs @@ -71,7 +71,7 @@ internal override IEnumerable GetFieldsToEmit() public override ImmutableArray GetTypeMembers(ReadOnlyMemory name) => []; public override ImmutableArray GetTypeMembers(ReadOnlyMemory name, int arity) => []; - internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, ref ArrayBuilder attributes) + internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, ref ArrayBuilder attributes) { base.AddSynthesizedAttributes(moduleBuilder, ref attributes); @@ -104,6 +104,7 @@ internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, r internal sealed override bool IsFileLocal => false; internal sealed override FileIdentifier? AssociatedFileIdentifier => null; internal override bool HasCodeAnalysisEmbeddedAttribute => true; + internal override bool HasCompilerLoweringPreserveAttribute => false; internal override bool IsInterpolatedStringHandlerType => false; internal override bool HasSpecialName => false; internal override bool IsComImport => false; diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedInlineArrayTypeSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedInlineArrayTypeSymbol.cs index 05dca7980687e..014d0e9005941 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedInlineArrayTypeSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedInlineArrayTypeSymbol.cs @@ -94,6 +94,8 @@ internal SynthesizedInlineArrayTypeSymbol(SourceModuleSymbol containingModule, s internal override bool HasCodeAnalysisEmbeddedAttribute => false; + internal override bool HasCompilerLoweringPreserveAttribute => false; + internal override bool GetGuidString(out string? guidString) { guidString = null; @@ -185,7 +187,7 @@ internal sealed override bool HasAsyncMethodBuilderAttribute(out TypeSymbol? bui internal override IEnumerable<(MethodSymbol Body, MethodSymbol Implemented)> SynthesizedInterfaceMethodImpls() => SpecializedCollections.EmptyEnumerable<(MethodSymbol Body, MethodSymbol Implemented)>(); - internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, ref ArrayBuilder attributes) + internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, ref ArrayBuilder attributes) { base.AddSynthesizedAttributes(moduleBuilder, ref attributes); diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedInstanceConstructor.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedInstanceConstructor.cs index e173fa2d011ef..70ea99af74714 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedInstanceConstructor.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedInstanceConstructor.cs @@ -319,7 +319,7 @@ internal virtual void GenerateMethodBodyStatements(SyntheticBoundNodeFactory fac protected override bool HasSetsRequiredMembersImpl => false; - internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, ref ArrayBuilder attributes) + internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, ref ArrayBuilder attributes) { base.AddSynthesizedAttributes(moduleBuilder, ref attributes); AddRequiredMembersMarkerAttributes(ref attributes, this); diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedParameterSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedParameterSymbol.cs index 87045c0165364..479ad310a97a8 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedParameterSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedParameterSymbol.cs @@ -145,7 +145,7 @@ public override ImmutableArray DeclaringSyntaxReferences } } - internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, ref ArrayBuilder attributes) + internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, ref ArrayBuilder attributes) { // Emit [Dynamic] on synthesized parameter symbols when the original parameter was dynamic // in order to facilitate debugging. In the case the necessary attributes are missing diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedPrivateImplementationDetailsType.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedPrivateImplementationDetailsType.cs index fbb5c68b07696..7436082c596fe 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedPrivateImplementationDetailsType.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedPrivateImplementationDetailsType.cs @@ -83,6 +83,8 @@ public SynthesizedPrivateImplementationDetailsType(PrivateImplementationDetails internal override bool HasCodeAnalysisEmbeddedAttribute => false; + internal override bool HasCompilerLoweringPreserveAttribute => false; + internal override bool IsInterpolatedStringHandlerType => false; internal override bool HasSpecialName => _privateImplementationDetails.IsSpecialName; diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedSubstitutedTypeParameterSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedSubstitutedTypeParameterSymbol.cs index 56979139e7487..f8ba3f20cb2e7 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedSubstitutedTypeParameterSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedSubstitutedTypeParameterSymbol.cs @@ -32,8 +32,21 @@ public override bool IsImplicitlyDeclared public override TypeParameterKind TypeParameterKind => ContainingSymbol is MethodSymbol ? TypeParameterKind.Method : TypeParameterKind.Type; - internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, ref ArrayBuilder attributes) + internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, ref ArrayBuilder attributes) { + if (ContainingSymbol.Kind == SymbolKind.NamedType && + _underlyingTypeParameter.OriginalDefinition is SourceMethodTypeParameterSymbol definition && + ContainingSymbol.ContainingModule == definition.ContainingModule) + { + foreach (CSharpAttributeData attr in definition.GetAttributes()) + { + if (attr.AttributeClass is { HasCompilerLoweringPreserveAttribute: true }) + { + AddSynthesizedAttribute(ref attributes, attr); + } + } + } + base.AddSynthesizedAttributes(moduleBuilder, ref attributes); if (this.HasUnmanagedTypeConstraint) diff --git a/src/Compilers/CSharp/Portable/Symbols/TypeSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/TypeSymbol.cs index 43f39cfb8a0fb..4763f5d7fa071 100644 --- a/src/Compilers/CSharp/Portable/Symbols/TypeSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/TypeSymbol.cs @@ -1855,25 +1855,23 @@ static void checkMethodOverride( reportMismatchInParameterType, (implementingType, isExplicit)); - if (SourceMemberContainerTypeSymbol.RequiresValidScopedOverrideForRefSafety(implementedMethod)) - { - SourceMemberContainerTypeSymbol.CheckValidScopedOverride( - implementedMethod, - implementingMethod, - diagnostics, - static (diagnostics, implementedMethod, implementingMethod, implementingParameter, _, arg) => - { - diagnostics.Add( - SourceMemberContainerTypeSymbol.ReportInvalidScopedOverrideAsError(implementedMethod, implementingMethod) ? - ErrorCode.ERR_ScopedMismatchInParameterOfOverrideOrImplementation : - ErrorCode.WRN_ScopedMismatchInParameterOfOverrideOrImplementation, - GetImplicitImplementationDiagnosticLocation(implementedMethod, arg.implementingType, implementingMethod), - new FormattedSymbol(implementingParameter, SymbolDisplayFormat.ShortFormat)); - }, - (implementingType, isExplicit), - allowVariance: true, - invokedAsExtensionMethod: false); - } + SourceMemberContainerTypeSymbol.CheckValidScopedOverride( + implementedMethod, + implementingMethod, + diagnostics, + static (diagnostics, implementedMethod, implementingMethod, implementingParameter, _, arg) => + { + diagnostics.Add( + SourceMemberContainerTypeSymbol.ReportInvalidScopedOverrideAsError(implementedMethod, implementingMethod) ? + ErrorCode.ERR_ScopedMismatchInParameterOfOverrideOrImplementation : + ErrorCode.WRN_ScopedMismatchInParameterOfOverrideOrImplementation, + GetImplicitImplementationDiagnosticLocation(implementedMethod, arg.implementingType, implementingMethod), + new FormattedSymbol(implementingParameter, SymbolDisplayFormat.ShortFormat)); + }, + (implementingType, isExplicit), + allowVariance: true, + invokedAsExtensionMethod: false); + SourceMemberContainerTypeSymbol.CheckRefReadonlyInMismatch( implementedMethod, implementingMethod, diagnostics, static (diagnostics, implementedMethod, implementingMethod, implementingParameter, _, arg) => @@ -1890,7 +1888,7 @@ static void checkMethodOverride( { if (implementedMethod.HasUnscopedRefAttributeOnMethodOrProperty()) { - if (!implementingMethod.IsExplicitInterfaceImplementation && implementingMethod is SourceMethodSymbolWithAttributes && + if (!implementingMethod.IsExplicitInterfaceImplementation && implementingMethod is SourceMethodSymbol && implementedMethod.ContainingModule != implementingMethod.ContainingModule) { checkRefStructInterfacesFeatureAvailabilityOnUnscopedRefAttribute(implementingMethod.HasUnscopedRefAttribute ? implementingMethod : implementingMethod.AssociatedSymbol, diagnostics); diff --git a/src/Compilers/CSharp/Portable/Symbols/TypeSymbolExtensions.cs b/src/Compilers/CSharp/Portable/Symbols/TypeSymbolExtensions.cs index 4649012b006d8..29eb2dce05ed9 100644 --- a/src/Compilers/CSharp/Portable/Symbols/TypeSymbolExtensions.cs +++ b/src/Compilers/CSharp/Portable/Symbols/TypeSymbolExtensions.cs @@ -2137,6 +2137,17 @@ internal static bool IsWellKnownTypeLock(this TypeSymbol typeSymbol) typeSymbol.IsContainedInNamespace(nameof(System), nameof(System.Threading)); } + internal static bool IsMicrosoftCodeAnalysisEmbeddedAttribute(this TypeSymbol typeSymbol) + { + return typeSymbol is NamedTypeSymbol + { + Name: "EmbeddedAttribute", + Arity: 0, + ContainingType: null, + } + && typeSymbol.IsContainedInNamespace("Microsoft", "CodeAnalysis"); + } + private static bool IsWellKnownInteropServicesTopLevelType(this TypeSymbol typeSymbol, string name) { if (typeSymbol.Name != name || typeSymbol.ContainingType is object) diff --git a/src/Compilers/CSharp/Portable/Symbols/Wrapped/WrappedParameterSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Wrapped/WrappedParameterSymbol.cs index c15838b1daea2..ca61e1f1b142e 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Wrapped/WrappedParameterSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Wrapped/WrappedParameterSymbol.cs @@ -71,7 +71,7 @@ public override ImmutableArray GetAttributes() return _underlyingParameter.GetAttributes(); } - internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, ref ArrayBuilder attributes) + internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, ref ArrayBuilder attributes) { _underlyingParameter.AddSynthesizedAttributes(moduleBuilder, ref attributes); } diff --git a/src/Compilers/CSharp/Portable/Syntax/SyntaxNodeRemover.cs b/src/Compilers/CSharp/Portable/Syntax/SyntaxNodeRemover.cs index efe068ca0abfa..f7c480ce7a002 100644 --- a/src/Compilers/CSharp/Portable/Syntax/SyntaxNodeRemover.cs +++ b/src/Compilers/CSharp/Portable/Syntax/SyntaxNodeRemover.cs @@ -45,7 +45,7 @@ internal static class SyntaxNodeRemover return (TRoot?)result; } - private class SyntaxRemover : CSharpSyntaxRewriter + private sealed class SyntaxRemover : CSharpSyntaxRewriter { private readonly HashSet _nodesToRemove; private readonly SyntaxRemoveOptions _options; @@ -432,8 +432,8 @@ private void AddDirectives(SyntaxNode node, TextSpan span) } var directivesInSpan = node.DescendantTrivia(span, n => n.ContainsDirectives, descendIntoTrivia: true) - .Where(tr => tr.IsDirective) - .Select(tr => (DirectiveTriviaSyntax)tr.GetStructure()!); + .Where(tr => tr.IsDirective) + .Select(tr => (DirectiveTriviaSyntax)tr.GetStructure()!); foreach (var directive in directivesInSpan) { @@ -465,10 +465,32 @@ private void AddDirectives(SyntaxNode node, TextSpan span) if (_directivesToKeep.Contains(directive)) { - AddResidualTrivia(SyntaxFactory.TriviaList(directive.ParentTrivia), requiresNewLine: true); + var parentTrivia = directive.ParentTrivia; + var (triviaList, directiveTriviaListIndex) = getTriviaListAndIndex(parentTrivia); + + // If we're keeping a directive, and it's not at the start of the line, keep the indentation + // whitespace that precedes it as well so that the directive stays in the right location. + if (directiveTriviaListIndex >= 1 && triviaList[directiveTriviaListIndex - 1] is { RawKind: (int)SyntaxKind.WhitespaceTrivia } indentationTrivia) + { + AddResidualTrivia(SyntaxFactory.TriviaList(indentationTrivia, parentTrivia), requiresNewLine: true); + } + else + { + AddResidualTrivia(SyntaxFactory.TriviaList(parentTrivia), requiresNewLine: true); + } } } } + + static (SyntaxTriviaList triviaList, int index) getTriviaListAndIndex(SyntaxTrivia trivia) + { + var parentToken = trivia.Token; + + var index = parentToken.LeadingTrivia.IndexOf(trivia); + return index >= 0 + ? (parentToken.LeadingTrivia, index) + : (parentToken.TrailingTrivia, parentToken.TrailingTrivia.IndexOf(trivia)); + } } private static bool HasRelatedDirectives(DirectiveTriviaSyntax directive) diff --git a/src/Compilers/CSharp/Portable/Utilities/InterceptableLocation.cs b/src/Compilers/CSharp/Portable/Utilities/InterceptableLocation.cs index 4f3a23634d307..85c76ab47e0e4 100644 --- a/src/Compilers/CSharp/Portable/Utilities/InterceptableLocation.cs +++ b/src/Compilers/CSharp/Portable/Utilities/InterceptableLocation.cs @@ -15,7 +15,9 @@ namespace Microsoft.CodeAnalysis.CSharp; -[Experimental(RoslynExperiments.Interceptors, UrlFormat = RoslynExperiments.Interceptors_Url)] +/// Denotes an interceptable call. Used by source generators to generate '[InterceptsLocation]' attributes. +/// +/// public abstract class InterceptableLocation { private protected InterceptableLocation() { } @@ -51,12 +53,13 @@ internal sealed class InterceptableLocation1 : InterceptableLocation private readonly ImmutableArray _checksum; private readonly string _path; + private readonly SourceReferenceResolver? _resolver; private readonly int _position; private readonly int _lineNumberOneIndexed; private readonly int _characterNumberOneIndexed; private string? _lazyData; - internal InterceptableLocation1(ImmutableArray checksum, string path, int position, int lineNumberOneIndexed, int characterNumberOneIndexed) + internal InterceptableLocation1(ImmutableArray checksum, string path, SourceReferenceResolver? resolver, int position, int lineNumberOneIndexed, int characterNumberOneIndexed) { Debug.Assert(checksum.Length == ContentHashLength); Debug.Assert(path is not null); @@ -66,6 +69,7 @@ internal InterceptableLocation1(ImmutableArray checksum, string path, int _checksum = checksum; _path = path; + _resolver = resolver; _position = position; _lineNumberOneIndexed = lineNumberOneIndexed; _characterNumberOneIndexed = characterNumberOneIndexed; @@ -73,8 +77,10 @@ internal InterceptableLocation1(ImmutableArray checksum, string path, int public override string GetDisplayLocation() { + var mappedPath = _resolver?.NormalizePath(_path, baseFilePath: null) ?? _path; // e.g. `C:\project\src\Program.cs(12,34)` - return $"{_path}({_lineNumberOneIndexed},{_characterNumberOneIndexed})"; + // or, with a typical pathmap setup, `/_/src/Program.cs(12,34)` + return $"{mappedPath}({_lineNumberOneIndexed},{_characterNumberOneIndexed})"; } public override string ToString() => GetDisplayLocation(); diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf index 1a1fe0211030e..f8bf057bf6f41 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf @@ -1992,6 +1992,11 @@ Typy a aliasy nemůžou mít název required. + + The type 'Microsoft.CodeAnalysis.EmbeddedAttribute' must be non-generic, internal, sealed, non-static, have a parameterless constructor, inherit from System.Attribute, and be able to be applied to any type. + The type 'Microsoft.CodeAnalysis.EmbeddedAttribute' must be non-generic, internal, sealed, non-static, have a parameterless constructor, inherit from System.Attribute, and be able to be applied to any type. + + Target runtime doesn't support by-ref-like generics. Cílový modul runtime nepodporuje obecné typy by-ref-like. @@ -2502,6 +2507,11 @@ nové řádky v interpolacích + + overload resolution priority + overload resolution priority + + parameterless struct constructors konstruktory struktury bez parametrů @@ -2622,11 +2632,6 @@ <missing> - - overload resolution priority - priorita řešení přetížení - - pointer element access přístup k elementu ukazatele @@ -2952,6 +2957,16 @@ Použití proměnné v tomto kontextu může vystavit odkazované proměnné mimo rozsah jejich oboru. + + '{0}' is for evaluation purposes only and is subject to change or removal in future updates: '{1}'. Suppress this diagnostic to proceed. + '{0}' is for evaluation purposes only and is subject to change or removal in future updates: '{1}'. Suppress this diagnostic to proceed. + + + + Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. + Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. + + In language version {0}, the 'field' keyword binds to a synthesized backing field for the property. To avoid generating a synthesized backing field, and to refer to the existing member, use 'this.field' or '@field' instead. V jazykové verzi {0}se klíčové slovo field váže na syntetizované zálohovací pole pro vlastnost. Pokud se chcete vyhnout generování syntetizovaného záložního pole a odkazovat na existujícího člena, použijte místo toho this.field nebo @field. @@ -3022,6 +3037,16 @@ Podpisy zachycovatelných a zachytávacích metod se neshodují. + + 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) + 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) + + + + 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) + 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) + + InterpolatedStringHandlerArgument has no effect when applied to lambda parameters and will be ignored at the call site. Argument InterpolatedStringHandlerArgument nemá při použití u parametrů lambda žádný účinek a bude se ignorovat v lokalitě volání. @@ -5358,6 +5383,16 @@ Parametr se nepřečetl. Nezapomněli jste ho použít k inicializaci vlastnosti s daným názvem? + + UnscopedRefAttribute is only valid in C# 11 or later or when targeting net7.0 or later. + UnscopedRefAttribute is only valid in C# 11 or later or when targeting net7.0 or later. + + + + UnscopedRefAttribute is only valid in C# 11 or later or when targeting net7.0 or later. + UnscopedRefAttribute is only valid in C# 11 or later or when targeting net7.0 or later. + + Use of unassigned local variable '{0}' Použila se nepřiřazená lokální proměnná {0}. @@ -12971,7 +13006,7 @@ Pokud chcete odstranit toto varování, můžete místo toho použít /reference '{0}' is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. - {0} slouží jen pro účely vyhodnocení a v budoucích aktualizacích může dojít ke změně nebo odebrání. Potlačte tuto diagnostiku, abyste mohli pokračovat. + '{0}' is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. @@ -13196,4 +13231,4 @@ Pokud chcete odstranit toto varování, můžete místo toho použít /reference - \ No newline at end of file + diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf index fc443f21f19d4..1f458cf89e14b 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf @@ -1992,6 +1992,11 @@ Typen und Aliase können nicht als "erforderlich" bezeichnet werden. + + The type 'Microsoft.CodeAnalysis.EmbeddedAttribute' must be non-generic, internal, sealed, non-static, have a parameterless constructor, inherit from System.Attribute, and be able to be applied to any type. + The type 'Microsoft.CodeAnalysis.EmbeddedAttribute' must be non-generic, internal, sealed, non-static, have a parameterless constructor, inherit from System.Attribute, and be able to be applied to any type. + + Target runtime doesn't support by-ref-like generics. Die Zielruntime unterstützt keine by-ref-like-Generics. @@ -2502,6 +2507,11 @@ Zeilenumbrüche in Interpolationen + + overload resolution priority + overload resolution priority + + parameterless struct constructors Parameterlose Strukturkonstruktoren @@ -2622,11 +2632,6 @@ <missing> - - overload resolution priority - Priorität der Überladungsauflösung - - pointer element access Zeigerelementzugriff @@ -2952,6 +2957,16 @@ Die Verwendung der Variablen in diesem Kontext kann dazu führen, dass referenzierte Variablen außerhalb ihres Deklarationsbereichs verfügbar gemacht werden. + + '{0}' is for evaluation purposes only and is subject to change or removal in future updates: '{1}'. Suppress this diagnostic to proceed. + '{0}' is for evaluation purposes only and is subject to change or removal in future updates: '{1}'. Suppress this diagnostic to proceed. + + + + Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. + Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. + + In language version {0}, the 'field' keyword binds to a synthesized backing field for the property. To avoid generating a synthesized backing field, and to refer to the existing member, use 'this.field' or '@field' instead. In der Sprachversion {0}wird das Schlüsselwort "field" an ein synthetisiertes Sicherungsfeld für die Eigenschaft gebunden. Verwenden Sie stattdessen "this.field" oder "@field", um ein synthetisiertes Sicherungsfeld zu vermeiden und auf das vorhandene Element zu verweisen. @@ -3022,6 +3037,16 @@ Signaturen von abfangbaren Methoden und Interceptormethoden stimmen nicht überein. + + 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) + 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) + + + + 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) + 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) + + InterpolatedStringHandlerArgument has no effect when applied to lambda parameters and will be ignored at the call site. Das InterpolatedStringHandlerArgument hat bei Anwendung auf Lambdaparameter keine Auswirkungen und wird am Aufrufstandort ignoriert. @@ -5358,6 +5383,16 @@ Der Parameter wird nicht gelesen. Möglicherweise haben Sie ihn nicht zum Initialisieren der gleichnamigen Eigenschaft verwendet? + + UnscopedRefAttribute is only valid in C# 11 or later or when targeting net7.0 or later. + UnscopedRefAttribute is only valid in C# 11 or later or when targeting net7.0 or later. + + + + UnscopedRefAttribute is only valid in C# 11 or later or when targeting net7.0 or later. + UnscopedRefAttribute is only valid in C# 11 or later or when targeting net7.0 or later. + + Use of unassigned local variable '{0}' Verwendung der nicht zugewiesenen lokalen Variablen "{0}". @@ -12971,7 +13006,7 @@ Um die Warnung zu beheben, können Sie stattdessen /reference verwenden (Einbett '{0}' is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. - "{0}" dient nur zu Testzwecken und kann in zukünftigen Aktualisierungen geändert oder entfernt werden. Unterdrücken Sie diese Diagnose, um fortzufahren. + '{0}' is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. @@ -13196,4 +13231,4 @@ Um die Warnung zu beheben, können Sie stattdessen /reference verwenden (Einbett - \ No newline at end of file + diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf index 5853b4d992cfd..490afc99e2585 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf @@ -1992,6 +1992,11 @@ Los tipos y alias no se pueden denominar 'required'. + + The type 'Microsoft.CodeAnalysis.EmbeddedAttribute' must be non-generic, internal, sealed, non-static, have a parameterless constructor, inherit from System.Attribute, and be able to be applied to any type. + The type 'Microsoft.CodeAnalysis.EmbeddedAttribute' must be non-generic, internal, sealed, non-static, have a parameterless constructor, inherit from System.Attribute, and be able to be applied to any type. + + Target runtime doesn't support by-ref-like generics. El entorno de ejecución de destino no admite tipos genéricos similares a ref. @@ -2502,6 +2507,11 @@ Nuevas líneas en interpolaciones + + overload resolution priority + overload resolution priority + + parameterless struct constructors constructores de estructuras sin parámetros @@ -2622,11 +2632,6 @@ <missing> - - overload resolution priority - prioridad de resolución de sobrecarga - - pointer element access acceso al elemento de puntero @@ -2952,6 +2957,16 @@ Usar la variable en este contexto puede exponer variables a las que se hace referencia fuera de su ámbito de declaración + + '{0}' is for evaluation purposes only and is subject to change or removal in future updates: '{1}'. Suppress this diagnostic to proceed. + '{0}' is for evaluation purposes only and is subject to change or removal in future updates: '{1}'. Suppress this diagnostic to proceed. + + + + Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. + Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. + + In language version {0}, the 'field' keyword binds to a synthesized backing field for the property. To avoid generating a synthesized backing field, and to refer to the existing member, use 'this.field' or '@field' instead. En la versión del lenguaje {0}, la palabra clave "campo" se vincula a un campo de respaldo sintetizado para la propiedad. Para evitar generar un campo de respaldo sintetizado y hacer referencia a la suscripción existente, utilice en su lugar "this.field" o "@field". @@ -3022,6 +3037,16 @@ Las firmas de los métodos interceptables e interceptores no coinciden. + + 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) + 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) + + + + 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) + 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) + + InterpolatedStringHandlerArgument has no effect when applied to lambda parameters and will be ignored at the call site. El argumento InterpolatedStringHandlerArgument no tiene ningún efecto cuando se aplica a parámetros lambda y se omitirá en el sitio de llamada. @@ -5358,6 +5383,16 @@ El parámetro no se ha leído ¿Olvidó usarlo para inicializar la propiedad con ese nombre? + + UnscopedRefAttribute is only valid in C# 11 or later or when targeting net7.0 or later. + UnscopedRefAttribute is only valid in C# 11 or later or when targeting net7.0 or later. + + + + UnscopedRefAttribute is only valid in C# 11 or later or when targeting net7.0 or later. + UnscopedRefAttribute is only valid in C# 11 or later or when targeting net7.0 or later. + + Use of unassigned local variable '{0}' Uso de la variable local no asignada '{0}' @@ -12971,7 +13006,7 @@ Para eliminar la advertencia puede usar /reference (establezca la propiedad Embe '{0}' is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. - "{0}" se incluye con fines de evaluación y está sujeto a cambios o a que se elimine en próximas actualizaciones. Suprima este diagnóstico para continuar. + '{0}' is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. @@ -13196,4 +13231,4 @@ Para eliminar la advertencia puede usar /reference (establezca la propiedad Embe - \ No newline at end of file + diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf index 2d8d4d1b8b0dc..50de8c51ce9c0 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf @@ -1992,6 +1992,11 @@ Les types et alias ne peuvent pas être nommés « required ». + + The type 'Microsoft.CodeAnalysis.EmbeddedAttribute' must be non-generic, internal, sealed, non-static, have a parameterless constructor, inherit from System.Attribute, and be able to be applied to any type. + The type 'Microsoft.CodeAnalysis.EmbeddedAttribute' must be non-generic, internal, sealed, non-static, have a parameterless constructor, inherit from System.Attribute, and be able to be applied to any type. + + Target runtime doesn't support by-ref-like generics. Le runtime cible ne prend pas en charge les génériques by-ref-like. @@ -2502,6 +2507,11 @@ sauts de ligne dans les interpolations + + overload resolution priority + overload resolution priority + + parameterless struct constructors constructeurs de struct sans paramètre @@ -2622,11 +2632,6 @@ <manquant> - - overload resolution priority - priorité de résolution de surcharge - - pointer element access accès à l’élément de pointeur @@ -2952,6 +2957,16 @@ Utiliser la variable dans ce contexte peut exposer des variables de référence en dehors de leur étendue de déclaration + + '{0}' is for evaluation purposes only and is subject to change or removal in future updates: '{1}'. Suppress this diagnostic to proceed. + '{0}' is for evaluation purposes only and is subject to change or removal in future updates: '{1}'. Suppress this diagnostic to proceed. + + + + Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. + Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. + + In language version {0}, the 'field' keyword binds to a synthesized backing field for the property. To avoid generating a synthesized backing field, and to refer to the existing member, use 'this.field' or '@field' instead. Dans la version linguistique {0}, le mot-clé « field » se lie à un champ de support synthétisé pour la propriété. Pour éviter de générer un champ de support synthétisé et pour faire référence au membre existant, utilisez plutôt « this.field » ou « @field ». @@ -3022,6 +3037,16 @@ Les signatures des méthodes interceptable et intercepteur ne correspondent pas. + + 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) + 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) + + + + 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) + 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) + + InterpolatedStringHandlerArgument has no effect when applied to lambda parameters and will be ignored at the call site. InterpolatedStringHandlerArgument n’a aucun effet lorsqu’il est appliqué aux paramètres lambda et qu’il est ignoré sur le site d’appel. @@ -5358,6 +5383,16 @@ Le paramètre est non lu. Avez-vous oublié de l'utiliser pour initialiser la propriété portant ce nom ? + + UnscopedRefAttribute is only valid in C# 11 or later or when targeting net7.0 or later. + UnscopedRefAttribute is only valid in C# 11 or later or when targeting net7.0 or later. + + + + UnscopedRefAttribute is only valid in C# 11 or later or when targeting net7.0 or later. + UnscopedRefAttribute is only valid in C# 11 or later or when targeting net7.0 or later. + + Use of unassigned local variable '{0}' Utilisation d'une variable locale non assignée '{0}' @@ -12971,7 +13006,7 @@ Pour supprimer l'avertissement, vous pouvez utiliser la commande /reference (dé '{0}' is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. - « {0} » est utilisé à des fins d’évaluation uniquement et est susceptible d’être modifié ou supprimé dans les futures mises à jour. Supprimez ce diagnostic pour continuer. + '{0}' is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. @@ -13196,4 +13231,4 @@ Pour supprimer l'avertissement, vous pouvez utiliser la commande /reference (dé - \ No newline at end of file + diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf index bb54d268b28de..5b63726a67558 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf @@ -1992,6 +1992,11 @@ I tipi e gli alias non possono essere denominati 'obbligatori'. + + The type 'Microsoft.CodeAnalysis.EmbeddedAttribute' must be non-generic, internal, sealed, non-static, have a parameterless constructor, inherit from System.Attribute, and be able to be applied to any type. + The type 'Microsoft.CodeAnalysis.EmbeddedAttribute' must be non-generic, internal, sealed, non-static, have a parameterless constructor, inherit from System.Attribute, and be able to be applied to any type. + + Target runtime doesn't support by-ref-like generics. Il runtime di destinazione non supporta generics simili a by-ref. @@ -2502,6 +2507,11 @@ nuove linee nelle interpolazioni + + overload resolution priority + overload resolution priority + + parameterless struct constructors costruttori struct senza parametri @@ -2622,11 +2632,6 @@ <missing> - - overload resolution priority - priorità di risoluzione dell'overload - - pointer element access accesso all'elemento puntatore @@ -2952,6 +2957,16 @@ L'uso di variabili in questo contesto potrebbe esporre le variabili a cui si fa riferimento al di fuori dell'ambito della dichiarazione + + '{0}' is for evaluation purposes only and is subject to change or removal in future updates: '{1}'. Suppress this diagnostic to proceed. + '{0}' is for evaluation purposes only and is subject to change or removal in future updates: '{1}'. Suppress this diagnostic to proceed. + + + + Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. + Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. + + In language version {0}, the 'field' keyword binds to a synthesized backing field for the property. To avoid generating a synthesized backing field, and to refer to the existing member, use 'this.field' or '@field' instead. Nella versione del linguaggio {0}, la parola chiave 'field' è associata a un campo di supporto sintetizzato per la proprietà. Per evitare di generare un campo di supporto sintetizzato e fare riferimento al membro esistente, utilizzare 'this.field' o '@field'. @@ -3022,6 +3037,16 @@ Le firme dei metodi intercettabili e intercettori non corrispondono. + + 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) + 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) + + + + 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) + 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) + + InterpolatedStringHandlerArgument has no effect when applied to lambda parameters and will be ignored at the call site. InterpolatedStringHandlerArgument non ha alcun effetto se viene applicato ai parametri lambda e verrà ignorato nel sito di chiamata. @@ -5358,6 +5383,16 @@ target:module Compila un modulo che può essere aggiunto ad altro Il parametro non è stato letto. Si è dimenticato di usarlo per inizializzare la proprietà con tale nome? + + UnscopedRefAttribute is only valid in C# 11 or later or when targeting net7.0 or later. + UnscopedRefAttribute is only valid in C# 11 or later or when targeting net7.0 or later. + + + + UnscopedRefAttribute is only valid in C# 11 or later or when targeting net7.0 or later. + UnscopedRefAttribute is only valid in C# 11 or later or when targeting net7.0 or later. + + Use of unassigned local variable '{0}' Uso della variabile locale '{0}' non assegnata @@ -12971,7 +13006,7 @@ Per rimuovere l'avviso, è invece possibile usare /reference (impostare la propr '{0}' is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. - '{0}' viene usato solo a scopo di valutazione e potrebbe essere modificato o rimosso in aggiornamenti futuri. Elimina questa diagnostica per continuare. + '{0}' is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. @@ -13196,4 +13231,4 @@ Per rimuovere l'avviso, è invece possibile usare /reference (impostare la propr - \ No newline at end of file + diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf index e642a6b48a4ac..d1ccd40212a23 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf @@ -1992,6 +1992,11 @@ 型とエイリアスに 'required' という名前を付けることはできません。 + + The type 'Microsoft.CodeAnalysis.EmbeddedAttribute' must be non-generic, internal, sealed, non-static, have a parameterless constructor, inherit from System.Attribute, and be able to be applied to any type. + The type 'Microsoft.CodeAnalysis.EmbeddedAttribute' must be non-generic, internal, sealed, non-static, have a parameterless constructor, inherit from System.Attribute, and be able to be applied to any type. + + Target runtime doesn't support by-ref-like generics. 対象のランタイムは、参照渡しのようなジェネリックをサポートしていません。 @@ -2502,6 +2507,11 @@ 補間における改行 + + overload resolution priority + overload resolution priority + + parameterless struct constructors パラメーターのない構造体コンストラクター @@ -2622,11 +2632,6 @@ <missing> - - overload resolution priority - オーバーロード解決の優先順位 - - pointer element access ポインター要素アクセス @@ -2952,6 +2957,16 @@ このコンテキストでの変数の使用は、参照される変数が宣言のスコープ外に公開される可能性があります + + '{0}' is for evaluation purposes only and is subject to change or removal in future updates: '{1}'. Suppress this diagnostic to proceed. + '{0}' is for evaluation purposes only and is subject to change or removal in future updates: '{1}'. Suppress this diagnostic to proceed. + + + + Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. + Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. + + In language version {0}, the 'field' keyword binds to a synthesized backing field for the property. To avoid generating a synthesized backing field, and to refer to the existing member, use 'this.field' or '@field' instead. 言語バージョン {0} では、'field' キーワードがプロパティの合成バッキング フィールドにバインドされます。合成されたバッキング フィールドが生成されないようにし、既存のメンバーを参照するには、代わりに 'this.field' または '@field' を使用します。 @@ -3022,6 +3037,16 @@ インターセプター可能なメソッドとインターセプター メソッドの署名が一致しません。 + + 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) + 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) + + + + 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) + 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) + + InterpolatedStringHandlerArgument has no effect when applied to lambda parameters and will be ignored at the call site. ラムダ パラメーターに適用しても InterpolatedStringHandlerArgument は効果がありません。呼び出しサイトでは無視されます。 @@ -5358,6 +5383,16 @@ パラメーターが未読のため、この名前のプロパティを初期化するために使用していることを確認する必要がある + + UnscopedRefAttribute is only valid in C# 11 or later or when targeting net7.0 or later. + UnscopedRefAttribute is only valid in C# 11 or later or when targeting net7.0 or later. + + + + UnscopedRefAttribute is only valid in C# 11 or later or when targeting net7.0 or later. + UnscopedRefAttribute is only valid in C# 11 or later or when targeting net7.0 or later. + + Use of unassigned local variable '{0}' 未割り当てのローカル変数 '{0}' が使用されました @@ -12971,7 +13006,7 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ '{0}' is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. - '{0}' は、評価の目的でのみ提供されています。将来の更新で変更または削除されることがあります。続行するには、この診断を非表示にします。 + '{0}' is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. @@ -13196,4 +13231,4 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ - \ No newline at end of file + diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf index ef744ebde22ff..243fd2ac0b7c9 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf @@ -1992,6 +1992,11 @@ 유형 및 별칭은 '필수'로 지정할 수 없습니다. + + The type 'Microsoft.CodeAnalysis.EmbeddedAttribute' must be non-generic, internal, sealed, non-static, have a parameterless constructor, inherit from System.Attribute, and be able to be applied to any type. + The type 'Microsoft.CodeAnalysis.EmbeddedAttribute' must be non-generic, internal, sealed, non-static, have a parameterless constructor, inherit from System.Attribute, and be able to be applied to any type. + + Target runtime doesn't support by-ref-like generics. 대상 런타임은 참조와 유사한 제네릭을 지원하지 않습니다. @@ -2502,6 +2507,11 @@ 보간에서 줄 바꿈 + + overload resolution priority + overload resolution priority + + parameterless struct constructors 매개 변수 없는 구조체 생성자 @@ -2622,11 +2632,6 @@ <missing> - - overload resolution priority - 오버로드 해결 우선 순위 - - pointer element access 포인터 요소 액세스 @@ -2952,6 +2957,16 @@ 이 컨텍스트에서 변수를 사용하면 선언 범위 외부에서 참조된 변수가 노출될 수 있습니다. + + '{0}' is for evaluation purposes only and is subject to change or removal in future updates: '{1}'. Suppress this diagnostic to proceed. + '{0}' is for evaluation purposes only and is subject to change or removal in future updates: '{1}'. Suppress this diagnostic to proceed. + + + + Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. + Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. + + In language version {0}, the 'field' keyword binds to a synthesized backing field for the property. To avoid generating a synthesized backing field, and to refer to the existing member, use 'this.field' or '@field' instead. 언어 버전 {0}에서 'field' 키워드는 속성에 대한 합성된 지원 필드에 바인딩됩니다. 합성된 지원 필드가 생성되지 않도록 하고 기존 멤버를 참조하려면 대신 'this.field' 또는 '@field'를 사용합니다. @@ -3022,6 +3037,16 @@ 인터셉터블 및 인터셉터 메서드의 서명이 일치하지 않습니다. + + 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) + 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) + + + + 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) + 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) + + InterpolatedStringHandlerArgument has no effect when applied to lambda parameters and will be ignored at the call site. InterpolatedStringHandlerArgument는 람다 매개 변수에 적용할 때 효과가 없으며 호출 사이트에서 무시됩니다. @@ -5358,6 +5383,16 @@ 매개 변수를 읽을 수 없습니다. 이 매개 변수를 사용하여 해당 이름으로 속성을 초기화했는지 확인하세요. + + UnscopedRefAttribute is only valid in C# 11 or later or when targeting net7.0 or later. + UnscopedRefAttribute is only valid in C# 11 or later or when targeting net7.0 or later. + + + + UnscopedRefAttribute is only valid in C# 11 or later or when targeting net7.0 or later. + UnscopedRefAttribute is only valid in C# 11 or later or when targeting net7.0 or later. + + Use of unassigned local variable '{0}' 할당되지 않은 '{0}' 지역 변수를 사용했습니다. @@ -12971,7 +13006,7 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ '{0}' is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. - '{0}'은(는) 평가 목적으로 제공되며, 이후 업데이트에서 변경되거나 제거될 수 있습니다. 계속하려면 이 진단을 표시하지 않습니다. + '{0}' is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. @@ -13196,4 +13231,4 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ - \ No newline at end of file + diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf index 18b507ba1ae01..643f44629c419 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf @@ -1992,6 +1992,11 @@ Typy i aliasy nie mogą mieć nazwy „required”. + + The type 'Microsoft.CodeAnalysis.EmbeddedAttribute' must be non-generic, internal, sealed, non-static, have a parameterless constructor, inherit from System.Attribute, and be able to be applied to any type. + The type 'Microsoft.CodeAnalysis.EmbeddedAttribute' must be non-generic, internal, sealed, non-static, have a parameterless constructor, inherit from System.Attribute, and be able to be applied to any type. + + Target runtime doesn't support by-ref-like generics. Docelowe środowisko uruchomieniowe nie obsługuje typów ogólnych by-ref-like. @@ -2502,6 +2507,11 @@ nowe wiersze w interpolacjach + + overload resolution priority + overload resolution priority + + parameterless struct constructors Konstruktory struktury bez parametrów @@ -2622,11 +2632,6 @@ <missing> - - overload resolution priority - priorytet rozwiązywania przeciążenia - - pointer element access dostęp do elementu wskaźnika @@ -2952,6 +2957,16 @@ Nie można używać zmiennej w tym kontekście, ponieważ może uwidaczniać odwoływane zmienne poza ich zakresem deklaracji + + '{0}' is for evaluation purposes only and is subject to change or removal in future updates: '{1}'. Suppress this diagnostic to proceed. + '{0}' is for evaluation purposes only and is subject to change or removal in future updates: '{1}'. Suppress this diagnostic to proceed. + + + + Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. + Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. + + In language version {0}, the 'field' keyword binds to a synthesized backing field for the property. To avoid generating a synthesized backing field, and to refer to the existing member, use 'this.field' or '@field' instead. W wersji językowej {0}, słowo kluczowe „field” jest powiązane ze zsyntetyzowanym polem zapasowym właściwości. Aby uniknąć generowania zsyntetyzowanego pola zapasowego i odwoływać się do istniejącego elementu członkowskiego, użyj zamiast niego wartości „this.field” lub „@field”. @@ -3022,6 +3037,16 @@ Podpisy metody możliwej do przechwycenia i metody interceptora nie są zgodne. + + 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) + 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) + + + + 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) + 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) + + InterpolatedStringHandlerArgument has no effect when applied to lambda parameters and will be ignored at the call site. Argument InterpolatedStringHandlerArgument nie odniesie żadnego skutku po zastosowaniu do parametrów lambda i zostanie zignorowany w lokacji wywołania. @@ -5358,6 +5383,16 @@ Parametr nie został odczytany. Czy zapomniano użyć go do zainicjowania właściwości o tej nazwie? + + UnscopedRefAttribute is only valid in C# 11 or later or when targeting net7.0 or later. + UnscopedRefAttribute is only valid in C# 11 or later or when targeting net7.0 or later. + + + + UnscopedRefAttribute is only valid in C# 11 or later or when targeting net7.0 or later. + UnscopedRefAttribute is only valid in C# 11 or later or when targeting net7.0 or later. + + Use of unassigned local variable '{0}' Użyto nieprzypisanej zmiennej lokalnej „{0}” @@ -12971,7 +13006,7 @@ Aby usunąć ostrzeżenie, możesz zamiast tego użyć opcji /reference (ustaw w '{0}' is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. - Element „{0}” jest przeznaczony wyłącznie do celów ewaluacyjnych i może zostać zmieniony albo usunięty w przyszłych aktualizacjach. Wstrzymaj tę diagnostykę, aby kontynuować. + '{0}' is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. @@ -13196,4 +13231,4 @@ Aby usunąć ostrzeżenie, możesz zamiast tego użyć opcji /reference (ustaw w - \ No newline at end of file + diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf index ead9efd5bb411..1407b0e3d35a4 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf @@ -1992,6 +1992,11 @@ Tipos e pseudônimos não podem ser nomeados 'requeridos'. + + The type 'Microsoft.CodeAnalysis.EmbeddedAttribute' must be non-generic, internal, sealed, non-static, have a parameterless constructor, inherit from System.Attribute, and be able to be applied to any type. + The type 'Microsoft.CodeAnalysis.EmbeddedAttribute' must be non-generic, internal, sealed, non-static, have a parameterless constructor, inherit from System.Attribute, and be able to be applied to any type. + + Target runtime doesn't support by-ref-like generics. O runtime de destino não dá suporte a genéricos by-ref-like. @@ -2502,6 +2507,11 @@ novas linhas em interpolações + + overload resolution priority + overload resolution priority + + parameterless struct constructors construtores struct sem parâmetros @@ -2622,11 +2632,6 @@ <ausente> - - overload resolution priority - prioridade de resolução de sobrecarga - - pointer element access acesso ao elemento de ponteiro @@ -2952,6 +2957,16 @@ O uso de variável neste contexto pode expor variáveis referenciadas fora de seu escopo de declaração + + '{0}' is for evaluation purposes only and is subject to change or removal in future updates: '{1}'. Suppress this diagnostic to proceed. + '{0}' is for evaluation purposes only and is subject to change or removal in future updates: '{1}'. Suppress this diagnostic to proceed. + + + + Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. + Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. + + In language version {0}, the 'field' keyword binds to a synthesized backing field for the property. To avoid generating a synthesized backing field, and to refer to the existing member, use 'this.field' or '@field' instead. Na versão da linguagem {0}, a palavra-chave ''field'' é associada a um campo de suporte sintetizado para a propriedade. Para evitar a geração de um campo de suporte sintetizado e para se referir ao membro existente, use 'this.field' ou '@field'. @@ -3022,6 +3037,16 @@ As assinaturas de métodos interceptáveis e interceptador não coincidem. + + 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) + 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) + + + + 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) + 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) + + InterpolatedStringHandlerArgument has no effect when applied to lambda parameters and will be ignored at the call site. InterpolatedStringHandlerArgument não tem efeito quando aplicado a parâmetros lambda e será ignorado no local de chamada. @@ -5358,6 +5383,16 @@ O parâmetro não foi lido. Você esqueceu de usá-lo para inicializar a propriedade com esse nome? + + UnscopedRefAttribute is only valid in C# 11 or later or when targeting net7.0 or later. + UnscopedRefAttribute is only valid in C# 11 or later or when targeting net7.0 or later. + + + + UnscopedRefAttribute is only valid in C# 11 or later or when targeting net7.0 or later. + UnscopedRefAttribute is only valid in C# 11 or later or when targeting net7.0 or later. + + Use of unassigned local variable '{0}' Uso de variável local não atribuída "{0}" @@ -12971,7 +13006,7 @@ Para incorporar informações de tipo de interoperabilidade para os dois assembl '{0}' is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. - '{0}'é apenas para fins de avaliação e está sujeito a alterações ou remoção em atualizações futuras. Suprima este diagnóstico para continuar. + '{0}' is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. @@ -13196,4 +13231,4 @@ Para incorporar informações de tipo de interoperabilidade para os dois assembl - \ No newline at end of file + diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf index acaddd744fa0d..feb729000ac8e 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf @@ -1992,6 +1992,11 @@ У типов и псевдонимов не может быть имя "required". + + The type 'Microsoft.CodeAnalysis.EmbeddedAttribute' must be non-generic, internal, sealed, non-static, have a parameterless constructor, inherit from System.Attribute, and be able to be applied to any type. + The type 'Microsoft.CodeAnalysis.EmbeddedAttribute' must be non-generic, internal, sealed, non-static, have a parameterless constructor, inherit from System.Attribute, and be able to be applied to any type. + + Target runtime doesn't support by-ref-like generics. Целевая среда выполнения не поддерживает параметрические полиморфизмы, подобные ref. @@ -2502,6 +2507,11 @@ новые линии в интерполяции + + overload resolution priority + overload resolution priority + + parameterless struct constructors конструкторы структуры без параметров @@ -2622,11 +2632,6 @@ <missing> - - overload resolution priority - приоритет разрешения перегрузки - - pointer element access доступ к элементу указателя @@ -2952,6 +2957,16 @@ Использование переменной в этом контексте может представить ссылочные переменные за пределами области их объявления. + + '{0}' is for evaluation purposes only and is subject to change or removal in future updates: '{1}'. Suppress this diagnostic to proceed. + '{0}' is for evaluation purposes only and is subject to change or removal in future updates: '{1}'. Suppress this diagnostic to proceed. + + + + Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. + Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. + + In language version {0}, the 'field' keyword binds to a synthesized backing field for the property. To avoid generating a synthesized backing field, and to refer to the existing member, use 'this.field' or '@field' instead. В версии языка {0} ключевое слово "field" привязывается к синтезированному резервному полю для свойства. Чтобы не создавать синтезированное резервное поле и ссылаться на существующий элемент, используйте вместо этого "this.field" или "@field". @@ -3022,6 +3037,16 @@ Сигнатуры методов перехвата и перехватчика не совпадают. + + 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) + 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) + + + + 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) + 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) + + InterpolatedStringHandlerArgument has no effect when applied to lambda parameters and will be ignored at the call site. Атрибут InterpolatedStringHandlerArgument не действует при применении к лямбда-параметрам и будет проигнорирован на сайте вызова. @@ -5359,6 +5384,16 @@ Параметр не читается. Возможно, вы забыли использовать его для инициализации свойства с таким же именем? + + UnscopedRefAttribute is only valid in C# 11 or later or when targeting net7.0 or later. + UnscopedRefAttribute is only valid in C# 11 or later or when targeting net7.0 or later. + + + + UnscopedRefAttribute is only valid in C# 11 or later or when targeting net7.0 or later. + UnscopedRefAttribute is only valid in C# 11 or later or when targeting net7.0 or later. + + Use of unassigned local variable '{0}' Использование локальной переменной "{0}", которой не присвоено значение. @@ -12972,7 +13007,7 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ '{0}' is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. - "{0}" предназначен только для оценки и может быть изменен или удален в будущих обновлениях. Чтобы продолжить, скройте эту диагностику. + '{0}' is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. @@ -13197,4 +13232,4 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ - \ No newline at end of file + diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf index 28a7a091b504a..3aafdcd4d9e0a 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf @@ -1992,6 +1992,11 @@ Türler ve diğer adlar 'gerekli' olarak adlandırılamaz. + + The type 'Microsoft.CodeAnalysis.EmbeddedAttribute' must be non-generic, internal, sealed, non-static, have a parameterless constructor, inherit from System.Attribute, and be able to be applied to any type. + The type 'Microsoft.CodeAnalysis.EmbeddedAttribute' must be non-generic, internal, sealed, non-static, have a parameterless constructor, inherit from System.Attribute, and be able to be applied to any type. + + Target runtime doesn't support by-ref-like generics. Hedef çalışma zamanı başvuru benzeri genel türleri desteklemez. @@ -2502,6 +2507,11 @@ ilişkilendirmedeki yeni satırlar + + overload resolution priority + overload resolution priority + + parameterless struct constructors parametresiz yapı oluşturucuları @@ -2622,11 +2632,6 @@ <missing> - - overload resolution priority - aşırı yükleme çözümlemesi önceliği - - pointer element access işaretçi öğesi erişimi @@ -2952,6 +2957,16 @@ Bu bağlamda değişken kullanımı, başvurulan değişkenleri bildirim kapsamının dışında gösterebilir. + + '{0}' is for evaluation purposes only and is subject to change or removal in future updates: '{1}'. Suppress this diagnostic to proceed. + '{0}' is for evaluation purposes only and is subject to change or removal in future updates: '{1}'. Suppress this diagnostic to proceed. + + + + Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. + Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. + + In language version {0}, the 'field' keyword binds to a synthesized backing field for the property. To avoid generating a synthesized backing field, and to refer to the existing member, use 'this.field' or '@field' instead. {0} dil sürümünde, 'field' anahtar sözcüğü, özellik için sentezlenmiş bir destek alanına bağlanır. Sentezlenmiş bir destek alanı oluşturmaktan kaçınmak ve mevcut üyeye başvurmak için bunun yerine 'this.field' veya '@field' kullanın. @@ -3022,6 +3037,16 @@ Engellenebilirlerin ve engelleyicilerin imzaları eşleşmiyor. + + 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) + 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) + + + + 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) + 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) + + InterpolatedStringHandlerArgument has no effect when applied to lambda parameters and will be ignored at the call site. InterpolatedStringHandlerArgument, lambda parametrelerine uygulandığında hiçbir etkiye sahip değildir ve çağrı sitesinde yok sayılır. @@ -5358,6 +5383,16 @@ Parametre okunmadı. Bu ada sahip özelliği başlatmak için bu parametreyi kullanmayı unutmuş olabilirsiniz. + + UnscopedRefAttribute is only valid in C# 11 or later or when targeting net7.0 or later. + UnscopedRefAttribute is only valid in C# 11 or later or when targeting net7.0 or later. + + + + UnscopedRefAttribute is only valid in C# 11 or later or when targeting net7.0 or later. + UnscopedRefAttribute is only valid in C# 11 or later or when targeting net7.0 or later. + + Use of unassigned local variable '{0}' Atanmayan '{0}' yerel değişkeninin kullanımı @@ -12971,7 +13006,7 @@ Uyarıyı kaldırmak için, /reference kullanabilirsiniz (Birlikte Çalışma T '{0}' is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. - '{0}' yalnızca değerlendirme amaçlıdır ve gelecekteki güncelleştirmelerde değiştirilebilir veya kaldırılabilir. Devam etmek için bu tanılamayı gizleyin. + '{0}' is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. @@ -13196,4 +13231,4 @@ Uyarıyı kaldırmak için, /reference kullanabilirsiniz (Birlikte Çalışma T - \ No newline at end of file + diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf index 141406a0d3ba1..11bd2b672e9b9 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf @@ -1992,6 +1992,11 @@ 类型和别名不能命名为 “required”。 + + The type 'Microsoft.CodeAnalysis.EmbeddedAttribute' must be non-generic, internal, sealed, non-static, have a parameterless constructor, inherit from System.Attribute, and be able to be applied to any type. + The type 'Microsoft.CodeAnalysis.EmbeddedAttribute' must be non-generic, internal, sealed, non-static, have a parameterless constructor, inherit from System.Attribute, and be able to be applied to any type. + + Target runtime doesn't support by-ref-like generics. 目标运行时不支持类似 ref 的泛型。 @@ -2502,6 +2507,11 @@ 内插中的换行符 + + overload resolution priority + overload resolution priority + + parameterless struct constructors 参数结构构造函数 @@ -2622,11 +2632,6 @@ <missing> - - overload resolution priority - 重载解析优先级 - - pointer element access 指针元素访问 @@ -2952,6 +2957,16 @@ 在此上下文中使用变量可能会在变量声明范围以外公开所引用的变量 + + '{0}' is for evaluation purposes only and is subject to change or removal in future updates: '{1}'. Suppress this diagnostic to proceed. + '{0}' is for evaluation purposes only and is subject to change or removal in future updates: '{1}'. Suppress this diagnostic to proceed. + + + + Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. + Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. + + In language version {0}, the 'field' keyword binds to a synthesized backing field for the property. To avoid generating a synthesized backing field, and to refer to the existing member, use 'this.field' or '@field' instead. 在语言版本 {0} 中,‘field’ 关键字绑定到属性的合成后备字段。要避免生成合成后备字段并引用现有成员,请改用 ‘this.field’ 或 ‘@field’。 @@ -3022,6 +3037,16 @@ 可截获方法和侦听器方法的签名不匹配。 + + 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) + 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) + + + + 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) + 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) + + InterpolatedStringHandlerArgument has no effect when applied to lambda parameters and will be ignored at the call site. 应用于 lambda 参数时,InterpolatedStringHandlerArgument 不起任何作用,并将在调用站点被忽略。 @@ -5358,6 +5383,16 @@ 参数未读。是否忘记通过它来使用该名称初始化属性? + + UnscopedRefAttribute is only valid in C# 11 or later or when targeting net7.0 or later. + UnscopedRefAttribute is only valid in C# 11 or later or when targeting net7.0 or later. + + + + UnscopedRefAttribute is only valid in C# 11 or later or when targeting net7.0 or later. + UnscopedRefAttribute is only valid in C# 11 or later or when targeting net7.0 or later. + + Use of unassigned local variable '{0}' 使用了未赋值的局部变量“{0}” @@ -12971,7 +13006,7 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ '{0}' is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. - “{0}”仅用于评估,在将来的更新中可能会被更改或删除。取消此诊断以继续。 + '{0}' is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. @@ -13196,4 +13231,4 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ - \ No newline at end of file + diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf index 80bae1129a747..f43aeab538011 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf @@ -1992,6 +1992,11 @@ 類型和別名不能命名為 'required'。 + + The type 'Microsoft.CodeAnalysis.EmbeddedAttribute' must be non-generic, internal, sealed, non-static, have a parameterless constructor, inherit from System.Attribute, and be able to be applied to any type. + The type 'Microsoft.CodeAnalysis.EmbeddedAttribute' must be non-generic, internal, sealed, non-static, have a parameterless constructor, inherit from System.Attribute, and be able to be applied to any type. + + Target runtime doesn't support by-ref-like generics. 目標執行階段不支援泛型之類 by-ref-。 @@ -2502,6 +2507,11 @@ 插補中的新行 + + overload resolution priority + overload resolution priority + + parameterless struct constructors 無參數結構建構函式 @@ -2622,11 +2632,6 @@ <missing> - - overload resolution priority - 多載解析優先順序 - - pointer element access 指標元素存取 @@ -2952,6 +2957,16 @@ 在此內容中使用變數,可能會將參考的變數公開在其宣告範圍外 + + '{0}' is for evaluation purposes only and is subject to change or removal in future updates: '{1}'. Suppress this diagnostic to proceed. + '{0}' is for evaluation purposes only and is subject to change or removal in future updates: '{1}'. Suppress this diagnostic to proceed. + + + + Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. + Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. + + In language version {0}, the 'field' keyword binds to a synthesized backing field for the property. To avoid generating a synthesized backing field, and to refer to the existing member, use 'this.field' or '@field' instead. 在語言版本 {0} 中,'field' 關鍵詞會繫結至屬性的合成備份欄位。若要避免產生合成的備份欄位,並參考現有的成員,請改用 'this.field' 或 '@field'。 @@ -3022,6 +3037,16 @@ 可攔截與攔截器方法的簽章不相符。 + + 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) + 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) + + + + 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) + 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) + + InterpolatedStringHandlerArgument has no effect when applied to lambda parameters and will be ignored at the call site. InterpolatedStringHandlerArgument 在套用至 Lambda 參數時沒有效果,將於呼叫網站忽略。 @@ -5358,6 +5383,16 @@ strument:TestCoverage 產生檢測要收集 參數未讀取。是否忘記使用該參數來初始化該名稱的屬性? + + UnscopedRefAttribute is only valid in C# 11 or later or when targeting net7.0 or later. + UnscopedRefAttribute is only valid in C# 11 or later or when targeting net7.0 or later. + + + + UnscopedRefAttribute is only valid in C# 11 or later or when targeting net7.0 or later. + UnscopedRefAttribute is only valid in C# 11 or later or when targeting net7.0 or later. + + Use of unassigned local variable '{0}' 使用未指派的區域變數 '{0}' @@ -12971,7 +13006,7 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ '{0}' is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. - '{0}' 僅供評估之用,可能會在未來更新中變更或移除。抑制此診斷以繼續。 + '{0}' is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. @@ -13196,4 +13231,4 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ - \ No newline at end of file + diff --git a/src/Compilers/CSharp/Test/CommandLine/CommandLineTests.cs b/src/Compilers/CSharp/Test/CommandLine/CommandLineTests.cs index 99048d694be53..31372989a3f2c 100644 --- a/src/Compilers/CSharp/Test/CommandLine/CommandLineTests.cs +++ b/src/Compilers/CSharp/Test/CommandLine/CommandLineTests.cs @@ -1729,7 +1729,7 @@ public void LanguageVersionAdded_Canary() // - update the "UpgradeProject" codefixer // - update all the tests that call this canary // - update _MaxAvailableLangVersion (a relevant test should break when new version is introduced) - // - email release management to add to the release notes (see old example: https://github.com/dotnet/core/pull/1454) + // - email release management to add to the release notes (see csharp-version in release.json in previous example: https://github.com/dotnet/core/pull/9493) AssertEx.SetEqual(new[] { "default", "1", "2", "3", "4", "5", "6", "7.0", "7.1", "7.2", "7.3", "8.0", "9.0", "10.0", "11.0", "12.0", "13.0", "latest", "latestmajor", "preview" }, Enum.GetValues(typeof(LanguageVersion)).Cast().Select(v => v.ToDisplayString())); // For minor versions and new major versions, the format should be "x.y", such as "7.1" @@ -14467,7 +14467,19 @@ public InterceptsLocationAttribute(string filePath, int line, int character) """; var generator = new SingleFileTestGenerator(generatedSource, "Generated.cs"); - VerifyOutput(dir, src, includeCurrentAssemblyAsAnalyzerReference: false, additionalFlags: ["/langversion:preview", "/out:embed.exe", "/features:InterceptorsNamespaces=Generated"], generators: [generator], analyzers: null); + // Future note: it would be good to have end-to-end tests using InterceptableLocation APIs. + // Once support for path-based attributes is fully dropped, consider porting these 'Interceptors_' tests accordingly. + VerifyOutput( + dir, + src, + includeCurrentAssemblyAsAnalyzerReference: false, + additionalFlags: ["/langversion:preview", + "/out:embed.exe", + "/features:InterceptorsNamespaces=Generated", + "/warn:9"], + expectedWarningCount: 1, + generators: [generator], + analyzers: null); ValidateWrittenSources([]); // Clean up temp files @@ -14526,7 +14538,17 @@ public InterceptsLocationAttribute(string filePath, int line, int character) var generator = new SingleFileTestGenerator(generatedSource, "Generated.cs"); var objDir = dir.CreateDirectory("obj"); - VerifyOutput(dir, src, includeCurrentAssemblyAsAnalyzerReference: false, additionalFlags: ["/langversion:preview", $"/out:{objDir.Path}/embed.exe", "/features:InterceptorsNamespaces=Generated"], generators: [generator], analyzers: null); + VerifyOutput( + dir, + src, + includeCurrentAssemblyAsAnalyzerReference: false, + additionalFlags: ["/langversion:preview", + $"/out:{objDir.Path}/embed.exe", + "/features:InterceptorsNamespaces=Generated", + "/warn:9"], + expectedWarningCount: 1, + generators: [generator], + analyzers: null); ValidateWrittenSources([]); // Clean up temp files @@ -14597,8 +14619,10 @@ public InterceptsLocationAttribute(string filePath, int line, int character) "/langversion:preview", "/out:embed.exe", "/features:InterceptorsNamespaces=Generated", + "/warn:9", .. string.IsNullOrEmpty(pathMapArgument) ? default(Span) : [pathMapArgument] ], + expectedWarningCount: 1, generators: [generator], analyzers: null); @@ -15638,6 +15662,142 @@ public static void M() { } comp.VerifyDiagnostics(); } + [Fact] + public void ExperimentalAttributeWithMessage_SuppressedWithEditorConfig() + { + var dir = Temp.CreateDirectory(); + var src = dir.CreateFile("test.cs").WriteAllText(""" +C.M(); + +namespace System.Diagnostics.CodeAnalysis +{ + [AttributeUsage(AttributeTargets.All, Inherited = false)] + public sealed class ExperimentalAttribute : Attribute + { + public ExperimentalAttribute(string diagnosticId) { } + + public string UrlFormat { get; set; } + public string Message { get; set; } + } +} + +[System.Diagnostics.CodeAnalysis.Experimental("DiagID1", Message = "use CCC")] +public class C +{ + public static void M() { } +} +"""); + + var analyzerConfig = dir.CreateFile(".editorconfig").WriteAllText(""" +[*.cs] +dotnet_diagnostic.DiagID1.severity = none +"""); + // Without editorconfig + var cmd = CreateCSharpCompiler(null, dir.Path, new[] { + "/nologo", + "/t:exe", + "/preferreduilang:en", + src.Path }); + + var outWriter = new StringWriter(CultureInfo.InvariantCulture); + var exitCode = cmd.Run(outWriter); + Assert.Equal(1, exitCode); + + // With editorconfig + cmd = CreateCSharpCompiler(null, dir.Path, new[] { + "/nologo", + "/t:exe", + "/preferreduilang:en", + "/analyzerconfig:" + analyzerConfig.Path, + src.Path }); + + Assert.Equal(analyzerConfig.Path, Assert.Single(cmd.Arguments.AnalyzerConfigPaths)); + + outWriter = new StringWriter(CultureInfo.InvariantCulture); + exitCode = cmd.Run(outWriter); + Assert.Equal(0, exitCode); + Assert.Equal("", outWriter.ToString()); + } + + [Fact] + public void ExperimentalAttributeWithMessage_SuppressedWithSpecificNoWarn() + { + var dir = Temp.CreateDirectory(); + var src = dir.CreateFile("test.cs").WriteAllText(""" +C.M(); + +namespace System.Diagnostics.CodeAnalysis +{ + [AttributeUsage(AttributeTargets.All, Inherited = false)] + public sealed class ExperimentalAttribute : Attribute + { + public ExperimentalAttribute(string diagnosticId) { } + + public string UrlFormat { get; set; } + public string Message { get; set; } + } +} + +[System.Diagnostics.CodeAnalysis.Experimental("DiagID1", Message = "use CCC")] +public class C +{ + public static void M() { } +} +"""); + + // Without nowarn + var cmd = CreateCSharpCompiler(null, dir.Path, new[] { + "/nologo", + "/t:exe", + "/preferreduilang:en", + src.Path }); + + var outWriter = new StringWriter(CultureInfo.InvariantCulture); + var exitCode = cmd.Run(outWriter); + Assert.Equal(1, exitCode); + + // With nowarn + cmd = CreateCSharpCompiler(null, dir.Path, new[] { + "/nologo", + "/t:exe", + "/preferreduilang:en", + "/nowarn:DiagID1", + src.Path }); + + outWriter = new StringWriter(CultureInfo.InvariantCulture); + exitCode = cmd.Run(outWriter); + Assert.Equal(0, exitCode); + } + + [Fact] + public void ExperimentalAttributeWithMessage_SuppressedWithGlobalNoWarn() + { + var src = """ +C.M(); + +namespace System.Diagnostics.CodeAnalysis +{ + [AttributeUsage(AttributeTargets.All, Inherited = false)] + public sealed class ExperimentalAttribute : Attribute + { + public ExperimentalAttribute(string diagnosticId) { } + + public string UrlFormat { get; set; } + public string Message { get; set; } + } +} + +[System.Diagnostics.CodeAnalysis.Experimental("DiagID1", Message = "use CCC")] +public class C +{ + public static void M() { } +} +"""; + + var comp = CreateCompilation(src, options: TestOptions.DebugExe.WithGeneralDiagnosticOption(ReportDiagnostic.Suppress)); + comp.VerifyDiagnostics(); + } + [Fact] public void ExperimentalWithWhitespaceDiagnosticID_WarnForInvalidDiagID() { diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncIteratorTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncIteratorTests.cs index 4459d0c3cc867..f0782c2d9d877 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncIteratorTests.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncIteratorTests.cs @@ -10531,5 +10531,120 @@ public static async System.Collections.Generic.IAsyncEnumerable M(S2 p) comp = CreateCompilation(source, options: TestOptions.UnsafeDebugDll, references: [libS2, missingLibS1], targetFramework: TargetFramework.Net80); comp.VerifyEmitDiagnostics(); } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/76078")] + public void StateAfterMoveNext_YieldReturn() + { + string src = """ +var enumerator = C.Produce(); +System.Console.Write(await enumerator.MoveNextAsync()); +System.Console.Write(enumerator.Current); + +await enumerator.DisposeAsync(); + +System.Console.Write(await enumerator.MoveNextAsync()); +System.Console.Write(enumerator.Current is null ? " null" : throw null); + +class C +{ + public static async System.Collections.Generic.IAsyncEnumerator Produce() + { + await System.Threading.Tasks.Task.CompletedTask; + yield return " one "; + yield return " two "; + } +} +"""; + CompileAndVerify(src, expectedOutput: ExpectedOutput("True one False null"), verify: Verification.Skipped, targetFramework: TargetFramework.Net80).VerifyDiagnostics(); + } + + [Fact] + public void CompilerLoweringPreserveAttribute_01() + { + string source1 = @" +using System; +using System.Runtime.CompilerServices; + +[CompilerLoweringPreserve] +[AttributeUsage(AttributeTargets.GenericParameter)] +public class Preserve1Attribute : Attribute { } + +[AttributeUsage(AttributeTargets.GenericParameter)] +public class Preserve2Attribute : Attribute { } +"; + + string source2 = @" +using System.Collections.Generic; +using System.Threading.Tasks; + +class Test1 +{ + async IAsyncEnumerable M2<[Preserve1][Preserve2]T>(T x) + { + await Task.Yield(); + yield return x; + } +} +"; + var comp1 = CreateCompilation([source1, source2, CompilerLoweringPreserveAttributeDefinition], targetFramework: TargetFramework.Net80); + CompileAndVerify(comp1, symbolValidator: validate, verify: Verification.FailsPEVerify).VerifyDiagnostics(); + + static void validate(ModuleSymbol m) + { + AssertEx.SequenceEqual( + ["Preserve1Attribute"], + m.GlobalNamespace.GetMember("Test1.d__0").TypeParameters.Single().GetAttributes().Select(a => a.ToString())); + } + } + + [Fact] + public void CompilerLoweringPreserveAttribute_02() + { + string source1 = @" +using System; +using System.Runtime.CompilerServices; + +[CompilerLoweringPreserve] +[AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter)] +public class Preserve1Attribute : Attribute { } + +[CompilerLoweringPreserve] +[AttributeUsage(AttributeTargets.Parameter)] +public class Preserve2Attribute : Attribute { } + +[AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter)] +public class Preserve3Attribute : Attribute { } +"; + + string source2 = @" +using System.Collections.Generic; +using System.Threading.Tasks; + +class Test1 +{ + async IAsyncEnumerable M2([Preserve1][Preserve2][Preserve3]int x) + { + await Task.Yield(); + yield return x; + } +} +"; + var comp1 = CreateCompilation( + [source1, source2, CompilerLoweringPreserveAttributeDefinition], + options: TestOptions.DebugDll.WithMetadataImportOptions(MetadataImportOptions.All), + targetFramework: TargetFramework.Net80); + CompileAndVerify(comp1, symbolValidator: validate, verify: Verification.FailsPEVerify).VerifyDiagnostics(); + + static void validate(ModuleSymbol m) + { + AssertEx.SequenceEqual( + ["Preserve1Attribute"], + m.GlobalNamespace.GetMember("Test1.d__0.x").GetAttributes().Select(a => a.ToString())); + + AssertEx.SequenceEqual( + ["Preserve1Attribute"], + m.GlobalNamespace.GetMember("Test1.d__0.<>3__x").GetAttributes().Select(a => a.ToString())); + } + } } } diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncTests.cs index 89482c2907c11..02805bebf64d5 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncTests.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncTests.cs @@ -6267,5 +6267,87 @@ .locals init (int V_0, } """); } + + [Fact] + public void CompilerLoweringPreserveAttribute_01() + { + string source1 = @" +using System; +using System.Runtime.CompilerServices; + +[CompilerLoweringPreserve] +[AttributeUsage(AttributeTargets.GenericParameter)] +public class Preserve1Attribute : Attribute { } + +[AttributeUsage(AttributeTargets.GenericParameter)] +public class Preserve2Attribute : Attribute { } +"; + + string source2 = @" +using System.Threading.Tasks; + +class Test1 +{ + async Task M2<[Preserve1][Preserve2]T>(T x) + { + await Task.Yield(); + return x; + } +} +"; + var comp1 = CreateCompilation([source1, source2, CompilerLoweringPreserveAttributeDefinition]); + CompileAndVerify(comp1, symbolValidator: validate).VerifyDiagnostics(); + + static void validate(ModuleSymbol m) + { + AssertEx.SequenceEqual( + ["Preserve1Attribute"], + m.GlobalNamespace.GetMember("Test1.d__0").TypeParameters.Single().GetAttributes().Select(a => a.ToString())); + } + } + + [Fact] + public void CompilerLoweringPreserveAttribute_02() + { + string source1 = @" +using System; +using System.Runtime.CompilerServices; + +[CompilerLoweringPreserve] +[AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter)] +public class Preserve1Attribute : Attribute { } + +[CompilerLoweringPreserve] +[AttributeUsage(AttributeTargets.Parameter)] +public class Preserve2Attribute : Attribute { } + +[AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter)] +public class Preserve3Attribute : Attribute { } +"; + + string source2 = @" +using System.Threading.Tasks; + +class Test1 +{ + async Task M2([Preserve1][Preserve2][Preserve3]int x) + { + await Task.Yield(); + return x; + } +} +"; + var comp1 = CreateCompilation( + [source1, source2, CompilerLoweringPreserveAttributeDefinition], + options: TestOptions.DebugDll.WithMetadataImportOptions(MetadataImportOptions.All)); + CompileAndVerify(comp1, symbolValidator: validate).VerifyDiagnostics(); + + static void validate(ModuleSymbol m) + { + AssertEx.SequenceEqual( + ["Preserve1Attribute"], + m.GlobalNamespace.GetMember("Test1.d__0.x").GetAttributes().Select(a => a.ToString())); + } + } } } diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenDisplayClassOptimisationTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenDisplayClassOptimisationTests.cs index 9de4494e5794c..3d22fd8422f03 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenDisplayClassOptimisationTests.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenDisplayClassOptimisationTests.cs @@ -7568,7 +7568,7 @@ .maxstack 8 } // end of class Program"); } - [Fact] + [Fact, CompilerTrait(CompilerFeature.Iterator)] public void YieldReturnCorrectDisplayClasseAreCreated() { var source = @@ -7604,416 +7604,419 @@ public IEnumerable M() { VerifyTypeIL(compilation, "C", @" .class public auto ansi beforefieldinit C - extends [mscorlib]System.Object + extends [mscorlib]System.Object { - // Nested Types - .class nested private auto ansi sealed beforefieldinit '<>c__DisplayClass0_0' - extends [mscorlib]System.Object - { - .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( - 01 00 00 00 - ) - // Fields - .field public int32 a - // Methods - .method public hidebysig specialname rtspecialname - instance void .ctor () cil managed - { - // Method begins at RVA 0x2059 - // Code size 7 (0x7) - .maxstack 8 - IL_0000: ldarg.0 - IL_0001: call instance void [mscorlib]System.Object::.ctor() - IL_0006: ret - } // end of method '<>c__DisplayClass0_0'::.ctor - } // end of class <>c__DisplayClass0_0 - .class nested private auto ansi sealed beforefieldinit '<>c__DisplayClass0_1' - extends [mscorlib]System.Object - { - .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( - 01 00 00 00 - ) - // Fields - .field public int32 b - .field public int32 c - .field public class C/'<>c__DisplayClass0_0' 'CS$<>8__locals1' - // Methods - .method public hidebysig specialname rtspecialname - instance void .ctor () cil managed - { - // Method begins at RVA 0x2059 - // Code size 7 (0x7) - .maxstack 8 - IL_0000: ldarg.0 - IL_0001: call instance void [mscorlib]System.Object::.ctor() - IL_0006: ret - } // end of method '<>c__DisplayClass0_1'::.ctor - } // end of class <>c__DisplayClass0_1 - .class nested private auto ansi sealed beforefieldinit '<>c__DisplayClass0_2' - extends [mscorlib]System.Object - { - .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( - 01 00 00 00 - ) - // Fields - .field public int32 d - .field public class C/'<>c__DisplayClass0_1' 'CS$<>8__locals2' - // Methods - .method public hidebysig specialname rtspecialname - instance void .ctor () cil managed - { - // Method begins at RVA 0x2059 - // Code size 7 (0x7) - .maxstack 8 - IL_0000: ldarg.0 - IL_0001: call instance void [mscorlib]System.Object::.ctor() - IL_0006: ret - } // end of method '<>c__DisplayClass0_2'::.ctor - .method assembly hidebysig - instance void 'b__0' () cil managed - { - // Method begins at RVA 0x2061 - // Code size 53 (0x35) - .maxstack 8 - IL_0000: ldarg.0 - IL_0001: ldfld class C/'<>c__DisplayClass0_1' C/'<>c__DisplayClass0_2'::'CS$<>8__locals2' - IL_0006: ldfld class C/'<>c__DisplayClass0_0' C/'<>c__DisplayClass0_1'::'CS$<>8__locals1' - IL_000b: ldfld int32 C/'<>c__DisplayClass0_0'::a - IL_0010: ldarg.0 - IL_0011: ldfld class C/'<>c__DisplayClass0_1' C/'<>c__DisplayClass0_2'::'CS$<>8__locals2' - IL_0016: ldfld int32 C/'<>c__DisplayClass0_1'::b - IL_001b: add - IL_001c: ldarg.0 - IL_001d: ldfld class C/'<>c__DisplayClass0_1' C/'<>c__DisplayClass0_2'::'CS$<>8__locals2' - IL_0022: ldfld int32 C/'<>c__DisplayClass0_1'::c - IL_0027: add - IL_0028: ldarg.0 - IL_0029: ldfld int32 C/'<>c__DisplayClass0_2'::d - IL_002e: add - IL_002f: call void [mscorlib]System.Console::WriteLine(int32) - IL_0034: ret - } // end of method '<>c__DisplayClass0_2'::'b__0' - } // end of class <>c__DisplayClass0_2 - .class nested private auto ansi sealed beforefieldinit 'd__0' - extends [mscorlib]System.Object - implements class [mscorlib]System.Collections.Generic.IEnumerable`1, - [mscorlib]System.Collections.IEnumerable, - class [mscorlib]System.Collections.Generic.IEnumerator`1, - [mscorlib]System.IDisposable, - [mscorlib]System.Collections.IEnumerator - { - .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( - 01 00 00 00 - ) - // Fields - .field private int32 '<>1__state' - .field private int32 '<>2__current' - .field private int32 '<>l__initialThreadId' - .field private class C/'<>c__DisplayClass0_0' '<>8__1' - .field private class C/'<>c__DisplayClass0_1' '<>8__2' - .field private class C/'<>c__DisplayClass0_2' '<>8__3' - // Methods - .method public hidebysig specialname rtspecialname - instance void .ctor ( - int32 '<>1__state' - ) cil managed - { - .custom instance void [mscorlib]System.Diagnostics.DebuggerHiddenAttribute::.ctor() = ( - 01 00 00 00 - ) - // Method begins at RVA 0x2097 - // Code size 25 (0x19) - .maxstack 8 - IL_0000: ldarg.0 - IL_0001: call instance void [mscorlib]System.Object::.ctor() - IL_0006: ldarg.0 - IL_0007: ldarg.1 - IL_0008: stfld int32 C/'d__0'::'<>1__state' - IL_000d: ldarg.0 - IL_000e: call int32 [mscorlib]System.Environment::get_CurrentManagedThreadId() - IL_0013: stfld int32 C/'d__0'::'<>l__initialThreadId' - IL_0018: ret - } // end of method 'd__0'::.ctor - .method private final hidebysig newslot virtual - instance void System.IDisposable.Dispose () cil managed - { - .custom instance void [mscorlib]System.Diagnostics.DebuggerHiddenAttribute::.ctor() = ( - 01 00 00 00 - ) - .override method instance void [mscorlib]System.IDisposable::Dispose() - // Method begins at RVA 0x20b1 - // Code size 22 (0x16) - .maxstack 8 - IL_0000: ldarg.0 - IL_0001: ldnull - IL_0002: stfld class C/'<>c__DisplayClass0_0' C/'d__0'::'<>8__1' - IL_0007: ldarg.0 - IL_0008: ldnull - IL_0009: stfld class C/'<>c__DisplayClass0_1' C/'d__0'::'<>8__2' - IL_000e: ldarg.0 - IL_000f: ldnull - IL_0010: stfld class C/'<>c__DisplayClass0_2' C/'d__0'::'<>8__3' - IL_0015: ret - } // end of method 'd__0'::System.IDisposable.Dispose - .method private final hidebysig newslot virtual - instance bool MoveNext () cil managed - { - .override method instance bool [mscorlib]System.Collections.IEnumerator::MoveNext() - // Method begins at RVA 0x20c8 - // Code size 342 (0x156) - .maxstack 2 - .locals init ( - [0] int32 - ) - IL_0000: ldarg.0 - IL_0001: ldfld int32 C/'d__0'::'<>1__state' - IL_0006: stloc.0 - IL_0007: ldloc.0 - IL_0008: switch (IL_002f, IL_005d, IL_0090, IL_00b3, IL_00ca, IL_00ed, IL_0120, IL_0135) - IL_002d: ldc.i4.0 - IL_002e: ret - IL_002f: ldarg.0 - IL_0030: ldc.i4.m1 - IL_0031: stfld int32 C/'d__0'::'<>1__state' - IL_0036: ldarg.0 - IL_0037: newobj instance void C/'<>c__DisplayClass0_0'::.ctor() - IL_003c: stfld class C/'<>c__DisplayClass0_0' C/'d__0'::'<>8__1' - IL_0041: ldarg.0 - IL_0042: ldfld class C/'<>c__DisplayClass0_0' C/'d__0'::'<>8__1' - IL_0047: ldc.i4.1 - IL_0048: stfld int32 C/'<>c__DisplayClass0_0'::a - IL_004d: ldarg.0 - IL_004e: ldc.i4.1 - IL_004f: stfld int32 C/'d__0'::'<>2__current' - IL_0054: ldarg.0 - IL_0055: ldc.i4.1 - IL_0056: stfld int32 C/'d__0'::'<>1__state' - IL_005b: ldc.i4.1 - IL_005c: ret - IL_005d: ldarg.0 - IL_005e: ldc.i4.m1 - IL_005f: stfld int32 C/'d__0'::'<>1__state' - IL_0064: ldarg.0 - IL_0065: newobj instance void C/'<>c__DisplayClass0_1'::.ctor() - IL_006a: stfld class C/'<>c__DisplayClass0_1' C/'d__0'::'<>8__2' - IL_006f: ldarg.0 - IL_0070: ldfld class C/'<>c__DisplayClass0_1' C/'d__0'::'<>8__2' - IL_0075: ldarg.0 - IL_0076: ldfld class C/'<>c__DisplayClass0_0' C/'d__0'::'<>8__1' - IL_007b: stfld class C/'<>c__DisplayClass0_0' C/'<>c__DisplayClass0_1'::'CS$<>8__locals1' - IL_0080: ldarg.0 - IL_0081: ldc.i4.2 - IL_0082: stfld int32 C/'d__0'::'<>2__current' - IL_0087: ldarg.0 - IL_0088: ldc.i4.2 - IL_0089: stfld int32 C/'d__0'::'<>1__state' - IL_008e: ldc.i4.1 - IL_008f: ret - IL_0090: ldarg.0 - IL_0091: ldc.i4.m1 - IL_0092: stfld int32 C/'d__0'::'<>1__state' - IL_0097: ldarg.0 - IL_0098: ldfld class C/'<>c__DisplayClass0_1' C/'d__0'::'<>8__2' - IL_009d: ldc.i4.2 - IL_009e: stfld int32 C/'<>c__DisplayClass0_1'::b - IL_00a3: ldarg.0 - IL_00a4: ldc.i4.3 - IL_00a5: stfld int32 C/'d__0'::'<>2__current' - IL_00aa: ldarg.0 - IL_00ab: ldc.i4.3 - IL_00ac: stfld int32 C/'d__0'::'<>1__state' - IL_00b1: ldc.i4.1 - IL_00b2: ret - IL_00b3: ldarg.0 - IL_00b4: ldc.i4.m1 - IL_00b5: stfld int32 C/'d__0'::'<>1__state' - IL_00ba: ldarg.0 - IL_00bb: ldc.i4.4 - IL_00bc: stfld int32 C/'d__0'::'<>2__current' - IL_00c1: ldarg.0 - IL_00c2: ldc.i4.4 - IL_00c3: stfld int32 C/'d__0'::'<>1__state' - IL_00c8: ldc.i4.1 - IL_00c9: ret - IL_00ca: ldarg.0 - IL_00cb: ldc.i4.m1 - IL_00cc: stfld int32 C/'d__0'::'<>1__state' - IL_00d1: ldarg.0 - IL_00d2: ldfld class C/'<>c__DisplayClass0_1' C/'d__0'::'<>8__2' - IL_00d7: ldc.i4.3 - IL_00d8: stfld int32 C/'<>c__DisplayClass0_1'::c - IL_00dd: ldarg.0 - IL_00de: ldc.i4.5 - IL_00df: stfld int32 C/'d__0'::'<>2__current' - IL_00e4: ldarg.0 - IL_00e5: ldc.i4.5 - IL_00e6: stfld int32 C/'d__0'::'<>1__state' - IL_00eb: ldc.i4.1 - IL_00ec: ret - IL_00ed: ldarg.0 - IL_00ee: ldc.i4.m1 - IL_00ef: stfld int32 C/'d__0'::'<>1__state' - IL_00f4: ldarg.0 - IL_00f5: newobj instance void C/'<>c__DisplayClass0_2'::.ctor() - IL_00fa: stfld class C/'<>c__DisplayClass0_2' C/'d__0'::'<>8__3' - IL_00ff: ldarg.0 - IL_0100: ldfld class C/'<>c__DisplayClass0_2' C/'d__0'::'<>8__3' - IL_0105: ldarg.0 - IL_0106: ldfld class C/'<>c__DisplayClass0_1' C/'d__0'::'<>8__2' - IL_010b: stfld class C/'<>c__DisplayClass0_1' C/'<>c__DisplayClass0_2'::'CS$<>8__locals2' - IL_0110: ldarg.0 - IL_0111: ldc.i4.6 - IL_0112: stfld int32 C/'d__0'::'<>2__current' - IL_0117: ldarg.0 - IL_0118: ldc.i4.6 - IL_0119: stfld int32 C/'d__0'::'<>1__state' - IL_011e: ldc.i4.1 - IL_011f: ret - IL_0120: ldarg.0 - IL_0121: ldc.i4.m1 - IL_0122: stfld int32 C/'d__0'::'<>1__state' - IL_0127: ldarg.0 - IL_0128: ldfld class C/'<>c__DisplayClass0_2' C/'d__0'::'<>8__3' - IL_012d: ldc.i4.4 - IL_012e: stfld int32 C/'<>c__DisplayClass0_2'::d - IL_0133: br.s IL_00dd - IL_0135: ldarg.0 - IL_0136: ldc.i4.m1 - IL_0137: stfld int32 C/'d__0'::'<>1__state' - IL_013c: ldarg.0 - IL_013d: ldfld class C/'<>c__DisplayClass0_2' C/'d__0'::'<>8__3' - IL_0142: pop - IL_0143: ldarg.0 - IL_0144: ldnull - IL_0145: stfld class C/'<>c__DisplayClass0_2' C/'d__0'::'<>8__3' - IL_014a: ldarg.0 - IL_014b: ldnull - IL_014c: stfld class C/'<>c__DisplayClass0_1' C/'d__0'::'<>8__2' - IL_0151: br IL_0064 - } // end of method 'd__0'::MoveNext - .method private final hidebysig specialname newslot virtual - instance int32 'System.Collections.Generic.IEnumerator.get_Current' () cil managed - { - .custom instance void [mscorlib]System.Diagnostics.DebuggerHiddenAttribute::.ctor() = ( - 01 00 00 00 - ) - .override method instance !0 class [mscorlib]System.Collections.Generic.IEnumerator`1::get_Current() - // Method begins at RVA 0x222a - // Code size 7 (0x7) - .maxstack 8 - IL_0000: ldarg.0 - IL_0001: ldfld int32 C/'d__0'::'<>2__current' - IL_0006: ret - } // end of method 'd__0'::'System.Collections.Generic.IEnumerator.get_Current' - .method private final hidebysig newslot virtual - instance void System.Collections.IEnumerator.Reset () cil managed - { - .custom instance void [mscorlib]System.Diagnostics.DebuggerHiddenAttribute::.ctor() = ( - 01 00 00 00 - ) - .override method instance void [mscorlib]System.Collections.IEnumerator::Reset() - // Method begins at RVA 0x2232 - // Code size 6 (0x6) - .maxstack 8 - IL_0000: newobj instance void [mscorlib]System.NotSupportedException::.ctor() - IL_0005: throw - } // end of method 'd__0'::System.Collections.IEnumerator.Reset - .method private final hidebysig specialname newslot virtual - instance object System.Collections.IEnumerator.get_Current () cil managed - { - .custom instance void [mscorlib]System.Diagnostics.DebuggerHiddenAttribute::.ctor() = ( - 01 00 00 00 - ) - .override method instance object [mscorlib]System.Collections.IEnumerator::get_Current() - // Method begins at RVA 0x2239 - // Code size 12 (0xc) - .maxstack 8 - IL_0000: ldarg.0 - IL_0001: ldfld int32 C/'d__0'::'<>2__current' - IL_0006: box [mscorlib]System.Int32 - IL_000b: ret - } // end of method 'd__0'::System.Collections.IEnumerator.get_Current - .method private final hidebysig newslot virtual - instance class [mscorlib]System.Collections.Generic.IEnumerator`1 'System.Collections.Generic.IEnumerable.GetEnumerator' () cil managed - { - .custom instance void [mscorlib]System.Diagnostics.DebuggerHiddenAttribute::.ctor() = ( - 01 00 00 00 - ) - .override method instance class [mscorlib]System.Collections.Generic.IEnumerator`1 class [mscorlib]System.Collections.Generic.IEnumerable`1::GetEnumerator() - // Method begins at RVA 0x2248 - // Code size 43 (0x2b) - .maxstack 2 - .locals init ( - [0] class C/'d__0' - ) - IL_0000: ldarg.0 - IL_0001: ldfld int32 C/'d__0'::'<>1__state' - IL_0006: ldc.i4.s -2 - IL_0008: bne.un.s IL_0022 - IL_000a: ldarg.0 - IL_000b: ldfld int32 C/'d__0'::'<>l__initialThreadId' - IL_0010: call int32 [mscorlib]System.Environment::get_CurrentManagedThreadId() - IL_0015: bne.un.s IL_0022 - IL_0017: ldarg.0 - IL_0018: ldc.i4.0 - IL_0019: stfld int32 C/'d__0'::'<>1__state' - IL_001e: ldarg.0 - IL_001f: stloc.0 - IL_0020: br.s IL_0029 - IL_0022: ldc.i4.0 - IL_0023: newobj instance void C/'d__0'::.ctor(int32) - IL_0028: stloc.0 - IL_0029: ldloc.0 - IL_002a: ret - } // end of method 'd__0'::'System.Collections.Generic.IEnumerable.GetEnumerator' - .method private final hidebysig newslot virtual - instance class [mscorlib]System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator () cil managed - { - .custom instance void [mscorlib]System.Diagnostics.DebuggerHiddenAttribute::.ctor() = ( - 01 00 00 00 - ) - .override method instance class [mscorlib]System.Collections.IEnumerator [mscorlib]System.Collections.IEnumerable::GetEnumerator() - // Method begins at RVA 0x227f - // Code size 7 (0x7) - .maxstack 8 - IL_0000: ldarg.0 - IL_0001: call instance class [mscorlib]System.Collections.Generic.IEnumerator`1 C/'d__0'::'System.Collections.Generic.IEnumerable.GetEnumerator'() - IL_0006: ret - } // end of method 'd__0'::System.Collections.IEnumerable.GetEnumerator - // Properties - .property instance int32 'System.Collections.Generic.IEnumerator.Current'() - { - .get instance int32 C/'d__0'::'System.Collections.Generic.IEnumerator.get_Current'() - } - .property instance object System.Collections.IEnumerator.Current() - { - .get instance object C/'d__0'::System.Collections.IEnumerator.get_Current() - } - } // end of class d__0 - // Methods - .method public hidebysig - instance class [mscorlib]System.Collections.Generic.IEnumerable`1 M () cil managed - { - .custom instance void [mscorlib]System.Runtime.CompilerServices.IteratorStateMachineAttribute::.ctor(class [mscorlib]System.Type) = ( - 01 00 09 43 2b 3c 4d 3e 64 5f 5f 30 00 00 - ) - // Method begins at RVA 0x2050 - // Code size 8 (0x8) - .maxstack 8 - IL_0000: ldc.i4.s -2 - IL_0002: newobj instance void C/'d__0'::.ctor(int32) - IL_0007: ret - } // end of method C::M - .method public hidebysig specialname rtspecialname - instance void .ctor () cil managed - { - // Method begins at RVA 0x2059 - // Code size 7 (0x7) - .maxstack 8 - IL_0000: ldarg.0 - IL_0001: call instance void [mscorlib]System.Object::.ctor() - IL_0006: ret - } // end of method C::.ctor + // Nested Types + .class nested private auto ansi sealed beforefieldinit '<>c__DisplayClass0_0' + extends [mscorlib]System.Object + { + .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( + 01 00 00 00 + ) + // Fields + .field public int32 a + // Methods + .method public hidebysig specialname rtspecialname + instance void .ctor () cil managed + { + // Method begins at RVA 0x2059 + // Code size 7 (0x7) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: call instance void [mscorlib]System.Object::.ctor() + IL_0006: ret + } // end of method '<>c__DisplayClass0_0'::.ctor + } // end of class <>c__DisplayClass0_0 + .class nested private auto ansi sealed beforefieldinit '<>c__DisplayClass0_1' + extends [mscorlib]System.Object + { + .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( + 01 00 00 00 + ) + // Fields + .field public int32 b + .field public int32 c + .field public class C/'<>c__DisplayClass0_0' 'CS$<>8__locals1' + // Methods + .method public hidebysig specialname rtspecialname + instance void .ctor () cil managed + { + // Method begins at RVA 0x2059 + // Code size 7 (0x7) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: call instance void [mscorlib]System.Object::.ctor() + IL_0006: ret + } // end of method '<>c__DisplayClass0_1'::.ctor + } // end of class <>c__DisplayClass0_1 + .class nested private auto ansi sealed beforefieldinit '<>c__DisplayClass0_2' + extends [mscorlib]System.Object + { + .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( + 01 00 00 00 + ) + // Fields + .field public int32 d + .field public class C/'<>c__DisplayClass0_1' 'CS$<>8__locals2' + // Methods + .method public hidebysig specialname rtspecialname + instance void .ctor () cil managed + { + // Method begins at RVA 0x2059 + // Code size 7 (0x7) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: call instance void [mscorlib]System.Object::.ctor() + IL_0006: ret + } // end of method '<>c__DisplayClass0_2'::.ctor + .method assembly hidebysig + instance void 'b__0' () cil managed + { + // Method begins at RVA 0x2061 + // Code size 53 (0x35) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldfld class C/'<>c__DisplayClass0_1' C/'<>c__DisplayClass0_2'::'CS$<>8__locals2' + IL_0006: ldfld class C/'<>c__DisplayClass0_0' C/'<>c__DisplayClass0_1'::'CS$<>8__locals1' + IL_000b: ldfld int32 C/'<>c__DisplayClass0_0'::a + IL_0010: ldarg.0 + IL_0011: ldfld class C/'<>c__DisplayClass0_1' C/'<>c__DisplayClass0_2'::'CS$<>8__locals2' + IL_0016: ldfld int32 C/'<>c__DisplayClass0_1'::b + IL_001b: add + IL_001c: ldarg.0 + IL_001d: ldfld class C/'<>c__DisplayClass0_1' C/'<>c__DisplayClass0_2'::'CS$<>8__locals2' + IL_0022: ldfld int32 C/'<>c__DisplayClass0_1'::c + IL_0027: add + IL_0028: ldarg.0 + IL_0029: ldfld int32 C/'<>c__DisplayClass0_2'::d + IL_002e: add + IL_002f: call void [mscorlib]System.Console::WriteLine(int32) + IL_0034: ret + } // end of method '<>c__DisplayClass0_2'::'b__0' + } // end of class <>c__DisplayClass0_2 + .class nested private auto ansi sealed beforefieldinit 'd__0' + extends [mscorlib]System.Object + implements class [mscorlib]System.Collections.Generic.IEnumerable`1, + [mscorlib]System.Collections.IEnumerable, + class [mscorlib]System.Collections.Generic.IEnumerator`1, + [mscorlib]System.IDisposable, + [mscorlib]System.Collections.IEnumerator + { + .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( + 01 00 00 00 + ) + // Fields + .field private int32 '<>1__state' + .field private int32 '<>2__current' + .field private int32 '<>l__initialThreadId' + .field private class C/'<>c__DisplayClass0_0' '<>8__1' + .field private class C/'<>c__DisplayClass0_1' '<>8__2' + .field private class C/'<>c__DisplayClass0_2' '<>8__3' + // Methods + .method public hidebysig specialname rtspecialname + instance void .ctor ( + int32 '<>1__state' + ) cil managed + { + .custom instance void [mscorlib]System.Diagnostics.DebuggerHiddenAttribute::.ctor() = ( + 01 00 00 00 + ) + // Method begins at RVA 0x2097 + // Code size 25 (0x19) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: call instance void [mscorlib]System.Object::.ctor() + IL_0006: ldarg.0 + IL_0007: ldarg.1 + IL_0008: stfld int32 C/'d__0'::'<>1__state' + IL_000d: ldarg.0 + IL_000e: call int32 [mscorlib]System.Environment::get_CurrentManagedThreadId() + IL_0013: stfld int32 C/'d__0'::'<>l__initialThreadId' + IL_0018: ret + } // end of method 'd__0'::.ctor + .method private final hidebysig newslot virtual + instance void System.IDisposable.Dispose () cil managed + { + .custom instance void [mscorlib]System.Diagnostics.DebuggerHiddenAttribute::.ctor() = ( + 01 00 00 00 + ) + .override method instance void [mscorlib]System.IDisposable::Dispose() + // Method begins at RVA 0x20b1 + // Code size 30 (0x1e) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldnull + IL_0002: stfld class C/'<>c__DisplayClass0_0' C/'d__0'::'<>8__1' + IL_0007: ldarg.0 + IL_0008: ldnull + IL_0009: stfld class C/'<>c__DisplayClass0_1' C/'d__0'::'<>8__2' + IL_000e: ldarg.0 + IL_000f: ldnull + IL_0010: stfld class C/'<>c__DisplayClass0_2' C/'d__0'::'<>8__3' + IL_0015: ldarg.0 + IL_0016: ldc.i4.s -2 + IL_0018: stfld int32 C/'d__0'::'<>1__state' + IL_001d: ret + } // end of method 'd__0'::System.IDisposable.Dispose + .method private final hidebysig newslot virtual + instance bool MoveNext () cil managed + { + .override method instance bool [mscorlib]System.Collections.IEnumerator::MoveNext() + // Method begins at RVA 0x20d0 + // Code size 342 (0x156) + .maxstack 2 + .locals init ( + [0] int32 + ) + IL_0000: ldarg.0 + IL_0001: ldfld int32 C/'d__0'::'<>1__state' + IL_0006: stloc.0 + IL_0007: ldloc.0 + IL_0008: switch (IL_002f, IL_005d, IL_0090, IL_00b3, IL_00ca, IL_00ed, IL_0120, IL_0135) + IL_002d: ldc.i4.0 + IL_002e: ret + IL_002f: ldarg.0 + IL_0030: ldc.i4.m1 + IL_0031: stfld int32 C/'d__0'::'<>1__state' + IL_0036: ldarg.0 + IL_0037: newobj instance void C/'<>c__DisplayClass0_0'::.ctor() + IL_003c: stfld class C/'<>c__DisplayClass0_0' C/'d__0'::'<>8__1' + IL_0041: ldarg.0 + IL_0042: ldfld class C/'<>c__DisplayClass0_0' C/'d__0'::'<>8__1' + IL_0047: ldc.i4.1 + IL_0048: stfld int32 C/'<>c__DisplayClass0_0'::a + IL_004d: ldarg.0 + IL_004e: ldc.i4.1 + IL_004f: stfld int32 C/'d__0'::'<>2__current' + IL_0054: ldarg.0 + IL_0055: ldc.i4.1 + IL_0056: stfld int32 C/'d__0'::'<>1__state' + IL_005b: ldc.i4.1 + IL_005c: ret + IL_005d: ldarg.0 + IL_005e: ldc.i4.m1 + IL_005f: stfld int32 C/'d__0'::'<>1__state' + IL_0064: ldarg.0 + IL_0065: newobj instance void C/'<>c__DisplayClass0_1'::.ctor() + IL_006a: stfld class C/'<>c__DisplayClass0_1' C/'d__0'::'<>8__2' + IL_006f: ldarg.0 + IL_0070: ldfld class C/'<>c__DisplayClass0_1' C/'d__0'::'<>8__2' + IL_0075: ldarg.0 + IL_0076: ldfld class C/'<>c__DisplayClass0_0' C/'d__0'::'<>8__1' + IL_007b: stfld class C/'<>c__DisplayClass0_0' C/'<>c__DisplayClass0_1'::'CS$<>8__locals1' + IL_0080: ldarg.0 + IL_0081: ldc.i4.2 + IL_0082: stfld int32 C/'d__0'::'<>2__current' + IL_0087: ldarg.0 + IL_0088: ldc.i4.2 + IL_0089: stfld int32 C/'d__0'::'<>1__state' + IL_008e: ldc.i4.1 + IL_008f: ret + IL_0090: ldarg.0 + IL_0091: ldc.i4.m1 + IL_0092: stfld int32 C/'d__0'::'<>1__state' + IL_0097: ldarg.0 + IL_0098: ldfld class C/'<>c__DisplayClass0_1' C/'d__0'::'<>8__2' + IL_009d: ldc.i4.2 + IL_009e: stfld int32 C/'<>c__DisplayClass0_1'::b + IL_00a3: ldarg.0 + IL_00a4: ldc.i4.3 + IL_00a5: stfld int32 C/'d__0'::'<>2__current' + IL_00aa: ldarg.0 + IL_00ab: ldc.i4.3 + IL_00ac: stfld int32 C/'d__0'::'<>1__state' + IL_00b1: ldc.i4.1 + IL_00b2: ret + IL_00b3: ldarg.0 + IL_00b4: ldc.i4.m1 + IL_00b5: stfld int32 C/'d__0'::'<>1__state' + IL_00ba: ldarg.0 + IL_00bb: ldc.i4.4 + IL_00bc: stfld int32 C/'d__0'::'<>2__current' + IL_00c1: ldarg.0 + IL_00c2: ldc.i4.4 + IL_00c3: stfld int32 C/'d__0'::'<>1__state' + IL_00c8: ldc.i4.1 + IL_00c9: ret + IL_00ca: ldarg.0 + IL_00cb: ldc.i4.m1 + IL_00cc: stfld int32 C/'d__0'::'<>1__state' + IL_00d1: ldarg.0 + IL_00d2: ldfld class C/'<>c__DisplayClass0_1' C/'d__0'::'<>8__2' + IL_00d7: ldc.i4.3 + IL_00d8: stfld int32 C/'<>c__DisplayClass0_1'::c + IL_00dd: ldarg.0 + IL_00de: ldc.i4.5 + IL_00df: stfld int32 C/'d__0'::'<>2__current' + IL_00e4: ldarg.0 + IL_00e5: ldc.i4.5 + IL_00e6: stfld int32 C/'d__0'::'<>1__state' + IL_00eb: ldc.i4.1 + IL_00ec: ret + IL_00ed: ldarg.0 + IL_00ee: ldc.i4.m1 + IL_00ef: stfld int32 C/'d__0'::'<>1__state' + IL_00f4: ldarg.0 + IL_00f5: newobj instance void C/'<>c__DisplayClass0_2'::.ctor() + IL_00fa: stfld class C/'<>c__DisplayClass0_2' C/'d__0'::'<>8__3' + IL_00ff: ldarg.0 + IL_0100: ldfld class C/'<>c__DisplayClass0_2' C/'d__0'::'<>8__3' + IL_0105: ldarg.0 + IL_0106: ldfld class C/'<>c__DisplayClass0_1' C/'d__0'::'<>8__2' + IL_010b: stfld class C/'<>c__DisplayClass0_1' C/'<>c__DisplayClass0_2'::'CS$<>8__locals2' + IL_0110: ldarg.0 + IL_0111: ldc.i4.6 + IL_0112: stfld int32 C/'d__0'::'<>2__current' + IL_0117: ldarg.0 + IL_0118: ldc.i4.6 + IL_0119: stfld int32 C/'d__0'::'<>1__state' + IL_011e: ldc.i4.1 + IL_011f: ret + IL_0120: ldarg.0 + IL_0121: ldc.i4.m1 + IL_0122: stfld int32 C/'d__0'::'<>1__state' + IL_0127: ldarg.0 + IL_0128: ldfld class C/'<>c__DisplayClass0_2' C/'d__0'::'<>8__3' + IL_012d: ldc.i4.4 + IL_012e: stfld int32 C/'<>c__DisplayClass0_2'::d + IL_0133: br.s IL_00dd + IL_0135: ldarg.0 + IL_0136: ldc.i4.m1 + IL_0137: stfld int32 C/'d__0'::'<>1__state' + IL_013c: ldarg.0 + IL_013d: ldfld class C/'<>c__DisplayClass0_2' C/'d__0'::'<>8__3' + IL_0142: pop + IL_0143: ldarg.0 + IL_0144: ldnull + IL_0145: stfld class C/'<>c__DisplayClass0_2' C/'d__0'::'<>8__3' + IL_014a: ldarg.0 + IL_014b: ldnull + IL_014c: stfld class C/'<>c__DisplayClass0_1' C/'d__0'::'<>8__2' + IL_0151: br IL_0064 + } // end of method 'd__0'::MoveNext + .method private final hidebysig specialname newslot virtual + instance int32 'System.Collections.Generic.IEnumerator.get_Current' () cil managed + { + .custom instance void [mscorlib]System.Diagnostics.DebuggerHiddenAttribute::.ctor() = ( + 01 00 00 00 + ) + .override method instance !0 class [mscorlib]System.Collections.Generic.IEnumerator`1::get_Current() + // Method begins at RVA 0x2232 + // Code size 7 (0x7) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldfld int32 C/'d__0'::'<>2__current' + IL_0006: ret + } // end of method 'd__0'::'System.Collections.Generic.IEnumerator.get_Current' + .method private final hidebysig newslot virtual + instance void System.Collections.IEnumerator.Reset () cil managed + { + .custom instance void [mscorlib]System.Diagnostics.DebuggerHiddenAttribute::.ctor() = ( + 01 00 00 00 + ) + .override method instance void [mscorlib]System.Collections.IEnumerator::Reset() + // Method begins at RVA 0x223a + // Code size 6 (0x6) + .maxstack 8 + IL_0000: newobj instance void [mscorlib]System.NotSupportedException::.ctor() + IL_0005: throw + } // end of method 'd__0'::System.Collections.IEnumerator.Reset + .method private final hidebysig specialname newslot virtual + instance object System.Collections.IEnumerator.get_Current () cil managed + { + .custom instance void [mscorlib]System.Diagnostics.DebuggerHiddenAttribute::.ctor() = ( + 01 00 00 00 + ) + .override method instance object [mscorlib]System.Collections.IEnumerator::get_Current() + // Method begins at RVA 0x2241 + // Code size 12 (0xc) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldfld int32 C/'d__0'::'<>2__current' + IL_0006: box [mscorlib]System.Int32 + IL_000b: ret + } // end of method 'd__0'::System.Collections.IEnumerator.get_Current + .method private final hidebysig newslot virtual + instance class [mscorlib]System.Collections.Generic.IEnumerator`1 'System.Collections.Generic.IEnumerable.GetEnumerator' () cil managed + { + .custom instance void [mscorlib]System.Diagnostics.DebuggerHiddenAttribute::.ctor() = ( + 01 00 00 00 + ) + .override method instance class [mscorlib]System.Collections.Generic.IEnumerator`1 class [mscorlib]System.Collections.Generic.IEnumerable`1::GetEnumerator() + // Method begins at RVA 0x2250 + // Code size 43 (0x2b) + .maxstack 2 + .locals init ( + [0] class C/'d__0' + ) + IL_0000: ldarg.0 + IL_0001: ldfld int32 C/'d__0'::'<>1__state' + IL_0006: ldc.i4.s -2 + IL_0008: bne.un.s IL_0022 + IL_000a: ldarg.0 + IL_000b: ldfld int32 C/'d__0'::'<>l__initialThreadId' + IL_0010: call int32 [mscorlib]System.Environment::get_CurrentManagedThreadId() + IL_0015: bne.un.s IL_0022 + IL_0017: ldarg.0 + IL_0018: ldc.i4.0 + IL_0019: stfld int32 C/'d__0'::'<>1__state' + IL_001e: ldarg.0 + IL_001f: stloc.0 + IL_0020: br.s IL_0029 + IL_0022: ldc.i4.0 + IL_0023: newobj instance void C/'d__0'::.ctor(int32) + IL_0028: stloc.0 + IL_0029: ldloc.0 + IL_002a: ret + } // end of method 'd__0'::'System.Collections.Generic.IEnumerable.GetEnumerator' + .method private final hidebysig newslot virtual + instance class [mscorlib]System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator () cil managed + { + .custom instance void [mscorlib]System.Diagnostics.DebuggerHiddenAttribute::.ctor() = ( + 01 00 00 00 + ) + .override method instance class [mscorlib]System.Collections.IEnumerator [mscorlib]System.Collections.IEnumerable::GetEnumerator() + // Method begins at RVA 0x2287 + // Code size 7 (0x7) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: call instance class [mscorlib]System.Collections.Generic.IEnumerator`1 C/'d__0'::'System.Collections.Generic.IEnumerable.GetEnumerator'() + IL_0006: ret + } // end of method 'd__0'::System.Collections.IEnumerable.GetEnumerator + // Properties + .property instance int32 'System.Collections.Generic.IEnumerator.Current'() + { + .get instance int32 C/'d__0'::'System.Collections.Generic.IEnumerator.get_Current'() + } + .property instance object System.Collections.IEnumerator.Current() + { + .get instance object C/'d__0'::System.Collections.IEnumerator.get_Current() + } + } // end of class d__0 + // Methods + .method public hidebysig + instance class [mscorlib]System.Collections.Generic.IEnumerable`1 M () cil managed + { + .custom instance void [mscorlib]System.Runtime.CompilerServices.IteratorStateMachineAttribute::.ctor(class [mscorlib]System.Type) = ( + 01 00 09 43 2b 3c 4d 3e 64 5f 5f 30 00 00 + ) + // Method begins at RVA 0x2050 + // Code size 8 (0x8) + .maxstack 8 + IL_0000: ldc.i4.s -2 + IL_0002: newobj instance void C/'d__0'::.ctor(int32) + IL_0007: ret + } // end of method C::M + .method public hidebysig specialname rtspecialname + instance void .ctor () cil managed + { + // Method begins at RVA 0x2059 + // Code size 7 (0x7) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: call instance void [mscorlib]System.Object::.ctor() + IL_0006: ret + } // end of method C::.ctor } // end of class C"); } diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenIterators.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenIterators.cs index 5ab7b180a4923..f39272b7c209c 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenIterators.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenIterators.cs @@ -12,6 +12,7 @@ namespace Microsoft.CodeAnalysis.CSharp.UnitTests.CodeGen { + [CompilerTrait(CompilerFeature.Iterator)] public class CodeGenIterators : CSharpTestBase { [Fact] @@ -445,7 +446,7 @@ .locals init (bool V_0, "); compilation.VerifyIL("Program.d__0.System.IDisposable.Dispose()", @" { - // Code size 76 (0x4c) + // Code size 84 (0x54) .maxstack 2 .locals init (int V_0) IL_0000: ldarg.0 @@ -510,7 +511,10 @@ .locals init (int V_0) IL_0045: call ""void Program.d__0.<>m__Finally1()"" IL_004a: endfinally } - IL_004b: ret + IL_004b: ldarg.0 + IL_004c: ldc.i4.s -2 + IL_004e: stfld ""int Program.d__0.<>1__state"" + IL_0053: ret } "); } @@ -3025,9 +3029,12 @@ public static System.Collections.Generic.IEnumerable Produce() var verifier = CompileAndVerify(src, expectedOutput: "42 42").VerifyDiagnostics(); verifier.VerifyIL("C.d__0.System.IDisposable.Dispose()", """ { - // Code size 1 (0x1) - .maxstack 0 - IL_0000: ret + // Code size 9 (0x9) + .maxstack 2 + IL_0000: ldarg.0 + IL_0001: ldc.i4.s -2 + IL_0003: stfld "int C.d__0.<>1__state" + IL_0008: ret } """); } @@ -3058,12 +3065,15 @@ public static System.Collections.Generic.IEnumerable Produce() var verifier = CompileAndVerify(src, expectedOutput: "ran ran True").VerifyDiagnostics(); verifier.VerifyIL("C.d__0.System.IDisposable.Dispose()", """ { - // Code size 8 (0x8) + // Code size 16 (0x10) .maxstack 2 IL_0000: ldarg.0 IL_0001: ldnull IL_0002: stfld "string C.d__0.5__2" - IL_0007: ret + IL_0007: ldarg.0 + IL_0008: ldc.i4.s -2 + IL_000a: stfld "int C.d__0.<>1__state" + IL_000f: ret } """); } @@ -3095,12 +3105,15 @@ public static System.Collections.Generic.IEnumerable Produce() var verifier = CompileAndVerify(src, expectedOutput: "ran ran True").VerifyDiagnostics(); verifier.VerifyIL("C.d__0.System.IDisposable.Dispose()", """ { - // Code size 8 (0x8) + // Code size 16 (0x10) .maxstack 2 IL_0000: ldarg.0 IL_0001: ldnull IL_0002: stfld "string C.d__0.5__2" - IL_0007: ret + IL_0007: ldarg.0 + IL_0008: ldc.i4.s -2 + IL_000a: stfld "int C.d__0.<>1__state" + IL_000f: ret } """); } @@ -3133,12 +3146,15 @@ public static System.Collections.Generic.IEnumerable Produce() var verifier = CompileAndVerify(comp, expectedOutput: "100 100 True").VerifyDiagnostics(); verifier.VerifyIL("C.d__0.System.IDisposable.Dispose()", """ { - // Code size 8 (0x8) + // Code size 16 (0x10) .maxstack 2 IL_0000: ldarg.0 IL_0001: ldnull IL_0002: stfld "int[] C.d__0.5__2" - IL_0007: ret + IL_0007: ldarg.0 + IL_0008: ldc.i4.s -2 + IL_000a: stfld "int C.d__0.<>1__state" + IL_000f: ret } """); } @@ -3186,12 +3202,15 @@ public static System.Collections.Generic.IEnumerable M(bool b) var verifier = CompileAndVerify(src, expectedOutput: "42 value value True").VerifyDiagnostics(); verifier.VerifyIL("C.d__0.System.IDisposable.Dispose()", """ { - // Code size 8 (0x8) + // Code size 16 (0x10) .maxstack 2 IL_0000: ldarg.0 IL_0001: ldnull IL_0002: stfld "string C.d__0.5__2" - IL_0007: ret + IL_0007: ldarg.0 + IL_0008: ldc.i4.s -2 + IL_000a: stfld "int C.d__0.<>1__state" + IL_000f: ret } """); } @@ -3239,12 +3258,15 @@ public static System.Collections.Generic.IEnumerable M(bool b) var verifier = CompileAndVerify(src, expectedOutput: "42 value value True").VerifyDiagnostics(); verifier.VerifyIL("C.d__0.System.IDisposable.Dispose()", """ { - // Code size 8 (0x8) + // Code size 16 (0x10) .maxstack 2 IL_0000: ldarg.0 IL_0001: ldnull IL_0002: stfld "string C.d__0.5__2" - IL_0007: ret + IL_0007: ldarg.0 + IL_0008: ldc.i4.s -2 + IL_000a: stfld "int C.d__0.<>1__state" + IL_000f: ret } """); } @@ -3314,9 +3336,12 @@ public static System.Collections.Generic.IEnumerable Produce(int s) var verifier = CompileAndVerify(src, expectedOutput: "42 4242").VerifyDiagnostics(); verifier.VerifyIL("C.d__0.System.IDisposable.Dispose()", """ { - // Code size 1 (0x1) - .maxstack 0 - IL_0000: ret + // Code size 9 (0x9) + .maxstack 2 + IL_0000: ldarg.0 + IL_0001: ldc.i4.s -2 + IL_0003: stfld "int C.d__0.<>1__state" + IL_0008: ret } """); } @@ -3344,9 +3369,12 @@ public static System.Collections.Generic.IEnumerable Produce(string s) var verifier = CompileAndVerify(src, expectedOutput: "value value value").VerifyDiagnostics(); verifier.VerifyIL("C.d__0.System.IDisposable.Dispose()", """ { - // Code size 1 (0x1) - .maxstack 0 - IL_0000: ret + // Code size 9 (0x9) + .maxstack 2 + IL_0000: ldarg.0 + IL_0001: ldc.i4.s -2 + IL_0003: stfld "int C.d__0.<>1__state" + IL_0008: ret } """); } @@ -3381,9 +3409,12 @@ void local() var verifier = CompileAndVerify(src, expectedOutput: "42 42").VerifyDiagnostics(); verifier.VerifyIL("C.d__0.System.IDisposable.Dispose()", """ { - // Code size 1 (0x1) - .maxstack 0 - IL_0000: ret + // Code size 9 (0x9) + .maxstack 2 + IL_0000: ldarg.0 + IL_0001: ldc.i4.s -2 + IL_0003: stfld "int C.d__0.<>1__state" + IL_0008: ret } """); } @@ -3418,10 +3449,13 @@ void local() """; var verifier = CompileAndVerify(src, expectedOutput: "42").VerifyDiagnostics(); verifier.VerifyIL("C.d__2.System.IDisposable.Dispose()", """ -{ - // Code size 1 (0x1) - .maxstack 0 - IL_0000: ret + { + // Code size 9 (0x9) + .maxstack 2 + IL_0000: ldarg.0 + IL_0001: ldc.i4.s -2 + IL_0003: stfld "int C.d__2.<>1__state" + IL_0008: ret } """); } @@ -3459,7 +3493,7 @@ public static System.Collections.Generic.IEnumerable Produce() var verifier = CompileAndVerify(src, expectedOutput: "value value ran True").VerifyDiagnostics(); verifier.VerifyIL("C.d__0.System.IDisposable.Dispose()", """ { - // Code size 34 (0x22) + // Code size 42 (0x2a) .maxstack 2 .locals init (int V_0) IL_0000: ldarg.0 @@ -3485,7 +3519,10 @@ .locals init (int V_0) IL_001a: ldarg.0 IL_001b: ldnull IL_001c: stfld "string C.d__0.5__2" - IL_0021: ret + IL_0021: ldarg.0 + IL_0022: ldc.i4.s -2 + IL_0024: stfld "int C.d__0.<>1__state" + IL_0029: ret } """); } @@ -3532,7 +3569,7 @@ public static System.Collections.Generic.IEnumerable Produce() var verifier = CompileAndVerify(src, expectedOutput: "value value exception True").VerifyDiagnostics(); verifier.VerifyIL("C.d__0.System.IDisposable.Dispose()", """ { - // Code size 34 (0x22) + // Code size 42 (0x2a) .maxstack 2 .locals init (int V_0) IL_0000: ldarg.0 @@ -3558,7 +3595,10 @@ .locals init (int V_0) IL_001a: ldarg.0 IL_001b: ldnull IL_001c: stfld "string C.d__0.5__2" - IL_0021: ret + IL_0021: ldarg.0 + IL_0022: ldc.i4.s -2 + IL_0024: stfld "int C.d__0.<>1__state" + IL_0029: ret } """); } @@ -3680,9 +3720,12 @@ public static System.Collections.Generic.IEnumerable M(bool b, T t) wher var verifier = CompileAndVerify(src, expectedOutput: "10 42 42").VerifyDiagnostics(); verifier.VerifyIL("C.d__0.System.IDisposable.Dispose()", """ { - // Code size 1 (0x1) - .maxstack 0 - IL_0000: ret + // Code size 9 (0x9) + .maxstack 2 + IL_0000: ldarg.0 + IL_0001: ldc.i4.s -2 + IL_0003: stfld "int C.d__0.<>1__state" + IL_0008: ret } """); } @@ -3739,9 +3782,12 @@ public static System.Collections.Generic.IEnumerable M(bool b, S s) var verifier = CompileAndVerify(src, expectedOutput: "10 42 42", references: [libComp.EmitToImageReference()]).VerifyDiagnostics(); verifier.VerifyIL("C.d__0.System.IDisposable.Dispose()", """ { - // Code size 1 (0x1) - .maxstack 0 - IL_0000: ret + // Code size 9 (0x9) + .maxstack 2 + IL_0000: ldarg.0 + IL_0001: ldc.i4.s -2 + IL_0003: stfld "int C.d__0.<>1__state" + IL_0008: ret } """); } @@ -3856,12 +3902,15 @@ public static System.Collections.Generic.IEnumerable Produce() var verifier = CompileAndVerify(src, expectedOutput: "values2 values2 values3 values3 True").VerifyDiagnostics(); verifier.VerifyIL("C.d__0.System.IDisposable.Dispose()", """ { - // Code size 8 (0x8) + // Code size 16 (0x10) .maxstack 2 IL_0000: ldarg.0 IL_0001: ldnull IL_0002: stfld "string C.d__0.5__2" - IL_0007: ret + IL_0007: ldarg.0 + IL_0008: ldc.i4.s -2 + IL_000a: stfld "int C.d__0.<>1__state" + IL_000f: ret } """); } @@ -3887,9 +3936,12 @@ public static System.Collections.Generic.IEnumerable Produce(string s) var verifier = CompileAndVerify(src, expectedOutput: "ran ran").VerifyDiagnostics(); verifier.VerifyIL("C.d__0.System.IDisposable.Dispose()", """ { - // Code size 1 (0x1) - .maxstack 0 - IL_0000: ret + // Code size 9 (0x9) + .maxstack 2 + IL_0000: ldarg.0 + IL_0001: ldc.i4.s -2 + IL_0003: stfld "int C.d__0.<>1__state" + IL_0008: ret } """); } @@ -3934,7 +3986,7 @@ public static System.Collections.Generic.IEnumerable Produce() var verifier = CompileAndVerify(src, expectedOutput: "value value outer True").VerifyDiagnostics(); verifier.VerifyIL("C.d__0.System.IDisposable.Dispose()", """ { - // Code size 55 (0x37) + // Code size 63 (0x3f) .maxstack 2 .locals init (int V_0) IL_0000: ldarg.0 @@ -3979,7 +4031,10 @@ .locals init (int V_0) IL_002f: ldarg.0 IL_0030: ldnull IL_0031: stfld "string C.d__0.5__2" - IL_0036: ret + IL_0036: ldarg.0 + IL_0037: ldc.i4.s -2 + IL_0039: stfld "int C.d__0.<>1__state" + IL_003e: ret } """); } @@ -4031,12 +4086,15 @@ public struct Buffer4 var verifier = CompileAndVerify(comp, expectedOutput: "FalseTrue", verify: Verification.Skipped).VerifyDiagnostics(); verifier.VerifyIL("Program.d__1.System.IDisposable.Dispose()", """ { - // Code size 8 (0x8) + // Code size 16 (0x10) .maxstack 2 IL_0000: ldarg.0 IL_0001: ldnull IL_0002: stfld "C Program.d__1.<>7__wrap2" - IL_0007: ret + IL_0007: ldarg.0 + IL_0008: ldc.i4.s -2 + IL_000a: stfld "int Program.d__1.<>1__state" + IL_000f: ret } """); } @@ -4070,12 +4128,15 @@ public static System.Collections.Generic.IEnumerator Produce() var verifier = CompileAndVerify(src, expectedOutput: "ran ran True").VerifyDiagnostics(); verifier.VerifyIL("C.d__0.System.IDisposable.Dispose()", """ { - // Code size 8 (0x8) + // Code size 16 (0x10) .maxstack 2 IL_0000: ldarg.0 IL_0001: ldnull IL_0002: stfld "string C.d__0.5__2" - IL_0007: ret + IL_0007: ldarg.0 + IL_0008: ldc.i4.s -2 + IL_000a: stfld "int C.d__0.<>1__state" + IL_000f: ret } """); } @@ -4120,5 +4181,924 @@ System.Collections.Generic.IEnumerable M1() comp = CreateCompilation(source, options: TestOptions.UnsafeDebugDll, references: [libS2, missingLibS1]); comp.VerifyEmitDiagnostics(); } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75666")] + public void AddVariableCleanup_StringLocal_MoveNextAfterDispose() + { + string src = """ +var values = new C([" one ", " two "]); +var enumerator = values.GetEnumerator(); +System.Console.Write(enumerator.MoveNext()); +System.Console.Write(enumerator.Current); + +System.Console.Write("disposing "); +enumerator.Dispose(); +System.Console.Write("disposed "); + +System.Console.Write(enumerator.MoveNext()); +System.Console.Write(enumerator.Current); + +class C +{ + private sealed class Node + { + internal readonly T _value; + internal Node _next; + + internal Node(T value) + { + _value = value; + _next = null; + } + } + + private Node _head; + + public C(System.Collections.Generic.IEnumerable collection) + { + Node lastNode = null; + foreach (T element in collection) + { + Node newNode = new Node(element); + newNode._next = lastNode; + lastNode = newNode; + } + + _head = lastNode; + } + + public System.Collections.Generic.IEnumerator GetEnumerator() + { + return GetEnumerator(_head); + } + + private static System.Collections.Generic.IEnumerator GetEnumerator(Node head) + { + Node current = head; + while (current != null) + { + yield return current._value; + current = current._next; + System.Console.Write("AFTER"); + } + } +} +"""; + var verifier = CompileAndVerify(src, expectedOutput: "True two disposing disposed False two").VerifyDiagnostics(); + verifier.VerifyIL("C.d__4.System.IDisposable.Dispose()", """ +{ + // Code size 16 (0x10) + .maxstack 2 + IL_0000: ldarg.0 + IL_0001: ldnull + IL_0002: stfld "C.Node C.d__4.5__2" + IL_0007: ldarg.0 + IL_0008: ldc.i4.s -2 + IL_000a: stfld "int C.d__4.<>1__state" + IL_000f: ret +} +"""); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/76078")] + public void StateAfterMoveNext_YieldReturn() + { + // When a yield return statement is encountered ... The state of the enumerator object is changed to suspended. + // If the state of the enumerator object is suspended, invoking Dispose: ... Changes the state to after. + string src = """ +var enumerator = C.GetEnumerator(); + +System.Console.Write(enumerator.MoveNext()); +System.Console.Write(enumerator.Current); + +enumerator.Dispose(); +System.Console.Write("disposed "); + +System.Console.Write(enumerator.MoveNext()); +System.Console.Write(enumerator.Current); + +class C +{ + public static System.Collections.Generic.IEnumerator GetEnumerator() + { + yield return " one "; + yield return " two "; + } +} +"""; + var verifier = CompileAndVerify(src, expectedOutput: "True one disposed False one").VerifyDiagnostics(); + verifier.VerifyIL("C.d__0.System.IDisposable.Dispose()", """ +{ + // Code size 9 (0x9) + .maxstack 2 + IL_0000: ldarg.0 + IL_0001: ldc.i4.s -2 + IL_0003: stfld "int C.d__0.<>1__state" + IL_0008: ret +} +"""); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/76078")] + public void StateAfterMoveNext_YieldReturn_IEnumerable() + { + // When a yield return statement is encountered ... The state of the enumerator object is changed to suspended. + // If the state of the enumerator object is suspended, invoking Dispose: ... Changes the state to after. + string src = """ +var enumerator = C.Produce().GetEnumerator(); + +System.Console.Write(enumerator.MoveNext()); +System.Console.Write(enumerator.Current); + +enumerator.Dispose(); +System.Console.Write("disposed "); + +System.Console.Write(enumerator.MoveNext()); +System.Console.Write(enumerator.Current); + +class C +{ + public static System.Collections.Generic.IEnumerable Produce() + { + yield return " one "; + yield return " two "; + } +} +"""; + CompileAndVerify(src, expectedOutput: "True one disposed False one").VerifyDiagnostics(); + + // Verify GetEnumerator + string src2 = """ +var enumerable = C.Produce(); +var enumerator = enumerable.GetEnumerator(); + +System.Console.Write(object.ReferenceEquals(enumerable, enumerator)); +System.Console.Write(!object.ReferenceEquals(enumerable, enumerable.GetEnumerator())); + +System.Console.Write(enumerator.MoveNext()); +System.Console.Write(!object.ReferenceEquals(enumerable, enumerable.GetEnumerator())); + +enumerator.Dispose(); + +System.Console.Write(object.ReferenceEquals(enumerable, enumerable.GetEnumerator())); + +enumerator.Dispose(); +enumerator.Dispose(); + +System.Console.Write(object.ReferenceEquals(enumerable, enumerable.GetEnumerator())); + +class C +{ + public static System.Collections.Generic.IEnumerable Produce() + { + yield return 42; + yield return 43; + } +} +"""; + CompileAndVerify(src2, expectedOutput: "TrueTrueTrueTrueTrueTrue").VerifyDiagnostics(); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/76078")] + public void StateAfterMoveNext_DisposeTwice() + { + // If the state of the enumerator object is after, invoking Dispose has no affect. + string src = """ +var enumerator = C.GetEnumerator(); + +System.Console.Write(enumerator.MoveNext()); +System.Console.Write(enumerator.Current); + +enumerator.Dispose(); +System.Console.Write("disposed "); + +enumerator.Dispose(); +System.Console.Write("disposed2 "); + +System.Console.Write(enumerator.MoveNext()); +System.Console.Write(enumerator.Current); + +class C +{ + public static System.Collections.Generic.IEnumerator GetEnumerator() + { + string local = ""; + yield return " one "; + local.ToString(); + } +} +"""; + // Note: we actually set the state to "after"/"finished" and cleanup hoisted locals again + var verifier = CompileAndVerify(src, expectedOutput: "True one disposed disposed2 False one").VerifyDiagnostics(); + verifier.VerifyIL("C.d__0.System.IDisposable.Dispose()", """ +{ + // Code size 16 (0x10) + .maxstack 2 + IL_0000: ldarg.0 + IL_0001: ldnull + IL_0002: stfld "string C.d__0.5__2" + IL_0007: ldarg.0 + IL_0008: ldc.i4.s -2 + IL_000a: stfld "int C.d__0.<>1__state" + IL_000f: ret +} +"""); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/76078")] + public void StateAfterMoveNext_YieldBreak() + { + // When a yield break statement is encountered ... The state of the enumerator object is changed to after. + string src = """ +var enumerator = C.GetEnumerator(true); + +System.Console.Write(enumerator.MoveNext()); +System.Console.Write(enumerator.Current); + +System.Console.Write(enumerator.MoveNext()); +System.Console.Write(enumerator.Current); + +System.Console.Write(enumerator.MoveNext()); +System.Console.Write(enumerator.Current); + +class C +{ + public static System.Collections.Generic.IEnumerator GetEnumerator(bool b) + { + yield return " one "; + if (b) yield break; + yield return " two "; + } +} +"""; + CompileAndVerify(src, expectedOutput: "True one False one False one").VerifyDiagnostics(); + + // Verify GetEnumerator + string src2 = """ +var enumerable = C.Produce(true); +var enumerator = enumerable.GetEnumerator(); + +System.Console.Write(enumerator.MoveNext()); +System.Console.Write(!object.ReferenceEquals(enumerable, enumerable.GetEnumerator())); + +System.Console.Write(!enumerator.MoveNext()); +System.Console.Write(object.ReferenceEquals(enumerable, enumerable.GetEnumerator())); + +class C +{ + public static System.Collections.Generic.IEnumerable Produce(bool b) + { + yield return 42; + if (b) yield break; + yield return 43; + } +} +"""; + // We're not setting the state to "after"/"finished" + // Tracked by https://github.com/dotnet/roslyn/issues/76089 + CompileAndVerify(src2, expectedOutput: "TrueTrueTrueFalse").VerifyDiagnostics(); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/76078")] + public void StateAfterMoveNext_EndOfBody() + { + // When the end of the iterator body is encountered ... The state of the enumerator object is changed to after. + string src = """ +var enumerator = C.GetEnumerator(true); + +System.Console.Write(enumerator.MoveNext()); +System.Console.Write(enumerator.Current); + +System.Console.Write(enumerator.MoveNext()); +System.Console.Write(enumerator.Current); + +System.Console.Write(enumerator.MoveNext()); +System.Console.Write(enumerator.Current); + +class C +{ + public static System.Collections.Generic.IEnumerator GetEnumerator(bool b) + { + yield return " one "; + System.Console.Write("done "); + } +} +"""; + CompileAndVerify(src, expectedOutput: "True one done False one False one").VerifyDiagnostics(); + + // Verify GetEnumerator + string src2 = """ +var enumerable = C.Produce(true); +var enumerator = enumerable.GetEnumerator(); + +System.Console.Write(enumerator.MoveNext()); +System.Console.Write(!object.ReferenceEquals(enumerable, enumerable.GetEnumerator())); + +System.Console.Write(!enumerator.MoveNext()); +System.Console.Write(object.ReferenceEquals(enumerable, enumerable.GetEnumerator())); + +class C +{ + public static System.Collections.Generic.IEnumerable Produce(bool b) + { + yield return 42; + } +} +"""; + // We're not setting the state to "after"/"finished" + // Tracked by https://github.com/dotnet/roslyn/issues/76089 + CompileAndVerify(src2, expectedOutput: "TrueTrueTrueFalse").VerifyDiagnostics(); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/76078")] + public void StateAfterMoveNext_ThrowException() + { + // When an exception is thrown and propagated out of the iterator block ... The state of the enumerator object is changed to after. + string src = """ +var enumerator = C.GetEnumerator(true); + +System.Console.Write(enumerator.MoveNext()); +System.Console.Write(enumerator.Current); + +try +{ + System.Console.Write(enumerator.MoveNext()); +} +catch (System.Exception e) +{ + System.Console.Write(e.Message); +} + +System.Console.Write(enumerator.Current); + +System.Console.Write(enumerator.MoveNext()); +System.Console.Write(enumerator.Current); + +class C +{ + public static System.Collections.Generic.IEnumerator GetEnumerator(bool b) + { + yield return " one "; + throw new System.Exception("exception"); + } +} +"""; + CompileAndVerify(src, expectedOutput: "True one exception one False one").VerifyDiagnostics(); + + // Verify GetEnumerator + string src2 = """ +var enumerable = C.Produce(); +var enumerator = enumerable.GetEnumerator(); + +System.Console.Write(enumerator.MoveNext()); +System.Console.Write(!object.ReferenceEquals(enumerable, enumerable.GetEnumerator())); + +try +{ + _ = enumerator.MoveNext(); +} +catch (System.Exception) +{ + System.Console.Write(object.ReferenceEquals(enumerable, enumerable.GetEnumerator())); +} + +enumerator.Dispose(); +System.Console.Write(object.ReferenceEquals(enumerable, enumerable.GetEnumerator())); + +class C +{ + public static System.Collections.Generic.IEnumerable Produce() + { + yield return 42; + throw new System.Exception("exception"); + } +} +"""; + // We're not setting the state to "after"/"finished" + // Tracked by https://github.com/dotnet/roslyn/issues/76089 + CompileAndVerify(src2, expectedOutput: "TrueTrueFalseTrue").VerifyDiagnostics(); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/76078")] + public void StateAfterMoveNext_YieldReturn_InTryFinally() + { + // When a yield return statement is encountered ... The state of the enumerator object is changed to suspended. + + // If the state of the enumerator object is suspended, invoking Dispose: + // ... + // Executes any finally blocks as if the last executed yield return statement were a yield break statement. + // If this causes an exception to be thrown and propagated out of the iterator body, + // the state of the enumerator object is set to after and the exception is propagated to the caller of the Dispose method. + string src = """ +var enumerator = C.GetEnumerator(); + +System.Console.Write(enumerator.MoveNext()); +System.Console.Write(enumerator.Current); + +System.Console.Write("disposing "); +try +{ + enumerator.Dispose(); +} +catch (System.Exception e) +{ + System.Console.Write(e.Message); +} +System.Console.Write(" disposed "); + +System.Console.Write(enumerator.MoveNext()); +System.Console.Write(enumerator.Current); + +class C +{ + public static System.Collections.Generic.IEnumerator GetEnumerator() + { + try + { + yield return " one "; + } + finally + { + throw new System.Exception("exception"); + } + } +} +"""; + var verifier = CompileAndVerify(src, expectedOutput: "True one disposing exception disposed False one").VerifyDiagnostics(); + verifier.VerifyIL("C.d__0.System.IDisposable.Dispose()", """ +{ + // Code size 35 (0x23) + .maxstack 2 + .locals init (int V_0) + IL_0000: ldarg.0 + IL_0001: ldfld "int C.d__0.<>1__state" + IL_0006: stloc.0 + IL_0007: ldloc.0 + IL_0008: ldc.i4.s -3 + IL_000a: beq.s IL_0010 + IL_000c: ldloc.0 + IL_000d: ldc.i4.1 + IL_000e: bne.un.s IL_001a + IL_0010: nop + .try + { + IL_0011: leave.s IL_001a + } + finally + { + IL_0013: ldarg.0 + IL_0014: call "void C.d__0.<>m__Finally1()" + IL_0019: endfinally + } + IL_001a: ldarg.0 + IL_001b: ldc.i4.s -2 + IL_001d: stfld "int C.d__0.<>1__state" + IL_0022: ret +} +"""); + verifier.VerifyIL("C.d__0.<>m__Finally1()", """ +{ + // Code size 18 (0x12) + .maxstack 2 + IL_0000: ldarg.0 + IL_0001: ldc.i4.m1 + IL_0002: stfld "int C.d__0.<>1__state" + IL_0007: ldstr "exception" + IL_000c: newobj "System.Exception..ctor(string)" + IL_0011: throw +} +"""); + + // Verify GetEnumerator + string src2 = """ +var enumerable = C.Produce(); +var enumerator = enumerable.GetEnumerator(); + +System.Console.Write(enumerator.MoveNext()); +System.Console.Write(!object.ReferenceEquals(enumerable, enumerable.GetEnumerator())); + +try +{ + enumerator.Dispose(); +} +catch (System.Exception) +{ + System.Console.Write(object.ReferenceEquals(enumerable, enumerable.GetEnumerator())); +} + +class C +{ + public static System.Collections.Generic.IEnumerable Produce() + { + try + { + yield return 42; + } + finally + { + throw new System.Exception("exception"); + } + } +} +"""; + // We're not setting the state to "after"/"finished" + // Tracked by https://github.com/dotnet/roslyn/issues/76089 + CompileAndVerify(src2, expectedOutput: "TrueTrueFalse").VerifyDiagnostics(); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/76078")] + public void StateAfterMoveNext_YieldBreak_InTryFinally() + { + // When a yield break statement is encountered: + // If the yield break statement is within one or more try blocks, the associated finally blocks are executed. + // The state of the enumerator object is changed to after. + string src = """ +var enumerator = C.GetEnumerator(true); + +System.Console.Write(enumerator.MoveNext()); +System.Console.Write(enumerator.Current); + +System.Console.Write(enumerator.MoveNext()); +System.Console.Write(enumerator.Current); + +System.Console.Write(enumerator.MoveNext()); +System.Console.Write(enumerator.Current); + +class C +{ + public static System.Collections.Generic.IEnumerator GetEnumerator(bool b) + { + yield return " one "; + try + { + if (b) yield break; + } + finally + { + System.Console.Write("finally "); + } + yield return " two "; + } +} +"""; + CompileAndVerify(src, expectedOutput: "True one finally False one False one").VerifyDiagnostics(); + + // Verify GetEnumerator + string src2 = """ +var enumerable = C.Produce(true); +var enumerator = enumerable.GetEnumerator(); + +System.Console.Write(enumerator.MoveNext()); +System.Console.Write(!object.ReferenceEquals(enumerable, enumerable.GetEnumerator())); + +System.Console.Write(!enumerator.MoveNext()); +System.Console.Write(object.ReferenceEquals(enumerable, enumerable.GetEnumerator())); + +class C +{ + public static System.Collections.Generic.IEnumerable Produce(bool b) + { + yield return 42; + try + { + if (b) yield break; + } + finally + { + System.Console.Write(" finally "); + } + yield return 43; + } +} +"""; + // We're not setting the state to "after"/"finished" + // Tracked by https://github.com/dotnet/roslyn/issues/76089 + CompileAndVerify(src2, expectedOutput: "TrueTrue finally TrueFalse").VerifyDiagnostics(); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/76078")] + public void StateAfterMoveNext_ThrowException_InTryFinally() + { + // When an exception is thrown and propagated out of the iterator block: ... The state of the enumerator object is changed to after. + string src = """ +var enumerator = C.GetEnumerator(true); + +System.Console.Write(enumerator.MoveNext()); +System.Console.Write(enumerator.Current); + +try +{ + System.Console.Write(enumerator.MoveNext()); +} +catch (System.Exception e) +{ + System.Console.Write(e.Message); +} + +System.Console.Write(enumerator.Current); + +System.Console.Write(enumerator.MoveNext()); +System.Console.Write(enumerator.Current); + +enumerator.Dispose(); + +System.Console.Write(enumerator.MoveNext()); +System.Console.Write(enumerator.Current); + +class C +{ + public static System.Collections.Generic.IEnumerator GetEnumerator(bool b) + { + yield return " one "; + try + { + throw new System.Exception("exception"); + } + finally + { + System.Console.Write("finally "); + } + } +} +"""; + CompileAndVerify(src, expectedOutput: "True one finally exception one False one False one").VerifyDiagnostics(); + + // Verify GetEnumerator + string src2 = """ +var enumerable = C.Produce(); +var enumerator = enumerable.GetEnumerator(); + +System.Console.Write(enumerator.MoveNext()); + +try +{ + _ = enumerator.MoveNext(); +} +catch (System.Exception) +{ + System.Console.Write(object.ReferenceEquals(enumerable, enumerable.GetEnumerator())); +} + +enumerator.Dispose(); +System.Console.Write(object.ReferenceEquals(enumerable, enumerable.GetEnumerator())); + +class C +{ + public static System.Collections.Generic.IEnumerable Produce() + { + yield return 42; + try + { + throw new System.Exception("exception"); + } + finally + { + System.Console.Write(" finally "); + } + } +} +"""; + // We're not setting the state to "after"/"finished" + // Tracked by https://github.com/dotnet/roslyn/issues/76089 + CompileAndVerify(src2, expectedOutput: "True finally FalseTrue").VerifyDiagnostics(); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/76078")] + public void StateAfterMoveNext_ThrowException_InTryFinally_WithYieldInTry() + { + // When an exception is thrown and propagated out of the iterator block: ... The state of the enumerator object is changed to after. + string src = """ +var enumerator = C.GetEnumerator(true); + +System.Console.Write(enumerator.MoveNext()); +System.Console.Write(enumerator.Current); + +try +{ + System.Console.Write(enumerator.MoveNext()); +} +catch (System.Exception e) +{ + System.Console.Write(e.Message); +} + +System.Console.Write(enumerator.Current); + +System.Console.Write(enumerator.MoveNext()); +System.Console.Write(enumerator.Current); + +class C +{ + public static System.Collections.Generic.IEnumerator GetEnumerator(bool b) + { + try + { + yield return " one "; + if (b) throw new System.Exception("exception"); + } + finally + { + System.Console.Write("finally "); + } + } +} +"""; + // Note: we generate a `fault { Dispose(); }`, but only if there is a `yield` in a `try`, which is surprising + var verifier = CompileAndVerify(src, expectedOutput: "True one finally exception one False one").VerifyDiagnostics(); + verifier.VerifyIL("C.d__0.System.Collections.IEnumerator.MoveNext()", """ +{ + // Code size 101 (0x65) + .maxstack 2 + .locals init (bool V_0, + int V_1) + .try + { + IL_0000: ldarg.0 + IL_0001: ldfld "int C.d__0.<>1__state" + IL_0006: stloc.1 + IL_0007: ldloc.1 + IL_0008: brfalse.s IL_0012 + IL_000a: ldloc.1 + IL_000b: ldc.i4.1 + IL_000c: beq.s IL_0037 + IL_000e: ldc.i4.0 + IL_000f: stloc.0 + IL_0010: leave.s IL_0063 + IL_0012: ldarg.0 + IL_0013: ldc.i4.m1 + IL_0014: stfld "int C.d__0.<>1__state" + IL_0019: ldarg.0 + IL_001a: ldc.i4.s -3 + IL_001c: stfld "int C.d__0.<>1__state" + IL_0021: ldarg.0 + IL_0022: ldstr " one " + IL_0027: stfld "string C.d__0.<>2__current" + IL_002c: ldarg.0 + IL_002d: ldc.i4.1 + IL_002e: stfld "int C.d__0.<>1__state" + IL_0033: ldc.i4.1 + IL_0034: stloc.0 + IL_0035: leave.s IL_0063 + IL_0037: ldarg.0 + IL_0038: ldc.i4.s -3 + IL_003a: stfld "int C.d__0.<>1__state" + IL_003f: ldarg.0 + IL_0040: ldfld "bool C.d__0.b" + IL_0045: brfalse.s IL_0052 + IL_0047: ldstr "exception" + IL_004c: newobj "System.Exception..ctor(string)" + IL_0051: throw + IL_0052: ldarg.0 + IL_0053: call "void C.d__0.<>m__Finally1()" + IL_0058: ldc.i4.0 + IL_0059: stloc.0 + IL_005a: leave.s IL_0063 + } + fault + { + IL_005c: ldarg.0 + IL_005d: call "void C.d__0.Dispose()" + IL_0062: endfinally + } + IL_0063: ldloc.0 + IL_0064: ret +} +"""); + + verifier.VerifyIL("C.d__0.System.IDisposable.Dispose()", """ +{ + // Code size 35 (0x23) + .maxstack 2 + .locals init (int V_0) + IL_0000: ldarg.0 + IL_0001: ldfld "int C.d__0.<>1__state" + IL_0006: stloc.0 + IL_0007: ldloc.0 + IL_0008: ldc.i4.s -3 + IL_000a: beq.s IL_0010 + IL_000c: ldloc.0 + IL_000d: ldc.i4.1 + IL_000e: bne.un.s IL_001a + IL_0010: nop + .try + { + IL_0011: leave.s IL_001a + } + finally + { + IL_0013: ldarg.0 + IL_0014: call "void C.d__0.<>m__Finally1()" + IL_0019: endfinally + } + IL_001a: ldarg.0 + IL_001b: ldc.i4.s -2 + IL_001d: stfld "int C.d__0.<>1__state" + IL_0022: ret +} +"""); + + // Verify GetEnumerator + string src2 = """ +var enumerable = C.Produce(); +var enumerator = enumerable.GetEnumerator(); + +System.Console.Write(enumerator.MoveNext()); + +try +{ + _ = enumerator.MoveNext(); +} +catch (System.Exception) +{ + System.Console.Write(object.ReferenceEquals(enumerable, enumerable.GetEnumerator())); +} + +class C +{ + public static System.Collections.Generic.IEnumerable Produce() + { + try + { + yield return 42; + throw new System.Exception("exception"); + } + finally + { + System.Console.Write(" finally "); + } + } +} +"""; + CompileAndVerify(src2, expectedOutput: "True finally True").VerifyDiagnostics(); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/76078")] + public void StateAfterMoveNext_YieldReturn_AfterTryFinally() + { + string src = """ +var enumerator = C.GetEnumerator(true); + +System.Console.Write(enumerator.MoveNext()); +System.Console.Write(enumerator.Current); + +System.Console.Write(enumerator.MoveNext()); +System.Console.Write(enumerator.Current); + +enumerator.Dispose(); + +System.Console.Write(enumerator.MoveNext()); +System.Console.Write(enumerator.Current); + +class C +{ + public static System.Collections.Generic.IEnumerator GetEnumerator(bool b) + { + try + { + yield return " one "; + } + finally + { + System.Console.Write("finally "); + } + + yield return " two "; + System.Console.Write("not executed after disposal"); + } +} +"""; + CompileAndVerify(src, expectedOutput: "True one finally True two False two").VerifyDiagnostics(); + + // Verify GetEnumerator + string src2 = """ +var enumerable = C.Produce(); +var enumerator = enumerable.GetEnumerator(); + +System.Console.Write(enumerator.MoveNext()); +System.Console.Write(enumerator.MoveNext()); + +enumerator.Dispose(); +System.Console.Write(object.ReferenceEquals(enumerable, enumerable.GetEnumerator())); + +class C +{ + public static System.Collections.Generic.IEnumerable Produce() + { + try + { + yield return 42; + } + finally + { + System.Console.Write(" finally "); + } + + yield return 43; + System.Console.Write("not executed after disposal"); + } +} +"""; + CompileAndVerify(src2, expectedOutput: "True finally TrueTrue").VerifyDiagnostics(); + } } } diff --git a/src/Compilers/CSharp/Test/Emit2/CodeGen/CodeGenMethodGroupConversionCachingTests.cs b/src/Compilers/CSharp/Test/Emit2/CodeGen/CodeGenMethodGroupConversionCachingTests.cs index 891ff106afb8e..877c8042eb162 100644 --- a/src/Compilers/CSharp/Test/Emit2/CodeGen/CodeGenMethodGroupConversionCachingTests.cs +++ b/src/Compilers/CSharp/Test/Emit2/CodeGen/CodeGenMethodGroupConversionCachingTests.cs @@ -6349,6 +6349,47 @@ .locals init (C1.F V_0) //x "); } + [Fact] + public void CompilerLoweringPreserveAttribute_01() + { + string source1 = @" +using System; +using System.Runtime.CompilerServices; + +[CompilerLoweringPreserve] +[AttributeUsage(AttributeTargets.GenericParameter)] +public class Preserve1Attribute : Attribute { } + +[AttributeUsage(AttributeTargets.GenericParameter)] +public class Preserve2Attribute : Attribute { } +"; + + string source2 = @" +class Test1 +{ + System.Action M2<[Preserve1][Preserve2]T>() + { + return (System.Action)D.Target; + } +} + +class D +{ + public static void Target() { } +} + +"; + var comp1 = CreateCompilation([source1, source2, CompilerLoweringPreserveAttributeDefinition]); + CompileAndVerify(comp1, symbolValidator: validate).VerifyDiagnostics(); + + static void validate(ModuleSymbol m) + { + AssertEx.SequenceEqual( + ["Preserve1Attribute"], + m.GlobalNamespace.GetMember("Test1.O__0_0").TypeParameters.Single().GetAttributes().Select(a => a.ToString())); + } + } + private static Action VerifyCacheContainer(string typeName, int arity, params string[] expectedFields) { return module => diff --git a/src/Compilers/CSharp/Test/Emit2/Emit/EditAndContinue/EditAndContinueStateMachineTests.cs b/src/Compilers/CSharp/Test/Emit2/Emit/EditAndContinue/EditAndContinueStateMachineTests.cs index 41169ac72a8ff..374d2e0ff27ba 100644 --- a/src/Compilers/CSharp/Test/Emit2/Emit/EditAndContinue/EditAndContinueStateMachineTests.cs +++ b/src/Compilers/CSharp/Test/Emit2/Emit/EditAndContinue/EditAndContinueStateMachineTests.cs @@ -19,6 +19,7 @@ namespace Microsoft.CodeAnalysis.CSharp.EditAndContinue.UnitTests { + [CompilerTrait(CompilerFeature.Iterator, CompilerFeature.Async, CompilerFeature.AsyncStreams)] public class EditAndContinueStateMachineTests(ITestOutputHelper logger) : EditAndContinueTestBase { private readonly ITestOutputHelper _logger = logger; @@ -4747,7 +4748,7 @@ .maxstack 2 v0.VerifyIL("C.d__0.System.IDisposable.Dispose", @" { - // Code size 33 (0x21) + // Code size 41 (0x29) .maxstack 2 .locals init (int V_0) IL_0000: ldarg.0 @@ -4773,12 +4774,15 @@ .locals init (int V_0) IL_001d: endfinally } IL_001e: br.s IL_0020 - IL_0020: ret + IL_0020: ldarg.0 + IL_0021: ldc.i4.s -2 + IL_0023: stfld ""int C.d__0.<>1__state"" + IL_0028: ret } "); diff1.VerifyIL("C.d__0.System.IDisposable.Dispose", @" { - // Code size 108 (0x6c) + // Code size 116 (0x74) .maxstack 2 .locals init (int V_0) IL_0000: ldarg.0 @@ -4843,7 +4847,10 @@ .locals init (int V_0) IL_0068: endfinally } IL_0069: br.s IL_006b - IL_006b: ret + IL_006b: ldarg.0 + IL_006c: ldc.i4.s -2 + IL_006e: stfld ""int C.d__0.<>1__state"" + IL_0073: ret } "); @@ -5176,7 +5183,7 @@ .maxstack 2 v0.VerifyIL("C.d__0.System.IDisposable.Dispose", @" { - // Code size 40 (0x28) + // Code size 48 (0x30) .maxstack 2 .locals init (int V_0) IL_0000: ldarg.0 @@ -5205,12 +5212,15 @@ .locals init (int V_0) IL_0020: ldarg.0 IL_0021: ldnull IL_0022: stfld ""System.IDisposable C.d__0.5__1"" - IL_0027: ret + IL_0027: ldarg.0 + IL_0028: ldc.i4.s -2 + IL_002a: stfld ""int C.d__0.<>1__state"" + IL_002f: ret } "); diff1.VerifyIL("C.d__0.System.IDisposable.Dispose", @" { - // Code size 42 (0x2a) + // Code size 50 (0x32) .maxstack 2 .locals init (int V_0) IL_0000: ldarg.0 @@ -5241,7 +5251,10 @@ .locals init (int V_0) IL_0022: ldarg.0 IL_0023: ldnull IL_0024: stfld ""System.IDisposable C.d__0.5__1"" - IL_0029: ret + IL_0029: ldarg.0 + IL_002a: ldc.i4.s -2 + IL_002c: stfld ""int C.d__0.<>1__state"" + IL_0031: ret } "); diff --git a/src/Compilers/CSharp/Test/Emit3/Attributes/AttributeTests_Embedded.cs b/src/Compilers/CSharp/Test/Emit3/Attributes/AttributeTests_Embedded.cs index eafec86eced6d..b3cd39c9e4fc7 100644 --- a/src/Compilers/CSharp/Test/Emit3/Attributes/AttributeTests_Embedded.cs +++ b/src/Compilers/CSharp/Test/Emit3/Attributes/AttributeTests_Embedded.cs @@ -7,6 +7,8 @@ using Microsoft.CodeAnalysis.CSharp.Symbols; using Microsoft.CodeAnalysis.CSharp.Test.Utilities; using Microsoft.CodeAnalysis.Test.Utilities; +using Roslyn.Test.Utilities; +using System.Collections.Generic; using System.Linq; using Xunit; @@ -20,7 +22,7 @@ public void ReferencingEmbeddedAttributesFromTheSameAssemblySucceeds() var code = @" namespace Microsoft.CodeAnalysis { - internal class EmbeddedAttribute : System.Attribute { } + internal sealed class EmbeddedAttribute : System.Attribute { } } namespace TestReference { @@ -91,7 +93,7 @@ public void ReferencingEmbeddedAttributesFromADifferentAssemblyFails_Module() var module = CreateCompilation(@" namespace Microsoft.CodeAnalysis { - internal class EmbeddedAttribute : System.Attribute { } + internal sealed class EmbeddedAttribute : System.Attribute { } } namespace TestReference { @@ -171,7 +173,7 @@ public void EmbeddedAttributeInSourceIsAllowedIfCompilerDoesNotNeedToGenerateOne var code = @" namespace Microsoft.CodeAnalysis { - public class EmbeddedAttribute : System.Attribute { } + internal sealed class EmbeddedAttribute : System.Attribute { } } namespace OtherNamespace { @@ -193,61 +195,488 @@ public static void Main() CompileAndVerify(code, parseOptions: TestOptions.Regular.WithNoRefSafetyRulesAttribute(), verify: Verification.Passes, expectedOutput: "3"); } + [Theory] + [CombinatorialData] + public void EmbeddedAttributeFromSourceValidation_Valid( + [CombinatorialValues("internal", "public")] string ctorAccessModifier, + [CombinatorialValues( + "System.AttributeTargets.Class | System.AttributeTargets.Struct | System.AttributeTargets.Interface | System.AttributeTargets.Enum | System.AttributeTargets.Delegate", + "System.AttributeTargets.All", + "")] + string targetsList) + { + var targets = targetsList != "" ? $", System.AttributeUsage({targetsList})" : ""; + + var code = $$""" + namespace Microsoft.CodeAnalysis + { + [Embedded{{targets}}] + internal sealed class EmbeddedAttribute : System.Attribute + { + {{ctorAccessModifier}} EmbeddedAttribute() { } + } + } + + [Microsoft.CodeAnalysis.Embedded] + public class Test + { + public static void Main() + { + M(1); + } + + public static void M(in int p) + { + System.Console.WriteLine("M"); + } + } + """; + + var verifier = CompileAndVerify(code, targetFramework: TargetFramework.NetStandard20, expectedOutput: "M", symbolValidator: module => + { + var embeddedAttribute = module.ContainingAssembly.GetTypeByMetadataName(AttributeDescription.CodeAnalysisEmbeddedAttribute.FullName); + Assert.NotNull(embeddedAttribute); + Assert.Equal("Microsoft.CodeAnalysis.EmbeddedAttribute", embeddedAttribute.GetAttributes().Single(a => a.AttributeClass.Name != "AttributeUsageAttribute").AttributeClass.ToTestDisplayString()); + }); + + verifier.VerifyDiagnostics(); + + var reference = verifier.Compilation.EmitToImageReference(); + + var comp2 = CreateCompilation(""" + Test.M(1); + """, references: [reference], targetFramework: TargetFramework.NetStandard20); + + comp2.VerifyDiagnostics( + // (1,1): error CS0103: The name 'Test' does not exist in the current context + // Test.M(1); + Diagnostic(ErrorCode.ERR_NameNotInContext, "Test").WithArguments("Test").WithLocation(1, 1)); + + comp2 = CreateCompilation(""" + public class Test + { + public static void M(in int p) {} + } + """, references: [reference], targetFramework: TargetFramework.NetStandard20); + + CompileAndVerify(comp2, symbolValidator: module => + { + var embeddedAttribute = module.ContainingAssembly.GetTypeByMetadataName(AttributeDescription.CodeAnalysisEmbeddedAttribute.FullName); + Assert.NotNull(embeddedAttribute); + Assert.Equal(["System.Runtime.CompilerServices.CompilerGeneratedAttribute", "Microsoft.CodeAnalysis.EmbeddedAttribute"], embeddedAttribute.GetAttributes().Select(a => a.AttributeClass.ToTestDisplayString())); + }).VerifyDiagnostics(); + } + [Fact] - public void EmbeddedAttributeInSourceShouldTriggerAnErrorIfCompilerNeedsToGenerateOne() + public void EmbeddedAttributeFromSourceValidation_Public() { - var code = @" -namespace Microsoft.CodeAnalysis -{ - public class EmbeddedAttribute : System.Attribute { } -} -class Test -{ - public void M(in int p) - { - // This should trigger generating another EmbeddedAttribute - } -}"; + var code = """ + namespace Microsoft.CodeAnalysis + { + [Embedded] + public sealed class EmbeddedAttribute : System.Attribute + { + public EmbeddedAttribute() { } + } + } + class Test + { + public void M(in int p) + { + // This would trigger generating another EmbeddedAttribute, if we hadn't already defined one + } + } + """; + + CreateCompilation(code, assemblyName: "testModule", targetFramework: TargetFramework.NetStandard20).VerifyEmitDiagnostics( + // (4,25): error CS9271: The type 'Microsoft.CodeAnalysis.EmbeddedAttribute' must be non-generic, internal, sealed, non-static, have a parameterless constructor, inherit from System.Attribute, and be able to be applied to any type. + // public sealed class EmbeddedAttribute : System.Attribute + Diagnostic(ErrorCode.ERR_EmbeddedAttributeMustFollowPattern, "EmbeddedAttribute").WithLocation(4, 25)); + } - CreateCompilation(code, assemblyName: "testModule").VerifyEmitDiagnostics( - // (4,18): error CS8336: The type name 'Microsoft.CodeAnalysis.EmbeddedAttribute' is reserved to be used by the compiler. - // public class EmbeddedAttribute : System.Attribute { } - Diagnostic(ErrorCode.ERR_TypeReserved, "EmbeddedAttribute").WithArguments("Microsoft.CodeAnalysis.EmbeddedAttribute").WithLocation(4, 18)); + [Fact] + public void EmbeddedAttributeFromSourceValidation_NoSealed() + { + var code = """ + namespace Microsoft.CodeAnalysis + { + [Embedded] + internal class EmbeddedAttribute : System.Attribute + { + public EmbeddedAttribute() { } + } + } + class Test + { + public void M(in int p) + { + // This would trigger generating another EmbeddedAttribute, if we hadn't already defined one + } + } + """; + + CreateCompilation(code, assemblyName: "testModule", targetFramework: TargetFramework.NetStandard20).VerifyEmitDiagnostics( + // (4,20): error CS9271: The type 'Microsoft.CodeAnalysis.EmbeddedAttribute' must be non-generic, internal, sealed, non-static, have a parameterless constructor, inherit from System.Attribute, and be able to be applied to any type. + // internal class EmbeddedAttribute : System.Attribute + Diagnostic(ErrorCode.ERR_EmbeddedAttributeMustFollowPattern, "EmbeddedAttribute").WithLocation(4, 20)); } [Fact] - public void EmbeddedAttributeInReferencedModuleShouldTriggerAnErrorIfCompilerNeedsToGenerateOne() + public void EmbeddedAttributeFromSourceValidation_File() { - var module = CreateCompilation(options: TestOptions.ReleaseModule, assemblyName: "testModule", source: @" -namespace Microsoft.CodeAnalysis -{ - public class EmbeddedAttribute : System.Attribute { } -}"); + var code = """ + namespace Microsoft.CodeAnalysis + { + [Embedded] + file sealed class EmbeddedAttribute : System.Attribute + { + public EmbeddedAttribute() { } + } + } + class Test + { + public void M(in int p) + { + // This would trigger generating another EmbeddedAttribute, if we hadn't already defined one + } + } + """; + + var verifier = CompileAndVerify(code, targetFramework: TargetFramework.NetStandard20, symbolValidator: module => + { + var codeAnalysisNamespace = (NamespaceSymbol)module.GlobalNamespace.GetMember("Microsoft.CodeAnalysis"); + var embeddedAttributes = codeAnalysisNamespace.GetMembers("EmbeddedAttribute").Cast().ToArray(); + Assert.Equal(2, embeddedAttributes.Length); + var embeddedAttribute = embeddedAttributes.Where(t => !t.IsFileLocal).Single(); + Assert.NotNull(embeddedAttribute); + Assert.Equal("Microsoft.CodeAnalysis.EmbeddedAttribute", embeddedAttribute.ToTestDisplayString()); + + var embeddedAttributeFile = embeddedAttributes.Where(t => t.IsFileLocal).Single(); + Assert.NotNull(embeddedAttributeFile); + Assert.Equal("Microsoft.CodeAnalysis.EmbeddedAttribute@", embeddedAttributeFile.ToTestDisplayString()); + Assert.NotSame(embeddedAttribute, embeddedAttributeFile); + + AssertEx.Equal("Microsoft.CodeAnalysis.EmbeddedAttribute@", embeddedAttributeFile.GetAttributes().Single().AttributeClass.ToTestDisplayString()); + }); + } - var moduleRef = ModuleMetadata.CreateFromImage(module.EmitToArray()).GetReference(); + [Theory] + [InlineData("private")] + [InlineData("protected")] + [InlineData("protected internal")] + [InlineData("private protected")] + public void EmbeddedAttributeFromSourceValidation_CtorAccessibility(string ctorAccessModifier) + { + var code = $$""" + namespace Microsoft.CodeAnalysis + { + [Embedded] + internal sealed class EmbeddedAttribute : System.Attribute + { + {{ctorAccessModifier}} EmbeddedAttribute() { } + } + } + class Test + { + public void M(in int p) + { + // This would trigger generating another EmbeddedAttribute, if we hadn't already defined one + } + } + """; + + List diagnostics = [ + // (4,27): error CS9271: The type 'Microsoft.CodeAnalysis.EmbeddedAttribute' must be non-generic, internal, sealed, non-static, have a parameterless constructor, inherit from System.Attribute, and be able to be applied to any type. + // internal sealed class EmbeddedAttribute : System.Attribute + Diagnostic(ErrorCode.ERR_EmbeddedAttributeMustFollowPattern, "EmbeddedAttribute").WithLocation(4, 27), + ]; + + if (ctorAccessModifier != "private") + { + diagnostics.Add( + // (6,27): warning CS0628: 'EmbeddedAttribute.EmbeddedAttribute()': new protected member declared in sealed type + // private protected EmbeddedAttribute() { } + Diagnostic(ErrorCode.WRN_ProtectedInSealed, "EmbeddedAttribute").WithArguments("Microsoft.CodeAnalysis.EmbeddedAttribute.EmbeddedAttribute()").WithLocation(6, 10 + ctorAccessModifier.Length) + ); + } + + CreateCompilation(code, assemblyName: "testModule", targetFramework: TargetFramework.NetStandard20) + .VerifyEmitDiagnostics(diagnostics.ToArray()); + } - var code = @" -class Test -{ - public void M(in int p) - { - // This should trigger generating another EmbeddedAttribute - } -}"; + [Theory, CombinatorialData] + public void EmbeddedAttributeFromSourceValidation_MissingEmbeddedAttributeApplicationGeneratesAttributeApplication(bool hasObsolete) + { + var code = $$""" + namespace Microsoft.CodeAnalysis + { + {{(hasObsolete ? "[System.Obsolete]" : "")}} + internal sealed class EmbeddedAttribute : System.Attribute + { + public EmbeddedAttribute() { } + } + } + class Test + { + public void M(in int p) + { + // This would trigger generating EmbeddedAttribute if we hadn't defined one + } + } + """; + + var comp = CreateCompilation(code, assemblyName: "testModule", targetFramework: TargetFramework.NetStandard20); + var embeddedAttribute = comp.Assembly.GetTypeByMetadataName(AttributeDescription.CodeAnalysisEmbeddedAttribute.FullName); + Assert.True(embeddedAttribute.HasCodeAnalysisEmbeddedAttribute); + + CompileAndVerify(comp, symbolValidator: static module => + { + var embeddedAttribute = module.ContainingAssembly.GetTypeByMetadataName(AttributeDescription.CodeAnalysisEmbeddedAttribute.FullName); + Assert.NotNull(embeddedAttribute); + Assert.Equal(["Microsoft.CodeAnalysis.EmbeddedAttribute"], embeddedAttribute.GetAttributes().Where(a => a.AttributeClass.Name != "ObsoleteAttribute").Select(a => a.AttributeClass.ToTestDisplayString())); + }) + .VerifyDiagnostics(); + } - CreateCompilation(code, references: new[] { moduleRef }).VerifyEmitDiagnostics( - // error CS8004: Type 'EmbeddedAttribute' exported from module 'testModule.netmodule' conflicts with type declared in primary module of this assembly. - Diagnostic(ErrorCode.ERR_ExportedTypeConflictsWithDeclaration).WithArguments("Microsoft.CodeAnalysis.EmbeddedAttribute", "testModule.netmodule").WithLocation(1, 1)); + [Fact] + public void EmbeddedAttributeFromSourceValidation_MissingEmbeddedAttributeApplicationGeneratesAttributeApplication_Partial() + { + var code = """ + namespace Microsoft.CodeAnalysis + { + internal sealed partial class EmbeddedAttribute : System.Attribute + { + } + } + """; + + var comp = CreateCompilation([code, code]); + var sourceDeclaration = comp.SourceAssembly.GetTypeByMetadataName("Microsoft.CodeAnalysis.EmbeddedAttribute"); + + Assert.Equal(2, sourceDeclaration.Locations.Length); + + CompileAndVerify(comp, symbolValidator: module => + { + var embeddedAttribute = module.ContainingAssembly.GetTypeByMetadataName(AttributeDescription.CodeAnalysisEmbeddedAttribute.FullName); + Assert.NotNull(embeddedAttribute); + Assert.Equal("Microsoft.CodeAnalysis.EmbeddedAttribute", embeddedAttribute.GetAttributes().Single().AttributeClass.ToTestDisplayString()); + }).VerifyDiagnostics(); + } + + [Fact] + public void EmbeddedAttributeFromSourceValidation_Generic() + { + var code = """ + namespace Microsoft.CodeAnalysis + { + [Embedded] + internal sealed class EmbeddedAttribute : System.Attribute + { + public EmbeddedAttribute() { } + } + } + class Test + { + public void M(in int p) + { + // This should trigger generating another EmbeddedAttribute + } + } + """; + + var comp = CreateCompilation(code, assemblyName: "testModule", targetFramework: TargetFramework.NetStandard20); + CompileAndVerify(comp, symbolValidator: verifyModule).VerifyDiagnostics(); + + static void verifyModule(ModuleSymbol module) + { + var nonGenericAttribute = module.ContainingAssembly.GetTypeByMetadataName(AttributeDescription.CodeAnalysisEmbeddedAttribute.FullName); + Assert.NotNull(nonGenericAttribute); + Assert.Equal("Microsoft.CodeAnalysis.EmbeddedAttribute", nonGenericAttribute.ToTestDisplayString()); + + var genericAttribute = module.ContainingAssembly.GetTypeByMetadataName(AttributeDescription.CodeAnalysisEmbeddedAttribute.FullName + "`1"); + Assert.NotNull(genericAttribute); + Assert.Equal("Microsoft.CodeAnalysis.EmbeddedAttribute", genericAttribute.ToTestDisplayString()); + + var isReadonlyAttribute = module.ContainingAssembly.GetTypeByMetadataName(AttributeDescription.IsReadOnlyAttribute.FullName); + Assert.NotNull(isReadonlyAttribute); + AssertEx.Equal("Microsoft.CodeAnalysis.EmbeddedAttribute", isReadonlyAttribute.GetAttributes().Single(a => a.AttributeClass.Name == "EmbeddedAttribute").AttributeClass.ToTestDisplayString()); + } + } + + [Fact] + public void EmbeddedAttributeFromSourceValidation_Generic_BothDefined() + { + var code = """ + namespace Microsoft.CodeAnalysis + { + [Embedded] + internal sealed class EmbeddedAttribute : System.Attribute + { + public EmbeddedAttribute() { } + } + + internal sealed class EmbeddedAttribute : System.Attribute {} + } + class Test + { + public void M(in int p) + { + // This would trigger generating another EmbeddedAttribute, if we hadn't already defined one + } + } + """; + + var comp = CreateCompilation(code, assemblyName: "testModule", targetFramework: TargetFramework.NetStandard20); + CompileAndVerify(comp, symbolValidator: verifyModule).VerifyDiagnostics(); + + static void verifyModule(ModuleSymbol module) + { + var nonGenericAttribute = module.ContainingAssembly.GetTypeByMetadataName(AttributeDescription.CodeAnalysisEmbeddedAttribute.FullName); + Assert.NotNull(nonGenericAttribute); + Assert.Equal("Microsoft.CodeAnalysis.EmbeddedAttribute", nonGenericAttribute.ToTestDisplayString()); + + var genericAttribute = module.ContainingAssembly.GetTypeByMetadataName(AttributeDescription.CodeAnalysisEmbeddedAttribute.FullName + "`1"); + Assert.NotNull(genericAttribute); + Assert.Equal("Microsoft.CodeAnalysis.EmbeddedAttribute", genericAttribute.ToTestDisplayString()); + + var isReadonlyAttribute = module.ContainingAssembly.GetTypeByMetadataName(AttributeDescription.IsReadOnlyAttribute.FullName); + Assert.NotNull(isReadonlyAttribute); + AssertEx.Equal("Microsoft.CodeAnalysis.EmbeddedAttribute", isReadonlyAttribute.GetAttributes().Single(a => a.AttributeClass.Name == "EmbeddedAttribute").AttributeClass.ToTestDisplayString()); + } + } + + [Fact] + public void EmbeddedAttributeFromSourceValidation_Static() + { + var code = """ + namespace Microsoft.CodeAnalysis + { + [Embedded] + internal sealed static class EmbeddedAttribute : System.Attribute + { + } + } + class Test + { + public void M(in int p) + { + // This would trigger generating another EmbeddedAttribute, if we hadn't already defined one + } + } + """; + + CreateCompilation(code, assemblyName: "testModule", targetFramework: TargetFramework.NetStandard20).VerifyEmitDiagnostics( + // (3,6): error CS0616: 'EmbeddedAttribute' is not an attribute class + // [Embedded] + Diagnostic(ErrorCode.ERR_NotAnAttributeClass, "Embedded").WithArguments("Microsoft.CodeAnalysis.EmbeddedAttribute").WithLocation(3, 6), + // (4,34): error CS0441: 'EmbeddedAttribute': a type cannot be both static and sealed + // internal sealed static class EmbeddedAttribute : System.Attribute + Diagnostic(ErrorCode.ERR_SealedStaticClass, "EmbeddedAttribute").WithArguments("Microsoft.CodeAnalysis.EmbeddedAttribute").WithLocation(4, 34), + // (4,34): error CS9271: The type 'Microsoft.CodeAnalysis.EmbeddedAttribute' must be non-generic, internal, sealed, non-static, have a parameterless constructor, inherit from System.Attribute, and be able to be applied to any type. + // internal sealed static class EmbeddedAttribute : System.Attribute + Diagnostic(ErrorCode.ERR_EmbeddedAttributeMustFollowPattern, "EmbeddedAttribute").WithLocation(4, 34), + // (4,54): error CS0713: Static class 'EmbeddedAttribute' cannot derive from type 'Attribute'. Static classes must derive from object. + // internal sealed static class EmbeddedAttribute : System.Attribute + Diagnostic(ErrorCode.ERR_StaticDerivedFromNonObject, "System.Attribute").WithArguments("Microsoft.CodeAnalysis.EmbeddedAttribute", "System.Attribute").WithLocation(4, 54)); + } + + [Fact] + public void EmbeddedAttributeFromSourceValidation_WrongBaseType() + { + var code = """ + namespace Microsoft.CodeAnalysis + { + [Embedded] + internal sealed class EmbeddedAttribute + { + public EmbeddedAttribute() { } + } + } + class Test + { + public void M(in int p) + { + // This would trigger generating another EmbeddedAttribute, if we hadn't already defined one + } + } + """; + + CreateCompilation(code, assemblyName: "testModule", targetFramework: TargetFramework.NetStandard20).VerifyEmitDiagnostics( + // (3,6): error CS0616: 'EmbeddedAttribute' is not an attribute class + // [Embedded] + Diagnostic(ErrorCode.ERR_NotAnAttributeClass, "Embedded").WithArguments("Microsoft.CodeAnalysis.EmbeddedAttribute").WithLocation(3, 6), + // (4,27): error CS9271: The type 'Microsoft.CodeAnalysis.EmbeddedAttribute' must be non-generic, internal, sealed, non-static, have a parameterless constructor, inherit from System.Attribute, and be able to be applied to any type. + // internal sealed class EmbeddedAttribute + Diagnostic(ErrorCode.ERR_EmbeddedAttributeMustFollowPattern, "EmbeddedAttribute").WithLocation(4, 27)); + } + + [Theory] + [InlineData("AttributeTargets.Struct | AttributeTargets.Interface | AttributeTargets.Enum | AttributeTargets.Delegate")] + [InlineData("AttributeTargets.Class | AttributeTargets.Interface | AttributeTargets.Enum | AttributeTargets.Delegate")] + [InlineData("AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Enum | AttributeTargets.Delegate")] + [InlineData("AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Interface | AttributeTargets.Delegate")] + [InlineData("AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Interface | AttributeTargets.Enum")] + public void EmbeddedAttributeFromSourceValidation_AttributeUsage(string targets) + { + var code = $$""" + using System; + namespace Microsoft.CodeAnalysis + { + [Embedded, AttributeUsage({{targets}})] + internal sealed class EmbeddedAttribute : System.Attribute + { + internal EmbeddedAttribute() { } + } + } + class Test + { + public void M(in int p) + { + // This would trigger generating EmbeddedAttribute if we hadn't defined one + } + } + """; + + List diagnostics = []; + if (!targets.Contains("Class")) + { + diagnostics.Add( + // (4,6): error CS0592: Attribute 'Embedded' is not valid on this declaration type. It is only valid on 'struct, enum, interface, delegate' declarations. + // [Embedded, AttributeUsage(AttributeTargets.Struct | AttributeTargets.Interface | AttributeTargets.Enum | AttributeTargets.Delegate)] + Diagnostic(ErrorCode.ERR_AttributeOnBadSymbolType, "Embedded").WithArguments("Embedded", "struct, enum, interface, delegate").WithLocation(4, 6) + ); + } + + diagnostics.Add( + // (5,27): error CS9271: The type 'Microsoft.CodeAnalysis.EmbeddedAttribute' must be non-generic, internal, sealed, non-static, have a parameterless constructor, inherit from System.Attribute, and be able to be applied to any type. + // internal sealed class EmbeddedAttribute : System.Attribute + Diagnostic(ErrorCode.ERR_EmbeddedAttributeMustFollowPattern, "EmbeddedAttribute").WithLocation(5, 27) + ); + + CreateCompilation(code, assemblyName: "testModule", targetFramework: TargetFramework.NetStandard20) + .VerifyEmitDiagnostics(diagnostics.ToArray()); } [Fact] public void EmbeddedAttributeForwardedToAnotherAssemblyShouldTriggerAnError() { - var reference = CreateCompilation(@" -namespace Microsoft.CodeAnalysis -{ - public class EmbeddedAttribute : System.Attribute { } -}", assemblyName: "reference").ToMetadataReference(); + var reference = CompileIL(""" + .assembly extern mscorlib { } + .assembly testRef + { + } + + .class public auto ansi beforefieldinit Microsoft.CodeAnalysis.EmbeddedAttribute + extends [mscorlib]System.Attribute + { + .method public hidebysig specialname rtspecialname instance void .ctor () cil managed + { + ldarg.0 + call instance void [mscorlib]System.Attribute::.ctor() + ret + } + } + """, prependDefaultHeader: false); var code = @" [assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(Microsoft.CodeAnalysis.EmbeddedAttribute))] @@ -267,15 +696,35 @@ public void M(in int p) [Fact] public void CompilerShouldIgnorePublicEmbeddedAttributesInReferencedAssemblies() { - var reference = CreateCompilation(assemblyName: "testRef", parseOptions: TestOptions.Regular.WithNoRefSafetyRulesAttribute(), source: @" -namespace Microsoft.CodeAnalysis -{ - public class EmbeddedAttribute : System.Attribute { } -} -namespace OtherNamespace -{ - public class TestReference { } -}").ToMetadataReference(); + var reference = CompileIL(""" + .assembly extern mscorlib { } + .assembly testRef + { + } + + .class public auto ansi beforefieldinit OtherNamespace.TestReference + extends [mscorlib]System.Object + { + // Methods + .method public hidebysig specialname rtspecialname instance void .ctor () cil managed + { + ldarg.0 + call instance void [mscorlib]System.Object::.ctor() + ret + } + } + + .class public auto ansi beforefieldinit Microsoft.CodeAnalysis.EmbeddedAttribute + extends [mscorlib]System.Attribute + { + .method public hidebysig specialname rtspecialname instance void .ctor () cil managed + { + ldarg.0 + call instance void [mscorlib]System.Attribute::.ctor() + ret + } + } + """, prependDefaultHeader: false); var code = @" class Test @@ -492,7 +941,7 @@ public void EmbeddedTypesInAnAssemblyAreNotExposedExternally() var compilation1 = CreateCompilation(parseOptions: TestOptions.Regular.WithNoRefSafetyRulesAttribute(), source: @" namespace Microsoft.CodeAnalysis { - public class EmbeddedAttribute : System.Attribute { } + internal sealed class EmbeddedAttribute : System.Attribute { } } [Microsoft.CodeAnalysis.Embedded] public class TestReference1 { } diff --git a/src/Compilers/CSharp/Test/Emit3/FirstClassSpanTests.cs b/src/Compilers/CSharp/Test/Emit3/FirstClassSpanTests.cs index 0bf1e55bfbc15..34ca8063a319b 100644 --- a/src/Compilers/CSharp/Test/Emit3/FirstClassSpanTests.cs +++ b/src/Compilers/CSharp/Test/Emit3/FirstClassSpanTests.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.Collections.Generic; using System.Collections.Immutable; using System.Linq; using Microsoft.CodeAnalysis.CSharp.Symbols; @@ -28,7 +29,7 @@ public static TheoryData LangVersions() } private sealed class CombinatorialLangVersions() - : CombinatorialValuesAttribute(LangVersions().Select(d => d.Single()).ToArray()); + : CombinatorialValuesAttribute(((IEnumerable)LangVersions()).Select(d => d.Single()).ToArray()); [Fact, WorkItem("https://github.com/dotnet/runtime/issues/101261")] public void Example_StringValuesAmbiguity() diff --git a/src/Compilers/CSharp/Test/Emit3/FlowAnalysis/RegionAnalysisTests.cs b/src/Compilers/CSharp/Test/Emit3/FlowAnalysis/RegionAnalysisTests.cs index d911a0f876095..f8a6f0b71d51c 100644 --- a/src/Compilers/CSharp/Test/Emit3/FlowAnalysis/RegionAnalysisTests.cs +++ b/src/Compilers/CSharp/Test/Emit3/FlowAnalysis/RegionAnalysisTests.cs @@ -14147,5 +14147,128 @@ ref struct RS Assert.Null(GetSymbolNamesJoined(flowAnalysis.ReadInside)); Assert.Equal("this", GetSymbolNamesJoined(flowAnalysis.WrittenInside)); } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/38087")] + public void Repro_38087() + { + var comp = CreateCompilation(""" + class Program + { + private static void Repro() + { + int i = 1, j = 2; + int k = i + j + 1; + } + } + """); + comp.VerifyEmitDiagnostics(); + + var tree = comp.CommonSyntaxTrees[0]; + var model = comp.GetSemanticModel(tree); + + var decls = tree.GetRoot().DescendantNodes().OfType().ToArray(); + Assert.Equal(2, decls.Length); + var decl = decls[1]; + Assert.Equal("int k = i + j + 1;", decl.ToString()); + var flowAnalysis = model.AnalyzeDataFlow(decl); + Assert.Equal("i, j", GetSymbolNamesJoined(flowAnalysis.ReadInside)); + + var binOps = tree.GetRoot().DescendantNodes().OfType().ToArray(); + Assert.Equal(2, binOps.Length); + var add = binOps[0]; + Assert.Equal("i + j + 1", add.ToString()); + flowAnalysis = model.AnalyzeDataFlow(add); + Assert.Equal("i, j", GetSymbolNamesJoined(flowAnalysis.ReadInside)); + + add = binOps[1]; + Assert.Equal("i + j", add.ToString()); + flowAnalysis = model.AnalyzeDataFlow(add); + Assert.Equal("i, j", GetSymbolNamesJoined(flowAnalysis.ReadInside)); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/38087")] + public void FourBinaryOperands() + { + var comp = CreateCompilation(""" + class Program + { + private static void Repro() + { + int i = 1, j = 2, k = 3, l = 4; + _ = i + j + k + l; + } + } + """); + comp.VerifyEmitDiagnostics(); + + var tree = comp.CommonSyntaxTrees[0]; + var model = comp.GetSemanticModel(tree); + + var decl = tree.GetRoot().DescendantNodes().OfType().Single(); + Assert.Equal("_ = i + j + k + l;", decl.ToString()); + var flowAnalysis = model.AnalyzeDataFlow(decl); + Assert.Equal("i, j, k, l", GetSymbolNamesJoined(flowAnalysis.ReadInside)); + + var binOps = tree.GetRoot().DescendantNodes().OfType().ToArray(); + Assert.Equal(3, binOps.Length); + var add = binOps[0]; + Assert.Equal("i + j + k + l", add.ToString()); + flowAnalysis = model.AnalyzeDataFlow(add); + Assert.Equal("i, j, k, l", GetSymbolNamesJoined(flowAnalysis.ReadInside)); + + add = binOps[1]; + Assert.Equal("i + j + k", add.ToString()); + flowAnalysis = model.AnalyzeDataFlow(add); + Assert.Equal("i, j, k", GetSymbolNamesJoined(flowAnalysis.ReadInside)); + + add = binOps[2]; + Assert.Equal("i + j", add.ToString()); + flowAnalysis = model.AnalyzeDataFlow(add); + Assert.Equal("i, j", GetSymbolNamesJoined(flowAnalysis.ReadInside)); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/38087")] + public void BinaryOpConditionalAccess() + { + var comp = CreateCompilation(""" + class C + { + public bool M(out int x) { x = 0; return false; } + + private static void Repro(C c) + { + const bool y = true; + const bool z = true; + int x; + _ = c?.M(out x) == y == z; + } + } + """); + comp.VerifyEmitDiagnostics(); + + var tree = comp.CommonSyntaxTrees[0]; + var model = comp.GetSemanticModel(tree); + + var decl = tree.GetRoot().DescendantNodes().OfType().Last(); + Assert.Equal("_ = c?.M(out x) == y == z;", decl.ToString()); + var flowAnalysis = model.AnalyzeDataFlow(decl); + Assert.Equal("c, y, z", GetSymbolNamesJoined(flowAnalysis.ReadInside)); + Assert.Equal("x", GetSymbolNamesJoined(flowAnalysis.WrittenInside)); + + var binOps = tree.GetRoot().DescendantNodes().OfType().ToArray(); + Assert.Equal(2, binOps.Length); + + var binOp = binOps[0]; + Assert.Equal("c?.M(out x) == y == z", binOp.ToString()); + flowAnalysis = model.AnalyzeDataFlow(binOp); + Assert.Equal("c, y, z", GetSymbolNamesJoined(flowAnalysis.ReadInside)); + Assert.Equal("x", GetSymbolNamesJoined(flowAnalysis.WrittenInside)); + + binOp = binOps[1]; + Assert.Equal("c?.M(out x) == y", binOp.ToString()); + flowAnalysis = model.AnalyzeDataFlow(binOp); + Assert.Equal("c, y", GetSymbolNamesJoined(flowAnalysis.ReadInside)); + Assert.Equal("x", GetSymbolNamesJoined(flowAnalysis.WrittenInside)); + } } } diff --git a/src/Compilers/CSharp/Test/Emit3/Microsoft.CodeAnalysis.CSharp.Emit3.UnitTests.csproj b/src/Compilers/CSharp/Test/Emit3/Microsoft.CodeAnalysis.CSharp.Emit3.UnitTests.csproj index a79819fbe934a..050bb050feff1 100644 --- a/src/Compilers/CSharp/Test/Emit3/Microsoft.CodeAnalysis.CSharp.Emit3.UnitTests.csproj +++ b/src/Compilers/CSharp/Test/Emit3/Microsoft.CodeAnalysis.CSharp.Emit3.UnitTests.csproj @@ -26,6 +26,7 @@ + @@ -35,4 +36,4 @@ - \ No newline at end of file + diff --git a/src/Compilers/CSharp/Test/Emit3/OverloadResolutionPriorityTests.cs b/src/Compilers/CSharp/Test/Emit3/OverloadResolutionPriorityTests.cs index 903c60708e9c9..987440c7778f6 100644 --- a/src/Compilers/CSharp/Test/Emit3/OverloadResolutionPriorityTests.cs +++ b/src/Compilers/CSharp/Test/Emit3/OverloadResolutionPriorityTests.cs @@ -992,9 +992,14 @@ static void Main() var attrs = ctors.SelectAsArray(ctor => ctor.GetAttributes()); Assert.Empty(attrs[0]); + Assert.Equal(1, ((MethodSymbol)ctors[1]).OverloadResolutionPriority); AssertEx.Equal("System.Runtime.CompilerServices.OverloadResolutionPriorityAttribute..ctor(System.Int32 priority)", attrs[1].Single().AttributeConstructor.ToTestDisplayString()); + var m = ((CSharpCompilation)verifier.Compilation).GetTypeByMetadataName("System.Runtime.CompilerServices.C")!.GetMembers("M").OfType().First(); + Assert.Equal(1, m.OverloadResolutionPriority); + AssertEx.Equal("System.Runtime.CompilerServices.OverloadResolutionPriorityAttribute..ctor(System.Int32 priority)", m.GetAttributes().First().AttributeConstructor.ToTestDisplayString()); + verifier.VerifyIL("System.Runtime.CompilerServices.C.Main()", """ { // Code size 7 (0x7) @@ -1059,6 +1064,92 @@ public OtherAttribute() {} CompileAndVerify(source).VerifyDiagnostics(); } + [Fact] + [WorkItem("https://github.com/dotnet/roslyn/issues/75985")] + public void CycleOnOverloadResolutionPriorityConstructor_07() + { + var source = """ + using System.Runtime.CompilerServices; + + namespace System + { + public class ObsoleteAttribute : Attribute + { + public ObsoleteAttribute(string x){} + + [OverloadResolutionPriority(1)] + public ObsoleteAttribute(string x, bool y = false){} + + } + } + + #pragma warning disable CS0436 // The type 'ObsoleteAttribute' in '' conflicts with the imported type 'ObsoleteAttribute' + + [System.Obsolete("Test")] + public class C {} + + public class D + { + public C x; + } + """; + + var verifier = CompileAndVerify([source, OverloadResolutionPriorityAttributeDefinition], + symbolValidator: (m) => + { + AssertEx.Equal("System.ObsoleteAttribute..ctor(System.String x)", + m.ContainingAssembly.GetTypeByMetadataName("C")!.GetAttributes().Single().AttributeConstructor.ToTestDisplayString()); + }); + verifier.VerifyDiagnostics( + // (22,12): warning CS0618: 'C' is obsolete: 'Test' + // public C x; + Diagnostic(ErrorCode.WRN_DeprecatedSymbolStr, "C").WithArguments("C", "Test").WithLocation(22, 12) + ); + } + + [Fact] + [WorkItem("https://github.com/dotnet/roslyn/issues/75985")] + public void CycleOnOverloadResolutionPriorityConstructor_08() + { + var source = """ + using System.Runtime.CompilerServices; + + namespace System + { + public class ObsoleteAttribute : Attribute + { + public ObsoleteAttribute(string x){} + + [OverloadResolutionPriority(1)] + public ObsoleteAttribute(string x, bool y = true){} + + } + } + + #pragma warning disable CS0436 // The type 'ObsoleteAttribute' in '' conflicts with the imported type 'ObsoleteAttribute' + + [System.Obsolete("Test")] + public class C {} + + public class D + { + public C x; + } + """; + + var verifier = CompileAndVerify([source, OverloadResolutionPriorityAttributeDefinition], + symbolValidator: (m) => + { + AssertEx.Equal("System.ObsoleteAttribute..ctor(System.String x)", + m.ContainingAssembly.GetTypeByMetadataName("C")!.GetAttributes().Single().AttributeConstructor.ToTestDisplayString()); + }); + verifier.VerifyDiagnostics( + // (22,12): warning CS0618: 'C' is obsolete: 'Test' + // public C x; + Diagnostic(ErrorCode.WRN_DeprecatedSymbolStr, "C").WithArguments("C", "Test").WithLocation(22, 12) + ); + } + [Theory, CombinatorialData] public void OverloadResolutionAppliedToIndexers(bool useMetadataReference, bool i1First) { @@ -1785,7 +1876,8 @@ End Set End Property End Class """; - var vb = CreateVisualBasicCompilation(GetUniqueName(), vbSource, referencedAssemblies: TargetFrameworkUtil.NetStandard20References, referencedCompilations: [attrRef]); + var vb = CreateVisualBasicCompilation(GetUniqueName(), vbSource, referencedAssemblies: TargetFrameworkUtil.NetStandard20References, referencedCompilations: [attrRef], + parseOptions: VisualBasic.VisualBasicParseOptions.Default.WithLanguageVersion(VisualBasic.LanguageVersion.Latest)); var vbRef = vb.EmitToImageReference(); var executable = """ @@ -2509,30 +2601,29 @@ public void HonoredInsideExpressionTree() { var source = """ using System; - using System.Collections.Generic; using System.Linq.Expressions; using System.Runtime.CompilerServices; - Expression e = () => C.M(1, 2, 3); + Expression e = () => C.M(""); + e.Compile()(); public class C { - public static void M(params int[] a) + public static void M(string a) { + throw null; } [OverloadResolutionPriority(1)] - public static void M(params IEnumerable e) + public static void M(object e) { + System.Console.Write(1); } } """; - CreateCompilation([source, OverloadResolutionPriorityAttributeDefinition]).VerifyDiagnostics( - // (6,30): error CS9226: An expression tree may not contain an expanded form of non-array params collection parameter. - // Expression e = () => C.M(1, 2, 3); - Diagnostic(ErrorCode.ERR_ParamsCollectionExpressionTree, "C.M(1, 2, 3)").WithLocation(6, 30) - ); + var comp = CreateCompilation([source, OverloadResolutionPriorityAttributeDefinition]); + CompileAndVerify(comp, expectedOutput: "1").VerifyDiagnostics(); } [Fact] @@ -2820,4 +2911,202 @@ partial class Program CompileAndVerify([code, OverloadResolutionPriorityAttributeDefinition], expectedOutput: "params").VerifyDiagnostics(); } + + private const string OverloadResolutionPriorityAttributeDefinitionVB = """ +namespace System.Runtime.CompilerServices + + public class OverloadResolutionPriorityAttribute + Inherits Attribute + + Public Sub New(priority As Integer) + Me.Priority = priority + End Sub + + public Readonly Property Priority As Integer + End Class +End Namespace +"""; + + [Fact] + public void ParameterlessProperty_01() + { + var vbSource = """ +Public Class Module1 + + + Shared WriteOnly Property M1 As Integer + Set + System.Console.Write(1) + End Set + End Property + + Shared WriteOnly Property M1(Optional x As Integer = 0) As Integer + Set + System.Console.Write(2) + End Set + End Property +End Class + +""" + OverloadResolutionPriorityAttributeDefinitionVB; + + var vb = CreateVisualBasicCompilation(GetUniqueName(), vbSource, referencedAssemblies: TargetFrameworkUtil.GetReferences(TargetFramework.Standard), + parseOptions: VisualBasic.VisualBasicParseOptions.Default.WithLanguageVersion(VisualBasic.LanguageVersion.Latest)); + var vbRef = vb.EmitToImageReference(); + + var source1 = """ +class Program +{ + static void Main() + { + Module1.M1 = 0; + } +} +"""; + + CompileAndVerify(source1, references: [vbRef], expectedOutput: "1"); + + var source2 = """ +class Program +{ + static void Main() + { + Module1.M1[1] = 0; + } +} +"""; + CreateCompilation(source2, references: [vbRef]).VerifyDiagnostics( + // (5,9): error CS0154: The property or indexer 'Module1.M1' cannot be used in this context because it lacks the get accessor + // Module1.M1[1] = 0; + Diagnostic(ErrorCode.ERR_PropertyLacksGet, "Module1.M1").WithArguments("Module1.M1").WithLocation(5, 9) + ); + } + + [Fact] + public void ParameterlessProperty_02() + { + var vbSource = """ +Public Class Module1 + + Shared WriteOnly Property M1 As Integer + Set + System.Console.Write(1) + End Set + End Property + + + Shared WriteOnly Property M1(Optional x As Integer = 0) As Integer + Set + System.Console.Write(2) + End Set + End Property +End Class + +""" + OverloadResolutionPriorityAttributeDefinitionVB; + + var vb = CreateVisualBasicCompilation(GetUniqueName(), vbSource, referencedAssemblies: TargetFrameworkUtil.GetReferences(TargetFramework.Standard), + parseOptions: VisualBasic.VisualBasicParseOptions.Default.WithLanguageVersion(VisualBasic.LanguageVersion.Latest)); + var vbRef = vb.EmitToImageReference(); + + var source1 = """ +class Program +{ + static void Main() + { + Module1.M1 = 0; + } +} +"""; + + CompileAndVerify(source1, references: [vbRef], expectedOutput: "1"); + } + + [Fact] + public void NarrowingFromNumericConstant_02() + { + var source = """ +class Program +{ + static void Main() + { + M1(0L); + M2(0L); + } + + static void M1(int x) => System.Console.Write(1); + + [System.Runtime.CompilerServices.OverloadResolutionPriority(1)] + static void M1(uint x) => System.Console.Write(2); + + static void M2(int x) => System.Console.Write(3); + + static void M2(uint x) => System.Console.Write(4); +} +"""; + + CreateCompilation([source, OverloadResolutionPriorityAttributeDefinition]). + VerifyDiagnostics( + // (5,12): error CS1503: Argument 1: cannot convert from 'long' to 'int' + // M1(0L); + Diagnostic(ErrorCode.ERR_BadArgType, "0L").WithArguments("1", "long", "int").WithLocation(5, 12), + // (6,12): error CS1503: Argument 1: cannot convert from 'long' to 'int' + // M2(0L); + Diagnostic(ErrorCode.ERR_BadArgType, "0L").WithArguments("1", "long", "int").WithLocation(6, 12) + ); + } + + [Fact] + public void NarrowingFromNumericConstant_03() + { + var source = """ +class Program +{ + static void Main() + { + M1(0L); + } + + static void M1(int x) => System.Console.Write(1); + + [System.Runtime.CompilerServices.OverloadResolutionPriority(1)] + static void M1(uint x) => System.Console.Write(2); + + static void M1(long x) => System.Console.Write(3); +} +"""; + + CompileAndVerify([source, OverloadResolutionPriorityAttributeDefinition], expectedOutput: "3").VerifyDiagnostics(); + } + + [Fact] + public void LiftedOperator_01() + { + var source = """ +struct S +{ + [System.Runtime.CompilerServices.OverloadResolutionPriority(1)] + public static S operator-(S x) + { + System.Console.Write(1); + return default; + } + + public static S? operator-(S? x) + { + System.Console.Write(2); + return default; + } +} + +class Program +{ + static void Main() + { + S? s = (S)default; + s = -s; + } +} +"""; + + CompileAndVerify([source, OverloadResolutionPriorityAttributeDefinition], expectedOutput: "1").VerifyDiagnostics(); + } } diff --git a/src/Compilers/CSharp/Test/Emit3/RefStructInterfacesTests.cs b/src/Compilers/CSharp/Test/Emit3/RefStructInterfacesTests.cs index ec891680f6a61..0c86323939911 100644 --- a/src/Compilers/CSharp/Test/Emit3/RefStructInterfacesTests.cs +++ b/src/Compilers/CSharp/Test/Emit3/RefStructInterfacesTests.cs @@ -16,6 +16,7 @@ namespace Microsoft.CodeAnalysis.CSharp.UnitTests { + [CompilerTrait(CompilerFeature.RefLifetime)] public class RefStructInterfacesTests : CSharpTestBase { private static readonly TargetFramework s_targetFrameworkSupportingByRefLikeGenerics = TargetFramework.Net90; @@ -21357,7 +21358,7 @@ class Helper delegate void D2(T x); static D1 d11 = M1; - static D1 d12 = M2; + static D1 d12 = M2; // 1 static D2 d21 = M1; static D2 d22 = M2; @@ -21371,7 +21372,7 @@ class Helper delegate void D2(Span x); static D1 d11 = M1; - static D1 d12 = M2; + static D1 d12 = M2; // 2 static D2 d21 = M1; static D2 d22 = M2; @@ -21380,7 +21381,13 @@ static void M2(Span x) {} } "; var comp = CreateCompilation(src, targetFramework: s_targetFrameworkSupportingByRefLikeGenerics); - comp.VerifyEmitDiagnostics(); + comp.VerifyEmitDiagnostics( + // (11,21): error CS8986: The 'scoped' modifier of parameter 'x' doesn't match target 'Helper.D1'. + // static D1 d12 = M2; // 1 + Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "M2").WithArguments("x", "Helper.D1").WithLocation(11, 21), + // (25,21): error CS8986: The 'scoped' modifier of parameter 'x' doesn't match target 'Helper.D1'. + // static D1 d12 = M2; // 2 + Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "M2").WithArguments("x", "Helper.D1").WithLocation(25, 21)); } [Fact] diff --git a/src/Compilers/CSharp/Test/Emit3/Semantics/ExperimentalAttributeTests.cs b/src/Compilers/CSharp/Test/Emit3/Semantics/ExperimentalAttributeTests.cs index f137057d96a58..74a88e8c339ed 100644 --- a/src/Compilers/CSharp/Test/Emit3/Semantics/ExperimentalAttributeTests.cs +++ b/src/Compilers/CSharp/Test/Emit3/Semantics/ExperimentalAttributeTests.cs @@ -29,6 +29,8 @@ public sealed class ExperimentalAttribute : Attribute public ExperimentalAttribute(string diagnosticId) { } public string? UrlFormat { get; set; } + + public string? Message { get; set; } } } """; @@ -1814,6 +1816,86 @@ public ExperimentalAttribute(string diagnosticId) { } Assert.Equal(DefaultHelpLinkUri, diag.Descriptor.HelpLinkUri); } + [Fact] + public void BadAttribute_IntMessageProperty_Metadata() + { + // A "Message" property with a type other than 'string' is ignored + var libSrc = """ +[System.Diagnostics.CodeAnalysis.Experimental("DiagID", Message = 42)] +public class C +{ + public static void M() { } +} + +namespace System.Diagnostics.CodeAnalysis +{ + [AttributeUsage(AttributeTargets.All, Inherited = false)] + public sealed class ExperimentalAttribute : Attribute + { + public ExperimentalAttribute(string diagnosticId) { } + public int Message { get; set; } + } +} +"""; + + var libComp = CreateCompilation(libSrc); + + var src = """ +C.M(); +"""; + + var comp = CreateCompilation(src, references: new[] { libComp.EmitToImageReference() }); + comp.VerifyDiagnostics( + // (1,1): error DiagID: 'C' is for evaluation purposes only and is subject to change or removal in future updates. + // C.M(); + Diagnostic("DiagID", "C").WithArguments("C").WithLocation(1, 1).WithWarningAsError(true) + ); + + var diag = comp.GetDiagnostics().Single(); + Assert.Equal("DiagID", diag.Id); + Assert.Equal(ErrorCode.WRN_Experimental, (ErrorCode)diag.Code); + Assert.Equal(DefaultHelpLinkUri, diag.Descriptor.HelpLinkUri); + } + + [Fact] + public void BadAttribute_IntMessageProperty_Source() + { + // A "Message" property with a type other than 'string' is ignored + var libSrc = """ +[System.Diagnostics.CodeAnalysis.Experimental("DiagID", Message = 42)] +public class C +{ + public static void M() { } +} + +namespace System.Diagnostics.CodeAnalysis +{ + [AttributeUsage(AttributeTargets.All, Inherited = false)] + public sealed class ExperimentalAttribute : Attribute + { + public ExperimentalAttribute(string diagnosticId) { } + public int Message { get; set; } + } +} +"""; + + var src = """ +C.M(); +"""; + + var comp = CreateCompilation([src, libSrc]); + comp.VerifyDiagnostics( + // (1,1): error DiagID: 'C' is for evaluation purposes only and is subject to change or removal in future updates. + // C.M(); + Diagnostic("DiagID", "C").WithArguments("C").WithLocation(1, 1).WithWarningAsError(true) + ); + + var diag = comp.GetDiagnostics().Single(); + Assert.Equal("DiagID", diag.Id); + Assert.Equal(ErrorCode.WRN_Experimental, (ErrorCode)diag.Code); + Assert.Equal(DefaultHelpLinkUri, diag.Descriptor.HelpLinkUri); + } + [Fact] public void BadAttribute_UrlFormatField_Metadata() { @@ -1855,12 +1937,92 @@ public ExperimentalAttribute(string diagnosticId) { } Assert.Equal(DefaultHelpLinkUri, diag.Descriptor.HelpLinkUri); } + [Fact] + public void BadAttribute_MessageField_Metadata() + { + // A field named "Message" is ignored + var libSrc = """ +[System.Diagnostics.CodeAnalysis.Experimental("DiagID", Message = "hello")] +public class C +{ + public static void M() { } +} + +namespace System.Diagnostics.CodeAnalysis +{ + [AttributeUsage(AttributeTargets.All, Inherited = false)] + public sealed class ExperimentalAttribute : Attribute + { + public ExperimentalAttribute(string diagnosticId) { } + public string Message = "hello"; + } +} +"""; + + var libComp = CreateCompilation(libSrc); + + var src = """ +C.M(); +"""; + + var comp = CreateCompilation(src, references: new[] { libComp.EmitToImageReference() }); + comp.VerifyDiagnostics( + // (1,1): error DiagID: 'C' is for evaluation purposes only and is subject to change or removal in future updates. + // C.M(); + Diagnostic("DiagID", "C").WithArguments("C").WithLocation(1, 1).WithWarningAsError(true) + ); + + var diag = comp.GetDiagnostics().Single(); + Assert.Equal("DiagID", diag.Id); + Assert.Equal(ErrorCode.WRN_Experimental, (ErrorCode)diag.Code); + Assert.Equal(DefaultHelpLinkUri, diag.Descriptor.HelpLinkUri); + } + + [Fact] + public void BadAttribute_MessageField_Source() + { + // A field named "Message" is ignored + var libSrc = """ +[System.Diagnostics.CodeAnalysis.Experimental("DiagID", Message = "hello")] +public class C +{ + public static void M() { } +} + +namespace System.Diagnostics.CodeAnalysis +{ + [AttributeUsage(AttributeTargets.All, Inherited = false)] + public sealed class ExperimentalAttribute : Attribute + { + public ExperimentalAttribute(string diagnosticId) { } + public string Message = "hello"; + } +} +"""; + + var src = """ +C.M(); +"""; + + var comp = CreateCompilation([src, libSrc]); + comp.VerifyDiagnostics( + // (1,1): error DiagID: 'C' is for evaluation purposes only and is subject to change or removal in future updates. + // C.M(); + Diagnostic("DiagID", "C").WithArguments("C").WithLocation(1, 1).WithWarningAsError(true) + ); + + var diag = comp.GetDiagnostics().Single(); + Assert.Equal("DiagID", diag.Id); + Assert.Equal(ErrorCode.WRN_Experimental, (ErrorCode)diag.Code); + Assert.Equal(DefaultHelpLinkUri, diag.Descriptor.HelpLinkUri); + } + [Fact] public void BadAttribute_OtherProperty_Metadata() { - // A property that isn't named "UrlFormat" is ignored + // A property that isn't named "UrlFormat" or "Message" is ignored var libSrc = """ -[System.Diagnostics.CodeAnalysis.Experimental("DiagID", NotUrlFormat = "hello")] +[System.Diagnostics.CodeAnalysis.Experimental("DiagID", Other = "hello")] public class C { public static void M() { } @@ -1872,7 +2034,7 @@ namespace System.Diagnostics.CodeAnalysis public sealed class ExperimentalAttribute : Attribute { public ExperimentalAttribute(string diagnosticId) { } - public string NotUrlFormat { get; set; } + public string Other { get; set; } } } """; @@ -1896,6 +2058,45 @@ public ExperimentalAttribute(string diagnosticId) { } Assert.Equal(DefaultHelpLinkUri, diag.Descriptor.HelpLinkUri); } + [Fact] + public void BadAttribute_OtherProperty_Source() + { + // A property that isn't named "UrlFormat" or "Message" is ignored + var libSrc = """ +[System.Diagnostics.CodeAnalysis.Experimental("DiagID", Other = "hello")] +public class C +{ + public static void M() { } +} + +namespace System.Diagnostics.CodeAnalysis +{ + [AttributeUsage(AttributeTargets.All, Inherited = false)] + public sealed class ExperimentalAttribute : Attribute + { + public ExperimentalAttribute(string diagnosticId) { } + public string Other { get; set; } + } +} +"""; + + var src = """ +C.M(); +"""; + + var comp = CreateCompilation([src, libSrc]); + comp.VerifyDiagnostics( + // (1,1): error DiagID: 'C' is for evaluation purposes only and is subject to change or removal in future updates. + // C.M(); + Diagnostic("DiagID", "C").WithArguments("C").WithLocation(1, 1).WithWarningAsError(true) + ); + + var diag = comp.GetDiagnostics().Single(); + Assert.Equal("DiagID", diag.Id); + Assert.Equal(ErrorCode.WRN_Experimental, (ErrorCode)diag.Code); + Assert.Equal(DefaultHelpLinkUri, diag.Descriptor.HelpLinkUri); + } + [Fact] public void UrlFormat() { @@ -1922,6 +2123,188 @@ public static void M() { } Assert.Equal("https://example.org/DiagID1", diag.Descriptor.HelpLinkUri); } + [Fact] + public void UrlFormat_Metadata() + { + // Combine the DiagnosticId with the UrlFormat if present + var src = """ +[System.Diagnostics.CodeAnalysis.Experimental("DiagID1", UrlFormat = "https://example.org/{0}")] +public class C +{ + public static void M() { } +} +"""; + var comp1 = CreateCompilation(new[] { src, experimentalAttributeSrc }); + + var comp = CreateCompilation("C.M();", references: [comp1.EmitToImageReference()]); + comp.VerifyDiagnostics( + // 0.cs(1,1): error DiagID1: 'C' is for evaluation purposes only and is subject to change or removal in future updates. (https://example.org/DiagID1) + // C.M(); + Diagnostic("DiagID1", "C").WithArguments("C").WithLocation(1, 1).WithWarningAsError(true) + ); + + var diag = comp.GetDiagnostics().Single(); + Assert.Equal("DiagID1", diag.Id); + Assert.Equal(ErrorCode.WRN_Experimental, (ErrorCode)diag.Code); + Assert.Equal("https://example.org/DiagID1", diag.Descriptor.HelpLinkUri); + } + + [Fact] + public void Message() + { + // Include Message if present + var src = """ +C.M(); + +[System.Diagnostics.CodeAnalysis.Experimental("DiagID1", Message = "use CCC instead")] +class C +{ + public static void M() { } +} +"""; + var comp = CreateCompilation(new[] { src, experimentalAttributeSrc }); + comp.VerifyDiagnostics( + // 0.cs(1,1): error DiagID1: 'C' is for evaluation purposes only and is subject to change or removal in future updates: 'use CCC instead'. Suppress this diagnostic to proceed. + // C.M(); + Diagnostic("DiagID1", "C").WithArguments("C", "use CCC instead").WithLocation(1, 1).WithWarningAsError(true) + ); + + var diag = comp.GetDiagnostics().Single(); + Assert.Equal("DiagID1", diag.Id); + Assert.Equal(ErrorCode.WRN_ExperimentalWithMessage, (ErrorCode)diag.Code); + Assert.Equal($"https://msdn.microsoft.com/query/roslyn.query?appId=roslyn&k=k(CS{(int)ErrorCode.WRN_ExperimentalWithMessage})", diag.Descriptor.HelpLinkUri); + } + + [Fact] + public void Message_Metadata() + { + // Include Message if present + var src = """ +[System.Diagnostics.CodeAnalysis.Experimental("DiagID1", Message = "use CCC instead")] +public class C +{ + public static void M() { } +} +"""; + var comp1 = CreateCompilation(new[] { src, experimentalAttributeSrc }); + + var comp = CreateCompilation("C.M();", references: [comp1.EmitToImageReference()]); + comp.VerifyDiagnostics( + // (1,1): error DiagID1: 'C' is for evaluation purposes only and is subject to change or removal in future updates: 'use CCC instead'. Suppress this diagnostic to proceed. + // C.M(); + Diagnostic("DiagID1", "C").WithArguments("C", "use CCC instead").WithLocation(1, 1).WithWarningAsError(true) + ); + + var diag = comp.GetDiagnostics().Single(); + Assert.Equal("DiagID1", diag.Id); + Assert.Equal(ErrorCode.WRN_ExperimentalWithMessage, (ErrorCode)diag.Code); + Assert.Equal($"https://msdn.microsoft.com/query/roslyn.query?appId=roslyn&k=k(CS{(int)ErrorCode.WRN_ExperimentalWithMessage})", diag.Descriptor.HelpLinkUri); + } + + [Fact] + public void UrlFormatAndMessage() + { + // Combine the DiagnosticId with the UrlFormat if present + var src = """ +C.M(); + +[System.Diagnostics.CodeAnalysis.Experimental("DiagID1", UrlFormat = "https://example.org/{0}", Message = "use CC instead")] +class C +{ + public static void M() { } +} +"""; + var comp = CreateCompilation(new[] { src, experimentalAttributeSrc }); + comp.VerifyDiagnostics( + // 0.cs(1,1): error DiagID1: 'C' is for evaluation purposes only and is subject to change or removal in future updates: 'use CC instead'. Suppress this diagnostic to proceed. + // C.M(); + Diagnostic("DiagID1", "C").WithArguments("C", "use CC instead").WithLocation(1, 1).WithWarningAsError(true) + ); + + var diag = comp.GetDiagnostics().Single(); + Assert.Equal("DiagID1", diag.Id); + Assert.Equal(ErrorCode.WRN_ExperimentalWithMessage, (ErrorCode)diag.Code); + Assert.Equal("https://example.org/DiagID1", diag.Descriptor.HelpLinkUri); + } + + [Fact] + public void UrlFormatAndMessage_Metadata() + { + // Combine the DiagnosticId with the UrlFormat if present + var src = """ +[System.Diagnostics.CodeAnalysis.Experimental("DiagID1", UrlFormat = "https://example.org/{0}", Message = "use CC instead")] +public class C +{ + public static void M() { } +} +"""; + var comp1 = CreateCompilation(new[] { src, experimentalAttributeSrc }); + + var comp = CreateCompilation("C.M();", references: [comp1.EmitToImageReference()]); + comp.VerifyDiagnostics( + // (1,1): error DiagID1: 'C' is for evaluation purposes only and is subject to change or removal in future updates: 'use CC instead'. Suppress this diagnostic to proceed. + // C.M(); + Diagnostic("DiagID1", "C").WithArguments("C", "use CC instead").WithLocation(1, 1).WithWarningAsError(true) + ); + + var diag = comp.GetDiagnostics().Single(); + Assert.Equal("DiagID1", diag.Id); + Assert.Equal(ErrorCode.WRN_ExperimentalWithMessage, (ErrorCode)diag.Code); + Assert.Equal("https://example.org/DiagID1", diag.Descriptor.HelpLinkUri); + } + + [Fact] + public void MessageAndUrlFormat() + { + // Combine the DiagnosticId with the UrlFormat if present + var src = """ +C.M(); + +[System.Diagnostics.CodeAnalysis.Experimental("DiagID1", Message = "use CC instead", UrlFormat = "https://example.org/{0}")] +class C +{ + public static void M() { } +} +"""; + var comp = CreateCompilation(new[] { src, experimentalAttributeSrc }); + comp.VerifyDiagnostics( + // 0.cs(1,1): error DiagID1: 'C' is for evaluation purposes only and is subject to change or removal in future updates: 'use CC instead'. Suppress this diagnostic to proceed. + // C.M(); + Diagnostic("DiagID1", "C").WithArguments("C", "use CC instead").WithLocation(1, 1).WithWarningAsError(true) + ); + + var diag = comp.GetDiagnostics().Single(); + Assert.Equal("DiagID1", diag.Id); + Assert.Equal(ErrorCode.WRN_ExperimentalWithMessage, (ErrorCode)diag.Code); + Assert.Equal("https://example.org/DiagID1", diag.Descriptor.HelpLinkUri); + } + + [Fact] + public void MessageAndUrlFormat_Metadata() + { + // Combine the DiagnosticId with the UrlFormat if present + var src = """ +[System.Diagnostics.CodeAnalysis.Experimental("DiagID1", Message = "use CC instead", UrlFormat = "https://example.org/{0}")] +public class C +{ + public static void M() { } +} +"""; + var comp1 = CreateCompilation(new[] { src, experimentalAttributeSrc }); + + var comp = CreateCompilation("C.M();", references: [comp1.EmitToImageReference()]); + comp.VerifyDiagnostics( + // (1,1): error DiagID1: 'C' is for evaluation purposes only and is subject to change or removal in future updates: 'use CC instead'. Suppress this diagnostic to proceed. + // C.M(); + Diagnostic("DiagID1", "C").WithArguments("C", "use CC instead").WithLocation(1, 1).WithWarningAsError(true) + ); + + var diag = comp.GetDiagnostics().Single(); + Assert.Equal("DiagID1", diag.Id); + Assert.Equal(ErrorCode.WRN_ExperimentalWithMessage, (ErrorCode)diag.Code); + Assert.Equal("https://example.org/DiagID1", diag.Descriptor.HelpLinkUri); + } + [Fact] public void BadUrlFormat() { @@ -1979,6 +2362,37 @@ public static void M() { } Assert.Equal("", diag.Descriptor.HelpLinkUri); } + [Theory, CombinatorialData] + public void EmptyMessage(bool inSource) + { + var libSrc = """ +[System.Diagnostics.CodeAnalysis.Experimental("DiagID1", Message = "")] +public class C +{ + public static void M() { } +} +"""; + + var src = """ +C.M(); +"""; + + var comp = inSource + ? CreateCompilation(new[] { src, libSrc, experimentalAttributeSrc }) + : CreateCompilation(src, references: new[] { CreateCompilation(new[] { libSrc, experimentalAttributeSrc }).EmitToImageReference() }); + + comp.VerifyDiagnostics( + // (1,1): error DiagID1: 'C' is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. + // C.M(); + Diagnostic("DiagID1", "C").WithArguments("C").WithLocation(1, 1).WithWarningAsError(true) + ); + + var diag = comp.GetDiagnostics().Single(); + Assert.Equal("DiagID1", diag.Id); + Assert.Equal(ErrorCode.WRN_Experimental, (ErrorCode)diag.Code); + Assert.Equal(DefaultHelpLinkUri, diag.Descriptor.HelpLinkUri); + } + [Fact] public void NullUrlFormat() { @@ -2005,6 +2419,82 @@ public static void M() { } Assert.Equal(DefaultHelpLinkUri, diag.Descriptor.HelpLinkUri); } + [Fact] + public void NullUrlFormat_Metadata() + { + // We use a default help URL if the UrlFormat is improper + var src = """ +[System.Diagnostics.CodeAnalysis.Experimental("DiagID1", UrlFormat = null)] +public class C +{ + public static void M() { } +} +"""; + var comp1 = CreateCompilation(new[] { src, experimentalAttributeSrc }); + + var comp = CreateCompilation("C.M();", references: [comp1.EmitToImageReference()]); + comp.VerifyDiagnostics( + // 0.cs(1,1): error DiagID1: 'C' is for evaluation purposes only and is subject to change or removal in future updates. + // C.M(); + Diagnostic("DiagID1", "C").WithArguments("C").WithLocation(1, 1).WithWarningAsError(true) + ); + + var diag = comp.GetDiagnostics().Single(); + Assert.Equal("DiagID1", diag.Id); + Assert.Equal(ErrorCode.WRN_Experimental, (ErrorCode)diag.Code); + Assert.Equal(DefaultHelpLinkUri, diag.Descriptor.HelpLinkUri); + } + + [Fact] + public void NullMessage() + { + var src = """ +C.M(); + +[System.Diagnostics.CodeAnalysis.Experimental("DiagID1", Message = null)] +class C +{ + public static void M() { } +} +"""; + var comp = CreateCompilation(new[] { src, experimentalAttributeSrc }); + comp.VerifyDiagnostics( + // (1,1): error DiagID1: 'C' is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. + // C.M(); + Diagnostic("DiagID1", "C").WithArguments("C").WithLocation(1, 1).WithWarningAsError(true) + ); + + var diag = comp.GetDiagnostics().Single(); + Assert.Equal("DiagID1", diag.Id); + Assert.Equal(ErrorCode.WRN_Experimental, (ErrorCode)diag.Code); + Assert.Equal(DefaultHelpLinkUri, diag.Descriptor.HelpLinkUri); + } + + [Fact] + public void NullMessage_Metadata() + { + var src = """ +[System.Diagnostics.CodeAnalysis.Experimental("DiagID1", Message = null)] +public class C +{ + public static void M() { } +} +"""; + var comp1 = CreateCompilation(new[] { src, experimentalAttributeSrc }); + + var comp = CreateCompilation("C.M();", references: [comp1.EmitToImageReference()]); + comp.VerifyDiagnostics( + // (1,1): error DiagID1: 'C' is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. + // C.M(); + Diagnostic("DiagID1", "C").WithArguments("C").WithLocation(1, 1).WithWarningAsError(true) + ); + + var diag = comp.GetDiagnostics().Single(); + Assert.Equal("DiagID1", diag.Id); + Assert.Equal(ErrorCode.WRN_Experimental, (ErrorCode)diag.Code); + Assert.Equal(DefaultHelpLinkUri, diag.Descriptor.HelpLinkUri); + } + [Fact] public void FullyQualified() { diff --git a/src/Compilers/CSharp/Test/Emit3/Semantics/PrimaryConstructorTests.cs b/src/Compilers/CSharp/Test/Emit3/Semantics/PrimaryConstructorTests.cs index 3559b208e34e7..623a2f0f15f6b 100644 --- a/src/Compilers/CSharp/Test/Emit3/Semantics/PrimaryConstructorTests.cs +++ b/src/Compilers/CSharp/Test/Emit3/Semantics/PrimaryConstructorTests.cs @@ -10,6 +10,7 @@ using System.Linq; using System.Threading; using Microsoft.CodeAnalysis.CSharp.Symbols; +using Microsoft.CodeAnalysis.CSharp.Symbols.Retargeting; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.CSharp.Test.Utilities; using Microsoft.CodeAnalysis.Diagnostics; @@ -16822,253 +16823,256 @@ public IEnumerable M() verifier1.VerifyTypeIL("C", (@" .class private auto ansi beforefieldinit C - extends [netstandard]System.Object + extends [netstandard]System.Object { - // Nested Types - .class nested private auto ansi sealed beforefieldinit 'd__2' - extends [netstandard]System.Object - implements class [netstandard]System.Collections.Generic.IEnumerable`1, - [netstandard]System.Collections.IEnumerable, - class [netstandard]System.Collections.Generic.IEnumerator`1, + // Nested Types + .class nested private auto ansi sealed beforefieldinit 'd__2' + extends [netstandard]System.Object + implements class [netstandard]System.Collections.Generic.IEnumerable`1, + [netstandard]System.Collections.IEnumerable, + class [netstandard]System.Collections.Generic.IEnumerator`1, " + (RuntimeUtilities.IsCoreClrRuntime ? @" [netstandard]System.Collections.IEnumerator, [netstandard]System.IDisposable" : @" [netstandard]System.IDisposable, [netstandard]System.Collections.IEnumerator") + @" - { - .custom instance void [netstandard]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( - 01 00 00 00 - ) - // Fields - .field private int32 '<>1__state' - .field private int32 '<>2__current' - .field private int32 '<>l__initialThreadId' - .field public class C '<>4__this' - // Methods - .method public hidebysig specialname rtspecialname - instance void .ctor ( - int32 '<>1__state' - ) cil managed - { - .custom instance void [netstandard]System.Diagnostics.DebuggerHiddenAttribute::.ctor() = ( - 01 00 00 00 - ) - // Method begins at RVA 0x20df - // Code size 25 (0x19) - .maxstack 8 - IL_0000: ldarg.0 - IL_0001: call instance void [netstandard]System.Object::.ctor() - IL_0006: ldarg.0 - IL_0007: ldarg.1 - IL_0008: stfld int32 C/'d__2'::'<>1__state' - IL_000d: ldarg.0 - IL_000e: call int32 [netstandard]System.Environment::get_CurrentManagedThreadId() - IL_0013: stfld int32 C/'d__2'::'<>l__initialThreadId' - IL_0018: ret - } // end of method 'd__2'::.ctor - .method private final hidebysig newslot virtual - instance void System.IDisposable.Dispose () cil managed - { - .custom instance void [netstandard]System.Diagnostics.DebuggerHiddenAttribute::.ctor() = ( - 01 00 00 00 - ) - .override method instance void [netstandard]System.IDisposable::Dispose() - // Method begins at RVA 0x20f9 - // Code size 1 (0x1) - .maxstack 8 - IL_0000: ret - } // end of method 'd__2'::System.IDisposable.Dispose - .method private final hidebysig newslot virtual - instance bool MoveNext () cil managed - { - .override method instance bool [netstandard]System.Collections.IEnumerator::MoveNext() - // Method begins at RVA 0x20fc - // Code size 95 (0x5f) - .maxstack 2 - .locals init ( - [0] int32, - [1] class C - ) - IL_0000: ldarg.0 - IL_0001: ldfld int32 C/'d__2'::'<>1__state' - IL_0006: stloc.0 - IL_0007: ldarg.0 - IL_0008: ldfld class C C/'d__2'::'<>4__this' - IL_000d: stloc.1 - IL_000e: ldloc.0 - IL_000f: switch (IL_0022, IL_003a, IL_0056) - IL_0020: ldc.i4.0 - IL_0021: ret - IL_0022: ldarg.0 - IL_0023: ldc.i4.m1 - IL_0024: stfld int32 C/'d__2'::'<>1__state' - IL_0029: ldarg.0 - IL_002a: ldc.i4.s 9 - IL_002c: stfld int32 C/'d__2'::'<>2__current' - IL_0031: ldarg.0 - IL_0032: ldc.i4.1 - IL_0033: stfld int32 C/'d__2'::'<>1__state' - IL_0038: ldc.i4.1 - IL_0039: ret - IL_003a: ldarg.0 - IL_003b: ldc.i4.m1 - IL_003c: stfld int32 C/'d__2'::'<>1__state' - IL_0041: ldarg.0 - IL_0042: ldloc.1 - IL_0043: ldfld int32 C::'P' - IL_0048: stfld int32 C/'d__2'::'<>2__current' - IL_004d: ldarg.0 - IL_004e: ldc.i4.2 - IL_004f: stfld int32 C/'d__2'::'<>1__state' - IL_0054: ldc.i4.1 - IL_0055: ret - IL_0056: ldarg.0 - IL_0057: ldc.i4.m1 - IL_0058: stfld int32 C/'d__2'::'<>1__state' - IL_005d: ldc.i4.0 - IL_005e: ret - } // end of method 'd__2'::MoveNext - .method private final hidebysig specialname newslot virtual - instance int32 'System.Collections.Generic.IEnumerator.get_Current' () cil managed - { - .custom instance void [netstandard]System.Diagnostics.DebuggerHiddenAttribute::.ctor() = ( - 01 00 00 00 - ) - .override method instance !0 class [netstandard]System.Collections.Generic.IEnumerator`1::get_Current() - // Method begins at RVA 0x2167 - // Code size 7 (0x7) - .maxstack 8 - IL_0000: ldarg.0 - IL_0001: ldfld int32 C/'d__2'::'<>2__current' - IL_0006: ret - } // end of method 'd__2'::'System.Collections.Generic.IEnumerator.get_Current' - .method private final hidebysig newslot virtual - instance void System.Collections.IEnumerator.Reset () cil managed - { - .custom instance void [netstandard]System.Diagnostics.DebuggerHiddenAttribute::.ctor() = ( - 01 00 00 00 - ) - .override method instance void [netstandard]System.Collections.IEnumerator::Reset() - // Method begins at RVA 0x216f - // Code size 6 (0x6) - .maxstack 8 - IL_0000: newobj instance void [netstandard]System.NotSupportedException::.ctor() - IL_0005: throw - } // end of method 'd__2'::System.Collections.IEnumerator.Reset - .method private final hidebysig specialname newslot virtual - instance object System.Collections.IEnumerator.get_Current () cil managed - { - .custom instance void [netstandard]System.Diagnostics.DebuggerHiddenAttribute::.ctor() = ( - 01 00 00 00 - ) - .override method instance object [netstandard]System.Collections.IEnumerator::get_Current() - // Method begins at RVA 0x2176 - // Code size 12 (0xc) - .maxstack 8 - IL_0000: ldarg.0 - IL_0001: ldfld int32 C/'d__2'::'<>2__current' - IL_0006: box [netstandard]System.Int32 - IL_000b: ret - } // end of method 'd__2'::System.Collections.IEnumerator.get_Current - .method private final hidebysig newslot virtual - instance class [netstandard]System.Collections.Generic.IEnumerator`1 'System.Collections.Generic.IEnumerable.GetEnumerator' () cil managed - { - .custom instance void [netstandard]System.Diagnostics.DebuggerHiddenAttribute::.ctor() = ( - 01 00 00 00 - ) - .override method instance class [netstandard]System.Collections.Generic.IEnumerator`1 class [netstandard]System.Collections.Generic.IEnumerable`1::GetEnumerator() - // Method begins at RVA 0x2184 - // Code size 55 (0x37) - .maxstack 2 - .locals init ( - [0] class C/'d__2' - ) - IL_0000: ldarg.0 - IL_0001: ldfld int32 C/'d__2'::'<>1__state' - IL_0006: ldc.i4.s -2 - IL_0008: bne.un.s IL_0022 - IL_000a: ldarg.0 - IL_000b: ldfld int32 C/'d__2'::'<>l__initialThreadId' - IL_0010: call int32 [netstandard]System.Environment::get_CurrentManagedThreadId() - IL_0015: bne.un.s IL_0022 - IL_0017: ldarg.0 - IL_0018: ldc.i4.0 - IL_0019: stfld int32 C/'d__2'::'<>1__state' - IL_001e: ldarg.0 - IL_001f: stloc.0 - IL_0020: br.s IL_0035 - IL_0022: ldc.i4.0 - IL_0023: newobj instance void C/'d__2'::.ctor(int32) - IL_0028: stloc.0 - IL_0029: ldloc.0 - IL_002a: ldarg.0 - IL_002b: ldfld class C C/'d__2'::'<>4__this' - IL_0030: stfld class C C/'d__2'::'<>4__this' - IL_0035: ldloc.0 - IL_0036: ret - } // end of method 'd__2'::'System.Collections.Generic.IEnumerable.GetEnumerator' - .method private final hidebysig newslot virtual - instance class [netstandard]System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator () cil managed - { - .custom instance void [netstandard]System.Diagnostics.DebuggerHiddenAttribute::.ctor() = ( - 01 00 00 00 - ) - .override method instance class [netstandard]System.Collections.IEnumerator [netstandard]System.Collections.IEnumerable::GetEnumerator() - // Method begins at RVA 0x21c7 - // Code size 7 (0x7) - .maxstack 8 - IL_0000: ldarg.0 - IL_0001: call instance class [netstandard]System.Collections.Generic.IEnumerator`1 C/'d__2'::'System.Collections.Generic.IEnumerable.GetEnumerator'() - IL_0006: ret - } // end of method 'd__2'::System.Collections.IEnumerable.GetEnumerator - // Properties - .property instance int32 'System.Collections.Generic.IEnumerator.Current'() - { - .get instance int32 C/'d__2'::'System.Collections.Generic.IEnumerator.get_Current'() - } - .property instance object System.Collections.IEnumerator.Current() - { - .get instance object C/'d__2'::System.Collections.IEnumerator.get_Current() - } - } // end of class d__2 - // Fields - .field private int32 'P' - .custom instance void [netstandard]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( - 01 00 00 00 - ) - // Methods - .method public hidebysig specialname rtspecialname - instance void .ctor ( - int32 y - ) cil managed - { - // Method begins at RVA 0x20c0 - // Code size 14 (0xe) - .maxstack 8 - IL_0000: ldarg.0 - IL_0001: ldarg.1 - IL_0002: stfld int32 C::'P' - IL_0007: ldarg.0 - IL_0008: call instance void [netstandard]System.Object::.ctor() - IL_000d: ret - } // end of method C::.ctor - .method public hidebysig - instance class [netstandard]System.Collections.Generic.IEnumerable`1 M () cil managed - { - .custom instance void [netstandard]System.Runtime.CompilerServices.IteratorStateMachineAttribute::.ctor(class [netstandard]System.Type) = ( - 01 00 09 43 2b 3c 4d 3e 64 5f 5f 32 00 00 - ) - // Method begins at RVA 0x20cf - // Code size 15 (0xf) - .maxstack 8 - IL_0000: ldc.i4.s -2 - IL_0002: newobj instance void C/'d__2'::.ctor(int32) - IL_0007: dup - IL_0008: ldarg.0 - IL_0009: stfld class C C/'d__2'::'<>4__this' - IL_000e: ret - } // end of method C::M + { + .custom instance void [netstandard]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( + 01 00 00 00 + ) + // Fields + .field private int32 '<>1__state' + .field private int32 '<>2__current' + .field private int32 '<>l__initialThreadId' + .field public class C '<>4__this' + // Methods + .method public hidebysig specialname rtspecialname + instance void .ctor ( + int32 '<>1__state' + ) cil managed + { + .custom instance void [netstandard]System.Diagnostics.DebuggerHiddenAttribute::.ctor() = ( + 01 00 00 00 + ) + // Method begins at RVA 0x20df + // Code size 25 (0x19) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: call instance void [netstandard]System.Object::.ctor() + IL_0006: ldarg.0 + IL_0007: ldarg.1 + IL_0008: stfld int32 C/'d__2'::'<>1__state' + IL_000d: ldarg.0 + IL_000e: call int32 [netstandard]System.Environment::get_CurrentManagedThreadId() + IL_0013: stfld int32 C/'d__2'::'<>l__initialThreadId' + IL_0018: ret + } // end of method 'd__2'::.ctor + .method private final hidebysig newslot virtual + instance void System.IDisposable.Dispose () cil managed + { + .custom instance void [netstandard]System.Diagnostics.DebuggerHiddenAttribute::.ctor() = ( + 01 00 00 00 + ) + .override method instance void [netstandard]System.IDisposable::Dispose() + // Method begins at RVA 0x20f9 + // Code size 9 (0x9) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldc.i4.s -2 + IL_0003: stfld int32 C/'d__2'::'<>1__state' + IL_0008: ret + } // end of method 'd__2'::System.IDisposable.Dispose + .method private final hidebysig newslot virtual + instance bool MoveNext () cil managed + { + .override method instance bool [netstandard]System.Collections.IEnumerator::MoveNext() + // Method begins at RVA 0x2104 + // Code size 95 (0x5f) + .maxstack 2 + .locals init ( + [0] int32, + [1] class C + ) + IL_0000: ldarg.0 + IL_0001: ldfld int32 C/'d__2'::'<>1__state' + IL_0006: stloc.0 + IL_0007: ldarg.0 + IL_0008: ldfld class C C/'d__2'::'<>4__this' + IL_000d: stloc.1 + IL_000e: ldloc.0 + IL_000f: switch (IL_0022, IL_003a, IL_0056) + IL_0020: ldc.i4.0 + IL_0021: ret + IL_0022: ldarg.0 + IL_0023: ldc.i4.m1 + IL_0024: stfld int32 C/'d__2'::'<>1__state' + IL_0029: ldarg.0 + IL_002a: ldc.i4.s 9 + IL_002c: stfld int32 C/'d__2'::'<>2__current' + IL_0031: ldarg.0 + IL_0032: ldc.i4.1 + IL_0033: stfld int32 C/'d__2'::'<>1__state' + IL_0038: ldc.i4.1 + IL_0039: ret + IL_003a: ldarg.0 + IL_003b: ldc.i4.m1 + IL_003c: stfld int32 C/'d__2'::'<>1__state' + IL_0041: ldarg.0 + IL_0042: ldloc.1 + IL_0043: ldfld int32 C::'P' + IL_0048: stfld int32 C/'d__2'::'<>2__current' + IL_004d: ldarg.0 + IL_004e: ldc.i4.2 + IL_004f: stfld int32 C/'d__2'::'<>1__state' + IL_0054: ldc.i4.1 + IL_0055: ret + IL_0056: ldarg.0 + IL_0057: ldc.i4.m1 + IL_0058: stfld int32 C/'d__2'::'<>1__state' + IL_005d: ldc.i4.0 + IL_005e: ret + } // end of method 'd__2'::MoveNext + .method private final hidebysig specialname newslot virtual + instance int32 'System.Collections.Generic.IEnumerator.get_Current' () cil managed + { + .custom instance void [netstandard]System.Diagnostics.DebuggerHiddenAttribute::.ctor() = ( + 01 00 00 00 + ) + .override method instance !0 class [netstandard]System.Collections.Generic.IEnumerator`1::get_Current() + // Method begins at RVA 0x216f + // Code size 7 (0x7) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldfld int32 C/'d__2'::'<>2__current' + IL_0006: ret + } // end of method 'd__2'::'System.Collections.Generic.IEnumerator.get_Current' + .method private final hidebysig newslot virtual + instance void System.Collections.IEnumerator.Reset () cil managed + { + .custom instance void [netstandard]System.Diagnostics.DebuggerHiddenAttribute::.ctor() = ( + 01 00 00 00 + ) + .override method instance void [netstandard]System.Collections.IEnumerator::Reset() + // Method begins at RVA 0x2177 + // Code size 6 (0x6) + .maxstack 8 + IL_0000: newobj instance void [netstandard]System.NotSupportedException::.ctor() + IL_0005: throw + } // end of method 'd__2'::System.Collections.IEnumerator.Reset + .method private final hidebysig specialname newslot virtual + instance object System.Collections.IEnumerator.get_Current () cil managed + { + .custom instance void [netstandard]System.Diagnostics.DebuggerHiddenAttribute::.ctor() = ( + 01 00 00 00 + ) + .override method instance object [netstandard]System.Collections.IEnumerator::get_Current() + // Method begins at RVA 0x217e + // Code size 12 (0xc) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldfld int32 C/'d__2'::'<>2__current' + IL_0006: box [netstandard]System.Int32 + IL_000b: ret + } // end of method 'd__2'::System.Collections.IEnumerator.get_Current + .method private final hidebysig newslot virtual + instance class [netstandard]System.Collections.Generic.IEnumerator`1 'System.Collections.Generic.IEnumerable.GetEnumerator' () cil managed + { + .custom instance void [netstandard]System.Diagnostics.DebuggerHiddenAttribute::.ctor() = ( + 01 00 00 00 + ) + .override method instance class [netstandard]System.Collections.Generic.IEnumerator`1 class [netstandard]System.Collections.Generic.IEnumerable`1::GetEnumerator() + // Method begins at RVA 0x218c + // Code size 55 (0x37) + .maxstack 2 + .locals init ( + [0] class C/'d__2' + ) + IL_0000: ldarg.0 + IL_0001: ldfld int32 C/'d__2'::'<>1__state' + IL_0006: ldc.i4.s -2 + IL_0008: bne.un.s IL_0022 + IL_000a: ldarg.0 + IL_000b: ldfld int32 C/'d__2'::'<>l__initialThreadId' + IL_0010: call int32 [netstandard]System.Environment::get_CurrentManagedThreadId() + IL_0015: bne.un.s IL_0022 + IL_0017: ldarg.0 + IL_0018: ldc.i4.0 + IL_0019: stfld int32 C/'d__2'::'<>1__state' + IL_001e: ldarg.0 + IL_001f: stloc.0 + IL_0020: br.s IL_0035 + IL_0022: ldc.i4.0 + IL_0023: newobj instance void C/'d__2'::.ctor(int32) + IL_0028: stloc.0 + IL_0029: ldloc.0 + IL_002a: ldarg.0 + IL_002b: ldfld class C C/'d__2'::'<>4__this' + IL_0030: stfld class C C/'d__2'::'<>4__this' + IL_0035: ldloc.0 + IL_0036: ret + } // end of method 'd__2'::'System.Collections.Generic.IEnumerable.GetEnumerator' + .method private final hidebysig newslot virtual + instance class [netstandard]System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator () cil managed + { + .custom instance void [netstandard]System.Diagnostics.DebuggerHiddenAttribute::.ctor() = ( + 01 00 00 00 + ) + .override method instance class [netstandard]System.Collections.IEnumerator [netstandard]System.Collections.IEnumerable::GetEnumerator() + // Method begins at RVA 0x21cf + // Code size 7 (0x7) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: call instance class [netstandard]System.Collections.Generic.IEnumerator`1 C/'d__2'::'System.Collections.Generic.IEnumerable.GetEnumerator'() + IL_0006: ret + } // end of method 'd__2'::System.Collections.IEnumerable.GetEnumerator + // Properties + .property instance int32 'System.Collections.Generic.IEnumerator.Current'() + { + .get instance int32 C/'d__2'::'System.Collections.Generic.IEnumerator.get_Current'() + } + .property instance object System.Collections.IEnumerator.Current() + { + .get instance object C/'d__2'::System.Collections.IEnumerator.get_Current() + } + } // end of class d__2 + // Fields + .field private int32 'P' + .custom instance void [netstandard]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( + 01 00 00 00 + ) + // Methods + .method public hidebysig specialname rtspecialname + instance void .ctor ( + int32 y + ) cil managed + { + // Method begins at RVA 0x20c0 + // Code size 14 (0xe) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldarg.1 + IL_0002: stfld int32 C::'P' + IL_0007: ldarg.0 + IL_0008: call instance void [netstandard]System.Object::.ctor() + IL_000d: ret + } // end of method C::.ctor + .method public hidebysig + instance class [netstandard]System.Collections.Generic.IEnumerable`1 M () cil managed + { + .custom instance void [netstandard]System.Runtime.CompilerServices.IteratorStateMachineAttribute::.ctor(class [netstandard]System.Type) = ( + 01 00 09 43 2b 3c 4d 3e 64 5f 5f 32 00 00 + ) + // Method begins at RVA 0x20cf + // Code size 15 (0xf) + .maxstack 8 + IL_0000: ldc.i4.s -2 + IL_0002: newobj instance void C/'d__2'::.ctor(int32) + IL_0007: dup + IL_0008: ldarg.0 + IL_0009: stfld class C C/'d__2'::'<>4__this' + IL_000e: ret + } // end of method C::M } // end of class C ").Replace("[netstandard]", RuntimeUtilities.IsCoreClrRuntime ? "[netstandard]" : "[mscorlib]")); @@ -17093,7 +17097,7 @@ class [netstandard]System.Collections.Generic.IEnumerator`1, [netstandard]System.IDisposable" : @" [netstandard]System.IDisposable, [netstandard]System.Collections.IEnumerator") + @" - { + { .custom instance void [netstandard]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) @@ -17133,15 +17137,18 @@ 01 00 00 00 ) .override method instance void [netstandard]System.IDisposable::Dispose() // Method begins at RVA 0x2108 - // Code size 1 (0x1) + // Code size 9 (0x9) .maxstack 8 - IL_0000: ret + IL_0000: ldarg.0 + IL_0001: ldc.i4.s -2 + IL_0003: stfld int32 C/'d__2'::'<>1__state' + IL_0008: ret } // end of method 'd__2'::System.IDisposable.Dispose .method private final hidebysig newslot virtual instance bool MoveNext () cil managed { .override method instance bool [netstandard]System.Collections.IEnumerator::MoveNext() - // Method begins at RVA 0x210c + // Method begins at RVA 0x2114 // Code size 102 (0x66) .maxstack 2 .locals init ( @@ -17196,7 +17203,7 @@ .method private final hidebysig specialname newslot virtual 01 00 00 00 ) .override method instance !0 class [netstandard]System.Collections.Generic.IEnumerator`1::get_Current() - // Method begins at RVA 0x217e + // Method begins at RVA 0x2186 // Code size 7 (0x7) .maxstack 8 IL_0000: ldarg.0 @@ -17210,7 +17217,7 @@ instance void System.Collections.IEnumerator.Reset () cil managed 01 00 00 00 ) .override method instance void [netstandard]System.Collections.IEnumerator::Reset() - // Method begins at RVA 0x2186 + // Method begins at RVA 0x218e // Code size 6 (0x6) .maxstack 8 IL_0000: newobj instance void [netstandard]System.NotSupportedException::.ctor() @@ -17223,7 +17230,7 @@ instance object System.Collections.IEnumerator.get_Current () cil managed 01 00 00 00 ) .override method instance object [netstandard]System.Collections.IEnumerator::get_Current() - // Method begins at RVA 0x218d + // Method begins at RVA 0x2195 // Code size 12 (0xc) .maxstack 8 IL_0000: ldarg.0 @@ -17238,7 +17245,7 @@ .method private final hidebysig newslot virtual 01 00 00 00 ) .override method instance class [netstandard]System.Collections.Generic.IEnumerator`1 class [netstandard]System.Collections.Generic.IEnumerable`1::GetEnumerator() - // Method begins at RVA 0x219c + // Method begins at RVA 0x21a4 // Code size 55 (0x37) .maxstack 2 .locals init ( @@ -17275,7 +17282,7 @@ instance class [netstandard]System.Collections.IEnumerator System.Collections.IE 01 00 00 00 ) .override method instance class [netstandard]System.Collections.IEnumerator [netstandard]System.Collections.IEnumerable::GetEnumerator() - // Method begins at RVA 0x21df + // Method begins at RVA 0x21e7 // Code size 7 (0x7) .maxstack 8 IL_0000: ldarg.0 @@ -18269,15 +18276,18 @@ 01 00 00 00 ) .override method instance void [netstandard]System.IDisposable::Dispose() // Method begins at RVA 0x212c - // Code size 1 (0x1) + // Code size 9 (0x9) .maxstack 8 - IL_0000: ret + IL_0000: ldarg.0 + IL_0001: ldc.i4.s -2 + IL_0003: stfld int32 C/'<>c__DisplayClass0_0'/'<<-ctor>g__local|1>d'::'<>1__state' + IL_0008: ret } // end of method '<<-ctor>g__local|1>d'::System.IDisposable.Dispose .method private final hidebysig newslot virtual instance bool MoveNext () cil managed { .override method instance bool [netstandard]System.Collections.IEnumerator::MoveNext() - // Method begins at RVA 0x2130 + // Method begins at RVA 0x2138 // Code size 95 (0x5f) .maxstack 2 .locals init ( @@ -18330,7 +18340,7 @@ .method private final hidebysig specialname newslot virtual 01 00 00 00 ) .override method instance !0 class [netstandard]System.Collections.Generic.IEnumerator`1::get_Current() - // Method begins at RVA 0x219b + // Method begins at RVA 0x21a3 // Code size 7 (0x7) .maxstack 8 IL_0000: ldarg.0 @@ -18344,7 +18354,7 @@ instance void System.Collections.IEnumerator.Reset () cil managed 01 00 00 00 ) .override method instance void [netstandard]System.Collections.IEnumerator::Reset() - // Method begins at RVA 0x21a3 + // Method begins at RVA 0x21ab // Code size 6 (0x6) .maxstack 8 IL_0000: newobj instance void [netstandard]System.NotSupportedException::.ctor() @@ -18357,7 +18367,7 @@ instance object System.Collections.IEnumerator.get_Current () cil managed 01 00 00 00 ) .override method instance object [netstandard]System.Collections.IEnumerator::get_Current() - // Method begins at RVA 0x21aa + // Method begins at RVA 0x21b2 // Code size 12 (0xc) .maxstack 8 IL_0000: ldarg.0 @@ -18372,7 +18382,7 @@ .method private final hidebysig newslot virtual 01 00 00 00 ) .override method instance class [netstandard]System.Collections.Generic.IEnumerator`1 class [netstandard]System.Collections.Generic.IEnumerable`1::GetEnumerator() - // Method begins at RVA 0x21b8 + // Method begins at RVA 0x21c0 // Code size 55 (0x37) .maxstack 2 .locals init ( @@ -18409,7 +18419,7 @@ instance class [netstandard]System.Collections.IEnumerator System.Collections.IE 01 00 00 00 ) .override method instance class [netstandard]System.Collections.IEnumerator [netstandard]System.Collections.IEnumerable::GetEnumerator() - // Method begins at RVA 0x21fb + // Method begins at RVA 0x2203 // Code size 7 (0x7) .maxstack 8 IL_0000: ldarg.0 @@ -18564,15 +18574,18 @@ 01 00 00 00 ) .override method instance void [netstandard]System.IDisposable::Dispose() // Method begins at RVA 0x2162 - // Code size 1 (0x1) + // Code size 9 (0x9) .maxstack 8 - IL_0000: ret + IL_0000: ldarg.0 + IL_0001: ldc.i4.s -2 + IL_0003: stfld int32 C/'<>c__DisplayClass0_0'/'<<-ctor>g__local|1>d'::'<>1__state' + IL_0008: ret } // end of method '<<-ctor>g__local|1>d'::System.IDisposable.Dispose .method private final hidebysig newslot virtual instance bool MoveNext () cil managed { .override method instance bool [netstandard]System.Collections.IEnumerator::MoveNext() - // Method begins at RVA 0x2164 + // Method begins at RVA 0x216c // Code size 102 (0x66) .maxstack 2 .locals init ( @@ -18627,7 +18640,7 @@ .method private final hidebysig specialname newslot virtual 01 00 00 00 ) .override method instance !0 class [netstandard]System.Collections.Generic.IEnumerator`1::get_Current() - // Method begins at RVA 0x21d6 + // Method begins at RVA 0x21de // Code size 7 (0x7) .maxstack 8 IL_0000: ldarg.0 @@ -18641,7 +18654,7 @@ instance void System.Collections.IEnumerator.Reset () cil managed 01 00 00 00 ) .override method instance void [netstandard]System.Collections.IEnumerator::Reset() - // Method begins at RVA 0x21de + // Method begins at RVA 0x21e6 // Code size 6 (0x6) .maxstack 8 IL_0000: newobj instance void [netstandard]System.NotSupportedException::.ctor() @@ -18654,7 +18667,7 @@ instance object System.Collections.IEnumerator.get_Current () cil managed 01 00 00 00 ) .override method instance object [netstandard]System.Collections.IEnumerator::get_Current() - // Method begins at RVA 0x21e5 + // Method begins at RVA 0x21ed // Code size 12 (0xc) .maxstack 8 IL_0000: ldarg.0 @@ -18669,7 +18682,7 @@ .method private final hidebysig newslot virtual 01 00 00 00 ) .override method instance class [netstandard]System.Collections.Generic.IEnumerator`1 class [netstandard]System.Collections.Generic.IEnumerable`1::GetEnumerator() - // Method begins at RVA 0x21f4 + // Method begins at RVA 0x21fc // Code size 55 (0x37) .maxstack 2 .locals init ( @@ -18706,7 +18719,7 @@ instance class [netstandard]System.Collections.IEnumerator System.Collections.IE 01 00 00 00 ) .override method instance class [netstandard]System.Collections.IEnumerator [netstandard]System.Collections.IEnumerable::GetEnumerator() - // Method begins at RVA 0x2237 + // Method begins at RVA 0x223f // Code size 7 (0x7) .maxstack 8 IL_0000: ldarg.0 @@ -22348,5 +22361,258 @@ public record {{typeKind}} C4 Diagnostic(ErrorCode.WRN_UninitializedNonNullableField, "C2").WithArguments("property", "Text").WithLocation(12, 12) ); } + + [Theory] + [CombinatorialData] + public void CompilerLoweringPreserveAttribute_01([CombinatorialValues("class ", "struct")] string keyword) + { + string source1 = @" +using System; +using System.Runtime.CompilerServices; + +[CompilerLoweringPreserve] +[AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter)] +public class Preserve1Attribute : Attribute { } + +[CompilerLoweringPreserve] +[AttributeUsage(AttributeTargets.Parameter)] +public class Preserve2Attribute : Attribute { } + +[AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter)] +public class Preserve3Attribute : Attribute { } +"; + + string source2 = @" +public " + keyword + @" Test1( + [Preserve1] + [Preserve2] + [Preserve3] + int P1) +{ + int M1() => P1; +} +"; + var comp1 = CreateCompilation( + [source1, source2, CompilerLoweringPreserveAttributeDefinition], + options: TestOptions.DebugDll.WithMetadataImportOptions(MetadataImportOptions.All)); + CompileAndVerify(comp1, symbolValidator: validate).VerifyDiagnostics(); + + var comp2 = CreateCompilation([source2], references: [comp1.ToMetadataReference()], options: TestOptions.DebugDll.WithMetadataImportOptions(MetadataImportOptions.All)); + CompileAndVerify(comp2, symbolValidator: validate).VerifyDiagnostics(); + + var comp3 = CreateCompilation([source2], references: [comp1.EmitToImageReference()], options: TestOptions.DebugDll.WithMetadataImportOptions(MetadataImportOptions.All)); + CompileAndVerify(comp3, symbolValidator: validate).VerifyDiagnostics(); + + static void validate(ModuleSymbol m) + { + AssertEx.SequenceEqual( + [ + "Preserve1Attribute", + "System.Runtime.CompilerServices.CompilerGeneratedAttribute", + "System.Diagnostics.DebuggerBrowsableAttribute(System.Diagnostics.DebuggerBrowsableState.Never)" + ], + m.GlobalNamespace.GetMember("Test1.P").GetAttributes().Select(a => a.ToString())); + } + } + + [Theory] + [CombinatorialData] + public void CompilerLoweringPreserveAttribute_02([CombinatorialValues("class ", "struct")] string keyword) + { + string source1 = @" +using System; +using System.Runtime.CompilerServices; + +[CompilerLoweringPreserve] +[AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter)] +public class Preserve1Attribute : Attribute { } + +[CompilerLoweringPreserve] +[AttributeUsage(AttributeTargets.Parameter)] +public class Preserve2Attribute : Attribute { } +"; + + string source2 = @" +public record " + keyword + @" Test1( + [Preserve1] + [Preserve2] + int P1) +{ + int M1() => P1; +} +"; + var comp1 = CreateCompilation( + [source1, source2, CompilerLoweringPreserveAttributeDefinition, IsExternalInitTypeDefinition], + options: TestOptions.DebugDll.WithMetadataImportOptions(MetadataImportOptions.All)); + CompileAndVerify(comp1, symbolValidator: validate, verify: Verification.Skipped).VerifyDiagnostics(); + + var comp2 = CreateCompilation([source2, IsExternalInitTypeDefinition], references: [comp1.ToMetadataReference()], options: TestOptions.DebugDll.WithMetadataImportOptions(MetadataImportOptions.All)); + CompileAndVerify(comp2, symbolValidator: validate, verify: Verification.Skipped).VerifyDiagnostics(); + + var comp3 = CreateCompilation([source2, IsExternalInitTypeDefinition], references: [comp1.EmitToImageReference()], options: TestOptions.DebugDll.WithMetadataImportOptions(MetadataImportOptions.All)); + CompileAndVerify(comp3, symbolValidator: validate, verify: Verification.Skipped).VerifyDiagnostics(); + + static void validate(ModuleSymbol m) + { + AssertEx.SequenceEqual( + [ + "System.Runtime.CompilerServices.CompilerGeneratedAttribute", + "System.Diagnostics.DebuggerBrowsableAttribute(System.Diagnostics.DebuggerBrowsableState.Never)" + ], + m.GlobalNamespace.GetMember("Test1.k__BackingField").GetAttributes().Select(a => a.ToString())); + } + } + + [Theory] + [CombinatorialData] + public void CompilerLoweringPreserveAttribute_03([CombinatorialValues("class ", "struct")] string keyword) + { + string source1 = @" +using System; + +[AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter)] +public class Preserve1Attribute : Attribute { } +"; + + string source2 = @" +public record " + keyword + @" Test1( + [field: Preserve1] + int P1) +{ + int M1() => P1; +} +"; + var comp1 = CreateCompilation( + [source1, source2, IsExternalInitTypeDefinition], + options: TestOptions.DebugDll.WithMetadataImportOptions(MetadataImportOptions.All)); + CompileAndVerify(comp1, symbolValidator: validate, verify: Verification.Skipped).VerifyDiagnostics(); + + static void validate(ModuleSymbol m) + { + AssertEx.SequenceEqual( + [ + "System.Runtime.CompilerServices.CompilerGeneratedAttribute", + "System.Diagnostics.DebuggerBrowsableAttribute(System.Diagnostics.DebuggerBrowsableState.Never)", + "Preserve1Attribute" + ], + m.GlobalNamespace.GetMember("Test1.k__BackingField").GetAttributes().Select(a => a.ToString())); + } + } + + [Theory] + [CombinatorialData] + public void CompilerLoweringPreserveAttribute_04_Retargeting([CombinatorialValues("class ", "struct")] string keyword) + { + string source0 = @" +public class Test0 {} +"; + + var comp0 = CreateCompilation(source0); + + string source1 = @" +using System; +using System.Runtime.CompilerServices; + +[CompilerLoweringPreserve] +[AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter)] +public class Preserve1Attribute : Attribute { } + +[CompilerLoweringPreserve] +[AttributeUsage(AttributeTargets.Parameter)] +public class Preserve2Attribute : Attribute { } + +[AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter)] +public class Preserve3Attribute : Attribute { } +"; + + string source2 = @" +public " + keyword + @" Test1( + [Preserve1] + [Preserve2] + [Preserve3] + int P1) +{ + int M1() => P1; +} +"; + var comp1 = CreateCompilation( + [source1, CompilerLoweringPreserveAttributeDefinition], + references: [comp0.ToMetadataReference()], + options: TestOptions.DebugDll.WithMetadataImportOptions(MetadataImportOptions.All)); + + var comp2 = CreateCompilation([source2], references: [comp1.ToMetadataReference()], options: TestOptions.DebugDll.WithMetadataImportOptions(MetadataImportOptions.All)); + + Assert.IsType(comp2.GetTypeByMetadataName("Preserve1Attribute")); + + CompileAndVerify(comp2, symbolValidator: validate).VerifyDiagnostics(); + + static void validate(ModuleSymbol m) + { + AssertEx.SequenceEqual( + [ + "Preserve1Attribute", + "System.Runtime.CompilerServices.CompilerGeneratedAttribute", + "System.Diagnostics.DebuggerBrowsableAttribute(System.Diagnostics.DebuggerBrowsableState.Never)" + ], + m.GlobalNamespace.GetMember("Test1.P").GetAttributes().Select(a => a.ToString())); + } + } + + [Theory] + [CombinatorialData] + public void CompilerLoweringPreserveAttribute_05_Generic([CombinatorialValues("class ", "struct")] string keyword) + { + string source0 = @" +public class Test0 {} +"; + + var comp0 = CreateCompilation(source0); + + string source1 = @" +using System; +using System.Runtime.CompilerServices; + +[CompilerLoweringPreserve] +[AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter)] +public class Preserve1Attribute : Attribute { } + +[CompilerLoweringPreserve] +[AttributeUsage(AttributeTargets.Parameter)] +public class Preserve2Attribute : Attribute { } + +[AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter)] +public class Preserve3Attribute : Attribute { } +"; + + string source2 = @" +public " + keyword + @" Test1( + [Preserve1] + [Preserve2] + [Preserve3] + int P1) +{ + int M1() => P1; +} +"; + var comp1 = CreateCompilation( + [source1, CompilerLoweringPreserveAttributeDefinition], + references: [comp0.ToMetadataReference()], + options: TestOptions.DebugDll.WithMetadataImportOptions(MetadataImportOptions.All)); + + var comp2 = CreateCompilation([source2], references: [comp1.ToMetadataReference()], options: TestOptions.DebugDll.WithMetadataImportOptions(MetadataImportOptions.All)); + + CompileAndVerify(comp2, symbolValidator: validate).VerifyDiagnostics(); + + static void validate(ModuleSymbol m) + { + AssertEx.SequenceEqual( + [ + "Preserve1Attribute", + "System.Runtime.CompilerServices.CompilerGeneratedAttribute", + "System.Diagnostics.DebuggerBrowsableAttribute(System.Diagnostics.DebuggerBrowsableState.Never)" + ], + m.GlobalNamespace.GetMember("Test1.P").GetAttributes().Select(a => a.ToString())); + } + } } } diff --git a/src/Compilers/CSharp/Test/Emit3/Semantics/RecordTests.cs b/src/Compilers/CSharp/Test/Emit3/Semantics/RecordTests.cs index 98c3c648efbaa..8fd3792ba13d2 100644 --- a/src/Compilers/CSharp/Test/Emit3/Semantics/RecordTests.cs +++ b/src/Compilers/CSharp/Test/Emit3/Semantics/RecordTests.cs @@ -14073,6 +14073,51 @@ public static void Main() CompileAndVerify(comp, verify: Verification.Skipped, expectedOutput: "123").VerifyDiagnostics(); } + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/72357")] + public void CopyCtor_AssemblyWarnings() + { + var comp1 = CreateCompilation(""" + public record BaseRecord + { + public required object Object1 { get; init; } + public required object Object2 { get; init; } + } + """, assemblyName: "Base", targetFramework: TargetFramework.Net70); + + var comp2 = CreateCompilation(""" + var sut = new DerivedRecord + { + Object1 = new object(), + Object2 = new object() + }; + + var broken = sut with { Object2 = new object()}; + System.Console.Write(broken.Object1 is null); + + public record DerivedRecord : BaseRecord; + """, assemblyName: "Derived", references: [comp1.EmitToImageReference()], targetFramework: TargetFramework.Net80); + + var verifier = CompileAndVerify(comp2, expectedOutput: ExecutionConditionUtil.IsCoreClr ? "False" : null, verify: Verification.FailsPEVerify); + + // Historical note: These warnings were the cause of the bug, so they are not being suppressed + var expectedDiagnostic = + // warning CS1701: Assuming assembly reference 'System.Runtime, Version=7.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' used by 'Base' matches identity 'System.Runtime, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' of 'System.Runtime', you may need to supply runtime policy + Diagnostic(ErrorCode.WRN_UnifyReferenceMajMin).WithArguments("System.Runtime, Version=7.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", "Base", "System.Runtime, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", "System.Runtime").WithLocation(1, 1); + + verifier.VerifyDiagnostics(Enumerable.Repeat(expectedDiagnostic, 21).ToArray()); + + verifier.VerifyIL("DerivedRecord..ctor(DerivedRecord)", """ + { + // Code size 8 (0x8) + .maxstack 2 + IL_0000: ldarg.0 + IL_0001: ldarg.1 + IL_0002: call "BaseRecord..ctor(BaseRecord)" + IL_0007: ret + } + """); + } + [Fact] public void Deconstruct_Simple() { diff --git a/src/Compilers/CSharp/Test/EndToEnd/EndToEndTests.cs b/src/Compilers/CSharp/Test/EndToEnd/EndToEndTests.cs index 3ecdfa9c4a313..9b82c44d634d1 100644 --- a/src/Compilers/CSharp/Test/EndToEnd/EndToEndTests.cs +++ b/src/Compilers/CSharp/Test/EndToEnd/EndToEndTests.cs @@ -21,6 +21,8 @@ using System.Runtime.InteropServices; using Microsoft.CodeAnalysis.FlowAnalysis; using Microsoft.CodeAnalysis.Operations; +using System.Collections.Immutable; +using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CSharp.UnitTests.EndToEnd { @@ -640,7 +642,9 @@ public void Interceptors() builder.AppendLine("C.M();"); } - files.Add((builder.ToString(), "Program.cs")); + var program = (builder.ToString(), "Program.cs"); + var locations = getInterceptableLocations(program); + files.Add(program); files.Add((""" class C @@ -652,20 +656,21 @@ namespace System.Runtime.CompilerServices { public class InterceptsLocationAttribute : Attribute { - public InterceptsLocationAttribute(string path, int line, int column) { } + public InterceptsLocationAttribute(int version, string data) { } } } """, "C.cs")); for (int i = 0; i < numberOfInterceptors; i++) { + var location = locations[i]; files.Add(($$""" using System; using System.Runtime.CompilerServices; class C{{i}} { - [InterceptsLocation("Program.cs", {{i + 1}}, 3)] + [InterceptsLocation({{location.Version}}, "{{location.Data}}")] public static void M() { Console.WriteLine({{i}}); @@ -686,6 +691,16 @@ string makeExpectedOutput() } return builder.ToString(); } + + ImmutableArray getInterceptableLocations(CSharpTestSource source) + { + var comp = CreateCompilation(source); + var tree = comp.SyntaxTrees.Single(); + var model = comp.GetSemanticModel(tree); + + var nodes = tree.GetRoot().DescendantNodes().OfType().SelectAsArray(node => model.GetInterceptableLocation(node)); + return nodes; + } } [Theory, CombinatorialData, WorkItem("https://github.com/dotnet/roslyn/issues/69093")] diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/DelegateTypeTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/DelegateTypeTests.cs index 212a1e79b9163..d8e9be5af9aa0 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/DelegateTypeTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/DelegateTypeTests.cs @@ -14344,6 +14344,38 @@ static void Main() Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "y").WithArguments("System.Diagnostics.CodeAnalysis.UnscopedRefAttribute", ".ctor").WithLocation(7, 51)); } + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75828")] + public void SynthesizedDelegateTypes_UnscopedRefAttribute_MissingConstructor_03() + { + string sourceA = """ + using System.Diagnostics.CodeAnalysis; + public class A + { + public static ref int F(int x, [UnscopedRef] ref int y) => ref y; + } + """; + var comp = CreateCompilation(sourceA, targetFramework: TargetFramework.Net70); + var refA = comp.EmitToImageReference(); + + string sourceB = """ + class Program + { + static void Main() + { + int i = 0; + var d = A.F; + d(0, ref i); + } + } + """; + comp = CreateCompilation(sourceB, references: [refA], parseOptions: TestOptions.Regular10); + comp.MakeMemberMissing(WellKnownMember.System_Diagnostics_CodeAnalysis_UnscopedRefAttribute__ctor); + comp.VerifyEmitDiagnostics( + // (6,17): error CS0656: Missing compiler required member 'System.Diagnostics.CodeAnalysis.UnscopedRefAttribute..ctor' + // var d = A.F; + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "A.F").WithArguments("System.Diagnostics.CodeAnalysis.UnscopedRefAttribute", ".ctor").WithLocation(6, 17)); + } + private static void VerifyLocalDelegateType(SemanticModel model, VariableDeclaratorSyntax variable, string expectedInvokeMethod) { var expectedBaseType = ((CSharpCompilation)model.Compilation).GetSpecialType(SpecialType.System_MulticastDelegate); diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/DynamicTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/DynamicTests.cs index 017ab0d3388b0..8b4dc57bdf9b9 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/DynamicTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/DynamicTests.cs @@ -11694,5 +11694,42 @@ static void Main() CompileAndVerify(comp1, expectedOutput: "123").VerifyDiagnostics(); } + + [Fact] + public void CompilerLoweringPreserveAttribute_01() + { + string source1 = @" +using System; +using System.Runtime.CompilerServices; + +[CompilerLoweringPreserve] +[AttributeUsage(AttributeTargets.GenericParameter)] +public class Preserve1Attribute : Attribute { } + +[AttributeUsage(AttributeTargets.GenericParameter)] +public class Preserve2Attribute : Attribute { } +"; + + string source2 = @" +class Test1 +{ + dynamic M2<[Preserve1][Preserve2]T>(T x, dynamic y) + { + return y.M(x); + } +} +"; + var comp1 = CreateCompilation( + [source1, source2, CompilerLoweringPreserveAttributeDefinition], + targetFramework: TargetFramework.StandardAndCSharp); + CompileAndVerify(comp1, symbolValidator: validate).VerifyDiagnostics(); + + static void validate(ModuleSymbol m) + { + AssertEx.SequenceEqual( + ["Preserve1Attribute"], + m.GlobalNamespace.GetMember("Test1.<>o__0").TypeParameters.Single().GetAttributes().Select(a => a.ToString())); + } + } } } diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/InterceptorsTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/InterceptorsTests.cs index 65e93bb7c829f..960e0e7476c0c 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/InterceptorsTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/InterceptorsTests.cs @@ -37,52 +37,102 @@ public InterceptsLocationAttribute(int version, string data) { } private static readonly SyntaxTree s_attributesTree = CSharpTestSource.Parse(s_attributesSource.text, s_attributesSource.path, RegularWithInterceptors); - [Fact] - public void FeatureFlag() + private static ImmutableArray GetInterceptableLocations(CSharpTestSource source) { - var source = """ + var comp = CreateCompilation(source); + var tree = comp.SyntaxTrees.Single(); + var model = comp.GetSemanticModel(tree); + + var nodes = tree.GetRoot().DescendantNodes().OfType().SelectAsArray(node => model.GetInterceptableLocation(node)); + return nodes; + } + + private static string GetAttributeArgs(InterceptableLocation location) => $@"{location.Version}, ""{location.Data}"""; + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/76641")] + public void UnsupportedWarningWave() + { + var source = (""" + C.M(); + + class C + { + public static void M() => throw null!; + } + """, "Program.cs"); + var interceptors = $$""" using System.Runtime.CompilerServices; using System; + class D + { + [InterceptsLocation("Program.cs", 1, 3)] + public static void M() => Console.Write(1); + } + """; + + var comp = CreateCompilation([source, interceptors, s_attributesSource], parseOptions: RegularWithInterceptors, options: TestOptions.DebugExe.WithWarningLevel(8)); + comp.VerifyEmitDiagnostics(); + + comp = CreateCompilation([source, interceptors, s_attributesSource], parseOptions: RegularWithInterceptors, options: TestOptions.DebugExe.WithWarningLevel(9)); + comp.VerifyEmitDiagnostics( + // (5,6): warning CS9270: 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) + // [InterceptsLocation("Program.cs", 1, 3)] + Diagnostic(ErrorCode.WRN_InterceptsLocationAttributeUnsupportedSignature, @"InterceptsLocation(""Program.cs"", 1, 3)").WithLocation(5, 6)); + + comp = CreateCompilation([source, interceptors, s_attributesSource], parseOptions: RegularWithInterceptors); + comp.VerifyEmitDiagnostics( + // (5,6): warning CS9270: 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) + // [InterceptsLocation("Program.cs", 1, 3)] + Diagnostic(ErrorCode.WRN_InterceptsLocationAttributeUnsupportedSignature, @"InterceptsLocation(""Program.cs"", 1, 3)").WithLocation(5, 6)); + } + [Fact] + public void FeatureFlag() + { + var source = """ C.M(); class C { public static void M() => throw null!; } - + """; + var locations = GetInterceptableLocations(source); + var interceptors = $$""" + using System.Runtime.CompilerServices; + using System; class D { - [InterceptsLocation("Program.cs", 4, 3)] + [InterceptsLocation({{GetAttributeArgs(locations[0]!)}})] public static void M() => Console.Write(1); } """; var sadCaseDiagnostics = new[] { - // Program.cs(13,6): error CS9206: An interceptor cannot be declared in the global namespace. - // [InterceptsLocation("Program.cs", 4, 3)] - Diagnostic(ErrorCode.ERR_InterceptorGlobalNamespace, @"InterceptsLocation(""Program.cs"", 4, 3)").WithLocation(13, 6) + // (5,6): error CS9206: An interceptor cannot be declared in the global namespace. + // [InterceptsLocation(1, "eY+urAo7Kg2rsKgGSGjShwIAAAA=")] + Diagnostic(ErrorCode.ERR_InterceptorGlobalNamespace, "InterceptsLocation").WithLocation(5, 6) }; - var comp = CreateCompilation(new[] { (source, "Program.cs"), s_attributesSource }); + var comp = CreateCompilation([source, interceptors, s_attributesSource]); comp.VerifyEmitDiagnostics(sadCaseDiagnostics); - comp = CreateCompilation(new[] { (source, "Program.cs"), s_attributesSource }, parseOptions: TestOptions.Regular.WithFeature("InterceptorsPreview-experimental")); + comp = CreateCompilation([source, interceptors, s_attributesSource], parseOptions: TestOptions.Regular.WithFeature("InterceptorsPreview-experimental")); comp.VerifyEmitDiagnostics(sadCaseDiagnostics); - comp = CreateCompilation(new[] { (source, "Program.cs"), s_attributesSource }, parseOptions: TestOptions.Regular.WithFeature("InterceptorsPreview", "false")); + comp = CreateCompilation([source, interceptors, s_attributesSource], parseOptions: TestOptions.Regular.WithFeature("InterceptorsPreview", "false")); comp.VerifyEmitDiagnostics(sadCaseDiagnostics); - comp = CreateCompilation(new[] { (source, "Program.cs"), s_attributesSource }, parseOptions: TestOptions.Regular.WithFeature("interceptorspreview")); + comp = CreateCompilation([source, interceptors, s_attributesSource], parseOptions: TestOptions.Regular.WithFeature("interceptorspreview")); comp.VerifyEmitDiagnostics(sadCaseDiagnostics); - comp = CreateCompilation(new[] { (source, "Program.cs"), s_attributesSource }, parseOptions: TestOptions.Regular.WithFeature("InterceptorsPreview", "Global")); + comp = CreateCompilation([source, interceptors, s_attributesSource], parseOptions: TestOptions.Regular.WithFeature("InterceptorsPreview", "Global")); comp.VerifyEmitDiagnostics(sadCaseDiagnostics); - comp = CreateCompilation(new[] { (source, "Program.cs"), s_attributesSource }, parseOptions: TestOptions.Regular.WithFeature("InterceptorsPreview", "global.a")); + comp = CreateCompilation([source, interceptors, s_attributesSource], parseOptions: TestOptions.Regular.WithFeature("InterceptorsPreview", "global.a")); comp.VerifyEmitDiagnostics(sadCaseDiagnostics); - var verifier = CompileAndVerify(new[] { (source, "Program.cs"), s_attributesSource }, parseOptions: RegularWithInterceptors, expectedOutput: "1"); + var verifier = CompileAndVerify([source, interceptors, s_attributesSource], parseOptions: RegularWithInterceptors, expectedOutput: "1"); verifier.VerifyDiagnostics(); } @@ -90,42 +140,44 @@ class D public void FeatureFlag_Granular_01() { var source = """ - using System.Runtime.CompilerServices; - using System; - C.M(); class C { public static void M() => throw null!; } + """; + var locations = GetInterceptableLocations(source); + var interceptors = $$""" + using System.Runtime.CompilerServices; + using System; namespace NS1 { class D { - [InterceptsLocation("Program.cs", 4, 3)] + [InterceptsLocation({{GetAttributeArgs(locations[0]!)}})] public static void M() => Console.Write(1); } } """; - var comp = CreateCompilation(new[] { (source, "Program.cs"), s_attributesSource }, parseOptions: TestOptions.Regular.WithFeature("InterceptorsNamespaces", "NS")); + var comp = CreateCompilation([source, interceptors, s_attributesSource], parseOptions: TestOptions.Regular.WithFeature("InterceptorsNamespaces", "NS")); comp.VerifyEmitDiagnostics( - // Program.cs(15,10): error CS9137: The 'interceptors' experimental feature is not enabled. Add '$(InterceptorsNamespaces);NS1' to your project. - // [InterceptsLocation("Program.cs", 4, 3)] - Diagnostic(ErrorCode.ERR_InterceptorsFeatureNotEnabled, @"InterceptsLocation(""Program.cs"", 4, 3)").WithArguments("$(InterceptorsNamespaces);NS1").WithLocation(15, 10)); + // (8,10): error CS9137: The 'interceptors' feature is not enabled in this namespace. Add '$(InterceptorsNamespaces);NS1' to your project. + // [InterceptsLocation(1, "eY+urAo7Kg2rsKgGSGjShwIAAAA=")] + Diagnostic(ErrorCode.ERR_InterceptorsFeatureNotEnabled, "InterceptsLocation").WithArguments("$(InterceptorsNamespaces);NS1").WithLocation(8, 10)); - comp = CreateCompilation(new[] { (source, "Program.cs"), s_attributesSource }, parseOptions: TestOptions.Regular.WithFeature("InterceptorsNamespaces", "NS1.NS2")); + comp = CreateCompilation([source, interceptors, s_attributesSource], parseOptions: TestOptions.Regular.WithFeature("InterceptorsNamespaces", "NS1.NS2")); comp.VerifyEmitDiagnostics( - // Program.cs(15,10): error CS9137: The 'interceptors' experimental feature is not enabled. Add '$(InterceptorsNamespaces);NS1' to your project. - // [InterceptsLocation("Program.cs", 4, 3)] - Diagnostic(ErrorCode.ERR_InterceptorsFeatureNotEnabled, @"InterceptsLocation(""Program.cs"", 4, 3)").WithArguments("$(InterceptorsNamespaces);NS1").WithLocation(15, 10)); + // (8,10): error CS9137: The 'interceptors' feature is not enabled in this namespace. Add '$(InterceptorsNamespaces);NS1' to your project. + // [InterceptsLocation(1, "eY+urAo7Kg2rsKgGSGjShwIAAAA=")] + Diagnostic(ErrorCode.ERR_InterceptorsFeatureNotEnabled, "InterceptsLocation").WithArguments("$(InterceptorsNamespaces);NS1").WithLocation(8, 10)); - var verifier = CompileAndVerify(new[] { (source, "Program.cs"), s_attributesSource }, parseOptions: TestOptions.Regular.WithFeature("InterceptorsNamespaces", "NS1"), expectedOutput: "1"); + var verifier = CompileAndVerify([source, interceptors, s_attributesSource], parseOptions: TestOptions.Regular.WithFeature("InterceptorsNamespaces", "NS1"), expectedOutput: "1"); verifier.VerifyDiagnostics(); - verifier = CompileAndVerify(new[] { (source, "Program.cs"), s_attributesSource }, parseOptions: TestOptions.Regular.WithFeature("InterceptorsNamespaces", "NS1;NS2"), expectedOutput: "1"); + verifier = CompileAndVerify([source, interceptors, s_attributesSource], parseOptions: TestOptions.Regular.WithFeature("InterceptorsNamespaces", "NS1;NS2"), expectedOutput: "1"); verifier.VerifyDiagnostics(); } @@ -196,21 +248,23 @@ class D public void FeatureFlag_Granular_02() { var source = """ - using System.Runtime.CompilerServices; - using System; - C.M(); class C { public static void M() => throw null!; } + """; + var locations = GetInterceptableLocations(source); + var interceptor = $$""" + using System.Runtime.CompilerServices; + using System; namespace NS1.NS2 { class D { - [InterceptsLocation("Program.cs", 4, 3)] + [InterceptsLocation({{GetAttributeArgs(locations[0]!)}})] public static void M() => Console.Write(1); } } @@ -237,16 +291,16 @@ class D void sadCase(string featureValue) { - var comp = CreateCompilation(new[] { (source, "Program.cs"), s_attributesSource }, parseOptions: TestOptions.Regular.WithFeature("InterceptorsNamespaces", featureValue)); + var comp = CreateCompilation([source, interceptor, s_attributesSource], parseOptions: TestOptions.Regular.WithFeature("InterceptorsNamespaces", featureValue)); comp.VerifyEmitDiagnostics( - // Program.cs(15,10): error CS9137: The 'interceptors' experimental feature is not enabled. Add '$(InterceptorsNamespaces);NS1.NS2' to your project. - // [InterceptsLocation("Program.cs", 4, 3)] - Diagnostic(ErrorCode.ERR_InterceptorsFeatureNotEnabled, @"InterceptsLocation(""Program.cs"", 4, 3)").WithArguments("$(InterceptorsNamespaces);NS1.NS2").WithLocation(15, 10)); + // (8,10): error CS9137: The 'interceptors' feature is not enabled in this namespace. Add '$(InterceptorsNamespaces);NS1.NS2' to your project. + // [InterceptsLocation(1, "eY+urAo7Kg2rsKgGSGjShwIAAAA=")] + Diagnostic(ErrorCode.ERR_InterceptorsFeatureNotEnabled, "InterceptsLocation").WithArguments("$(InterceptorsNamespaces);NS1.NS2").WithLocation(8, 10)); } void happyCase(string featureValue) { - var verifier = CompileAndVerify(new[] { (source, "Program.cs"), s_attributesSource }, parseOptions: TestOptions.Regular.WithFeature("InterceptorsNamespaces", featureValue), expectedOutput: "1"); + var verifier = CompileAndVerify([source, interceptor, s_attributesSource], parseOptions: TestOptions.Regular.WithFeature("InterceptorsNamespaces", featureValue), expectedOutput: "1"); verifier.VerifyDiagnostics(); } } @@ -255,58 +309,61 @@ void happyCase(string featureValue) public void FeatureFlag_Granular_03() { var source = """ - using System.Runtime.CompilerServices; - using System; - C.M(); class C { public static void M() => throw null!; } + """; + var locations = GetInterceptableLocations(source); + var interceptors = $$""" + using System.Runtime.CompilerServices; + using System; class D { - [InterceptsLocation("Program.cs", 4, 3)] + [InterceptsLocation({{GetAttributeArgs(locations[0]!)}})] public static void M() => Console.Write(1); } """; - var comp = CreateCompilation(new[] { (source, "Program.cs"), s_attributesSource }, parseOptions: TestOptions.Regular.WithFeature("InterceptorsNamespaces", "")); + var comp = CreateCompilation([source, interceptors, s_attributesSource], parseOptions: TestOptions.Regular.WithFeature("InterceptorsNamespaces", "")); comp.VerifyEmitDiagnostics( - // Program.cs(13,6): error CS9206: An interceptor cannot be declared in the global namespace. - // [InterceptsLocation("Program.cs", 4, 3)] - Diagnostic(ErrorCode.ERR_InterceptorGlobalNamespace, @"InterceptsLocation(""Program.cs"", 4, 3)").WithLocation(13, 6)); + // (6,6): error CS9206: An interceptor cannot be declared in the global namespace. + // [InterceptsLocation(1, "eY+urAo7Kg2rsKgGSGjShwIAAAA=")] + Diagnostic(ErrorCode.ERR_InterceptorGlobalNamespace, "InterceptsLocation").WithLocation(6, 6)); } [Fact] public void FeatureFlag_Granular_04() { var source = """ - using System.Runtime.CompilerServices; - using System; - C.M(); class C { public static void M() => throw null!; } - + """; + var locations = GetInterceptableLocations(source); + var interceptors = $$""" + using System.Runtime.CompilerServices; + using System; namespace global { class D { - [InterceptsLocation("Program.cs", 4, 3)] + [InterceptsLocation({{GetAttributeArgs(locations[0]!)}})] public static void M() => Console.Write(1); } } """; - var verifier = CompileAndVerify(new[] { (source, "Program.cs"), s_attributesSource }, parseOptions: TestOptions.Regular.WithFeature("InterceptorsNamespaces", "global"), expectedOutput: "1"); + var verifier = CompileAndVerify([source, interceptors, s_attributesSource], parseOptions: TestOptions.Regular.WithFeature("InterceptorsNamespaces", "global"), expectedOutput: "1"); verifier.VerifyDiagnostics(); - verifier = CompileAndVerify(new[] { (source, "Program.cs"), s_attributesSource }, parseOptions: TestOptions.Regular.WithFeature("InterceptorsNamespaces", "global"), expectedOutput: "1"); + verifier = CompileAndVerify([source, interceptors, s_attributesSource], parseOptions: TestOptions.Regular.WithFeature("InterceptorsNamespaces", "global"), expectedOutput: "1"); verifier.VerifyDiagnostics(); } @@ -314,53 +371,63 @@ class D public void FeatureFlag_Granular_05() { var source = """ - using System.Runtime.CompilerServices; - using System; - C.M(); class C { public static void M() => throw null!; } + """; + + var locations = GetInterceptableLocations(source); + var interceptors = $$""" + using System.Runtime.CompilerServices; + using System; namespace global.B { class D { - [InterceptsLocation("Program.cs", 4, 3)] + [InterceptsLocation({{GetAttributeArgs(locations[0]!)}})] public static void M() => Console.Write(1); } } """; - var comp = CreateCompilation(new[] { (source, "Program.cs"), s_attributesSource }, parseOptions: TestOptions.Regular.WithFeature("InterceptorsNamespaces", "global.A")); + var comp = CreateCompilation([source, interceptors, s_attributesSource], parseOptions: TestOptions.Regular.WithFeature("InterceptorsNamespaces", "global.A")); comp.VerifyEmitDiagnostics( - // Program.cs(15,10): error CS9137: The 'interceptors' experimental feature is not enabled in this namespace. Add '$(InterceptorsNamespaces);global.B' to your project. - // [InterceptsLocation("Program.cs", 4, 3)] - Diagnostic(ErrorCode.ERR_InterceptorsFeatureNotEnabled, @"InterceptsLocation(""Program.cs"", 4, 3)").WithArguments("$(InterceptorsNamespaces);global.B").WithLocation(15, 10)); + // (8,10): error CS9137: The 'interceptors' feature is not enabled in this namespace. Add '$(InterceptorsNamespaces);global.B' to your project. + // [InterceptsLocation(1, "eY+urAo7Kg2rsKgGSGjShwIAAAA=")] + Diagnostic(ErrorCode.ERR_InterceptorsFeatureNotEnabled, "InterceptsLocation").WithArguments("$(InterceptorsNamespaces);global.B").WithLocation(8, 10)); } [Fact] public void SelfInterception() { var source = """ - using System.Runtime.CompilerServices; using System; - class C + partial class C { public static void Main() { InterceptableMethod(); } + public static partial void InterceptableMethod() { Console.Write(1); } + } + """; + var locations = GetInterceptableLocations(source); + var interceptors = $$""" + using System.Runtime.CompilerServices; - [InterceptsLocation("Program.cs", 8, 9)] - public static void InterceptableMethod() { Console.Write(1); } + partial class C + { + [InterceptsLocation({{GetAttributeArgs(locations[0]!)}})] + public static partial void InterceptableMethod(); } """; - var verifier = CompileAndVerify(new[] { (source, "Program.cs"), s_attributesSource }, parseOptions: RegularWithInterceptors, expectedOutput: "1"); + var verifier = CompileAndVerify([source, interceptors, s_attributesSource], parseOptions: RegularWithInterceptors, expectedOutput: "1"); verifier.VerifyDiagnostics(); } @@ -368,7 +435,6 @@ public static void Main() public void StaticInterceptable_StaticInterceptor_NoParameters() { var source = """ - using System.Runtime.CompilerServices; using System; class C @@ -381,14 +447,19 @@ public static void Main() InterceptableMethod(); } } + """; + var locations = GetInterceptableLocations(source); + var interceptors = $$""" + using System.Runtime.CompilerServices; + using System; class D { - [InterceptsLocation("Program.cs", 11, 9)] + [InterceptsLocation({{GetAttributeArgs(locations[1]!)}})] public static void Interceptor1() { Console.Write("interceptor 1"); } } """; - var verifier = CompileAndVerify(new[] { (source, "Program.cs"), s_attributesSource }, parseOptions: RegularWithInterceptors, expectedOutput: "interceptor 1"); + var verifier = CompileAndVerify([source, interceptors, s_attributesSource], parseOptions: RegularWithInterceptors, expectedOutput: "interceptor 1"); verifier.VerifyDiagnostics(); } @@ -396,7 +467,6 @@ class D public void Accessibility_01() { var source = """ - using System.Runtime.CompilerServices; using System; class C @@ -409,18 +479,23 @@ public static void Main() InterceptableMethod(); } } + """; + var locations = GetInterceptableLocations(source); + var interceptors = $$""" + using System.Runtime.CompilerServices; + using System; class D { - [InterceptsLocation("Program.cs", 11, 9)] + [InterceptsLocation({{GetAttributeArgs(locations[1]!)}})] private static void Interceptor1() { Console.Write("interceptor 1"); } } """; - var comp = CreateCompilation(new[] { (source, "Program.cs"), s_attributesSource }, parseOptions: RegularWithInterceptors); + var comp = CreateCompilation([source, interceptors, s_attributesSource], parseOptions: RegularWithInterceptors); comp.VerifyEmitDiagnostics( - // Program.cs(17,6): error CS9155: Cannot intercept because 'D.Interceptor1()' is not accessible within 'C.Main()'. - // [InterceptsLocation("Program.cs", 11, 9)] - Diagnostic(ErrorCode.ERR_InterceptorNotAccessible, @"InterceptsLocation(""Program.cs"", 11, 9)").WithArguments("D.Interceptor1()", "C.Main()").WithLocation(17, 6)); + // (6,6): error CS9155: Cannot intercept call with 'D.Interceptor1()' because it is not accessible within 'C.Main()'. + // [InterceptsLocation(1, "BKq4YXWKYsMUMsR6wdliFJkAAAA=")] + Diagnostic(ErrorCode.ERR_InterceptorNotAccessible, "InterceptsLocation").WithArguments("D.Interceptor1()", "C.Main()").WithLocation(6, 6)); } [Fact] @@ -441,14 +516,14 @@ public static void Main() } } """; - - var source2 = """ + var locations = GetInterceptableLocations(source1); + var source2 = $$""" using System.Runtime.CompilerServices; using System; file class D { - [InterceptsLocation("Program.cs", 10, 9)] + [InterceptsLocation({{GetAttributeArgs(locations[1]!)}})] public static void Interceptor1() { Console.Write("interceptor 1"); } } """; @@ -462,19 +537,21 @@ public void FileLocalAttributeDefinitions_01() { // Treat a file-local declaration of InterceptsLocationAttribute as a well-known attribute within the declaring compilation. var source = """ - using System; - using System.Runtime.CompilerServices; - C.M(); class C { public static void M() => throw null!; } + """; + var locations = GetInterceptableLocations(source); + var interceptors = $$""" + using System.Runtime.CompilerServices; + using System; static class D { - [InterceptsLocation("Program.cs", 4, 3)] + [InterceptsLocation({{GetAttributeArgs(locations[0]!)}})] public static void M() { Console.Write(1); @@ -485,12 +562,12 @@ namespace System.Runtime.CompilerServices { file class InterceptsLocationAttribute : Attribute { - public InterceptsLocationAttribute(string filePath, int line, int character) { } + public InterceptsLocationAttribute(int version, string data) { } } } """; - var verifier = CompileAndVerify((source, "Program.cs"), parseOptions: RegularWithInterceptors, expectedOutput: "1"); + var verifier = CompileAndVerify([source, (interceptors, "Interceptors.cs")], parseOptions: RegularWithInterceptors, expectedOutput: "1"); verifier.VerifyDiagnostics(); } @@ -543,10 +620,16 @@ class D : C """; var comp1 = CreateCompilation((source1, "Program.cs"), parseOptions: RegularWithInterceptors); - comp1.VerifyEmitDiagnostics(); + comp1.VerifyEmitDiagnostics( + // Program.cs(11,6): warning CS9270: 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) + // [InterceptsLocation("Program.cs", 5, 3)] + Diagnostic(ErrorCode.WRN_InterceptsLocationAttributeUnsupportedSignature, @"InterceptsLocation(""Program.cs"", 5, 3)").WithLocation(11, 6)); var comp2Verifier = CompileAndVerify((source2, "Program.cs"), references: new[] { comp1.ToMetadataReference() }, parseOptions: RegularWithInterceptors, expectedOutput: "1"); - comp2Verifier.VerifyDiagnostics(); + comp2Verifier.VerifyDiagnostics( + // Program.cs(11,6): warning CS9270: 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) + // [InterceptsLocation("Program.cs", 5, 3)] + Diagnostic(ErrorCode.WRN_InterceptsLocationAttributeUnsupportedSignature, @"InterceptsLocation(""Program.cs"", 5, 3)").WithLocation(11, 6)); comp2Verifier = CompileAndVerify((source2, "Program.cs"), references: new[] { comp1.EmitToImageReference() }, parseOptions: RegularWithInterceptors, expectedOutput: "1"); comp2Verifier.VerifyDiagnostics(); @@ -556,7 +639,6 @@ class D : C public void InterceptableExtensionMethod_InterceptorExtensionMethod() { var source = """ - using System.Runtime.CompilerServices; using System; interface I1 { } @@ -573,14 +655,19 @@ public static void Main() c.InterceptableMethod("call site"); } } + """; + var locations = GetInterceptableLocations(source); + var interceptors = $$""" + using System.Runtime.CompilerServices; + using System; static class D { - [InterceptsLocation("Program.cs", 15, 11)] + [InterceptsLocation({{GetAttributeArgs(locations[1]!)}})] public static I1 Interceptor1(this I1 i1, string param) { Console.Write("interceptor " + param); return i1; } } """; - var verifier = CompileAndVerify(new[] { (source, "Program.cs"), s_attributesSource }, parseOptions: RegularWithInterceptors, expectedOutput: "interceptor call site"); + var verifier = CompileAndVerify([source, interceptors, s_attributesSource], parseOptions: RegularWithInterceptors, expectedOutput: "interceptor call site"); verifier.VerifyDiagnostics(); } @@ -588,7 +675,6 @@ static class D public void InterceptableExtensionMethod_InterceptorExtensionMethod_NormalForm() { var source = """ - using System.Runtime.CompilerServices; using System; interface I1 { } @@ -605,14 +691,19 @@ public static void Main() InterceptableMethod(c, "call site"); } } + """; + var locations = GetInterceptableLocations(source); + var interceptors = $$""" + using System.Runtime.CompilerServices; + using System; static class D { - [InterceptsLocation("Program.cs", 15, 9)] + [InterceptsLocation({{GetAttributeArgs(locations[1]!)}})] public static I1 Interceptor1(this I1 i1, string param) { Console.Write("interceptor " + param); return i1; } } """; - var verifier = CompileAndVerify(new[] { (source, "Program.cs"), s_attributesSource }, parseOptions: RegularWithInterceptors, expectedOutput: "interceptor call site"); + var verifier = CompileAndVerify([source, interceptors, s_attributesSource], parseOptions: RegularWithInterceptors, expectedOutput: "interceptor call site"); verifier.VerifyDiagnostics(); } @@ -620,7 +711,6 @@ static class D public void InterceptableInstanceMethod_InterceptorExtensionMethod() { var source = """ - using System.Runtime.CompilerServices; using System; class C @@ -637,14 +727,19 @@ public static void Main() c.InterceptableMethod("call site"); } } + """; + var locations = GetInterceptableLocations(source); + var interceptors = $$""" + using System.Runtime.CompilerServices; + using System; static class D { - [InterceptsLocation("Program.cs", 15, 11)] + [InterceptsLocation({{GetAttributeArgs(locations[1]!)}})] public static C Interceptor1(this C i1, string param) { Console.Write("interceptor " + param); return i1; } } """; - var verifier = CompileAndVerify(new[] { (source, "Program.cs"), s_attributesSource }, parseOptions: RegularWithInterceptors, expectedOutput: "interceptor call site"); + var verifier = CompileAndVerify([source, interceptors, s_attributesSource], parseOptions: RegularWithInterceptors, expectedOutput: "interceptor call site"); verifier.VerifyDiagnostics(); } @@ -669,18 +764,23 @@ public static void Main() c.InterceptableMethod("call site"); } } + """; + var locations = GetInterceptableLocations(source); + var interceptors = $$""" + using System.Runtime.CompilerServices; + using System; static class D { - [InterceptsLocation("Program.cs", 15, 11)] + [InterceptsLocation({{GetAttributeArgs(locations[1]!)}})] public static C Interceptor1(C i1, string param) { Console.Write("interceptor " + param); return i1; } } """; - var comp = CreateCompilation(new[] { (source, "Program.cs"), s_attributesSource }, parseOptions: RegularWithInterceptors); + var comp = CreateCompilation([source, interceptors, s_attributesSource], parseOptions: RegularWithInterceptors); comp.VerifyEmitDiagnostics( - // Program.cs(21,6): error CS9144: Cannot intercept method 'C.InterceptableMethod(string)' with interceptor 'D.Interceptor1(C, string)' because the signatures do not match. - // [InterceptsLocation("Program.cs", 15, 11)] - Diagnostic(ErrorCode.ERR_InterceptorSignatureMismatch, @"InterceptsLocation(""Program.cs"", 15, 11)").WithArguments("C.InterceptableMethod(string)", "D.Interceptor1(C, string)").WithLocation(21, 6) + // (6,6): error CS9144: Cannot intercept method 'C.InterceptableMethod(string)' with interceptor 'D.Interceptor1(C, string)' because the signatures do not match. + // [InterceptsLocation(1, "++/BPYeNndnfOx03gyhygBkBAAA=")] + Diagnostic(ErrorCode.ERR_InterceptorSignatureMismatch, "InterceptsLocation").WithArguments("C.InterceptableMethod(string)", "D.Interceptor1(C, string)").WithLocation(6, 6) ); } @@ -729,6 +829,9 @@ public static class Interceptor var comp = CreateCompilation(new[] { source0, source1, source2, s_attributesSource }, parseOptions: RegularWithInterceptors); comp.VerifyEmitDiagnostics( + // Interceptor.cs(15,6): warning CS9270: 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) + // [InterceptsLocation("Program.cs", 5, 11)] + Diagnostic(ErrorCode.WRN_InterceptsLocationAttributeUnsupportedSignature, @"InterceptsLocation(""Program.cs"", 5, 11)").WithLocation(15, 6), // Interceptor.cs(15,25): error CS9152: Cannot intercept a call in file with path 'Program.cs' because multiple files in the compilation have this path. // [InterceptsLocation("Program.cs", 5, 11)] Diagnostic(ErrorCode.ERR_InterceptorNonUniquePath, @"""Program.cs""").WithArguments("Program.cs").WithLocation(15, 25)); @@ -738,8 +841,6 @@ public static class Interceptor public void DuplicateLocation_01() { var source = """ - using System.Runtime.CompilerServices; - C.M(); class C @@ -747,25 +848,30 @@ class C public static void M() { } } + """; + var locations = GetInterceptableLocations(source); + var interceptors = $$""" + using System.Runtime.CompilerServices; class D { - [InterceptsLocation("Program.cs", 3, 3)] + [InterceptsLocation({{GetAttributeArgs(locations[0]!)}})] public static void M1() { } - [InterceptsLocation("Program.cs", 3, 3)] + [InterceptsLocation({{GetAttributeArgs(locations[0]!)}})] public static void M2() { } } """; - var comp = CreateCompilation(new[] { (source, "Program.cs"), s_attributesSource }, parseOptions: RegularWithInterceptors); + var comp = CreateCompilation([source, interceptors, s_attributesSource], parseOptions: RegularWithInterceptors); comp.VerifyEmitDiagnostics( - // Program.cs(13,6): error CS9153: The indicated call is intercepted multiple times. - // [InterceptsLocation("Program.cs", 3, 3)] - Diagnostic(ErrorCode.ERR_DuplicateInterceptor, @"InterceptsLocation(""Program.cs"", 3, 3)").WithLocation(13, 6), - // Program.cs(16,6): error CS9153: The indicated call is intercepted multiple times. - // [InterceptsLocation("Program.cs", 3, 3)] - Diagnostic(ErrorCode.ERR_DuplicateInterceptor, @"InterceptsLocation(""Program.cs"", 3, 3)").WithLocation(16, 6)); + // (5,6): error CS9153: The indicated call is intercepted multiple times. + // [InterceptsLocation(1, "W99OXsRRPXziuK607Sn0QgIAAAA=")] + Diagnostic(ErrorCode.ERR_DuplicateInterceptor, "InterceptsLocation").WithLocation(5, 6), + // (8,6): error CS9153: The indicated call is intercepted multiple times. + // [InterceptsLocation(1, "W99OXsRRPXziuK607Sn0QgIAAAA=")] + Diagnostic(ErrorCode.ERR_DuplicateInterceptor, "InterceptsLocation").WithLocation(8, 6) + ); } [Fact] @@ -782,23 +888,24 @@ class C public static void M() { } } """; + var locations = GetInterceptableLocations(source0); - var source1 = """ + var source1 = $$""" using System.Runtime.CompilerServices; class D1 { - [InterceptsLocation("Program.cs", 3, 3)] + [InterceptsLocation({{GetAttributeArgs(locations[0]!)}})] public static void M1() { } } """; - var source2 = """ + var source2 = $$""" using System.Runtime.CompilerServices; class D2 { - [InterceptsLocation("Program.cs", 3, 3)] + [InterceptsLocation({{GetAttributeArgs(locations[0]!)}})] public static void M1() { } } """; @@ -806,11 +913,11 @@ public static void M1() { } var comp = CreateCompilation(new[] { (source0, "Program.cs"), (source1, "File1.cs"), (source2, "File2.cs"), s_attributesSource }, parseOptions: RegularWithInterceptors); comp.VerifyEmitDiagnostics( // File2.cs(5,6): error CS9153: The indicated call is intercepted multiple times. - // [InterceptsLocation("Program.cs", 3, 3)] - Diagnostic(ErrorCode.ERR_DuplicateInterceptor, @"InterceptsLocation(""Program.cs"", 3, 3)").WithLocation(5, 6), + // [InterceptsLocation(1, "n2BejMbKpTRExveL7QXL7CwAAAA=")] + Diagnostic(ErrorCode.ERR_DuplicateInterceptor, "InterceptsLocation").WithLocation(5, 6), // File1.cs(5,6): error CS9153: The indicated call is intercepted multiple times. - // [InterceptsLocation("Program.cs", 3, 3)] - Diagnostic(ErrorCode.ERR_DuplicateInterceptor, @"InterceptsLocation(""Program.cs"", 3, 3)").WithLocation(5, 6) + // [InterceptsLocation(1, "n2BejMbKpTRExveL7QXL7CwAAAA=")] + Diagnostic(ErrorCode.ERR_DuplicateInterceptor, "InterceptsLocation").WithLocation(5, 6) ); } @@ -819,42 +926,36 @@ public void DuplicateLocation_03() { // InterceptsLocationAttribute is not considered to *duplicate* an interception, even if it is inherited. var source = """ - using System.Runtime.CompilerServices; using System; var d = new D(); d.M(); - class C + partial class C { public void M() => throw null!; - [InterceptsLocation("Program.cs", 5, 3)] - public virtual void Interceptor() => throw null!; + public virtual partial void Interceptor() => throw null!; } class D : C { public override void Interceptor() => Console.Write(1); } + """; + var locations = GetInterceptableLocations(source); + var interceptors = $$""" + using System.Runtime.CompilerServices; - namespace System.Runtime.CompilerServices + partial class C { - [AttributeUsage(AttributeTargets.Method)] - public sealed class InterceptableAttribute : Attribute { } - - [AttributeUsage(AttributeTargets.Method, AllowMultiple = true, Inherited = true)] - public sealed class InterceptsLocationAttribute : Attribute - { - public InterceptsLocationAttribute(string filePath, int line, int character) - { - } - } + [InterceptsLocation({{GetAttributeArgs(locations[0]!)}})] + public virtual partial void Interceptor(); } """; - var verifier = CompileAndVerify((source, "Program.cs"), parseOptions: RegularWithInterceptors, expectedOutput: "1"); + var verifier = CompileAndVerify([source, interceptors, s_attributesSource], parseOptions: RegularWithInterceptors, expectedOutput: "1"); verifier.VerifyDiagnostics(); } @@ -871,23 +972,28 @@ class C public static void M() { } } + """; + var locations = GetInterceptableLocations(source); + var interceptors = $$""" + using System.Runtime.CompilerServices; + using System; class D { - [InterceptsLocation("Program.cs", 3, 3)] - [InterceptsLocation("Program.cs", 3, 3)] + [InterceptsLocation({{GetAttributeArgs(locations[0]!)}})] + [InterceptsLocation({{GetAttributeArgs(locations[0]!)}})] public static void M1() { } } """; - var comp = CreateCompilation(new[] { (source, "Program.cs"), s_attributesSource }, parseOptions: RegularWithInterceptors); + var comp = CreateCompilation([source, interceptors, s_attributesSource], parseOptions: RegularWithInterceptors); comp.VerifyEmitDiagnostics( - // Program.cs(13,6): error CS9153: The indicated call is intercepted multiple times. - // [InterceptsLocation("Program.cs", 3, 3)] - Diagnostic(ErrorCode.ERR_DuplicateInterceptor, @"InterceptsLocation(""Program.cs"", 3, 3)").WithLocation(13, 6), - // Program.cs(14,6): error CS9153: The indicated call is intercepted multiple times. - // [InterceptsLocation("Program.cs", 3, 3)] - Diagnostic(ErrorCode.ERR_DuplicateInterceptor, @"InterceptsLocation(""Program.cs"", 3, 3)").WithLocation(14, 6)); + // (6,6): error CS9153: The indicated call is intercepted multiple times. + // [InterceptsLocation(1, "n2BejMbKpTRExveL7QXL7CwAAAA=")] + Diagnostic(ErrorCode.ERR_DuplicateInterceptor, "InterceptsLocation").WithLocation(6, 6), + // (7,6): error CS9153: The indicated call is intercepted multiple times. + // [InterceptsLocation(1, "n2BejMbKpTRExveL7QXL7CwAAAA=")] + Diagnostic(ErrorCode.ERR_DuplicateInterceptor, "InterceptsLocation").WithLocation(7, 6)); } [Fact] @@ -895,7 +1001,6 @@ public void InterceptorVirtual_01() { // Intercept a method call with a call to a virtual method on the same type. var source = """ - using System.Runtime.CompilerServices; using System; C c = new C(); @@ -904,37 +1009,32 @@ public void InterceptorVirtual_01() c = new D(); c.M(); - class C + partial class C { - public void M() => throw null!; - - [InterceptsLocation("Program.cs", 5, 3)] - [InterceptsLocation("Program.cs", 8, 3)] - public virtual void Interceptor() => Console.Write("C"); } class D : C { public override void Interceptor() => Console.Write("D"); } + """; - namespace System.Runtime.CompilerServices - { - [AttributeUsage(AttributeTargets.Method)] - public sealed class InterceptableAttribute : Attribute { } + var locations = GetInterceptableLocations(source); - [AttributeUsage(AttributeTargets.Method, AllowMultiple = true, Inherited = true)] - public sealed class InterceptsLocationAttribute : Attribute - { - public InterceptsLocationAttribute(string filePath, int line, int character) - { - } - } + var interceptors = $$""" + using System.Runtime.CompilerServices; + using System; + + partial class C + { + [InterceptsLocation({{GetAttributeArgs(locations[0]!)}})] + [InterceptsLocation({{GetAttributeArgs(locations[1]!)}})] + public virtual void Interceptor() => Console.Write("C"); } """; - var verifier = CompileAndVerify((source, "Program.cs"), parseOptions: RegularWithInterceptors, expectedOutput: "CD"); + var verifier = CompileAndVerify([source, interceptors, s_attributesSource], parseOptions: RegularWithInterceptors, expectedOutput: "CD"); verifier.VerifyDiagnostics(); } @@ -949,10 +1049,9 @@ public void InterceptorVirtual_02() D d = new D(); d.M(); - class C + partial class C { - [InterceptsLocation("Program.cs", 5, 3)] - public virtual void Interceptor() => throw null!; + public virtual partial void Interceptor(); } class D : C @@ -962,27 +1061,24 @@ class D : C public override void Interceptor() => throw null!; } + """; + var locations = GetInterceptableLocations(source); + var interceptors = $$""" + using System.Runtime.CompilerServices; + using System; - namespace System.Runtime.CompilerServices + partial class C { - [AttributeUsage(AttributeTargets.Method)] - public sealed class InterceptableAttribute : Attribute { } - - [AttributeUsage(AttributeTargets.Method, AllowMultiple = true, Inherited = true)] - public sealed class InterceptsLocationAttribute : Attribute - { - public InterceptsLocationAttribute(string filePath, int line, int character) - { - } - } + [InterceptsLocation({{GetAttributeArgs(locations[0]!)}})] + public virtual partial void Interceptor() => throw null!; } """; - var comp = CreateCompilation((source, "Program.cs"), parseOptions: RegularWithInterceptors); + var comp = CreateCompilation([source, interceptors, s_attributesSource], parseOptions: RegularWithInterceptors); comp.VerifyEmitDiagnostics( - // Program.cs(9,6): error CS9148: Interceptor must have a 'this' parameter matching parameter 'D this' on 'D.M()'. - // [InterceptsLocation("Program.cs", 5, 3)] - Diagnostic(ErrorCode.ERR_InterceptorMustHaveMatchingThisParameter, @"InterceptsLocation(""Program.cs"", 5, 3)").WithArguments("D this", "D.M()").WithLocation(9, 6)); + // (6,6): error CS9148: Interceptor must have a 'this' parameter matching parameter 'D this' on 'D.M()'. + // [InterceptsLocation(1, "HOfsJKA9cGIUJFWxsV9jeksAAAA=")] + Diagnostic(ErrorCode.ERR_InterceptorMustHaveMatchingThisParameter, "InterceptsLocation").WithArguments("D this", "D.M()").WithLocation(6, 6)); } [Fact] @@ -990,9 +1086,6 @@ public void InterceptorOverride_01() { // Intercept a call with a call to an override method on a derived type. var source = """ - using System.Runtime.CompilerServices; - using System; - D d = new D(); d.M(); @@ -1003,33 +1096,25 @@ class C public virtual void Interceptor() => throw null!; } + """; + var locations = GetInterceptableLocations(source); + var interceptors = $$""" + using System.Runtime.CompilerServices; + using System; class D : C { - [InterceptsLocation("Program.cs", 5, 3)] // 1 + [InterceptsLocation({{GetAttributeArgs(locations[0]!)}})] // 1 public override void Interceptor() => throw null!; } - - namespace System.Runtime.CompilerServices - { - [AttributeUsage(AttributeTargets.Method)] - public sealed class InterceptableAttribute : Attribute { } - - [AttributeUsage(AttributeTargets.Method, AllowMultiple = true, Inherited = true)] - public sealed class InterceptsLocationAttribute : Attribute - { - public InterceptsLocationAttribute(string filePath, int line, int character) - { - } - } - } """; - var comp = CreateCompilation((source, "Program.cs"), parseOptions: RegularWithInterceptors); + var comp = CreateCompilation([source, interceptors, s_attributesSource], parseOptions: RegularWithInterceptors); comp.VerifyEmitDiagnostics( - // Program.cs(17,6): error CS9148: Interceptor must have a 'this' parameter matching parameter 'C this' on 'C.M()'. - // [InterceptsLocation("Program.cs", 5, 3)] // 1 - Diagnostic(ErrorCode.ERR_InterceptorMustHaveMatchingThisParameter, @"InterceptsLocation(""Program.cs"", 5, 3)").WithArguments("C this", "C.M()").WithLocation(17, 6)); + // (6,6): error CS9148: Interceptor must have a 'this' parameter matching parameter 'C this' on 'C.M()'. + // [InterceptsLocation(1, "u4STVrPS9MrXo2LQRYzzABIAAAA=")] // 1 + Diagnostic(ErrorCode.ERR_InterceptorMustHaveMatchingThisParameter, "InterceptsLocation").WithArguments("C this", "C.M()").WithLocation(6, 6) + ); } [Fact] @@ -1037,9 +1122,6 @@ public void InterceptorOverride_02() { // Intercept a call with an override method on the same type. var source = """ - using System.Runtime.CompilerServices; - using System; - D d = new D(); d.M(); @@ -1048,31 +1130,24 @@ class C public virtual void Interceptor() => throw null!; } - class D : C + partial class D : C { - public void M() => throw null!; - - [InterceptsLocation("Program.cs", 5, 3)] - public override void Interceptor() => Console.Write(1); } + """; + var locations = GetInterceptableLocations(source); + var interceptors = $$""" + using System.Runtime.CompilerServices; + using System; - namespace System.Runtime.CompilerServices + partial class D : C { - [AttributeUsage(AttributeTargets.Method)] - public sealed class InterceptableAttribute : Attribute { } - - [AttributeUsage(AttributeTargets.Method, AllowMultiple = true, Inherited = true)] - public sealed class InterceptsLocationAttribute : Attribute - { - public InterceptsLocationAttribute(string filePath, int line, int character) - { - } - } + [InterceptsLocation({{GetAttributeArgs(locations[0]!)}})] + public override void Interceptor() => Console.Write(1); } """; - var verifier = CompileAndVerify((source, "Program.cs"), parseOptions: RegularWithInterceptors, expectedOutput: "1"); + var verifier = CompileAndVerify([source, interceptors, s_attributesSource], parseOptions: RegularWithInterceptors, expectedOutput: "1"); verifier.VerifyDiagnostics(); } @@ -1081,8 +1156,6 @@ public void EmitMetadataOnly_01() { // We can emit a ref assembly even though there are duplicate interceptions. var source = """ - using System.Runtime.CompilerServices; - class C { public static void Main() @@ -1093,28 +1166,32 @@ public static void Main() public static void M() { } } + """; + var locations = GetInterceptableLocations(source); + var interceptors = $$""" + using System.Runtime.CompilerServices; class D { - [InterceptsLocation("Program.cs", 7, 11)] + [InterceptsLocation({{GetAttributeArgs(locations[0]!)}})] public static void M1() { } - [InterceptsLocation("Program.cs", 7, 11)] + [InterceptsLocation({{GetAttributeArgs(locations[0]!)}})] public static void M2() { } } """; - var verifier = CompileAndVerify(new[] { (source, "Program.cs"), s_attributesSource }, parseOptions: RegularWithInterceptors, emitOptions: EmitOptions.Default.WithEmitMetadataOnly(true)); + var verifier = CompileAndVerify([source, interceptors, s_attributesSource], parseOptions: RegularWithInterceptors, emitOptions: EmitOptions.Default.WithEmitMetadataOnly(true)); verifier.VerifyDiagnostics(); - var comp = CreateCompilation(new[] { (source, "Program.cs"), s_attributesSource }, parseOptions: RegularWithInterceptors); + var comp = CreateCompilation([source, interceptors, s_attributesSource], parseOptions: RegularWithInterceptors); comp.VerifyEmitDiagnostics( - // Program.cs(16,6): error CS9153: The indicated call is intercepted multiple times. - // [InterceptsLocation("Program.cs", 7, 11)] - Diagnostic(ErrorCode.ERR_DuplicateInterceptor, @"InterceptsLocation(""Program.cs"", 7, 11)").WithLocation(16, 6), - // Program.cs(19,6): error CS9153: The indicated call is intercepted multiple times. - // [InterceptsLocation("Program.cs", 7, 11)] - Diagnostic(ErrorCode.ERR_DuplicateInterceptor, @"InterceptsLocation(""Program.cs"", 7, 11)").WithLocation(19, 6)); + // (5,6): error CS9153: The indicated call is intercepted multiple times. + // [InterceptsLocation(1, "K5uRlX0Frr/Ngo5L9TVTNTwAAAA=")] + Diagnostic(ErrorCode.ERR_DuplicateInterceptor, "InterceptsLocation").WithLocation(5, 6), + // (8,6): error CS9153: The indicated call is intercepted multiple times. + // [InterceptsLocation(1, "K5uRlX0Frr/Ngo5L9TVTNTwAAAA=")] + Diagnostic(ErrorCode.ERR_DuplicateInterceptor, "InterceptsLocation").WithLocation(8, 6)); } [Fact] @@ -1135,7 +1212,7 @@ public static void M() { } class D { - [InterceptsLocation("Program.cs", 3, 4)] + [InterceptsLocation(1, "ERROR")] public static void M1() { } } @@ -1143,9 +1220,9 @@ public static void M1() { } var comp = CreateCompilation(new[] { (source, "Program.cs"), s_attributesSource }, parseOptions: RegularWithInterceptors); comp.VerifyEmitDiagnostics(EmitOptions.Default.WithEmitMetadataOnly(true), - // Program.cs(13,6): error CS9141: The provided line and character number does not refer to an interceptable method name, but rather to token '('. - // [InterceptsLocation("Program.cs", 3, 4)] - Diagnostic(ErrorCode.ERR_InterceptorPositionBadToken, @"InterceptsLocation(""Program.cs"", 3, 4)").WithArguments("(").WithLocation(13, 6)); + // Program.cs(13,6): error CS9231: The data argument to InterceptsLocationAttribute is not in the correct format. + // [InterceptsLocation(1, "ERROR")] + Diagnostic(ErrorCode.ERR_InterceptsLocationDataInvalidFormat, "InterceptsLocation").WithLocation(13, 6)); } [Fact] @@ -1174,7 +1251,10 @@ public static class D } """; var comp0 = CreateCompilation(new[] { (source0, "Program.cs"), s_attributesSource }, parseOptions: RegularWithInterceptors); - comp0.VerifyEmitDiagnostics(); + comp0.VerifyEmitDiagnostics( + // Program.cs(17,6): warning CS9270: 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) + // [InterceptsLocation("Program.cs", 11, 9)] + Diagnostic(ErrorCode.WRN_InterceptsLocationAttributeUnsupportedSignature, @"InterceptsLocation(""Program.cs"", 11, 9)").WithLocation(17, 6)); var source1 = """ @@ -1193,7 +1273,10 @@ static void Main() """; var comp1 = CompileAndVerify(new[] { (source1, "Program.cs") }, new[] { comp0.ToMetadataReference() }, parseOptions: RegularWithInterceptors, expectedOutput: "interceptable 1"); - comp1.VerifyDiagnostics(); + comp1.VerifyDiagnostics( + // Program.cs(17,6): warning CS9270: 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) + // [InterceptsLocation("Program.cs", 11, 9)] + Diagnostic(ErrorCode.WRN_InterceptsLocationAttributeUnsupportedSignature, @"InterceptsLocation(""Program.cs"", 11, 9)").WithLocation(17, 6)); comp1 = CompileAndVerify(new[] { (source1, "Program.cs") }, new[] { comp0.EmitToImageReference() }, parseOptions: RegularWithInterceptors, expectedOutput: "interceptable 1"); comp1.VerifyDiagnostics(); @@ -1229,6 +1312,9 @@ static class D """; var compilation = CreateCompilation(new[] { (source, "Program.cs"), s_attributesSource }, parseOptions: RegularWithInterceptors); compilation.VerifyEmitDiagnostics( + // Program.cs(21,6): warning CS9270: 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) + // [InterceptsLocation("Program.cs", 15, 21)] + Diagnostic(ErrorCode.WRN_InterceptsLocationAttributeUnsupportedSignature, @"InterceptsLocation(""Program.cs"", 15, 21)").WithLocation(21, 6), // Program.cs(21,6): error CS9151: Possible method name 'InterceptableMethod' cannot be intercepted because it is not being invoked. // [InterceptsLocation("Program.cs", 15, 21)] Diagnostic(ErrorCode.ERR_InterceptorNameNotInvoked, @"InterceptsLocation(""Program.cs"", 15, 21)").WithArguments("InterceptableMethod").WithLocation(21, 6) @@ -1239,8 +1325,6 @@ static class D public void InterceptableNameof() { var source = """ - using System.Runtime.CompilerServices; - static class Program { public static void Main() @@ -1248,18 +1332,22 @@ public static void Main() _ = nameof(Main); } } + """; + var locations = GetInterceptableLocations(source); + var interceptors = $$""" + using System.Runtime.CompilerServices; static class D { - [InterceptsLocation("Program.cs", 7, 13)] + [InterceptsLocation({{GetAttributeArgs(locations[0]!)}})] public static void Interceptor1(object param) { } } """; - var compilation = CreateCompilation(new[] { (source, "Program.cs"), s_attributesSource }, parseOptions: RegularWithInterceptors); + var compilation = CreateCompilation([source, interceptors, s_attributesSource], parseOptions: RegularWithInterceptors); compilation.VerifyEmitDiagnostics( - // Program.cs(7,13): error CS9160: A nameof operator cannot be intercepted. + // (5,13): error CS9160: A nameof operator cannot be intercepted. // _ = nameof(Main); - Diagnostic(ErrorCode.ERR_InterceptorCannotInterceptNameof, "nameof").WithLocation(7, 13) + Diagnostic(ErrorCode.ERR_InterceptorCannotInterceptNameof, "nameof").WithLocation(5, 13) ); } @@ -1267,9 +1355,6 @@ public static void Interceptor1(object param) { } public void InterceptableNameof_MethodCall() { var source = """ - using System.Runtime.CompilerServices; - using System; - static class Program { public static void Main() @@ -1282,10 +1367,15 @@ public static void Main() public static string nameof(object param) => throw null!; } + """; + var locations = GetInterceptableLocations(source); + var interceptors = $$""" + using System.Runtime.CompilerServices; + using System; static class D { - [InterceptsLocation("Program.cs", 8, 13)] + [InterceptsLocation({{GetAttributeArgs(locations[0]!)}})] public static string Interceptor1(object param) { Console.Write(1); @@ -1293,14 +1383,16 @@ public static string Interceptor1(object param) } } """; - var verifier = CompileAndVerify(new[] { (source, "Program.cs"), s_attributesSource }, parseOptions: RegularWithInterceptors, expectedOutput: "1"); + var verifier = CompileAndVerify([source, interceptors, s_attributesSource], parseOptions: RegularWithInterceptors, expectedOutput: "1"); verifier.VerifyDiagnostics(); } [Fact] public void InterceptableDoubleUnderscoreReservedIdentifiers() { - var source = """ + // Verify that '__arglist', '__makeref', '__refvalue', and '__reftype' cannot be intercepted. + // Because the APIs for obtaining InterceptableLocation don't work with these constructs, we have effectively blocked it. + var source = CSharpTestSource.Parse(""" using System.Runtime.CompilerServices; using System; @@ -1318,38 +1410,21 @@ public static void Main() static void M1(__arglist) { } } + """, "Program.cs", options: RegularWithInterceptors); - static class D - { - [InterceptsLocation("Program.cs", 8, 12)] // __arglist - [InterceptsLocation("Program.cs", 11, 29)] // __makeref - [InterceptsLocation("Program.cs", 12, 26)] // __refvalue - [InterceptsLocation("Program.cs", 13, 18)] // __reftype - public static void Interceptor1(int x, int y, int z) { } - } - """; - var compilation = CreateCompilation(new[] { (source, "Program.cs"), s_attributesSource }, parseOptions: RegularWithInterceptors); - compilation.VerifyEmitDiagnostics( - // Program.cs(21,6): error CS9141: The provided line and character number does not refer to an interceptable method name, but rather to token '__arglist'. - // [InterceptsLocation("Program.cs", 8, 12)] // __arglist - Diagnostic(ErrorCode.ERR_InterceptorPositionBadToken, @"InterceptsLocation(""Program.cs"", 8, 12)").WithArguments("__arglist").WithLocation(21, 6), - // Program.cs(22,6): error CS9141: The provided line and character number does not refer to an interceptable method name, but rather to token '__makeref'. - // [InterceptsLocation("Program.cs", 11, 29)] // __makeref - Diagnostic(ErrorCode.ERR_InterceptorPositionBadToken, @"InterceptsLocation(""Program.cs"", 11, 29)").WithArguments("__makeref").WithLocation(22, 6), - // Program.cs(23,6): error CS9141: The provided line and character number does not refer to an interceptable method name, but rather to token '__refvalue'. - // [InterceptsLocation("Program.cs", 12, 26)] // __refvalue - Diagnostic(ErrorCode.ERR_InterceptorPositionBadToken, @"InterceptsLocation(""Program.cs"", 12, 26)").WithArguments("__refvalue").WithLocation(23, 6), - // Program.cs(24,6): error CS9141: The provided line and character number does not refer to an interceptable method name, but rather to token '__reftype'. - // [InterceptsLocation("Program.cs", 13, 18)] // __reftype - Diagnostic(ErrorCode.ERR_InterceptorPositionBadToken, @"InterceptsLocation(""Program.cs"", 13, 18)").WithArguments("__reftype").WithLocation(24, 6) - ); + Assert.Collection(source.GetRoot().DescendantNodes().OfType(), + first => Assert.Equal("M1(__arglist(1, 2, 3))", first.ToString()), + second => Assert.Equal("__arglist(1, 2, 3)", second.ToString())); + + Assert.Collection(GetInterceptableLocations(source), + first => Assert.Equal("Program.cs(8,9)", first!.GetDisplayLocation()), + second => Assert.Null(second)); } [Fact] public void InterceptableDelegateInvocation_01() { var source = """ - using System.Runtime.CompilerServices; using System; C.M(() => Console.Write(1)); @@ -1367,29 +1442,33 @@ public static void M1((Action action, int) pair) pair.action(); } } + """; + var locations = GetInterceptableLocations(source); + var interceptors = $$""" + using System.Runtime.CompilerServices; + using System; static class D { - [InterceptsLocation("Program.cs", 11, 9)] - [InterceptsLocation("Program.cs", 16, 14)] + [InterceptsLocation({{GetAttributeArgs(locations[4]!)}})] + [InterceptsLocation({{GetAttributeArgs(locations[5]!)}})] public static void Interceptor1(this Action action) { action(); Console.Write(2); } } """; - var compilation = CreateCompilation(new[] { (source, "Program.cs"), s_attributesSource }, parseOptions: RegularWithInterceptors); + var compilation = CreateCompilation([source, interceptors, s_attributesSource], parseOptions: RegularWithInterceptors); compilation.VerifyEmitDiagnostics( - // Program.cs(22,6): error CS9207: Cannot intercept 'action' because it is not an invocation of an ordinary member method. - // [InterceptsLocation("Program.cs", 11, 9)] - Diagnostic(ErrorCode.ERR_InterceptableMethodMustBeOrdinary, @"InterceptsLocation(""Program.cs"", 11, 9)").WithArguments("action").WithLocation(22, 6), - // Program.cs(23,6): error CS9207: Cannot intercept 'action' because it is not an invocation of an ordinary member method. - // [InterceptsLocation("Program.cs", 16, 14)] - Diagnostic(ErrorCode.ERR_InterceptableMethodMustBeOrdinary, @"InterceptsLocation(""Program.cs"", 16, 14)").WithArguments("action").WithLocation(23, 6)); + // (6,6): error CS9207: Cannot intercept 'action' because it is not an invocation of an ordinary member method. + // [InterceptsLocation(1, "OC8Ntn0ZsekhqswDcyGy6ZgAAAA=")] + Diagnostic(ErrorCode.ERR_InterceptableMethodMustBeOrdinary, "InterceptsLocation").WithArguments("action").WithLocation(6, 6), + // (7,6): error CS9207: Cannot intercept 'action' because it is not an invocation of an ordinary member method. + // [InterceptsLocation(1, "OC8Ntn0ZsekhqswDcyGy6f4AAAA=")] + Diagnostic(ErrorCode.ERR_InterceptableMethodMustBeOrdinary, "InterceptsLocation").WithArguments("action").WithLocation(7, 6)); } [Fact] public void InterceptableDelegateInvocation_02() { var source = """ - using System.Runtime.CompilerServices; using System; C.M(() => Console.Write(1)); @@ -1407,29 +1486,45 @@ public static void M1((Action action, int) pair) pair.action!(); } } + """; + + // 'action!' syntactic form prevents obtaining a location for these. + // They semantically cannot be intercepted so we don't really care. + var locations = GetInterceptableLocations(source); + Assert.Null(locations[4]); + Assert.Null(locations[5]); + + var interceptors = $$""" + using System.Runtime.CompilerServices; + using System; static class D { - [InterceptsLocation("Program.cs", 11, 9)] - [InterceptsLocation("Program.cs", 16, 14)] + [InterceptsLocation("Program.cs", 10, 9)] + [InterceptsLocation("Program.cs", 15, 14)] public static void Interceptor1(this Action action) { action(); Console.Write(2); } } """; - var compilation = CreateCompilation(new[] { (source, "Program.cs"), s_attributesSource }, parseOptions: RegularWithInterceptors); + var compilation = CreateCompilation([(source, "Program.cs"), interceptors, s_attributesSource], parseOptions: RegularWithInterceptors); compilation.VerifyEmitDiagnostics( - // Program.cs(22,6): error CS9151: Possible method name 'action' cannot be intercepted because it is not being invoked. - // [InterceptsLocation("Program.cs", 11, 9)] - Diagnostic(ErrorCode.ERR_InterceptorNameNotInvoked, @"InterceptsLocation(""Program.cs"", 11, 9)").WithArguments("action").WithLocation(22, 6), - // Program.cs(23,6): error CS9151: Possible method name 'action' cannot be intercepted because it is not being invoked. - // [InterceptsLocation("Program.cs", 16, 14)] - Diagnostic(ErrorCode.ERR_InterceptorNameNotInvoked, @"InterceptsLocation(""Program.cs"", 16, 14)").WithArguments("action").WithLocation(23, 6)); + // (6,6): warning CS9270: 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) + // [InterceptsLocation("Program.cs", 10, 9)] + Diagnostic(ErrorCode.WRN_InterceptsLocationAttributeUnsupportedSignature, @"InterceptsLocation(""Program.cs"", 10, 9)").WithLocation(6, 6), + // (6,6): error CS9151: Possible method name 'action' cannot be intercepted because it is not being invoked. + // [InterceptsLocation("Program.cs", 10, 9)] + Diagnostic(ErrorCode.ERR_InterceptorNameNotInvoked, @"InterceptsLocation(""Program.cs"", 10, 9)").WithArguments("action").WithLocation(6, 6), + // (7,6): warning CS9270: 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) + // [InterceptsLocation("Program.cs", 15, 14)] + Diagnostic(ErrorCode.WRN_InterceptsLocationAttributeUnsupportedSignature, @"InterceptsLocation(""Program.cs"", 15, 14)").WithLocation(7, 6), + // (7,6): error CS9151: Possible method name 'action' cannot be intercepted because it is not being invoked. + // [InterceptsLocation("Program.cs", 15, 14)] + Diagnostic(ErrorCode.ERR_InterceptorNameNotInvoked, @"InterceptsLocation(""Program.cs"", 15, 14)").WithArguments("action").WithLocation(7, 6)); } [Fact] public void QualifiedNameAtCallSite() { var source = """ - using System.Runtime.CompilerServices; using System; class C @@ -1446,14 +1541,19 @@ public static void Main() C.InterceptableMethod(c, "call site"); } } + """; + var locations = GetInterceptableLocations(source); + var interceptors = $$""" + using System.Runtime.CompilerServices; + using System; static class D { - [InterceptsLocation("Program.cs", 15, 11)] + [InterceptsLocation({{GetAttributeArgs(locations[1]!)}})] public static C Interceptor1(C c, string param) { Console.Write("interceptor " + param); return c; } } """; - var verifier = CompileAndVerify(new[] { (source, "Program.cs"), s_attributesSource }, parseOptions: RegularWithInterceptors, expectedOutput: "interceptor call site"); + var verifier = CompileAndVerify([source, interceptors, s_attributesSource], parseOptions: RegularWithInterceptors, expectedOutput: "interceptor call site"); verifier.VerifyDiagnostics(); } @@ -1461,7 +1561,6 @@ static class D public void InterceptableStaticMethod_InterceptorExtensionMethod() { var source = """ - using System.Runtime.CompilerServices; using System; class C @@ -1478,14 +1577,19 @@ public static void Main() C.InterceptableMethod(c, "call site"); } } + """; + var locations = GetInterceptableLocations(source); + var interceptors = $$""" + using System.Runtime.CompilerServices; + using System; static class D { - [InterceptsLocation("Program.cs", 15, 11)] + [InterceptsLocation({{GetAttributeArgs(locations[1]!)}})] public static C Interceptor1(this C c, string param) { Console.Write("interceptor " + param); return c; } } """; - var verifier = CompileAndVerify(new[] { (source, "Program.cs"), s_attributesSource }, parseOptions: RegularWithInterceptors, expectedOutput: "interceptor call site"); + var verifier = CompileAndVerify([source, interceptors, s_attributesSource], parseOptions: RegularWithInterceptors, expectedOutput: "interceptor call site"); verifier.VerifyDiagnostics(); } @@ -1501,44 +1605,56 @@ public void InterceptableExtensionMethod_InterceptorStaticMethod() class C { } - static class D + static partial class D { public static void InterceptableMethod(this C c) => throw null!; + } + """; + var locations = GetInterceptableLocations(source); + var interceptors = $$""" + using System.Runtime.CompilerServices; + using System; - [InterceptsLocation("Program.cs", 5, 3)] + static partial class D + { + [InterceptsLocation({{GetAttributeArgs(locations[0]!)}})] public static void Interceptor1(C c) => throw null!; } """; - var comp = CreateCompilation(new[] { (source, "Program.cs"), s_attributesSource }, parseOptions: RegularWithInterceptors); + var comp = CreateCompilation([source, interceptors, s_attributesSource], parseOptions: RegularWithInterceptors); comp.VerifyEmitDiagnostics( - // Program.cs(14,6): error CS9148: Interceptor must have a 'this' parameter matching parameter 'C c' on 'D.InterceptableMethod(C)'. - // [InterceptsLocation("Program.cs", 5, 3)] - Diagnostic(ErrorCode.ERR_InterceptorMustHaveMatchingThisParameter, @"InterceptsLocation(""Program.cs"", 5, 3)").WithArguments("C c", "D.InterceptableMethod(C)").WithLocation(14, 6)); + // (6,6): error CS9148: Interceptor must have a 'this' parameter matching parameter 'C c' on 'D.InterceptableMethod(C)'. + // [InterceptsLocation(1, "4eoe0tUG+oqPzA8jHIWbdU0AAAA=")] + Diagnostic(ErrorCode.ERR_InterceptorMustHaveMatchingThisParameter, "InterceptsLocation").WithArguments("C c", "D.InterceptableMethod(C)").WithLocation(6, 6)); } [Fact] public void InterceptableExtensionMethod_InterceptorStaticMethod_NormalForm() { var source = """ - using System.Runtime.CompilerServices; - using System; - var c = new C(); D.InterceptableMethod(c); class C { } - static class D + static partial class D { - public static void InterceptableMethod(this C c) => throw null!; + } + """; + var locations = GetInterceptableLocations(source); + var interceptor = $$""" + using System.Runtime.CompilerServices; + using System; - [InterceptsLocation("Program.cs", 5, 3)] + static partial class D + { + [InterceptsLocation({{GetAttributeArgs(locations[0]!)}})] public static void Interceptor1(C c) => Console.Write(1); } """; - var verifier = CompileAndVerify(new[] { (source, "Program.cs"), s_attributesSource }, parseOptions: RegularWithInterceptors, expectedOutput: "1"); + var verifier = CompileAndVerify([source, interceptor, s_attributesSource], parseOptions: RegularWithInterceptors, expectedOutput: "1"); verifier.VerifyDiagnostics(); } @@ -1546,7 +1662,6 @@ static class D public void InterceptableStaticMethod_InterceptorInstanceMethod() { var source = """ - using System.Runtime.CompilerServices; using System; static class Program @@ -1557,27 +1672,34 @@ public static void Main() } } - class C + partial class C { public static void InterceptableMethod(string param) { Console.Write("interceptable " + param); } + } + """; + var locations = GetInterceptableLocations(source); + var interceptors = $$""" + using System.Runtime.CompilerServices; + using System; - [InterceptsLocation("Program.cs", 8, 11)] + partial class C + { + [InterceptsLocation({{GetAttributeArgs(locations[0]!)}})] public void Interceptor1(string param) { Console.Write("interceptor " + param); } } """; - var comp = CreateCompilation(new[] { (source, "Program.cs"), s_attributesSource }, parseOptions: RegularWithInterceptors); + var comp = CreateCompilation([source, interceptors, s_attributesSource], parseOptions: RegularWithInterceptors); comp.VerifyEmitDiagnostics( - // Program.cs(17,6): error CS9149: Interceptor must not have a 'this' parameter because 'C.InterceptableMethod(string)' does not have a 'this' parameter. - // [InterceptsLocation("Program.cs", 8, 11)] - Diagnostic(ErrorCode.ERR_InterceptorMustNotHaveThisParameter, @"InterceptsLocation(""Program.cs"", 8, 11)").WithArguments("C.InterceptableMethod(string)").WithLocation(17, 6)); + // (6,6): error CS9149: Interceptor must not have a 'this' parameter because 'C.InterceptableMethod(string)' does not have a 'this' parameter. + // [InterceptsLocation(1, "s3IopQ8OwA+tKaUOHzxvAFoAAAA=")] + Diagnostic(ErrorCode.ERR_InterceptorMustNotHaveThisParameter, "InterceptsLocation").WithArguments("C.InterceptableMethod(string)").WithLocation(6, 6)); } [Fact] public void ArgumentLabels() { var source = """ - using System.Runtime.CompilerServices; using System; class C @@ -1594,14 +1716,19 @@ public static void Main() c.InterceptableMethod(s2: "World", s1: "Hello "); } } + """; + var locations = GetInterceptableLocations(source); + var interceptors = $$""" + using System.Runtime.CompilerServices; + using System; static class D { - [InterceptsLocation("Program.cs", 15, 11)] + [InterceptsLocation({{GetAttributeArgs(locations[1]!)}})] public static void Interceptor1(this C c, string s1, string s2) { Console.Write("interceptor " + s1 + s2); } } """; - var verifier = CompileAndVerify(new[] { (source, "Program.cs"), s_attributesSource }, parseOptions: RegularWithInterceptors, expectedOutput: "interceptor Hello World"); + var verifier = CompileAndVerify([source, interceptors, s_attributesSource], parseOptions: RegularWithInterceptors, expectedOutput: "interceptor Hello World"); verifier.VerifyDiagnostics(); } @@ -1609,9 +1736,6 @@ static class D public void ParameterNameDifference() { var source = """ - using System.Runtime.CompilerServices; - using System; - class C { @@ -1626,14 +1750,19 @@ public static void Main() c.InterceptableMethod(s1: "1"); } } + """; + var locations = GetInterceptableLocations(source); + var interceptors = $$""" + using System.Runtime.CompilerServices; + using System; static class D { - [InterceptsLocation("Program.cs", 15, 11)] + [InterceptsLocation({{GetAttributeArgs(locations[0]!)}})] public static void Interceptor1(this C c, string s2) { Console.Write(s2); } } """; - var verifier = CompileAndVerify(new[] { (source, "Program.cs"), s_attributesSource }, parseOptions: RegularWithInterceptors, expectedOutput: "1"); + var verifier = CompileAndVerify([source, interceptors, s_attributesSource], parseOptions: RegularWithInterceptors, expectedOutput: "1"); verifier.VerifyDiagnostics(); } @@ -1641,9 +1770,6 @@ static class D public void ParameterNamesInDifferentOrder() { var source = """ - using System.Runtime.CompilerServices; - using System; - class C { @@ -1659,15 +1785,20 @@ public static void Main() c.InterceptableMethod(s2: "4", s1: "3"); } } + """; + var locations = GetInterceptableLocations(source); + var interceptors = $$""" + using System.Runtime.CompilerServices; + using System; static class D { - [InterceptsLocation("Program.cs", 15, 11)] - [InterceptsLocation("Program.cs", 16, 11)] + [InterceptsLocation({{GetAttributeArgs(locations[0]!)}})] + [InterceptsLocation({{GetAttributeArgs(locations[1]!)}})] public static void Interceptor1(this C c, string s2, string s1) { Console.Write(s2); Console.Write(s1); } } """; - var verifier = CompileAndVerify(new[] { (source, "Program.cs"), s_attributesSource }, parseOptions: RegularWithInterceptors, expectedOutput: "1234"); + var verifier = CompileAndVerify([source, interceptors, s_attributesSource], parseOptions: RegularWithInterceptors, expectedOutput: "1234"); verifier.VerifyDiagnostics(); } @@ -1675,9 +1806,6 @@ static class D public void AttributeArgumentLabels_01() { var source = """ - using System.Runtime.CompilerServices; - using System; - class C { @@ -1692,14 +1820,19 @@ public static void Main() c.InterceptableMethod(); } } + """; + var location = GetInterceptableLocations(source)[0]!; + var interceptor = $$""" + using System.Runtime.CompilerServices; + using System; static class D { - [InterceptsLocation("Program.cs", character: 11, line: 15)] + [InterceptsLocation(version: {{location.Version}}, data: "{{location.Data}}")] public static void Interceptor1(this C c) { Console.Write(1); } } """; - var verifier = CompileAndVerify(new[] { (source, "Program.cs"), s_attributesSource }, parseOptions: RegularWithInterceptors, expectedOutput: "1"); + var verifier = CompileAndVerify([source, interceptor, s_attributesSource], parseOptions: RegularWithInterceptors, expectedOutput: "1"); verifier.VerifyDiagnostics(); } @@ -1707,8 +1840,6 @@ static class D public void AttributeArgumentLabels_02() { var source = """ - using System.Runtime.CompilerServices; - class C { @@ -1723,26 +1854,25 @@ public static void Main() c.InterceptableMethod(); } } + """; + var location = GetInterceptableLocations(source)[0]!; + var interceptors = $$""" + using System.Runtime.CompilerServices; static class D { - [InterceptsLocation("Program.cs", character: 1, line: 50)] // 1 + [InterceptsLocation(data: "{{location.Data}}", version: {{location.Version}})] // 1 public static void Interceptor1(this C c) => throw null!; } """; - var comp = CreateCompilation(new[] { (source, "Program.cs"), s_attributesSource }, parseOptions: RegularWithInterceptors); - comp.VerifyDiagnostics( - // Program.cs(20,53): error CS9142: The given file has '22' lines, which is fewer than the provided line number '50'. - // [InterceptsLocation("Program.cs", character: 1, line: 50)] // 1 - Diagnostic(ErrorCode.ERR_InterceptorLineOutOfRange, "line: 50").WithArguments("22", "50").WithLocation(20, 53) - ); + var comp = CreateCompilation([source, interceptors, s_attributesSource], parseOptions: RegularWithInterceptors); + comp.VerifyDiagnostics(); } [Fact] public void InterceptableExtensionMethod_InterceptorExtensionMethod_Sequence() { var source = """ - using System.Runtime.CompilerServices; using System; interface I1 { } @@ -1760,14 +1890,19 @@ public static void Main() .InterceptableMethod("call site"); } } + """; + var locations = GetInterceptableLocations(source); + var interceptors = $$""" + using System.Runtime.CompilerServices; + using System; static class D { - [InterceptsLocation("Program.cs", 15, 11)] + [InterceptsLocation({{GetAttributeArgs(locations[2]!)}})] public static I1 Interceptor1(this I1 i1, string param) { Console.Write("interceptor " + param); return i1; } } """; - var verifier = CompileAndVerify(new[] { (source, "Program.cs"), s_attributesSource }, parseOptions: RegularWithInterceptors, expectedOutput: "interceptor call siteinterceptable call site"); + var verifier = CompileAndVerify([source, interceptors, s_attributesSource], parseOptions: RegularWithInterceptors, expectedOutput: "interceptor call siteinterceptable call site"); verifier.VerifyDiagnostics(); } @@ -1809,16 +1944,17 @@ static class D comp1.VerifyEmitDiagnostics(); var verifier = CompileAndVerify((source2, "Program.cs"), references: new[] { comp1.ToMetadataReference() }, parseOptions: RegularWithInterceptors, expectedOutput: "interceptor call site"); - verifier.VerifyDiagnostics(); + verifier.VerifyDiagnostics( + // Program.cs(15,6): warning CS9270: 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) + // [InterceptsLocation("Program.cs", 9, 11)] + Diagnostic(ErrorCode.WRN_InterceptsLocationAttributeUnsupportedSignature, @"InterceptsLocation(""Program.cs"", 9, 11)").WithLocation(15, 6)); } [Fact] public void InterceptsLocation_BadMethodKind() { var source = """ - using System.Runtime.CompilerServices; - - static class Program + static partial class Program { public static void InterceptableMethod(string param) { } @@ -1826,32 +1962,42 @@ public static void InterceptableMethod(string param) { } public static void Main() { InterceptableMethod(""); - Interceptor1(""); + } + } + """; + var locations = GetInterceptableLocations(source); + var interceptors = $$""" + #pragma warning disable 8321 // The local function is declared but never used + using System.Runtime.CompilerServices; - var lambda = [InterceptsLocation("Program.cs", 13, 8)] (string param) => { }; // 1 + static partial class Program + { + static void M() + { + var lambda = [InterceptsLocation({{GetAttributeArgs(locations[0]!)}})] (string param) => { }; // 1 - [InterceptsLocation("Program.cs", 13, 8)] // 2 + [InterceptsLocation({{GetAttributeArgs(locations[0]!)}})] // 2 static void Interceptor1(string param) { } } public static string Prop { - [InterceptsLocation("Program.cs", 13, 8)] // 3 + [InterceptsLocation({{GetAttributeArgs(locations[0]!)}})] // 3 set { } } } """; - var comp = CreateCompilation(new[] { (source, "Program.cs"), s_attributesSource }, parseOptions: RegularWithInterceptors); + var comp = CreateCompilation([source, interceptors, s_attributesSource], parseOptions: RegularWithInterceptors); comp.VerifyDiagnostics( - // Program.cs(13,23): error CS9146: An interceptor method must be an ordinary member method. - // var lambda = [InterceptsLocation("Program.cs", 13, 8)] (string param) => { }; // 1 - Diagnostic(ErrorCode.ERR_InterceptorMethodMustBeOrdinary, @"InterceptsLocation(""Program.cs"", 13, 8)").WithLocation(13, 23), - // Program.cs(15,10): error CS9146: An interceptor method must be an ordinary member method. - // [InterceptsLocation("Program.cs", 13, 8)] // 2 - Diagnostic(ErrorCode.ERR_InterceptorMethodMustBeOrdinary, @"InterceptsLocation(""Program.cs"", 13, 8)").WithLocation(15, 10), - // Program.cs(21,10): error CS9146: An interceptor method must be an ordinary member method. - // [InterceptsLocation("Program.cs", 13, 8)] // 3 - Diagnostic(ErrorCode.ERR_InterceptorMethodMustBeOrdinary, @"InterceptsLocation(""Program.cs"", 13, 8)").WithLocation(21, 10) + // (8,23): error CS9146: An interceptor method must be an ordinary member method. + // var lambda = [InterceptsLocation(1, "Od9e6GAEIdSlUyHQlAJMLIkAAAA=")] (string param) => { }; // 1 + Diagnostic(ErrorCode.ERR_InterceptorMethodMustBeOrdinary, "InterceptsLocation").WithLocation(8, 23), + // (10,10): error CS9146: An interceptor method must be an ordinary member method. + // [InterceptsLocation(1, "Od9e6GAEIdSlUyHQlAJMLIkAAAA=")] // 2 + Diagnostic(ErrorCode.ERR_InterceptorMethodMustBeOrdinary, "InterceptsLocation").WithLocation(10, 10), + // (16,10): error CS9146: An interceptor method must be an ordinary member method. + // [InterceptsLocation(1, "Od9e6GAEIdSlUyHQlAJMLIkAAAA=")] // 3 + Diagnostic(ErrorCode.ERR_InterceptorMethodMustBeOrdinary, "InterceptsLocation").WithLocation(16, 10) ); } @@ -1938,12 +2084,21 @@ static void Interceptor1() { } """; var comp = CreateCompilation(new[] { (source, "Program.cs"), s_attributesSource }, parseOptions: RegularWithInterceptors, options: TestOptions.UnsafeDebugExe); comp.VerifyDiagnostics( + // Program.cs(16,6): warning CS9270: 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) + // [InterceptsLocation("Program.cs", 8, 13)] // 1 + Diagnostic(ErrorCode.WRN_InterceptsLocationAttributeUnsupportedSignature, @"InterceptsLocation(""Program.cs"", 8, 13)").WithLocation(16, 6), // Program.cs(16,6): error CS9151: Possible method name 'Prop' cannot be intercepted because it is not being invoked. // [InterceptsLocation("Program.cs", 8, 13)] // 1 Diagnostic(ErrorCode.ERR_InterceptorNameNotInvoked, @"InterceptsLocation(""Program.cs"", 8, 13)").WithArguments("Prop").WithLocation(16, 6), + // Program.cs(17,6): warning CS9270: 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) + // [InterceptsLocation("Program.cs", 11, 9)] // 2, 'new' + Diagnostic(ErrorCode.WRN_InterceptsLocationAttributeUnsupportedSignature, @"InterceptsLocation(""Program.cs"", 11, 9)").WithLocation(17, 6), // Program.cs(17,6): error CS9141: The provided line and character number does not refer to an interceptable method name, but rather to token 'new'. // [InterceptsLocation("Program.cs", 11, 9)] // 2, 'new' Diagnostic(ErrorCode.ERR_InterceptorPositionBadToken, @"InterceptsLocation(""Program.cs"", 11, 9)").WithArguments("new").WithLocation(17, 6), + // Program.cs(18,6): warning CS9270: 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) + // [InterceptsLocation("Program.cs", 11, 13)] // 3, 'Program' + Diagnostic(ErrorCode.WRN_InterceptsLocationAttributeUnsupportedSignature, @"InterceptsLocation(""Program.cs"", 11, 13)").WithLocation(18, 6), // Program.cs(18,6): error CS9151: Possible method name 'Program' cannot be intercepted because it is not being invoked. // [InterceptsLocation("Program.cs", 11, 13)] // 3, 'Program' Diagnostic(ErrorCode.ERR_InterceptorNameNotInvoked, @"InterceptsLocation(""Program.cs"", 11, 13)").WithArguments("Program").WithLocation(18, 6) @@ -2013,9 +2168,8 @@ public void InterceptableMethod_BadMethodKind_02() { var source = """ using System; - using System.Runtime.CompilerServices; - class Program + partial class Program { public static unsafe void Main() { @@ -2034,23 +2188,32 @@ public static unsafe void Main() public static int Prop { get; } - [InterceptsLocation("Program.cs", 10, 9)] // 1 - [InterceptsLocation("Program.cs", 14, 9)] // 2 - [InterceptsLocation("Program.cs", 18, 9)] // 3 - static void Interceptor1() { } + static partial void Interceptor1() { } } """; - var comp = CreateCompilation(new[] { (source, "Program.cs"), s_attributesSource }, parseOptions: RegularWithInterceptors, options: TestOptions.UnsafeDebugExe); + var locations = GetInterceptableLocations(source); + var interceptors = $$""" + using System.Runtime.CompilerServices; + + partial class Program + { + [InterceptsLocation({{GetAttributeArgs(locations[0]!)}})] // 1 + [InterceptsLocation({{GetAttributeArgs(locations[1]!)}})] // 2 + [InterceptsLocation({{GetAttributeArgs(locations[2]!)}})] // 3 + static partial void Interceptor1(); + } + """; + var comp = CreateCompilation([source, interceptors, s_attributesSource], parseOptions: RegularWithInterceptors, options: TestOptions.UnsafeDebugExe); comp.VerifyEmitDiagnostics( - // Program.cs(23,6): error CS9207: Cannot intercept 'a' because it is not an invocation of an ordinary member method. - // [InterceptsLocation("Program.cs", 10, 9)] // 1 - Diagnostic(ErrorCode.ERR_InterceptableMethodMustBeOrdinary, @"InterceptsLocation(""Program.cs"", 10, 9)").WithArguments("a").WithLocation(23, 6), - // Program.cs(24,6): error CS9207: Cannot intercept 'local' because it is not an invocation of an ordinary member method. - // [InterceptsLocation("Program.cs", 14, 9)] // 2 - Diagnostic(ErrorCode.ERR_InterceptableMethodMustBeOrdinary, @"InterceptsLocation(""Program.cs"", 14, 9)").WithArguments("local").WithLocation(24, 6), - // Program.cs(25,6): error CS9207: Cannot intercept 'fnptr' because it is not an invocation of an ordinary member method. - // [InterceptsLocation("Program.cs", 18, 9)] // 3 - Diagnostic(ErrorCode.ERR_InterceptableMethodMustBeOrdinary, @"InterceptsLocation(""Program.cs"", 18, 9)").WithArguments("fnptr").WithLocation(25, 6) + // (5,6): error CS9207: Cannot intercept 'a' because it is not an invocation of an ordinary member method. + // [InterceptsLocation(1, "ugKu5/LV5oAEk8GTsnS0hJQAAAA=")] // 1 + Diagnostic(ErrorCode.ERR_InterceptableMethodMustBeOrdinary, "InterceptsLocation").WithArguments("a").WithLocation(5, 6), + // (6,6): error CS9207: Cannot intercept 'local' because it is not an invocation of an ordinary member method. + // [InterceptsLocation(1, "ugKu5/LV5oAEk8GTsnS0hOUAAAA=")] // 2 + Diagnostic(ErrorCode.ERR_InterceptableMethodMustBeOrdinary, "InterceptsLocation").WithArguments("local").WithLocation(6, 6), + // (7,6): error CS9207: Cannot intercept 'fnptr' because it is not an invocation of an ordinary member method. + // [InterceptsLocation(1, "ugKu5/LV5oAEk8GTsnS0hEIBAAA=")] // 3 + Diagnostic(ErrorCode.ERR_InterceptableMethodMustBeOrdinary, "InterceptsLocation").WithArguments("fnptr").WithLocation(7, 6) ); } @@ -2058,7 +2221,6 @@ static void Interceptor1() { } public void InterceptorCannotBeGeneric_01() { var source = """ - using System.Runtime.CompilerServices; using System; interface I1 { } @@ -2076,25 +2238,29 @@ public static void Main() c.InterceptableMethod("call site"); } } + """; + var locations = GetInterceptableLocations(source); + var interceptor = $$""" + using System.Runtime.CompilerServices; + using System; static class D { - [InterceptsLocation("Program.cs", 16, 11)] + [InterceptsLocation({{GetAttributeArgs(locations[0]!)}})] public static I1 Interceptor1(this I1 i1, string param) { Console.Write("interceptor " + param); return i1; } } """; - var comp = CreateCompilation(new[] { (source, "Program.cs"), s_attributesSource }, parseOptions: RegularWithInterceptors); + var comp = CreateCompilation([source, interceptor, s_attributesSource], parseOptions: RegularWithInterceptors); comp.VerifyEmitDiagnostics( - // Program.cs(22,6): error CS9138: Method 'D.Interceptor1(I1, string)' must be non-generic to match 'C.InterceptableMethod(string)'. - // [InterceptsLocation("Program.cs", 16, 11)] - Diagnostic(ErrorCode.ERR_InterceptorCannotBeGeneric, @"InterceptsLocation(""Program.cs"", 16, 11)").WithArguments("D.Interceptor1(I1, string)", "C.InterceptableMethod(string)").WithLocation(22, 6)); + // (6,6): error CS9178: Method 'D.Interceptor1(I1, string)' must be non-generic to match 'Console.Write(string)'. + // [InterceptsLocation(1, "ASfq/xnhlb1QGHJAQ5lqJXAAAAA=")] + Diagnostic(ErrorCode.ERR_InterceptorCannotBeGeneric, "InterceptsLocation").WithArguments("D.Interceptor1(I1, string)", "System.Console.Write(string)").WithLocation(6, 6)); } [Fact] public void InterceptorCannotBeGeneric_02() { var source = """ - using System.Runtime.CompilerServices; using System; interface I1 { } @@ -2111,18 +2277,23 @@ public static void Main() C.InterceptableMethod("call site"); } } + """; + var locations = GetInterceptableLocations(source); + var interceptor = $$""" + using System.Runtime.CompilerServices; + using System; static class D { - [InterceptsLocation("Program.cs", 15, 11)] + [InterceptsLocation({{GetAttributeArgs(locations[0]!)}})] public static void Interceptor1(string param) { Console.Write("interceptor " + param); } } """; - var comp = CreateCompilation(new[] { (source, "Program.cs"), s_attributesSource }, parseOptions: RegularWithInterceptors); + var comp = CreateCompilation([source, interceptor, s_attributesSource], parseOptions: RegularWithInterceptors); comp.VerifyEmitDiagnostics( - // Program.cs(21,6): error CS9138: Method 'D.Interceptor1(string)' cannot be used as an interceptor because its containing type has type parameters. - // [InterceptsLocation("Program.cs", 15, 11)] - Diagnostic(ErrorCode.ERR_InterceptorContainingTypeCannotBeGeneric, @"InterceptsLocation(""Program.cs"", 15, 11)").WithArguments("D.Interceptor1(string)").WithLocation(21, 6)); + // (6,6): error CS9138: Method 'D.Interceptor1(string)' cannot be used as an interceptor because its containing type has type parameters. + // [InterceptsLocation(1, "ZCdvmiprtZ938pueLU5g6HkAAAA=")] + Diagnostic(ErrorCode.ERR_InterceptorContainingTypeCannotBeGeneric, "InterceptsLocation").WithArguments("D.Interceptor1(string)").WithLocation(6, 6)); } [Fact] @@ -2174,7 +2345,6 @@ static class D public void InterceptorCannotBeGeneric_03() { var source = """ - using System.Runtime.CompilerServices; using System; interface I1 { } @@ -2191,21 +2361,26 @@ public static void Main() C.InterceptableMethod("call site"); } } + """; + var locations = GetInterceptableLocations(source); + var interceptors = $$""" + using System.Runtime.CompilerServices; + using System; static class Outer { static class D { - [InterceptsLocation("Program.cs", 15, 11)] + [InterceptsLocation({{GetAttributeArgs(locations[1]!)}})] public static void Interceptor1(string param) { Console.Write("interceptor " + param); } } } """; - var comp = CreateCompilation(new[] { (source, "Program.cs"), s_attributesSource }, parseOptions: RegularWithInterceptors); + var comp = CreateCompilation([source, interceptors, s_attributesSource], parseOptions: RegularWithInterceptors); comp.VerifyEmitDiagnostics( - // Program.cs(23,10): error CS9138: Method 'Outer.D.Interceptor1(string)' cannot be used as an interceptor because its containing type has type parameters. - // [InterceptsLocation("Program.cs", 15, 11)] - Diagnostic(ErrorCode.ERR_InterceptorContainingTypeCannotBeGeneric, @"InterceptsLocation(""Program.cs"", 15, 11)").WithArguments("Outer.D.Interceptor1(string)").WithLocation(23, 10) + // (8,10): error CS9138: Method 'Outer.D.Interceptor1(string)' cannot be used as an interceptor because its containing type has type parameters. + // [InterceptsLocation(1, "ZCdvmiprtZ938pueLU5g6OsAAAA=")] + Diagnostic(ErrorCode.ERR_InterceptorContainingTypeCannotBeGeneric, "InterceptsLocation").WithArguments("Outer.D.Interceptor1(string)").WithLocation(8, 10) ); } @@ -2213,12 +2388,10 @@ static class D public void InterceptableGeneric_01() { var source = """ - using System.Runtime.CompilerServices; using System; class C { - public static void InterceptableMethod(T t) { Console.Write("0"); } } @@ -2230,15 +2403,20 @@ public static void Main() C.InterceptableMethod("2"); } } + """; + var locations = GetInterceptableLocations(source); + var interceptors = $$""" + using System.Runtime.CompilerServices; + using System; static class D { - [InterceptsLocation("Program.cs", 14, 11)] - [InterceptsLocation("Program.cs", 15, 11)] + [InterceptsLocation({{GetAttributeArgs(locations[1]!)}})] + [InterceptsLocation({{GetAttributeArgs(locations[2]!)}})] public static void Interceptor1(string s) { Console.Write(s); } } """; - var verifier = CompileAndVerify(new[] { (source, "Program.cs"), s_attributesSource }, parseOptions: RegularWithInterceptors, expectedOutput: "12"); + var verifier = CompileAndVerify([source, interceptors, s_attributesSource], parseOptions: RegularWithInterceptors, expectedOutput: "12"); verifier.VerifyDiagnostics(); } @@ -2273,12 +2451,21 @@ static class D """; var comp = CreateCompilation(new[] { (source, "Program.cs"), s_attributesSource }, parseOptions: RegularWithInterceptors); comp.VerifyEmitDiagnostics( + // Program.cs(20,6): warning CS9270: 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) + // [InterceptsLocation("Program.cs", 14, 30)] + Diagnostic(ErrorCode.WRN_InterceptsLocationAttributeUnsupportedSignature, @"InterceptsLocation(""Program.cs"", 14, 30)").WithLocation(20, 6), // Program.cs(20,6): error CS9141: The provided line and character number does not refer to an interceptable method name, but rather to token '<'. // [InterceptsLocation("Program.cs", 14, 30)] Diagnostic(ErrorCode.ERR_InterceptorPositionBadToken, @"InterceptsLocation(""Program.cs"", 14, 30)").WithArguments("<").WithLocation(20, 6), + // Program.cs(21,6): warning CS9270: 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) + // [InterceptsLocation("Program.cs", 14, 31)] + Diagnostic(ErrorCode.WRN_InterceptsLocationAttributeUnsupportedSignature, @"InterceptsLocation(""Program.cs"", 14, 31)").WithLocation(21, 6), // Program.cs(21,6): error CS9141: The provided line and character number does not refer to an interceptable method name, but rather to token 'string'. // [InterceptsLocation("Program.cs", 14, 31)] Diagnostic(ErrorCode.ERR_InterceptorPositionBadToken, @"InterceptsLocation(""Program.cs"", 14, 31)").WithArguments("string").WithLocation(21, 6), + // Program.cs(22,6): warning CS9270: 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) + // [InterceptsLocation("Program.cs", 14, 37)] + Diagnostic(ErrorCode.WRN_InterceptsLocationAttributeUnsupportedSignature, @"InterceptsLocation(""Program.cs"", 14, 37)").WithLocation(22, 6), // Program.cs(22,6): error CS9141: The provided line and character number does not refer to an interceptable method name, but rather to token '>'. // [InterceptsLocation("Program.cs", 14, 37)] Diagnostic(ErrorCode.ERR_InterceptorPositionBadToken, @"InterceptsLocation(""Program.cs"", 14, 37)").WithArguments(">").WithLocation(22, 6) @@ -2289,9 +2476,6 @@ static class D public void InterceptableGeneric_03() { var source = """ - using System.Runtime.CompilerServices; - using System; - class C { @@ -2305,14 +2489,18 @@ public static void Main() C.InterceptableMethod("1"); } } - + """; + var locations = GetInterceptableLocations(source); + var interceptors = $$""" + using System.Runtime.CompilerServices; + using System; static class D { - [InterceptsLocation("Program.cs", 14, 11)] + [InterceptsLocation({{GetAttributeArgs(locations[0]!)}})] public static void Interceptor1(string s) { Console.Write(s); } } """; - var verifier = CompileAndVerify(new[] { (source, "Program.cs"), s_attributesSource }, parseOptions: RegularWithInterceptors, expectedOutput: "1"); + var verifier = CompileAndVerify([source, interceptors, s_attributesSource], parseOptions: RegularWithInterceptors, expectedOutput: "1"); verifier.VerifyDiagnostics(); } @@ -2320,9 +2508,6 @@ static class D public void InterceptableGeneric_04() { var source = """ - using System.Runtime.CompilerServices; - using System; - class C { @@ -2338,23 +2523,28 @@ public static void M(T2 t) C.InterceptableMethod(t); } } + """; + var locations = GetInterceptableLocations(source); + var interceptors = $$""" + using System.Runtime.CompilerServices; + using System; static class D { - [InterceptsLocation("Program.cs", 14, 11)] // 1 - [InterceptsLocation("Program.cs", 15, 11)] // 2 - [InterceptsLocation("Program.cs", 16, 11)] + [InterceptsLocation({{GetAttributeArgs(locations[0]!)}})] // 1 + [InterceptsLocation({{GetAttributeArgs(locations[1]!)}})] // 2 + [InterceptsLocation({{GetAttributeArgs(locations[2]!)}})] public static void Interceptor1(object s) { Console.Write(s); } } """; - var comp = CreateCompilation(new[] { (source, "Program.cs"), s_attributesSource }, parseOptions: RegularWithInterceptors); + var comp = CreateCompilation([source, interceptors, s_attributesSource], parseOptions: RegularWithInterceptors); comp.VerifyEmitDiagnostics( - // Program.cs(22,6): error CS9144: Cannot intercept method 'C.InterceptableMethod(T2)' with interceptor 'D.Interceptor1(object)' because the signatures do not match. - // [InterceptsLocation("Program.cs", 14, 11)] // 1 - Diagnostic(ErrorCode.ERR_InterceptorSignatureMismatch, @"InterceptsLocation(""Program.cs"", 14, 11)").WithArguments("C.InterceptableMethod(T2)", "D.Interceptor1(object)").WithLocation(22, 6), - // Program.cs(23,6): error CS9144: Cannot intercept method 'C.InterceptableMethod(T2)' with interceptor 'D.Interceptor1(object)' because the signatures do not match. - // [InterceptsLocation("Program.cs", 15, 11)] // 2 - Diagnostic(ErrorCode.ERR_InterceptorSignatureMismatch, @"InterceptsLocation(""Program.cs"", 15, 11)").WithArguments("C.InterceptableMethod(T2)", "D.Interceptor1(object)").WithLocation(23, 6) + // (6,6): error CS9144: Cannot intercept method 'C.InterceptableMethod(T2)' with interceptor 'D.Interceptor1(object)' because the signatures do not match. + // [InterceptsLocation(1, "GRj3gKijugIAuusp6isB1qcAAAA=")] // 1 + Diagnostic(ErrorCode.ERR_InterceptorSignatureMismatch, "InterceptsLocation").WithArguments("C.InterceptableMethod(T2)", "D.Interceptor1(object)").WithLocation(6, 6), + // (7,6): error CS9144: Cannot intercept method 'C.InterceptableMethod(T2)' with interceptor 'D.Interceptor1(object)' because the signatures do not match. + // [InterceptsLocation(1, "GRj3gKijugIAuusp6isB1soAAAA=")] // 2 + Diagnostic(ErrorCode.ERR_InterceptorSignatureMismatch, "InterceptsLocation").WithArguments("C.InterceptableMethod(T2)", "D.Interceptor1(object)").WithLocation(7, 6) ); } @@ -2362,9 +2552,6 @@ static class D public void InterceptableGeneric_05() { var source = """ - using System.Runtime.CompilerServices; - using System; - C.Usage(1); C.Usage(2); @@ -2379,16 +2566,21 @@ public static void Usage(T2 t) C.InterceptableMethod(t); } } + """; + var locations = GetInterceptableLocations(source); + var interceptors = $$""" + using System.Runtime.CompilerServices; + using System; static class D { - [InterceptsLocation("Program.cs", 13, 11)] - [InterceptsLocation("Program.cs", 14, 11)] - [InterceptsLocation("Program.cs", 15, 11)] + [InterceptsLocation({{GetAttributeArgs(locations[2]!)}})] + [InterceptsLocation({{GetAttributeArgs(locations[3]!)}})] + [InterceptsLocation({{GetAttributeArgs(locations[4]!)}})] public static void Interceptor1(T t) { Console.Write(t); } } """; - var verifier = CompileAndVerify(new[] { (source, "Program.cs"), s_attributesSource }, parseOptions: RegularWithInterceptors, expectedOutput: "111222"); + var verifier = CompileAndVerify([source, interceptors, s_attributesSource], parseOptions: RegularWithInterceptors, expectedOutput: "111222"); verifier.VerifyDiagnostics(); } @@ -2408,18 +2600,22 @@ public static void Usage() C.InterceptableMethod("abc"); } } + """; + var locations = GetInterceptableLocations(source); + var interceptor = $$""" + using System.Runtime.CompilerServices; static class D { - [InterceptsLocation("Program.cs", 10, 11)] // 1 + [InterceptsLocation({{GetAttributeArgs(locations[0]!)}})] // 1 public static void Interceptor1(T t) where T : struct => throw null!; } """; - var comp = CreateCompilation(new[] { (source, "Program.cs"), s_attributesSource }, parseOptions: RegularWithInterceptors); + var comp = CreateCompilation([source, interceptor, s_attributesSource], parseOptions: RegularWithInterceptors); comp.VerifyEmitDiagnostics( - // Program.cs(16,6): error CS0453: The type 'string' must be a non-nullable value type in order to use it as parameter 'T' in the generic type or method 'D.Interceptor1(T)' - // [InterceptsLocation("Program.cs", 10, 11)] // 1 - Diagnostic(ErrorCode.ERR_ValConstraintNotSatisfied, @"InterceptsLocation(""Program.cs"", 10, 11)").WithArguments("D.Interceptor1(T)", "T", "string").WithLocation(16, 6)); + // (5,6): error CS0453: The type 'string' must be a non-nullable value type in order to use it as parameter 'T' in the generic type or method 'D.Interceptor1(T)' + // [InterceptsLocation(1, "jdOMgqJQrFcHcRZ6LGTup74AAAA=")] // 1 + Diagnostic(ErrorCode.ERR_ValConstraintNotSatisfied, "InterceptsLocation").WithArguments("D.Interceptor1(T)", "T", "string").WithLocation(5, 6)); } [Fact] @@ -2427,9 +2623,6 @@ public void InterceptableGeneric_07() { // original containing type is generic var source = """ - using System.Runtime.CompilerServices; - using System; - D.Usage(1); D.Usage(2); @@ -2438,20 +2631,28 @@ class C public static void InterceptableMethod(T1 t) => throw null!; } - static class D + static partial class D { public static void Usage(T2 t) { C.InterceptableMethod(t); C.InterceptableMethod(t); } + } + """; + var locations = GetInterceptableLocations(source); + var interceptors = $$""" + using System.Runtime.CompilerServices; + using System; - [InterceptsLocation("Program.cs", 16, 15)] - [InterceptsLocation("Program.cs", 17, 19)] + static partial class D + { + [InterceptsLocation({{GetAttributeArgs(locations[2]!)}})] + [InterceptsLocation({{GetAttributeArgs(locations[3]!)}})] public static void Interceptor1(T t) { Console.Write(t); } } """; - var verifier = CompileAndVerify(new[] { (source, "Program.cs"), s_attributesSource }, parseOptions: RegularWithInterceptors, expectedOutput: "1122"); + var verifier = CompileAndVerify([source, interceptors, s_attributesSource], parseOptions: RegularWithInterceptors, expectedOutput: "1122"); verifier.VerifyDiagnostics(); } @@ -2461,9 +2662,6 @@ public void InterceptableGeneric_09() // original containing type and method are generic // interceptor has arity 2 var source = """ - using System.Runtime.CompilerServices; - using System; - D.Usage(1, "a"); D.Usage(2, "b"); @@ -2472,16 +2670,24 @@ class C public static void InterceptableMethod(T1 t1, T2 t2) => throw null!; } - static class D + static partial class D { public static void Usage(T1 t1, T2 t2) { C.InterceptableMethod(t1, t2); C.InterceptableMethod(t1, t2); } + } + """; + var locations = GetInterceptableLocations(source); + var interceptors = $$""" + using System.Runtime.CompilerServices; + using System; - [InterceptsLocation("Program.cs", 16, 15)] - [InterceptsLocation("Program.cs", 17, 19)] + static partial class D + { + [InterceptsLocation({{GetAttributeArgs(locations[2]!)}})] + [InterceptsLocation({{GetAttributeArgs(locations[3]!)}})] public static void Interceptor1(T1 t1, T2 t2) { Console.Write(t1); @@ -2489,7 +2695,7 @@ public static void Interceptor1(T1 t1, T2 t2) } } """; - var verifier = CompileAndVerify(new[] { (source, "Program.cs"), s_attributesSource }, parseOptions: RegularWithInterceptors, expectedOutput: "1a1a2b2b"); + var verifier = CompileAndVerify([source, interceptors, s_attributesSource], parseOptions: RegularWithInterceptors, expectedOutput: "1a1a2b2b"); verifier.VerifyDiagnostics(); } @@ -2502,29 +2708,35 @@ public void InterceptableGeneric_10() // Note: the behavior in this scenario might push us toward using a "unification" model for generic interceptors. // All the cases supported in our current design would also be supported by unification, so we should be able to add it later. var source = """ - using System.Runtime.CompilerServices; class C { public static void InterceptableMethod(T1 t1, T2 t2) => throw null!; } - static class D + static partial class D { public static void Usage(object obj, T t) { C.InterceptableMethod(obj, t); } + } + """; + var locations = GetInterceptableLocations(source); + var interceptor = $$""" + using System.Runtime.CompilerServices; - [InterceptsLocation("Program.cs", 12, 19)] // 1 + static partial class D + { + [InterceptsLocation({{GetAttributeArgs(locations[0]!)}})] // 1 public static void Interceptor1(object obj, T t) => throw null!; } """; - var comp = CreateCompilation(new[] { (source, "Program.cs"), s_attributesSource }, parseOptions: RegularWithInterceptors); + var comp = CreateCompilation([source, interceptor, s_attributesSource], parseOptions: RegularWithInterceptors); comp.VerifyEmitDiagnostics( - // Program.cs(15,6): error CS9177: Method 'D.Interceptor1(object, T)' must be non-generic or have arity 2 to match 'C.InterceptableMethod(object, T)'. - // [InterceptsLocation("Program.cs", 12, 19)] // 1 - Diagnostic(ErrorCode.ERR_InterceptorArityNotCompatible, @"InterceptsLocation(""Program.cs"", 12, 19)").WithArguments("D.Interceptor1(object, T)", "2", "C.InterceptableMethod(object, T)").WithLocation(15, 6)); + // (5,6): error CS9177: Method 'D.Interceptor1(object, T)' must be non-generic or have arity 2 to match 'C.InterceptableMethod(object, T)'. + // [InterceptsLocation(1, "h+iqjaw4yol1Ge3U77MWn8sAAAA=")] // 1 + Diagnostic(ErrorCode.ERR_InterceptorArityNotCompatible, "InterceptsLocation").WithArguments("D.Interceptor1(object, T)", "2", "C.InterceptableMethod(object, T)").WithLocation(5, 6)); } [Fact] @@ -2533,24 +2745,29 @@ public void InterceptableGeneric_11() // original containing type and method are generic // interceptor has arity 0 var source = """ - using System.Runtime.CompilerServices; - using System; - class C { public static void InterceptableMethod(T1 t1, T2 t2) => throw null!; } - static class D + static partial class D { public static void Main() { C.InterceptableMethod(1, "a"); C.InterceptableMethod(2, "b"); } + } + """; + var locations = GetInterceptableLocations(source); + var interceptors = $$""" + using System.Runtime.CompilerServices; + using System; - [InterceptsLocation("Program.cs", 13, 16)] - [InterceptsLocation("Program.cs", 14, 16)] + static partial class D + { + [InterceptsLocation({{GetAttributeArgs(locations[0]!)}})] + [InterceptsLocation({{GetAttributeArgs(locations[1]!)}})] public static void Interceptor1(int i, string s) { Console.Write(i); @@ -2558,7 +2775,7 @@ public static void Interceptor1(int i, string s) } } """; - var verifier = CompileAndVerify(new[] { (source, "Program.cs"), s_attributesSource }, parseOptions: RegularWithInterceptors, expectedOutput: "1a2b"); + var verifier = CompileAndVerify([source, interceptors, s_attributesSource], parseOptions: RegularWithInterceptors, expectedOutput: "1a2b"); verifier.VerifyDiagnostics(); } @@ -2568,9 +2785,6 @@ public void InterceptableGeneric_12() // original grandparent type and method are generic // interceptor has arity 2 var source = """ - using System.Runtime.CompilerServices; - using System; - D.Usage(1, "a"); D.Usage(2, "b"); @@ -2582,16 +2796,24 @@ public class C } } - static class D + static partial class D { public static void Usage(T1 t1, T2 t2) { Outer.C.InterceptableMethod(t1, t2); Outer.C.InterceptableMethod(t1, t2); } + } + """; + var locations = GetInterceptableLocations(source); + var interceptors = $$""" + using System.Runtime.CompilerServices; + using System; - [InterceptsLocation("Program.cs", 19, 21)] - [InterceptsLocation("Program.cs", 20, 25)] + static partial class D + { + [InterceptsLocation({{GetAttributeArgs(locations[2]!)}})] + [InterceptsLocation({{GetAttributeArgs(locations[3]!)}})] public static void Interceptor1(T1 t1, T2 t2) { Console.Write(t1); @@ -2599,7 +2821,7 @@ public static void Interceptor1(T1 t1, T2 t2) } } """; - var verifier = CompileAndVerify(new[] { (source, "Program.cs"), s_attributesSource }, parseOptions: RegularWithInterceptors, expectedOutput: "1a1a2b2b"); + var verifier = CompileAndVerify([source, interceptors, s_attributesSource], parseOptions: RegularWithInterceptors, expectedOutput: "1a1a2b2b"); verifier.VerifyDiagnostics(); } @@ -2609,9 +2831,6 @@ public void InterceptableGeneric_13() // original grandparent type, containing type, and method are generic // interceptor has arity 3 var source = """ - using System.Runtime.CompilerServices; - using System; - D.Usage(1, 2, 3); D.Usage(4, 5, 6); @@ -2623,16 +2842,24 @@ public class C } } - static class D + static partial class D { public static void Usage(T1 t1, T2 t2, T3 t3) { Outer.C.InterceptableMethod(t1, t2, t3); Outer.C.InterceptableMethod(t1, t2, t3); } + } + """; + var locations = GetInterceptableLocations(source); + var interceptors = $$""" + using System.Runtime.CompilerServices; + using System; - [InterceptsLocation("Program.cs", 19, 25)] - [InterceptsLocation("Program.cs", 20, 33)] + static partial class D + { + [InterceptsLocation({{GetAttributeArgs(locations[2]!)}})] + [InterceptsLocation({{GetAttributeArgs(locations[3]!)}})] public static void Interceptor1(T1 t1, T2 t2, T3 t3) { Console.Write(t1); @@ -2641,7 +2868,7 @@ public static void Interceptor1(T1 t1, T2 t2, T3 t3) } } """; - var verifier = CompileAndVerify(new[] { (source, "Program.cs"), s_attributesSource }, parseOptions: RegularWithInterceptors, expectedOutput: "123123456456"); + var verifier = CompileAndVerify([source, interceptors, s_attributesSource], parseOptions: RegularWithInterceptors, expectedOutput: "123123456456"); verifier.VerifyDiagnostics(); } @@ -2651,9 +2878,6 @@ public void InterceptableGeneric_14() // containing type has 2 type parameters, method is generic // interceptor has arity 3 var source = """ - using System.Runtime.CompilerServices; - using System; - D.Usage(1, 2, 3); D.Usage(4, 5, 6); @@ -2662,16 +2886,24 @@ class C public static void InterceptableMethod(T1 t1, T2 t2, T3 t3) => throw null!; } - static class D + static partial class D { public static void Usage(T1 t1, T2 t2, T3 t3) { C.InterceptableMethod(t1, t2, t3); C.InterceptableMethod(t1, t2, t3); } + } + """; + var locations = GetInterceptableLocations(source); + var interceptors = $$""" + using System.Runtime.CompilerServices; + using System; - [InterceptsLocation("Program.cs", 16, 19)] - [InterceptsLocation("Program.cs", 17, 27)] + static partial class D + { + [InterceptsLocation({{GetAttributeArgs(locations[2]!)}})] + [InterceptsLocation({{GetAttributeArgs(locations[3]!)}})] public static void Interceptor1(T1 t1, T2 t2, T3 t3) { Console.Write(t1); @@ -2680,7 +2912,7 @@ public static void Interceptor1(T1 t1, T2 t2, T3 t3) } } """; - var verifier = CompileAndVerify(new[] { (source, "Program.cs"), s_attributesSource }, parseOptions: RegularWithInterceptors, expectedOutput: "123123456456"); + var verifier = CompileAndVerify([source, interceptors, s_attributesSource], parseOptions: RegularWithInterceptors, expectedOutput: "123123456456"); verifier.VerifyDiagnostics(); } @@ -2689,27 +2921,28 @@ public void InterceptableGeneric_15() { // original method is non-generic, interceptor is generic var source = """ - using System.Runtime.CompilerServices; - using System; - C.Original(); class C { public static void Original() => throw null!; } + """; + var locations = GetInterceptableLocations(source); + var interceptor = $$""" + using System.Runtime.CompilerServices; static class D { - [InterceptsLocation("Program.cs", 4, 3)] // 1 + [InterceptsLocation({{GetAttributeArgs(locations[0]!)}})] // 1 public static void Interceptor1() => throw null!; } """; - var comp = CreateCompilation(new[] { (source, "Program.cs"), s_attributesSource }, parseOptions: RegularWithInterceptors); + var comp = CreateCompilation([source, interceptor, s_attributesSource], parseOptions: RegularWithInterceptors); comp.VerifyEmitDiagnostics( - // Program.cs(13,6): error CS9178: Method 'D.Interceptor1()' must be non-generic to match 'C.Original()'. - // [InterceptsLocation("Program.cs", 4, 3)] // 1 - Diagnostic(ErrorCode.ERR_InterceptorCannotBeGeneric, @"InterceptsLocation(""Program.cs"", 4, 3)").WithArguments("D.Interceptor1()", "C.Original()").WithLocation(13, 6)); + // (5,6): error CS9178: Method 'D.Interceptor1()' must be non-generic to match 'C.Original()'. + // [InterceptsLocation(1, "PfujbqHNZVPxez1Ug8rXIAIAAAA=")] // 1 + Diagnostic(ErrorCode.ERR_InterceptorCannotBeGeneric, "InterceptsLocation").WithArguments("D.Interceptor1()", "C.Original()").WithLocation(5, 6)); } [Fact] @@ -2718,9 +2951,6 @@ public void InterceptableGeneric_16() var source = """ #nullable enable - using System.Runtime.CompilerServices; - using System; - class C { public static void InterceptableMethod(T1 t) => throw null!; @@ -2730,18 +2960,25 @@ public static void Main() C.InterceptableMethod(null); } } + """; + var locations = GetInterceptableLocations(source); + var interceptor = $$""" + #nullable enable + + using System.Runtime.CompilerServices; + using System; static class D { - [InterceptsLocation("Program.cs", 12, 11)] // 1 + [InterceptsLocation({{GetAttributeArgs(locations[0]!)}})] // 1 public static void Interceptor1(T t) where T : notnull => Console.Write(1); } """; - var verifier = CompileAndVerify(new[] { (source, "Program.cs"), s_attributesSource }, parseOptions: RegularWithInterceptors, expectedOutput: "1"); + var verifier = CompileAndVerify([source, interceptor, s_attributesSource], parseOptions: RegularWithInterceptors, expectedOutput: "1"); verifier.VerifyDiagnostics( - // Program.cs(18,6): warning CS8714: The type 'string?' cannot be used as type parameter 'T' in the generic type or method 'D.Interceptor1(T)'. Nullability of type argument 'string?' doesn't match 'notnull' constraint. - // [InterceptsLocation("Program.cs", 12, 11)] // 1 - Diagnostic(ErrorCode.WRN_NullabilityMismatchInTypeParameterNotNullConstraint, @"InterceptsLocation(""Program.cs"", 12, 11)").WithArguments("D.Interceptor1(T)", "T", "string?").WithLocation(18, 6)); + // (8,6): warning CS8714: The type 'string?' cannot be used as type parameter 'T' in the generic type or method 'D.Interceptor1(T)'. Nullability of type argument 'string?' doesn't match 'notnull' constraint. + // [InterceptsLocation(1, "kWQj9SspA3ZDLFRLuB00A5gAAAA=")] // 1 + Diagnostic(ErrorCode.WRN_NullabilityMismatchInTypeParameterNotNullConstraint, "InterceptsLocation").WithArguments("D.Interceptor1(T)", "T", "string?").WithLocation(8, 6)); } [Fact] @@ -2807,6 +3044,9 @@ static class D """; var comp = CreateCompilation(new[] { (source, "Program.cs"), s_attributesSource }, parseOptions: RegularWithInterceptors); comp.VerifyEmitDiagnostics( + // Program.cs(21,6): warning CS9270: 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) + // [InterceptsLocation("BAD", 15, 11)] + Diagnostic(ErrorCode.WRN_InterceptsLocationAttributeUnsupportedSignature, @"InterceptsLocation(""BAD"", 15, 11)").WithLocation(21, 6), // Program.cs(21,25): error CS9139: Cannot intercept: compilation does not contain a file with path 'BAD'. // [InterceptsLocation("BAD", 15, 11)] Diagnostic(ErrorCode.ERR_InterceptorPathNotInCompilation, @"""BAD""").WithArguments("BAD").WithLocation(21, 25) @@ -2843,6 +3083,9 @@ static class D """; var comp = CreateCompilation(new[] { (source, PlatformInformation.IsWindows ? @"C:\Users\me\projects\Program.cs" : "/Users/me/projects/Program.cs"), s_attributesSource }, parseOptions: RegularWithInterceptors); comp.VerifyEmitDiagnostics( + // C:\Users\me\projects\Program.cs(21,6): warning CS9270: 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) + // [InterceptsLocation("projects/Program.cs", 15, 11)] + Diagnostic(ErrorCode.WRN_InterceptsLocationAttributeUnsupportedSignature, @"InterceptsLocation(""projects/Program.cs"", 15, 11)").WithLocation(21, 6), // C:\Users\me\projects\Program.cs(21,25): error CS9140: Cannot intercept: compilation does not contain a file with path 'projects/Program.cs'. Did you mean to use path 'Program.cs'? // [InterceptsLocation("projects/Program.cs", 15, 11)] Diagnostic(ErrorCode.ERR_InterceptorPathNotInCompilationWithCandidate, @"""projects/Program.cs""").WithArguments("projects/Program.cs", "Program.cs").WithLocation(21, 25) @@ -2878,6 +3121,9 @@ static class D """; var comp = CreateCompilation(new[] { (source, "Program.cs"), s_attributesSource }, parseOptions: RegularWithInterceptors); comp.VerifyEmitDiagnostics( + // Program.cs(20,6): warning CS9270: 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) + // [InterceptsLocation(null, 15, 11)] + Diagnostic(ErrorCode.WRN_InterceptsLocationAttributeUnsupportedSignature, "InterceptsLocation(null, 15, 11)").WithLocation(20, 6), // Program.cs(20,25): error CS9150: Interceptor cannot have a 'null' file path. // [InterceptsLocation(null, 15, 11)] Diagnostic(ErrorCode.ERR_InterceptorFilePathCannotBeNull, "null").WithLocation(20, 25) @@ -2913,6 +3159,9 @@ static class D """; var comp = CreateCompilation(new[] { (source, "Program.cs"), s_attributesSource }, parseOptions: RegularWithInterceptors); comp.VerifyEmitDiagnostics( + // Program.cs(20,6): warning CS9270: 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) + // [InterceptsLocation("program.cs", 15, 11)] + Diagnostic(ErrorCode.WRN_InterceptsLocationAttributeUnsupportedSignature, @"InterceptsLocation(""program.cs"", 15, 11)").WithLocation(20, 6), // Program.cs(20,25): error CS9139: Cannot intercept: compilation does not contain a file with path 'program.cs'. // [InterceptsLocation("program.cs", 15, 11)] Diagnostic(ErrorCode.ERR_InterceptorPathNotInCompilation, @"""program.cs""").WithArguments("program.cs").WithLocation(20, 25) @@ -2951,12 +3200,21 @@ static class D """; var comp = CreateCompilation(new[] { (source, "Program.cs"), s_attributesSource }, parseOptions: RegularWithInterceptors); comp.VerifyEmitDiagnostics( + // Program.cs(21,6): warning CS9270: 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) + // [InterceptsLocation("Program.cs", 25, 1)] + Diagnostic(ErrorCode.WRN_InterceptsLocationAttributeUnsupportedSignature, @"InterceptsLocation(""Program.cs"", 25, 1)").WithLocation(21, 6), // Program.cs(21,6): error CS9141: The provided line and character number does not refer to an interceptable method name, but rather to token '}'. // [InterceptsLocation("Program.cs", 25, 1)] Diagnostic(ErrorCode.ERR_InterceptorPositionBadToken, @"InterceptsLocation(""Program.cs"", 25, 1)").WithArguments("}").WithLocation(21, 6), + // Program.cs(22,6): warning CS9270: 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) + // [InterceptsLocation("Program.cs", 26, 1)] + Diagnostic(ErrorCode.WRN_InterceptsLocationAttributeUnsupportedSignature, @"InterceptsLocation(""Program.cs"", 26, 1)").WithLocation(22, 6), // Program.cs(22,39): error CS9142: The given file has '25' lines, which is fewer than the provided line number '26'. // [InterceptsLocation("Program.cs", 26, 1)] Diagnostic(ErrorCode.ERR_InterceptorLineOutOfRange, "26").WithArguments("25", "26").WithLocation(22, 39), + // Program.cs(23,6): warning CS9270: 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) + // [InterceptsLocation("Program.cs", 100, 1)] + Diagnostic(ErrorCode.WRN_InterceptsLocationAttributeUnsupportedSignature, @"InterceptsLocation(""Program.cs"", 100, 1)").WithLocation(23, 6), // Program.cs(23,39): error CS9142: The given file has '25' lines, which is fewer than the provided line number '100'. // [InterceptsLocation("Program.cs", 100, 1)] Diagnostic(ErrorCode.ERR_InterceptorLineOutOfRange, "100").WithArguments("25", "100").WithLocation(23, 39) @@ -2995,12 +3253,21 @@ static class D """; var comp = CreateCompilation(new[] { (source, "Program.cs"), s_attributesSource }, parseOptions: RegularWithInterceptors); comp.VerifyEmitDiagnostics( + // Program.cs(21,6): warning CS9270: 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) + // [InterceptsLocation("Program.cs", 16, 5)] + Diagnostic(ErrorCode.WRN_InterceptsLocationAttributeUnsupportedSignature, @"InterceptsLocation(""Program.cs"", 16, 5)").WithLocation(21, 6), // Program.cs(21,6): error CS9141: The provided line and character number does not refer to an interceptable method name, but rather to token '}'. // [InterceptsLocation("Program.cs", 16, 5)] Diagnostic(ErrorCode.ERR_InterceptorPositionBadToken, @"InterceptsLocation(""Program.cs"", 16, 5)").WithArguments("}").WithLocation(21, 6), + // Program.cs(22,6): warning CS9270: 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) + // [InterceptsLocation("Program.cs", 16, 6)] + Diagnostic(ErrorCode.WRN_InterceptsLocationAttributeUnsupportedSignature, @"InterceptsLocation(""Program.cs"", 16, 6)").WithLocation(22, 6), // Program.cs(22,43): error CS9143: The given line is '5' characters long, which is fewer than the provided character number '6'. // [InterceptsLocation("Program.cs", 16, 6)] Diagnostic(ErrorCode.ERR_InterceptorCharacterOutOfRange, "6").WithArguments("5", "6").WithLocation(22, 43), + // Program.cs(23,6): warning CS9270: 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) + // [InterceptsLocation("Program.cs", 16, 1000)] + Diagnostic(ErrorCode.WRN_InterceptsLocationAttributeUnsupportedSignature, @"InterceptsLocation(""Program.cs"", 16, 1000)").WithLocation(23, 6), // Program.cs(23,43): error CS9143: The given line is '5' characters long, which is fewer than the provided character number '1000'. // [InterceptsLocation("Program.cs", 16, 1000)] Diagnostic(ErrorCode.ERR_InterceptorCharacterOutOfRange, "1000").WithArguments("5", "1000").WithLocation(23, 43) @@ -3037,9 +3304,12 @@ static class D """; var comp = CreateCompilation(new[] { (source, "Program.cs"), s_attributesSource }, parseOptions: RegularWithInterceptors); comp.VerifyEmitDiagnostics( - // Program.cs(21,6): error CS9141: The provided line and character number does not refer to an interceptable method, but rather to token 'c'. - // [InterceptsLocation("Program.cs", 15, 9)] - Diagnostic(ErrorCode.ERR_InterceptorPositionBadToken, @"InterceptsLocation(""Program.cs"", 15, 9)").WithArguments("c").WithLocation(21, 6) + // Program.cs(21,6): warning CS9270: 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) + // [InterceptsLocation("Program.cs", 15, 9)] + Diagnostic(ErrorCode.WRN_InterceptsLocationAttributeUnsupportedSignature, @"InterceptsLocation(""Program.cs"", 15, 9)").WithLocation(21, 6), + // Program.cs(21,6): error CS9141: The provided line and character number does not refer to an interceptable method name, but rather to token 'c'. + // [InterceptsLocation("Program.cs", 15, 9)] + Diagnostic(ErrorCode.ERR_InterceptorPositionBadToken, @"InterceptsLocation(""Program.cs"", 15, 9)").WithArguments("c").WithLocation(21, 6) ); } @@ -3073,6 +3343,9 @@ static class D """; var comp = CreateCompilation(new[] { (source, "Program.cs"), s_attributesSource }, parseOptions: RegularWithInterceptors); comp.VerifyEmitDiagnostics( + // Program.cs(21,6): warning CS9270: 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) + // [InterceptsLocation("Program.cs", 15, 13)] + Diagnostic(ErrorCode.WRN_InterceptsLocationAttributeUnsupportedSignature, @"InterceptsLocation(""Program.cs"", 15, 13)").WithLocation(21, 6), // Program.cs(21,6): error CS9147: The provided line and character number does not refer to the start of token 'InterceptableMethod'. Did you mean to use line '15' and character '11'? // [InterceptsLocation("Program.cs", 15, 13)] Diagnostic(ErrorCode.ERR_InterceptorMustReferToStartOfTokenPosition, @"InterceptsLocation(""Program.cs"", 15, 13)").WithArguments("InterceptableMethod", "15", "11").WithLocation(21, 6) @@ -3113,9 +3386,15 @@ static class CExt """; var comp = CreateCompilation(new[] { (source, "Program.cs"), s_attributesSource }, parseOptions: RegularWithInterceptors); comp.VerifyEmitDiagnostics( + // Program.cs(20,6): warning CS9270: 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) + // [InterceptsLocation("Program.cs", 12, 11)] // intercept spaces before 'InterceptableMethod' token + Diagnostic(ErrorCode.WRN_InterceptsLocationAttributeUnsupportedSignature, @"InterceptsLocation(""Program.cs"", 12, 11)").WithLocation(20, 6), // Program.cs(20,6): error CS9147: The provided line and character number does not refer to the start of token 'InterceptableMethod'. Did you mean to use line '12' and character '13'? // [InterceptsLocation("Program.cs", 12, 11)] // intercept spaces before 'InterceptableMethod' token Diagnostic(ErrorCode.ERR_InterceptorMustReferToStartOfTokenPosition, @"InterceptsLocation(""Program.cs"", 12, 11)").WithArguments("InterceptableMethod", "12", "13").WithLocation(20, 6), + // Program.cs(21,6): warning CS9270: 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) + // [InterceptsLocation("Program.cs", 14, 33)] // intercept spaces after 'InterceptableMethod' token + Diagnostic(ErrorCode.WRN_InterceptsLocationAttributeUnsupportedSignature, @"InterceptsLocation(""Program.cs"", 14, 33)").WithLocation(21, 6), // Program.cs(21,6): error CS9147: The provided line and character number does not refer to the start of token 'InterceptableMethod'. Did you mean to use line '14' and character '11'? // [InterceptsLocation("Program.cs", 14, 33)] // intercept spaces after 'InterceptableMethod' token Diagnostic(ErrorCode.ERR_InterceptorMustReferToStartOfTokenPosition, @"InterceptsLocation(""Program.cs"", 14, 33)").WithArguments("InterceptableMethod", "14", "11").WithLocation(21, 6) @@ -3152,6 +3431,9 @@ static class CExt """; var comp = CreateCompilation(new[] { (source, "Program.cs"), s_attributesSource }, parseOptions: RegularWithInterceptors); comp.VerifyEmitDiagnostics( + // Program.cs(17,6): warning CS9270: 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) + // [InterceptsLocation("Program.cs", 11, 31)] // intercept comment after 'InterceptableMethod' token + Diagnostic(ErrorCode.WRN_InterceptsLocationAttributeUnsupportedSignature, @"InterceptsLocation(""Program.cs"", 11, 31)").WithLocation(17, 6), // Program.cs(17,6): error CS9147: The provided line and character number does not refer to the start of token 'InterceptableMethod'. Did you mean to use line '11' and character '11'? // [InterceptsLocation("Program.cs", 11, 31)] // intercept comment after 'InterceptableMethod' token Diagnostic(ErrorCode.ERR_InterceptorMustReferToStartOfTokenPosition, @"InterceptsLocation(""Program.cs"", 11, 31)").WithArguments("InterceptableMethod", "11", "11").WithLocation(17, 6) @@ -3191,9 +3473,12 @@ static class CExt var comp = CreateCompilation(new[] { (source, "Program.cs"), s_attributesSource }, parseOptions: RegularWithInterceptors); comp.VerifyEmitDiagnostics( - // Program.cs(19,6): error CS9147: The provided line and character number does not refer to the start of token 'InterceptableMethod'. Did you mean to use line '13' and character '13'? - // [InterceptsLocation("Program.cs", 12, 13)] // intercept comment above 'InterceptableMethod' token - Diagnostic(ErrorCode.ERR_InterceptorMustReferToStartOfTokenPosition, @"InterceptsLocation(""Program.cs"", 12, 13)").WithArguments("InterceptableMethod", "13", "13").WithLocation(19, 6) + // Program.cs(19,6): warning CS9270: 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) + // [InterceptsLocation("Program.cs", 12, 13)] // intercept comment above 'InterceptableMethod' token + Diagnostic(ErrorCode.WRN_InterceptsLocationAttributeUnsupportedSignature, @"InterceptsLocation(""Program.cs"", 12, 13)").WithLocation(19, 6), + // Program.cs(19,6): error CS9147: The provided line and character number does not refer to the start of token 'InterceptableMethod'. Did you mean to use line '13' and character '13'? + // [InterceptsLocation("Program.cs", 12, 13)] // intercept comment above 'InterceptableMethod' token + Diagnostic(ErrorCode.ERR_InterceptorMustReferToStartOfTokenPosition, @"InterceptsLocation(""Program.cs"", 12, 13)").WithArguments("InterceptableMethod", "13", "13").WithLocation(19, 6) ); } @@ -3229,21 +3514,39 @@ public static void Main() var comp = CreateCompilation(new[] { (source, "Program.cs"), s_attributesSource }, parseOptions: RegularWithInterceptors); comp.VerifyEmitDiagnostics( + // Program.cs(17,6): warning CS9270: 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) + // [InterceptsLocation("Program.cs", -1, 1)] // 1 + Diagnostic(ErrorCode.WRN_InterceptsLocationAttributeUnsupportedSignature, @"InterceptsLocation(""Program.cs"", -1, 1)").WithLocation(17, 6), // Program.cs(17,39): error CS9157: Line and character numbers provided to InterceptsLocationAttribute must be positive. // [InterceptsLocation("Program.cs", -1, 1)] // 1 Diagnostic(ErrorCode.ERR_InterceptorLineCharacterMustBePositive, "-1").WithLocation(17, 39), + // Program.cs(18,6): warning CS9270: 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) + // [InterceptsLocation("Program.cs", 1, -1)] // 2 + Diagnostic(ErrorCode.WRN_InterceptsLocationAttributeUnsupportedSignature, @"InterceptsLocation(""Program.cs"", 1, -1)").WithLocation(18, 6), // Program.cs(18,42): error CS9157: Line and character numbers provided to InterceptsLocationAttribute must be positive. // [InterceptsLocation("Program.cs", 1, -1)] // 2 Diagnostic(ErrorCode.ERR_InterceptorLineCharacterMustBePositive, "-1").WithLocation(18, 42), + // Program.cs(19,6): warning CS9270: 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) + // [InterceptsLocation("Program.cs", -1, -1)] // 3 + Diagnostic(ErrorCode.WRN_InterceptsLocationAttributeUnsupportedSignature, @"InterceptsLocation(""Program.cs"", -1, -1)").WithLocation(19, 6), // Program.cs(19,39): error CS9157: Line and character numbers provided to InterceptsLocationAttribute must be positive. // [InterceptsLocation("Program.cs", -1, -1)] // 3 Diagnostic(ErrorCode.ERR_InterceptorLineCharacterMustBePositive, "-1").WithLocation(19, 39), + // Program.cs(20,6): warning CS9270: 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) + // [InterceptsLocation("Program.cs", 0, 1)] // 4 + Diagnostic(ErrorCode.WRN_InterceptsLocationAttributeUnsupportedSignature, @"InterceptsLocation(""Program.cs"", 0, 1)").WithLocation(20, 6), // Program.cs(20,39): error CS9157: Line and character numbers provided to InterceptsLocationAttribute must be positive. // [InterceptsLocation("Program.cs", 0, 1)] // 4 Diagnostic(ErrorCode.ERR_InterceptorLineCharacterMustBePositive, "0").WithLocation(20, 39), + // Program.cs(21,6): warning CS9270: 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) + // [InterceptsLocation("Program.cs", 1, 0)] // 5 + Diagnostic(ErrorCode.WRN_InterceptsLocationAttributeUnsupportedSignature, @"InterceptsLocation(""Program.cs"", 1, 0)").WithLocation(21, 6), // Program.cs(21,42): error CS9157: Line and character numbers provided to InterceptsLocationAttribute must be positive. // [InterceptsLocation("Program.cs", 1, 0)] // 5 Diagnostic(ErrorCode.ERR_InterceptorLineCharacterMustBePositive, "0").WithLocation(21, 42), + // Program.cs(22,6): warning CS9270: 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) + // [InterceptsLocation("Program.cs", 0, 0)] // 6 + Diagnostic(ErrorCode.WRN_InterceptsLocationAttributeUnsupportedSignature, @"InterceptsLocation(""Program.cs"", 0, 0)").WithLocation(22, 6), // Program.cs(22,39): error CS9157: Line and character numbers provided to InterceptsLocationAttribute must be positive. // [InterceptsLocation("Program.cs", 0, 0)] // 6 Diagnostic(ErrorCode.ERR_InterceptorLineCharacterMustBePositive, "0").WithLocation(22, 39) @@ -3356,7 +3659,6 @@ static class D public void SignatureMismatch_01() { var source = """ - using System.Runtime.CompilerServices; using System; interface I1 { } @@ -3373,18 +3675,23 @@ public static void Main() c.InterceptableMethod("call site"); } } + """; + var locations = GetInterceptableLocations(source); + var interceptor = $$""" + using System.Runtime.CompilerServices; + using System; static class D { - [InterceptsLocation("Program.cs", 15, 11)] + [InterceptsLocation({{GetAttributeArgs(locations[1]!)}})] public static I1 Interceptor1(this I1 i1, int param) { Console.Write("interceptor " + param); return i1; } } """; - var comp = CreateCompilation(new[] { (source, "Program.cs"), s_attributesSource }, parseOptions: RegularWithInterceptors); + var comp = CreateCompilation([source, interceptor, s_attributesSource], parseOptions: RegularWithInterceptors); comp.VerifyEmitDiagnostics( - // Program.cs(21,6): error CS9144: Cannot intercept method 'Program.InterceptableMethod(I1, string)' with interceptor 'D.Interceptor1(I1, int)' because the signatures do not match. - // [InterceptsLocation("Program.cs", 15, 11)] - Diagnostic(ErrorCode.ERR_InterceptorSignatureMismatch, @"InterceptsLocation(""Program.cs"", 15, 11)").WithArguments("Program.InterceptableMethod(I1, string)", "D.Interceptor1(I1, int)").WithLocation(21, 6) + // (6,6): error CS9144: Cannot intercept method 'Program.InterceptableMethod(I1, string)' with interceptor 'D.Interceptor1(I1, int)' because the signatures do not match. + // [InterceptsLocation(1, "OkC1VTxf7+rwBoJPC2IWBhoBAAA=")] + Diagnostic(ErrorCode.ERR_InterceptorSignatureMismatch, "InterceptsLocation").WithArguments("Program.InterceptableMethod(I1, string)", "D.Interceptor1(I1, int)").WithLocation(6, 6) ); } @@ -3393,7 +3700,6 @@ public void SignatureMismatch_02() { // Instance method receiver type differs from interceptor 'this' parameter type. var source = """ - using System.Runtime.CompilerServices; using System; interface I1 { } @@ -3411,18 +3717,23 @@ public static void Main() c.InterceptableMethod("call site"); } } + """; + var locations = GetInterceptableLocations(source); + var interceptor = $$""" + using System.Runtime.CompilerServices; + using System; static class D { - [InterceptsLocation("Program.cs", 16, 11)] + [InterceptsLocation({{GetAttributeArgs(locations[1]!)}})] public static I1 Interceptor1(this I1 i1, string param) { Console.Write("interceptor " + param); return i1; } } """; - var comp = CreateCompilation(new[] { (source, "Program.cs"), s_attributesSource }, parseOptions: RegularWithInterceptors); + var comp = CreateCompilation([source, interceptor, s_attributesSource], parseOptions: RegularWithInterceptors); comp.VerifyEmitDiagnostics( - // Program.cs(22,6): error CS9148: Interceptor must have a 'this' parameter matching parameter 'C this' on 'C.InterceptableMethod(string)'. - // [InterceptsLocation("Program.cs", 16, 11)] - Diagnostic(ErrorCode.ERR_InterceptorMustHaveMatchingThisParameter, @"InterceptsLocation(""Program.cs"", 16, 11)").WithArguments("C this", "C.InterceptableMethod(string)").WithLocation(22, 6) + // (6,6): error CS9148: Interceptor must have a 'this' parameter matching parameter 'C this' on 'C.InterceptableMethod(string)'. + // [InterceptsLocation(1, "ASfq/xnhlb1QGHJAQ5lqJQkBAAA=")] + Diagnostic(ErrorCode.ERR_InterceptorMustHaveMatchingThisParameter, "InterceptsLocation").WithArguments("C this", "C.InterceptableMethod(string)").WithLocation(6, 6) ); } @@ -3431,7 +3742,6 @@ public void SignatureMismatch_03() { // Instance method 'this' parameter ref kind differs from interceptor 'this' parameter ref kind. var source = """ - using System.Runtime.CompilerServices; using System; struct S @@ -3448,18 +3758,23 @@ public static void Main() s.InterceptableMethod("call site"); } } + """; + var locations = GetInterceptableLocations(source); + var interceptors = $$""" + using System.Runtime.CompilerServices; + using System; static class D { - [InterceptsLocation("Program.cs", 15, 11)] + [InterceptsLocation({{GetAttributeArgs(locations[1]!)}})] public static void Interceptor1(this S s, string param) { Console.Write("interceptor " + param); } } """; - var comp = CreateCompilation(new[] { (source, "Program.cs"), s_attributesSource }, parseOptions: RegularWithInterceptors); + var comp = CreateCompilation([source, interceptors, s_attributesSource], parseOptions: RegularWithInterceptors); comp.VerifyEmitDiagnostics( - // Program.cs(21,6): error CS9148: Interceptor must have a 'this' parameter matching parameter 'ref S this' on 'S.InterceptableMethod(string)'. - // [InterceptsLocation("Program.cs", 15, 11)] - Diagnostic(ErrorCode.ERR_InterceptorMustHaveMatchingThisParameter, @"InterceptsLocation(""Program.cs"", 15, 11)").WithArguments("ref S this", "S.InterceptableMethod(string)").WithLocation(21, 6) + // (6,6): error CS9148: Interceptor must have a 'this' parameter matching parameter 'ref S this' on 'S.InterceptableMethod(string)'. + // [InterceptsLocation(1, "fqj37DJySjNYT6e7owxQrugAAAA=")] + Diagnostic(ErrorCode.ERR_InterceptorMustHaveMatchingThisParameter, "InterceptsLocation").WithArguments("ref S this", "S.InterceptableMethod(string)").WithLocation(6, 6) ); } @@ -3468,8 +3783,6 @@ public void SignatureMismatch_04() { // Safe nullability difference var source = """ - using System.Runtime.CompilerServices; - class C { @@ -3484,14 +3797,18 @@ public static void Main() c.InterceptableMethod("call site"); } } + """; + var locations = GetInterceptableLocations(source); + var interceptor = $$""" + using System.Runtime.CompilerServices; static class D { - [InterceptsLocation("Program.cs", 14, 11)] + [InterceptsLocation({{GetAttributeArgs(locations[0]!)}})] public static string Interceptor1(this C s, string? param) => throw null!; } """; - var comp = CreateCompilation(new[] { (source, "Program.cs"), s_attributesSource }, parseOptions: RegularWithInterceptors, options: WithNullableEnable()); + var comp = CreateCompilation([source, interceptor, s_attributesSource], parseOptions: RegularWithInterceptors, options: WithNullableEnable()); comp.VerifyEmitDiagnostics(); } @@ -3500,8 +3817,6 @@ public void SignatureMismatch_05() { // Unsafe nullability difference var source = """ - using System.Runtime.CompilerServices; - class C { @@ -3520,35 +3835,39 @@ public static void Main() _ = c.Method2(); } } + """; + var locations = GetInterceptableLocations(source); + var interceptors = $$""" + using System.Runtime.CompilerServices; static class D { - [InterceptsLocation("Program.cs", 17, 11)] // 1 + [InterceptsLocation({{GetAttributeArgs(locations[0]!)}})] // 1 public static void Interceptor1(this C s, string param2) => throw null!; - [InterceptsLocation("Program.cs", 18, 15)] // 2 + [InterceptsLocation({{GetAttributeArgs(locations[1]!)}})] // 2 public static string? Interceptor2(this C s) => throw null!; } """; - var comp = CreateCompilation(new[] { (source, "Program.cs"), s_attributesSource }, parseOptions: RegularWithInterceptors, options: WithNullableEnable()); + var comp = CreateCompilation([source, interceptors, s_attributesSource], parseOptions: RegularWithInterceptors, options: WithNullableEnable()); comp.VerifyEmitDiagnostics( - // Program.cs(24,6): warning CS9159: Nullability of reference types in type of parameter 'param2' doesn't match interceptable method 'C.Method1(string?)'. - // [InterceptsLocation("Program.cs", 17, 11)] // 1 - Diagnostic(ErrorCode.WRN_NullabilityMismatchInParameterTypeOnInterceptor, @"InterceptsLocation(""Program.cs"", 17, 11)").WithArguments("param2", "C.Method1(string?)").WithLocation(24, 6), - // Program.cs(27,6): warning CS9158: Nullability of reference types in return type doesn't match interceptable method 'C.Method2()'. - // [InterceptsLocation("Program.cs", 18, 15)] // 2 - Diagnostic(ErrorCode.WRN_NullabilityMismatchInReturnTypeOnInterceptor, @"InterceptsLocation(""Program.cs"", 18, 15)").WithArguments("C.Method2()").WithLocation(27, 6) + // (5,6): warning CS9159: Nullability of reference types in type of parameter 'param2' doesn't match interceptable method 'C.Method1(string?)'. + // [InterceptsLocation(1, "535qo9hAHI56AdJiXvHKiOAAAAA=")] // 1 + Diagnostic(ErrorCode.WRN_NullabilityMismatchInParameterTypeOnInterceptor, "InterceptsLocation").WithArguments("param2", "C.Method1(string?)").WithLocation(5, 6), + // (8,6): warning CS9158: Nullability of reference types in return type doesn't match interceptable method 'C.Method2()'. + // [InterceptsLocation(1, "535qo9hAHI56AdJiXvHKiAUBAAA=")] // 2 + Diagnostic(ErrorCode.WRN_NullabilityMismatchInReturnTypeOnInterceptor, "InterceptsLocation").WithArguments("C.Method2()").WithLocation(8, 6) ); - comp = CreateCompilation(new[] { (source, "Program.cs"), s_attributesSource }, parseOptions: RegularWithInterceptors, options: WithNullableDisable()); + comp = CreateCompilation([source, interceptors, s_attributesSource], parseOptions: RegularWithInterceptors, options: WithNullableDisable()); comp.VerifyEmitDiagnostics( - // Program.cs(6,31): warning CS8632: The annotation for nullable reference types should only be used in code within a '#nullable' annotations context. + // (4,31): warning CS8632: The annotation for nullable reference types should only be used in code within a '#nullable' annotations context. // public void Method1(string? param1) => throw null!; - Diagnostic(ErrorCode.WRN_MissingNonNullTypesContextForAnnotation, "?").WithLocation(6, 31), - // Program.cs(28,25): warning CS8632: The annotation for nullable reference types should only be used in code within a '#nullable' annotations context. + Diagnostic(ErrorCode.WRN_MissingNonNullTypesContextForAnnotation, "?").WithLocation(4, 31), + // (9,25): warning CS8632: The annotation for nullable reference types should only be used in code within a '#nullable' annotations context. // public static string? Interceptor2(this C s) => throw null!; - Diagnostic(ErrorCode.WRN_MissingNonNullTypesContextForAnnotation, "?").WithLocation(28, 25) + Diagnostic(ErrorCode.WRN_MissingNonNullTypesContextForAnnotation, "?").WithLocation(9, 25) ); } @@ -3557,8 +3876,6 @@ public void SignatureMismatch_06() { // 'dynamic' difference var source = """ - using System.Runtime.CompilerServices; - class C { @@ -3577,24 +3894,28 @@ public static void Main() _ = c.Method2(); } } + """; + var locations = GetInterceptableLocations(source); + var interceptors = $$""" + using System.Runtime.CompilerServices; static class D { - [InterceptsLocation("Program.cs", 17, 11)] // 1 + [InterceptsLocation({{GetAttributeArgs(locations[0]!)}})] // 1 public static void Interceptor1(this C s, dynamic param2) => throw null!; - [InterceptsLocation("Program.cs", 18, 15)] // 2 + [InterceptsLocation({{GetAttributeArgs(locations[1]!)}})] // 2 public static object Interceptor2(this C s) => throw null!; } """; - var comp = CreateCompilation(new[] { (source, "Program.cs"), s_attributesSource }, parseOptions: RegularWithInterceptors); + var comp = CreateCompilation([source, interceptors, s_attributesSource], parseOptions: RegularWithInterceptors); comp.VerifyEmitDiagnostics( - // Program.cs(24,6): warning CS9154: Intercepting a call to 'C.Method1(object)' with interceptor 'D.Interceptor1(C, dynamic)', but the signatures do not match. - // [InterceptsLocation("Program.cs", 17, 11)] // 1 - Diagnostic(ErrorCode.WRN_InterceptorSignatureMismatch, @"InterceptsLocation(""Program.cs"", 17, 11)").WithArguments("C.Method1(object)", "D.Interceptor1(C, dynamic)").WithLocation(24, 6), - // Program.cs(27,6): warning CS9154: Intercepting a call to 'C.Method2()' with interceptor 'D.Interceptor2(C)', but the signatures do not match. - // [InterceptsLocation("Program.cs", 18, 15)] // 2 - Diagnostic(ErrorCode.WRN_InterceptorSignatureMismatch, @"InterceptsLocation(""Program.cs"", 18, 15)").WithArguments("C.Method2()", "D.Interceptor2(C)").WithLocation(27, 6) + // (5,6): warning CS9154: Intercepting a call to 'C.Method1(object)' with interceptor 'D.Interceptor1(C, dynamic)', but the signatures do not match. + // [InterceptsLocation(1, "tat2uM+CawVuszRsZdGgpOAAAAA=")] // 1 + Diagnostic(ErrorCode.WRN_InterceptorSignatureMismatch, "InterceptsLocation").WithArguments("C.Method1(object)", "D.Interceptor1(C, dynamic)").WithLocation(5, 6), + // (8,6): warning CS9154: Intercepting a call to 'C.Method2()' with interceptor 'D.Interceptor2(C)', but the signatures do not match. + // [InterceptsLocation(1, "tat2uM+CawVuszRsZdGgpAUBAAA=")] // 2 + Diagnostic(ErrorCode.WRN_InterceptorSignatureMismatch, "InterceptsLocation").WithArguments("C.Method2()", "D.Interceptor2(C)").WithLocation(8, 6) ); } @@ -3603,9 +3924,6 @@ public void SignatureMismatch_07() { // tuple element name difference var source = """ - using System.Runtime.CompilerServices; - using System; - class C { public void Method1((string a, string b) param1) => throw null!; @@ -3632,45 +3950,50 @@ public static void Main() c.Method3(default!); } } + """; + var locations = GetInterceptableLocations(source); + var interceptors = $$""" + using System.Runtime.CompilerServices; + using System; static class D { - [InterceptsLocation("Program.cs", 17, 11)] - [InterceptsLocation("Program.cs", 18, 11)] // 1 - [InterceptsLocation("Program.cs", 19, 11)] // 2 + [InterceptsLocation({{GetAttributeArgs(locations[0]!)}})] + [InterceptsLocation({{GetAttributeArgs(locations[1]!)}})] // 1 + [InterceptsLocation({{GetAttributeArgs(locations[2]!)}})] // 2 public static void Interceptor1(this C s, (string a, string b) param2) => Console.Write(1); - [InterceptsLocation("Program.cs", 21, 11)] // 3 - [InterceptsLocation("Program.cs", 22, 11)] - [InterceptsLocation("Program.cs", 23, 11)] // 4 + [InterceptsLocation({{GetAttributeArgs(locations[3]!)}})] // 3 + [InterceptsLocation({{GetAttributeArgs(locations[4]!)}})] + [InterceptsLocation({{GetAttributeArgs(locations[5]!)}})] // 4 public static void Interceptor2(this C s, (string x, string y) param2) => Console.Write(2); - [InterceptsLocation("Program.cs", 25, 11)] // 5 - [InterceptsLocation("Program.cs", 26, 11)] // 6 - [InterceptsLocation("Program.cs", 27, 11)] + [InterceptsLocation({{GetAttributeArgs(locations[6]!)}})] // 5 + [InterceptsLocation({{GetAttributeArgs(locations[7]!)}})] // 6 + [InterceptsLocation({{GetAttributeArgs(locations[8]!)}})] public static void Interceptor3(this C s, (string, string) param2) => Console.Write(3); } """; - var verifier = CompileAndVerify(new[] { (source, "Program.cs"), s_attributesSource }, parseOptions: RegularWithInterceptors, expectedOutput: "111222333"); + var verifier = CompileAndVerify([source, interceptors, s_attributesSource], parseOptions: RegularWithInterceptors, expectedOutput: "111222333"); verifier.VerifyDiagnostics( - // Program.cs(34,6): warning CS9154: Intercepting a call to 'C.Method2((string x, string y))' with interceptor 'D.Interceptor1(C, (string a, string b))', but the signatures do not match. - // [InterceptsLocation("Program.cs", 18, 11)] // 1 - Diagnostic(ErrorCode.WRN_InterceptorSignatureMismatch, @"InterceptsLocation(""Program.cs"", 18, 11)").WithArguments("C.Method2((string x, string y))", "D.Interceptor1(C, (string a, string b))").WithLocation(34, 6), - // Program.cs(35,6): warning CS9154: Intercepting a call to 'C.Method3((string, string))' with interceptor 'D.Interceptor1(C, (string a, string b))', but the signatures do not match. - // [InterceptsLocation("Program.cs", 19, 11)] // 2 - Diagnostic(ErrorCode.WRN_InterceptorSignatureMismatch, @"InterceptsLocation(""Program.cs"", 19, 11)").WithArguments("C.Method3((string, string))", "D.Interceptor1(C, (string a, string b))").WithLocation(35, 6), - // Program.cs(38,6): warning CS9154: Intercepting a call to 'C.Method1((string a, string b))' with interceptor 'D.Interceptor2(C, (string x, string y))', but the signatures do not match. - // [InterceptsLocation("Program.cs", 21, 11)] // 3 - Diagnostic(ErrorCode.WRN_InterceptorSignatureMismatch, @"InterceptsLocation(""Program.cs"", 21, 11)").WithArguments("C.Method1((string a, string b))", "D.Interceptor2(C, (string x, string y))").WithLocation(38, 6), - // Program.cs(40,6): warning CS9154: Intercepting a call to 'C.Method3((string, string))' with interceptor 'D.Interceptor2(C, (string x, string y))', but the signatures do not match. - // [InterceptsLocation("Program.cs", 23, 11)] // 4 - Diagnostic(ErrorCode.WRN_InterceptorSignatureMismatch, @"InterceptsLocation(""Program.cs"", 23, 11)").WithArguments("C.Method3((string, string))", "D.Interceptor2(C, (string x, string y))").WithLocation(40, 6), - // Program.cs(43,6): warning CS9154: Intercepting a call to 'C.Method1((string a, string b))' with interceptor 'D.Interceptor3(C, (string, string))', but the signatures do not match. - // [InterceptsLocation("Program.cs", 25, 11)] // 5 - Diagnostic(ErrorCode.WRN_InterceptorSignatureMismatch, @"InterceptsLocation(""Program.cs"", 25, 11)").WithArguments("C.Method1((string a, string b))", "D.Interceptor3(C, (string, string))").WithLocation(43, 6), - // Program.cs(44,6): warning CS9154: Intercepting a call to 'C.Method2((string x, string y))' with interceptor 'D.Interceptor3(C, (string, string))', but the signatures do not match. - // [InterceptsLocation("Program.cs", 26, 11)] // 6 - Diagnostic(ErrorCode.WRN_InterceptorSignatureMismatch, @"InterceptsLocation(""Program.cs"", 26, 11)").WithArguments("C.Method2((string x, string y))", "D.Interceptor3(C, (string, string))").WithLocation(44, 6) + // (7,6): warning CS9154: Intercepting a call to 'C.Method2((string x, string y))' with interceptor 'D.Interceptor1(C, (string a, string b))', but the signatures do not match. + // [InterceptsLocation(1, "hiVsFn3lfjYE43RKvMvwPGIBAAA=")] // 1 + Diagnostic(ErrorCode.WRN_InterceptorSignatureMismatch, "InterceptsLocation").WithArguments("C.Method2((string x, string y))", "D.Interceptor1(C, (string a, string b))").WithLocation(7, 6), + // (8,6): warning CS9154: Intercepting a call to 'C.Method3((string, string))' with interceptor 'D.Interceptor1(C, (string a, string b))', but the signatures do not match. + // [InterceptsLocation(1, "hiVsFn3lfjYE43RKvMvwPIABAAA=")] // 2 + Diagnostic(ErrorCode.WRN_InterceptorSignatureMismatch, "InterceptsLocation").WithArguments("C.Method3((string, string))", "D.Interceptor1(C, (string a, string b))").WithLocation(8, 6), + // (11,6): warning CS9154: Intercepting a call to 'C.Method1((string a, string b))' with interceptor 'D.Interceptor2(C, (string x, string y))', but the signatures do not match. + // [InterceptsLocation(1, "hiVsFn3lfjYE43RKvMvwPKABAAA=")] // 3 + Diagnostic(ErrorCode.WRN_InterceptorSignatureMismatch, "InterceptsLocation").WithArguments("C.Method1((string a, string b))", "D.Interceptor2(C, (string x, string y))").WithLocation(11, 6), + // (13,6): warning CS9154: Intercepting a call to 'C.Method3((string, string))' with interceptor 'D.Interceptor2(C, (string x, string y))', but the signatures do not match. + // [InterceptsLocation(1, "hiVsFn3lfjYE43RKvMvwPNwBAAA=")] // 4 + Diagnostic(ErrorCode.WRN_InterceptorSignatureMismatch, "InterceptsLocation").WithArguments("C.Method3((string, string))", "D.Interceptor2(C, (string x, string y))").WithLocation(13, 6), + // (16,6): warning CS9154: Intercepting a call to 'C.Method1((string a, string b))' with interceptor 'D.Interceptor3(C, (string, string))', but the signatures do not match. + // [InterceptsLocation(1, "hiVsFn3lfjYE43RKvMvwPPwBAAA=")] // 5 + Diagnostic(ErrorCode.WRN_InterceptorSignatureMismatch, "InterceptsLocation").WithArguments("C.Method1((string a, string b))", "D.Interceptor3(C, (string, string))").WithLocation(16, 6), + // (17,6): warning CS9154: Intercepting a call to 'C.Method2((string x, string y))' with interceptor 'D.Interceptor3(C, (string, string))', but the signatures do not match. + // [InterceptsLocation(1, "hiVsFn3lfjYE43RKvMvwPBoCAAA=")] // 6 + Diagnostic(ErrorCode.WRN_InterceptorSignatureMismatch, "InterceptsLocation").WithArguments("C.Method2((string x, string y))", "D.Interceptor3(C, (string, string))").WithLocation(17, 6) ); } @@ -3679,7 +4002,6 @@ public void SignatureMismatch_08() { // nint/IntPtr difference var source = """ - using System.Runtime.CompilerServices; using System; class C @@ -3701,33 +4023,38 @@ public static void Main() c.Method1(default!); } } + """; + var locations = GetInterceptableLocations(source); + var interceptors = $$""" + using System.Runtime.CompilerServices; + using System; static class D { - [InterceptsLocation("Program.cs", 16, 11)] // 1 - [InterceptsLocation("Program.cs", 17, 11)] + [InterceptsLocation({{GetAttributeArgs(locations[0]!)}})] // 1 + [InterceptsLocation({{GetAttributeArgs(locations[1]!)}})] public static void Interceptor1(this C s, IntPtr param2) => Console.Write(1); - [InterceptsLocation("Program.cs", 19, 11)] // 2 - [InterceptsLocation("Program.cs", 20, 11)] + [InterceptsLocation({{GetAttributeArgs(locations[2]!)}})] // 2 + [InterceptsLocation({{GetAttributeArgs(locations[3]!)}})] public static void Interceptor2(this C s, nint param2) => Console.Write(2); } """; - var verifier = CompileAndVerify(new[] { (source, "Program.cs"), s_attributesSource }, parseOptions: RegularWithInterceptors, expectedOutput: "1122"); + + var verifier = CompileAndVerify([source, interceptors, s_attributesSource], parseOptions: RegularWithInterceptors, expectedOutput: "1122"); verifier.VerifyDiagnostics( - // Program.cs(26,6): warning CS9154: Intercepting a call to 'C.Method1(nint)' with interceptor 'D.Interceptor1(C, IntPtr)', but the signatures do not match. - // [InterceptsLocation("Program.cs", 16, 11)] // 1 - Diagnostic(ErrorCode.WRN_InterceptorSignatureMismatch, @"InterceptsLocation(""Program.cs"", 16, 11)").WithArguments("C.Method1(nint)", "D.Interceptor1(C, System.IntPtr)").WithLocation(26, 6), - // Program.cs(30,6): warning CS9154: Intercepting a call to 'C.Method2(IntPtr)' with interceptor 'D.Interceptor2(C, nint)', but the signatures do not match. - // [InterceptsLocation("Program.cs", 19, 11)] // 2 - Diagnostic(ErrorCode.WRN_InterceptorSignatureMismatch, @"InterceptsLocation(""Program.cs"", 19, 11)").WithArguments("C.Method2(System.IntPtr)", "D.Interceptor2(C, nint)").WithLocation(30, 6)); + // (6,6): warning CS9154: Intercepting a call to 'C.Method1(nint)' with interceptor 'D.Interceptor1(C, IntPtr)', but the signatures do not match. + // [InterceptsLocation(1, "3ONc0QK7vNwCujpTORn5YvcAAAA=")] // 1 + Diagnostic(ErrorCode.WRN_InterceptorSignatureMismatch, "InterceptsLocation").WithArguments("C.Method1(nint)", "D.Interceptor1(C, System.IntPtr)").WithLocation(6, 6), + // (10,6): warning CS9154: Intercepting a call to 'C.Method2(IntPtr)' with interceptor 'D.Interceptor2(C, nint)', but the signatures do not match. + // [InterceptsLocation(1, "3ONc0QK7vNwCujpTORn5YjUBAAA=")] // 2 + Diagnostic(ErrorCode.WRN_InterceptorSignatureMismatch, "InterceptsLocation").WithArguments("C.Method2(System.IntPtr)", "D.Interceptor2(C, nint)").WithLocation(10, 6)); } [Fact] public void SignatureMismatch_09() { var source = """ - using System.Runtime.CompilerServices; using System; static class Program @@ -3740,25 +4067,30 @@ public static void Main() InterceptableMethod(in x); } } + """; + + var locations = GetInterceptableLocations(source); + var interceptor = $$""" + using System.Runtime.CompilerServices; + using System; static class D { - [InterceptsLocation("Program.cs", 11, 9)] + [InterceptsLocation({{GetAttributeArgs(locations[0]!)}})] public static void Interceptor(in int x) => Console.Write("interceptor " + x); } """; - var comp = CreateCompilation(new[] { (source, "Program.cs"), s_attributesSource }, parseOptions: RegularWithInterceptors); + var comp = CreateCompilation([source, interceptor, s_attributesSource], parseOptions: RegularWithInterceptors); comp.VerifyEmitDiagnostics( - // Program.cs(17,6): error CS9144: Cannot intercept method 'Program.InterceptableMethod(ref readonly int)' with interceptor 'D.Interceptor(in int)' because the signatures do not match. - // [InterceptsLocation("Program.cs", 11, 9)] - Diagnostic(ErrorCode.ERR_InterceptorSignatureMismatch, @"InterceptsLocation(""Program.cs"", 11, 9)").WithArguments("Program.InterceptableMethod(ref readonly int)", "D.Interceptor(in int)").WithLocation(17, 6)); + // (6,6): error CS9144: Cannot intercept method 'Console.Write(string)' with interceptor 'D.Interceptor(in int)' because the signatures do not match. + // [InterceptsLocation(1, "tMK4g8K+v1dr3MEydPY1wXQAAAA=")] + Diagnostic(ErrorCode.ERR_InterceptorSignatureMismatch, "InterceptsLocation").WithArguments("System.Console.Write(string)", "D.Interceptor(in int)").WithLocation(6, 6)); } [Fact] public void SignatureMismatch_10() { var source = """ - using System.Runtime.CompilerServices; using System; struct Program @@ -3770,18 +4102,23 @@ public static void Main() new Program().InterceptableMethod(); } } + """; + var locations = GetInterceptableLocations(source); + var interceptors = $$""" + using System.Runtime.CompilerServices; + using System; static class D { - [InterceptsLocation("Program.cs", 10, 23)] + [InterceptsLocation({{GetAttributeArgs(locations[1]!)}})] public static void Interceptor(this in Program x) => Console.Write("Intercepted"); } """; - var comp = CreateCompilation(new[] { (source, "Program.cs"), s_attributesSource }, parseOptions: RegularWithInterceptors); + var comp = CreateCompilation([source, interceptors, s_attributesSource], parseOptions: RegularWithInterceptors); comp.VerifyEmitDiagnostics( - // Program.cs(16,6): error CS9148: Interceptor must have a 'this' parameter matching parameter 'ref Program this' on 'Program.InterceptableMethod()'. - // [InterceptsLocation("Program.cs", 10, 23)] - Diagnostic(ErrorCode.ERR_InterceptorMustHaveMatchingThisParameter, @"InterceptsLocation(""Program.cs"", 10, 23)").WithArguments("ref Program this", "Program.InterceptableMethod()").WithLocation(16, 6)); + // (6,6): error CS9148: Interceptor must have a 'this' parameter matching parameter 'ref Program this' on 'Program.InterceptableMethod()'. + // [InterceptsLocation(1, "g6EgVyqlLSG1DCYza3Uon6cAAAA=")] + Diagnostic(ErrorCode.ERR_InterceptorMustHaveMatchingThisParameter, "InterceptsLocation").WithArguments("ref Program this", "Program.InterceptableMethod()").WithLocation(6, 6)); } [Fact] @@ -3800,14 +4137,14 @@ public static void Main() } } """, "Program.cs"); - - var interceptor = (""" + var locations = GetInterceptableLocations(source); + var interceptor = ($$""" using System.Runtime.CompilerServices; using System; static class D { - [InterceptsLocation("Program.cs", 9, 23)] + [InterceptsLocation({{GetAttributeArgs(locations[1]!)}})] public static void Interceptor(this in Program x) => Console.Write("Intercepted"); } """, "Interceptor.cs"); @@ -3837,14 +4174,14 @@ public static void Main() } } """, "Program.cs"); - + var locations = GetInterceptableLocations(source); var interceptor = ($$""" using System.Runtime.CompilerServices; using System; static class D { - [InterceptsLocation("Program.cs", 9, 23)] + [InterceptsLocation({{GetAttributeArgs(locations[1]!)}})] public static void Interceptor(this {{interceptorRefKind}} Program x) => Console.Write("Intercepted"); } """, "Interceptor.cs"); @@ -3856,8 +4193,8 @@ static class D var comp = CreateCompilation(new[] { source, interceptor, s_attributesSource }, parseOptions: RegularWithInterceptors); comp.VerifyEmitDiagnostics( // Interceptor.cs(6,6): error CS9148: Interceptor must have a 'this' parameter matching parameter 'in Program this' on 'Program.InterceptableMethod()'. - // [InterceptsLocation("Program.cs", 9, 23)] - Diagnostic(ErrorCode.ERR_InterceptorMustHaveMatchingThisParameter, @"InterceptsLocation(""Program.cs"", 9, 23)").WithArguments("in Program this", "Program.InterceptableMethod()").WithLocation(6, 6)); + // [InterceptsLocation(1, "Z8jOxZ1RAOmFFHIDd0PvFLAAAABQcm9ncmFtLmNz")] + Diagnostic(ErrorCode.ERR_InterceptorMustHaveMatchingThisParameter, "InterceptsLocation").WithArguments("in Program this", "Program.InterceptableMethod()").WithLocation(6, 6)); } [Fact] @@ -3865,8 +4202,6 @@ public void ScopedMismatch_01() { // Unsafe 'scoped' difference var source = """ - using System.Runtime.CompilerServices; - class C { @@ -3881,18 +4216,22 @@ public static void Main() C.InterceptableMethod(ref i); } } + """; + var locations = GetInterceptableLocations(source); + var interceptor = $$""" + using System.Runtime.CompilerServices; static class D { - [InterceptsLocation("Program.cs", 14, 11)] // 1 + [InterceptsLocation({{GetAttributeArgs(locations[0]!)}})] // 1 public static ref int Interceptor1(ref int value) => throw null!; } """; - var comp = CreateCompilation(new[] { (source, "Program.cs"), s_attributesSource }, parseOptions: RegularWithInterceptors, options: WithNullableEnable()); + var comp = CreateCompilation([source, interceptor, s_attributesSource], parseOptions: RegularWithInterceptors, options: WithNullableEnable()); comp.VerifyEmitDiagnostics( - // Program.cs(20,6): error CS9156: Cannot intercept call to 'C.InterceptableMethod(scoped ref int)' with 'D.Interceptor1(ref int)' because of a difference in 'scoped' modifiers or '[UnscopedRef]' attributes. - // [InterceptsLocation("Program.cs", 14, 11)] // 1 - Diagnostic(ErrorCode.ERR_InterceptorScopedMismatch, @"InterceptsLocation(""Program.cs"", 14, 11)").WithArguments("C.InterceptableMethod(scoped ref int)", "D.Interceptor1(ref int)").WithLocation(20, 6) + // (5,6): error CS9156: Cannot intercept call to 'C.InterceptableMethod(scoped ref int)' with 'D.Interceptor1(ref int)' because of a difference in 'scoped' modifiers or '[UnscopedRef]' attributes. + // [InterceptsLocation(1, "0iiDkFPlvM/mJGTV+4iUXcUAAAA=")] // 1 + Diagnostic(ErrorCode.ERR_InterceptorScopedMismatch, "InterceptsLocation").WithArguments("C.InterceptableMethod(scoped ref int)", "D.Interceptor1(ref int)").WithLocation(5, 6) ); } @@ -3901,9 +4240,6 @@ public void ScopedMismatch_02() { // safe 'scoped' difference var source = """ - using System.Runtime.CompilerServices; - using System; - class C { @@ -3918,12 +4254,17 @@ public static void Main() _ = C.InterceptableMethod(ref i); } } + """; + var locations = GetInterceptableLocations(source); + var interceptors = $$""" + using System.Runtime.CompilerServices; + using System; static class D { static int i; - [InterceptsLocation("Program.cs", 15, 15)] + [InterceptsLocation({{GetAttributeArgs(locations[0]!)}})] public static ref int Interceptor1(scoped ref int value) { Console.Write(1); @@ -3931,7 +4272,7 @@ public static ref int Interceptor1(scoped ref int value) } } """; - var verifier = CompileAndVerify(new[] { (source, "Program.cs"), s_attributesSource }, parseOptions: RegularWithInterceptors, expectedOutput: "1"); + var verifier = CompileAndVerify([source, interceptors, s_attributesSource], parseOptions: RegularWithInterceptors, expectedOutput: "1"); verifier.VerifyDiagnostics(); } @@ -3941,8 +4282,6 @@ public void ScopedMismatch_03() // safe '[UnscopedRef]' difference var source = """ using System.Diagnostics.CodeAnalysis; - using System.Runtime.CompilerServices; - using System; class C { @@ -3957,12 +4296,17 @@ public static void Main() _ = C.InterceptableMethod(out int i); } } + """; + var locations = GetInterceptableLocations(source); + var interceptor = $$""" + using System.Runtime.CompilerServices; + using System; static class D { static int i; - [InterceptsLocation("Program.cs", 15, 15)] + [InterceptsLocation({{GetAttributeArgs(locations[0]!)}})] public static ref int Interceptor1(out int value) { Console.Write(1); @@ -3971,7 +4315,7 @@ public static ref int Interceptor1(out int value) } } """; - var verifier = CompileAndVerify(new[] { (source, "Program.cs"), s_attributesSource, (UnscopedRefAttributeDefinition, "UnscopedRefAttribute.cs") }, parseOptions: RegularWithInterceptors, expectedOutput: "1"); + var verifier = CompileAndVerify([source, interceptor, s_attributesSource, UnscopedRefAttributeDefinition], parseOptions: RegularWithInterceptors, expectedOutput: "1"); verifier.VerifyDiagnostics(); } @@ -3980,10 +4324,6 @@ public void ScopedMismatch_04() { // unsafe '[UnscopedRef]' difference var source = """ - using System.Diagnostics.CodeAnalysis; - using System.Runtime.CompilerServices; - using System; - class C { @@ -3997,18 +4337,24 @@ public static void Main() C.InterceptableMethod(out int i); } } + """; + var locations = GetInterceptableLocations(source); + var interceptor = $$""" + using System.Diagnostics.CodeAnalysis; + using System.Runtime.CompilerServices; + using System; static class D { - [InterceptsLocation("Program.cs", 15, 11)] // 1 + [InterceptsLocation({{GetAttributeArgs(locations[0]!)}})] // 1 public static ref int Interceptor1([UnscopedRef] out int value) => throw null!; } """; - var comp = CreateCompilation(new[] { (source, "Program.cs"), s_attributesSource, (UnscopedRefAttributeDefinition, "UnscopedRefAttribute.cs") }, parseOptions: RegularWithInterceptors, options: WithNullableEnable()); + var comp = CreateCompilation([source, interceptor, s_attributesSource, UnscopedRefAttributeDefinition], parseOptions: RegularWithInterceptors, options: WithNullableEnable()); comp.VerifyEmitDiagnostics( - // Program.cs(21,6): error CS9156: Cannot intercept call to 'C.InterceptableMethod(out int)' with 'D.Interceptor1(out int)' because of a difference in 'scoped' modifiers or '[UnscopedRef]' attributes. - // [InterceptsLocation("Program.cs", 15, 11)] // 1 - Diagnostic(ErrorCode.ERR_InterceptorScopedMismatch, @"InterceptsLocation(""Program.cs"", 15, 11)").WithArguments("C.InterceptableMethod(out int)", "D.Interceptor1(out int)").WithLocation(21, 6) + // (7,6): error CS9156: Cannot intercept call to 'C.InterceptableMethod(out int)' with 'D.Interceptor1(out int)' because of a difference in 'scoped' modifiers or '[UnscopedRef]' attributes. + // [InterceptsLocation(1, "vduOaI3RVsjD7fczcgX/N6oAAAA=")] // 1 + Diagnostic(ErrorCode.ERR_InterceptorScopedMismatch, "InterceptsLocation").WithArguments("C.InterceptableMethod(out int)", "D.Interceptor1(out int)").WithLocation(7, 6) ); } @@ -4200,9 +4546,6 @@ public void ParamsMismatch_01() { // Test when interceptable method has 'params' parameter. var source = """ - using System.Runtime.CompilerServices; - using System; - class C { @@ -4217,17 +4560,22 @@ public static void Main() C.InterceptableMethod(4, 5, 6); } } + """; + var locations = GetInterceptableLocations(source); + var interceptors = $$""" + using System.Runtime.CompilerServices; + using System; static class D { - [InterceptsLocation("Program.cs", 14, 11)] + [InterceptsLocation({{GetAttributeArgs(locations[0]!)}})] public static void Interceptor1(int[] value) { foreach (var i in value) Console.Write(i); } - [InterceptsLocation("Program.cs", 15, 11)] + [InterceptsLocation({{GetAttributeArgs(locations[1]!)}})] public static void Interceptor2(params int[] value) { foreach (var i in value) @@ -4235,7 +4583,7 @@ public static void Interceptor2(params int[] value) } } """; - var verifier = CompileAndVerify(new[] { (source, "Program.cs"), s_attributesSource }, parseOptions: RegularWithInterceptors, expectedOutput: "123456"); + var verifier = CompileAndVerify([source, interceptors, s_attributesSource], parseOptions: RegularWithInterceptors, expectedOutput: "123456"); verifier.VerifyDiagnostics(); } @@ -4244,9 +4592,6 @@ public void ParamsMismatch_02() { // Test when interceptable method lacks 'params' parameter, and interceptor has one, and method is called as if it has one. var source = """ - using System.Runtime.CompilerServices; - using System; - class C { @@ -4261,17 +4606,22 @@ public static void Main() C.InterceptableMethod(4, 5, 6); // 2 } } + """; + var locations = GetInterceptableLocations(source); + var interceptors = $$""" + using System.Runtime.CompilerServices; + using System; static class D { - [InterceptsLocation("Program.cs", 14, 11)] + [InterceptsLocation({{GetAttributeArgs(locations[0]!)}})] public static void Interceptor1(int[] value) { foreach (var i in value) Console.Write(i); } - [InterceptsLocation("Program.cs", 15, 11)] + [InterceptsLocation({{GetAttributeArgs(locations[1]!)}})] public static void Interceptor2(params int[] value) { foreach (var i in value) @@ -4279,14 +4629,14 @@ public static void Interceptor2(params int[] value) } } """; - var comp = CreateCompilation(new[] { (source, "Program.cs"), s_attributesSource }, parseOptions: RegularWithInterceptors); + var comp = CreateCompilation([source, interceptors, s_attributesSource], parseOptions: RegularWithInterceptors); comp.VerifyEmitDiagnostics( - // Program.cs(14,11): error CS1501: No overload for method 'InterceptableMethod' takes 3 arguments - // C.InterceptableMethod(1, 2, 3 ); // 1 - Diagnostic(ErrorCode.ERR_BadArgCount, "InterceptableMethod").WithArguments("InterceptableMethod", "3").WithLocation(14, 11), - // Program.cs(15,11): error CS1501: No overload for method 'InterceptableMethod' takes 3 arguments - // C.InterceptableMethod(4, 5, 6); // 2 - Diagnostic(ErrorCode.ERR_BadArgCount, "InterceptableMethod").WithArguments("InterceptableMethod", "3").WithLocation(15, 11)); + // (11,11): error CS1501: No overload for method 'InterceptableMethod' takes 3 arguments + // C.InterceptableMethod(1, 2, 3 ); // 1 + Diagnostic(ErrorCode.ERR_BadArgCount, "InterceptableMethod").WithArguments("InterceptableMethod", "3").WithLocation(11, 11), + // (12,11): error CS1501: No overload for method 'InterceptableMethod' takes 3 arguments + // C.InterceptableMethod(4, 5, 6); // 2 + Diagnostic(ErrorCode.ERR_BadArgCount, "InterceptableMethod").WithArguments("InterceptableMethod", "3").WithLocation(12, 11)); } [Fact] @@ -4294,9 +4644,6 @@ public void ParamsMismatch_03() { // Test when interceptable method lacks 'params' parameter, and interceptor has one, and method is called in normal form. var source = """ - using System.Runtime.CompilerServices; - using System; - class C { @@ -4311,17 +4658,23 @@ public static void Main() C.InterceptableMethod(new[] { 4, 5, 6 }); } } + """; + + var locations = GetInterceptableLocations(source); + var interceptors = $$""" + using System.Runtime.CompilerServices; + using System; static class D { - [InterceptsLocation("Program.cs", 14, 11)] + [InterceptsLocation({{GetAttributeArgs(locations[0]!)}})] public static void Interceptor1(int[] value) { foreach (var i in value) Console.Write(i); } - [InterceptsLocation("Program.cs", 15, 11)] + [InterceptsLocation({{GetAttributeArgs(locations[1]!)}})] public static void Interceptor2(params int[] value) { foreach (var i in value) @@ -4329,7 +4682,7 @@ public static void Interceptor2(params int[] value) } } """; - var verifier = CompileAndVerify(new[] { (source, "Program.cs"), s_attributesSource }, parseOptions: RegularWithInterceptors, expectedOutput: "123456"); + var verifier = CompileAndVerify([source, interceptors, s_attributesSource], parseOptions: RegularWithInterceptors, expectedOutput: "123456"); verifier.VerifyDiagnostics(); } @@ -4338,49 +4691,52 @@ public void InterpolatedStringHandler_01() { // Verify that interpolated string-related attributes on an intercepted call use the attributes from the interceptable method. var code = """ -using System; -using System.Runtime.CompilerServices; + using System; + using System.Runtime.CompilerServices; -var s = new S1(); -s.M($""); + var s = new S1(); + s.M($""); -public struct S1 -{ - public S1() { } - public int Field = 1; + public struct S1 + { + public S1() { } + public int Field = 1; - public void M([InterpolatedStringHandlerArgument("")] CustomHandler c) - { - Console.Write(0); - } -} + public void M([InterpolatedStringHandlerArgument("")] CustomHandler c) + { + Console.Write(0); + } + } -public static class S1Ext -{ - [InterceptsLocation("Program.cs", 5, 3)] - public static void M1(ref this S1 s1, CustomHandler c) - { - Console.Write(2); - } -} + partial struct CustomHandler + { + public CustomHandler(int literalLength, int formattedCount, S1 s) + { + Console.Write(1); + } + } + """; + var locations = GetInterceptableLocations(code); + var interceptor = $$""" + using System; + using System.Runtime.CompilerServices; -partial struct CustomHandler -{ - public CustomHandler(int literalLength, int formattedCount, S1 s) - { - Console.Write(1); - } -} -"""; - var verifier = CompileAndVerify( - new[] + public static class S1Ext { - (code, "Program.cs"), - (InterpolatedStringHandlerArgumentAttribute, "a.cs"), - (GetInterpolatedStringCustomHandlerType("CustomHandler", "partial struct", useBoolReturns: false), "b.cs"), - s_attributesSource - }, + [InterceptsLocation({{GetAttributeArgs(locations[0]!)}})] + public static void M1(ref this S1 s1, CustomHandler c) + { + Console.Write(2); + } + } + """; + var verifier = CompileAndVerify([ + code, + interceptor, + InterpolatedStringHandlerArgumentAttribute, + GetInterpolatedStringCustomHandlerType("CustomHandler", "partial struct", useBoolReturns: false), + s_attributesSource], parseOptions: RegularWithInterceptors, expectedOutput: "12"); verifier.VerifyDiagnostics(); @@ -4392,7 +4748,6 @@ public void InterpolatedStringHandler_02() // Verify that interpolated string-related attributes are ignored on an interceptor in an intercepted call. var code = """ using System; -using System.Runtime.CompilerServices; var s = new S1(); s.M($""); @@ -4409,31 +4764,34 @@ public void M(CustomHandler c) } } -public static class S1Ext +partial struct CustomHandler { - [InterceptsLocation("Program.cs", 5, 3)] - public static void M1(ref this S1 s1, [InterpolatedStringHandlerArgument("s1")] CustomHandler c) + public CustomHandler(int literalLength, int formattedCount, S1 s) { - Console.Write(1); + throw null!; // we don't expect this to be called } } +"""; + var locations = GetInterceptableLocations(code); + var interceptors = $$""" +using System.Runtime.CompilerServices; +using System; -partial struct CustomHandler +public static class S1Ext { - public CustomHandler(int literalLength, int formattedCount, S1 s) + [InterceptsLocation({{GetAttributeArgs(locations[0]!)}})] + public static void M1(ref this S1 s1, [InterpolatedStringHandlerArgument("s1")] CustomHandler c) { - throw null!; // we don't expect this to be called + Console.Write(1); } } """; - var verifier = CompileAndVerify( - new[] - { - (code, "Program.cs"), - (InterpolatedStringHandlerArgumentAttribute, "a.cs"), - (GetInterpolatedStringCustomHandlerType("CustomHandler", "partial struct", useBoolReturns: false), "b.cs"), - s_attributesSource - }, + var verifier = CompileAndVerify([ + code, + interceptors, + InterpolatedStringHandlerArgumentAttribute, + GetInterpolatedStringCustomHandlerType("CustomHandler", "partial struct", useBoolReturns: false), + s_attributesSource], parseOptions: RegularWithInterceptors, expectedOutput: "1"); verifier.VerifyDiagnostics(); @@ -4463,31 +4821,35 @@ public static void M(S1 s1, S1 s2, [InterpolatedStringHandlerArgument("s1")] Cus } } -public static class S1Ext +partial struct CustomHandler { - [InterceptsLocation("Program.cs", 6, 4)] - public static void M1(S1 s2, S1 s3, [InterpolatedStringHandlerArgument("s2")] CustomHandler c) + public CustomHandler(int literalLength, int formattedCount, S1 s) { - Console.Write(2); + Console.Write(s.Field); } } +"""; + var locations = GetInterceptableLocations(code); + var interceptors = $$""" +using System.Runtime.CompilerServices; +using System; -partial struct CustomHandler +public static class S1Ext { - public CustomHandler(int literalLength, int formattedCount, S1 s) + [InterceptsLocation({{GetAttributeArgs(locations[0]!)}})] + public static void M1(S1 s2, S1 s3, [InterpolatedStringHandlerArgument("s2")] CustomHandler c) { - Console.Write(s.Field); + Console.Write(2); } } """; - var verifier = CompileAndVerify( - new[] - { - (code, "Program.cs"), - (InterpolatedStringHandlerArgumentAttribute, "a.cs"), - (GetInterpolatedStringCustomHandlerType("CustomHandler", "partial struct", useBoolReturns: false), "b.cs"), + var verifier = CompileAndVerify([ + code, + interceptors, + InterpolatedStringHandlerArgumentAttribute, + GetInterpolatedStringCustomHandlerType("CustomHandler", "partial struct", useBoolReturns: false), s_attributesSource - }, + ], parseOptions: RegularWithInterceptors, expectedOutput: "12"); verifier.VerifyDiagnostics(); @@ -4520,7 +4882,10 @@ class D } """; var verifier = CompileAndVerify(new[] { (source, "Program.cs"), s_attributesSource }, parseOptions: RegularWithInterceptors, expectedOutput: "interceptor 1"); - verifier.VerifyDiagnostics(); + verifier.VerifyDiagnostics( + // OtherFile.cs(48,6): warning CS9270: 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) + // [InterceptsLocation("Program.cs", 12, 9)] + Diagnostic(ErrorCode.WRN_InterceptsLocationAttributeUnsupportedSignature, @"InterceptsLocation(""Program.cs"", 12, 9)").WithLocation(48, 6)); } [Fact] @@ -4551,6 +4916,9 @@ class D """; var comp = CreateCompilation(new[] { (source, "Program.cs"), s_attributesSource }, parseOptions: RegularWithInterceptors); comp.VerifyEmitDiagnostics( + // OtherFile.cs(48,6): warning CS9270: 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) + // [InterceptsLocation("OtherFile.cs", 42, 9)] + Diagnostic(ErrorCode.WRN_InterceptsLocationAttributeUnsupportedSignature, @"InterceptsLocation(""OtherFile.cs"", 42, 9)").WithLocation(48, 6), // OtherFile.cs(48,25): error CS9139: Cannot intercept: compilation does not contain a file with path 'OtherFile.cs'. // [InterceptsLocation("OtherFile.cs", 42, 9)] Diagnostic(ErrorCode.ERR_InterceptorPathNotInCompilation, @"""OtherFile.cs""").WithArguments("OtherFile.cs").WithLocation(48, 25)); @@ -4561,9 +4929,6 @@ public void ObsoleteInterceptor() { // Expect no Obsolete diagnostics to be reported var source = """ - using System.Runtime.CompilerServices; - using System; - C.M(); class C @@ -4571,16 +4936,21 @@ class C public static void M() => throw null!; } + """; + var locations = GetInterceptableLocations(source); + var interceptor = $$""" + using System.Runtime.CompilerServices; + using System; class D { [Obsolete] - [InterceptsLocation("Program.cs", 4, 3)] + [InterceptsLocation({{GetAttributeArgs(locations[0]!)}})] public static void M1() => Console.Write(1); } """; - var verifier = CompileAndVerify(new[] { (source, "Program.cs"), s_attributesSource }, parseOptions: RegularWithInterceptors, expectedOutput: "1"); + var verifier = CompileAndVerify([source, interceptor, s_attributesSource], parseOptions: RegularWithInterceptors, expectedOutput: "1"); verifier.VerifyDiagnostics(); } @@ -4589,9 +4959,6 @@ public void CallerInfo() { // CallerLineNumber, etc. on the interceptor doesn't affect the default arguments passed to an intercepted call. var source = """ - using System.Runtime.CompilerServices; - using System; - C.M(); class C @@ -4599,15 +4966,20 @@ class C public static void M(int lineNumber = 1) => throw null!; } + """; + var locations = GetInterceptableLocations(source); + var interceptors = $$""" + using System.Runtime.CompilerServices; + using System; class D { - [InterceptsLocation("Program.cs", 4, 3)] + [InterceptsLocation({{GetAttributeArgs(locations[0]!)}})] public static void M1([CallerLineNumber] int lineNumber = 0) => Console.Write(lineNumber); } """; - var verifier = CompileAndVerify(new[] { (source, "Program.cs"), s_attributesSource }, parseOptions: RegularWithInterceptors, expectedOutput: "1"); + var verifier = CompileAndVerify([source, interceptors, s_attributesSource], parseOptions: RegularWithInterceptors, expectedOutput: "1"); verifier.VerifyDiagnostics(); } @@ -4616,9 +4988,6 @@ public void DefaultArguments_01() { // Default parameter values on the interceptor doesn't affect the default arguments passed to an intercepted call. var source = """ - using System.Runtime.CompilerServices; - using System; - C.M(); class C @@ -4626,15 +4995,21 @@ class C public static void M(int lineNumber = 1) => throw null!; } + """; + + var locations = GetInterceptableLocations(source); + var interceptor = $$""" + using System.Runtime.CompilerServices; + using System; class D { - [InterceptsLocation("Program.cs", 4, 3)] + [InterceptsLocation({{GetAttributeArgs(locations[0]!)}})] public static void M1(int lineNumber = 0) => Console.Write(lineNumber); } """; - var verifier = CompileAndVerify(new[] { (source, "Program.cs"), s_attributesSource }, parseOptions: RegularWithInterceptors, expectedOutput: "1"); + var verifier = CompileAndVerify([source, interceptor, s_attributesSource], parseOptions: RegularWithInterceptors, expectedOutput: "1"); verifier.VerifyDiagnostics(); } @@ -4643,36 +5018,36 @@ public void DefaultArguments_02() { // Interceptor cannot add a default argument when original method lacks it. var source = """ - using System.Runtime.CompilerServices; - using System; - C.M(); // 1 class C { public static void M(int lineNumber) => throw null!; } + """; + var locations = GetInterceptableLocations(source); + var interceptors = $$""" + using System.Runtime.CompilerServices; + using System; class D { - [InterceptsLocation("Program.cs", 4, 3)] + [InterceptsLocation({{GetAttributeArgs(locations[0]!)}})] public static void M1(int lineNumber = 0) => Console.Write(lineNumber); } """; - var comp = CreateCompilation(new[] { (source, "Program.cs"), s_attributesSource }, parseOptions: RegularWithInterceptors); + var comp = CreateCompilation([source, interceptors, s_attributesSource], parseOptions: RegularWithInterceptors); comp.VerifyEmitDiagnostics( - // Program.cs(4,3): error CS7036: There is no argument given that corresponds to the required parameter 'lineNumber' of 'C.M(int)' + // (1,3): error CS7036: There is no argument given that corresponds to the required parameter 'lineNumber' of 'C.M(int)' // C.M(); // 1 - Diagnostic(ErrorCode.ERR_NoCorrespondingArgument, "M").WithArguments("lineNumber", "C.M(int)").WithLocation(4, 3)); + Diagnostic(ErrorCode.ERR_NoCorrespondingArgument, "M").WithArguments("lineNumber", "C.M(int)").WithLocation(1, 3)); } [Fact] public void InterceptorExtern() { var source = """ - using System.Runtime.CompilerServices; - C.M(); class C @@ -4680,15 +5055,19 @@ class C public static void M() => throw null!; } + """; + var locations = GetInterceptableLocations(source); + var interceptors = $$""" + using System.Runtime.CompilerServices; static class D { - [InterceptsLocation("Program.cs", 3, 3)] + [InterceptsLocation({{GetAttributeArgs(locations[0]!)}})] public static extern void Interceptor(); } """; - var verifier = CompileAndVerify(new[] { (source, "Program.cs"), s_attributesSource }, parseOptions: RegularWithInterceptors, verify: Verification.Skipped); + var verifier = CompileAndVerify([source, interceptors, s_attributesSource], parseOptions: RegularWithInterceptors, verify: Verification.Skipped); verifier.VerifyDiagnostics(); verifier.VerifyIL("", """ @@ -4705,28 +5084,34 @@ .maxstack 0 public void InterceptorAbstract() { var source = """ - using System.Runtime.CompilerServices; - using System; - var d = new D(); d.M(); - abstract class C + abstract partial class C { - public void M() => throw null!; + } - [InterceptsLocation("Program.cs", 5, 3)] + partial class D { } + """; + var locations = GetInterceptableLocations(source); + var interceptor = $$""" + using System.Runtime.CompilerServices; + using System; + + abstract partial class C + { + [InterceptsLocation({{GetAttributeArgs(locations[0]!)}})] public abstract void Interceptor(); } - class D : C + partial class D : C { public override void Interceptor() => Console.Write(1); } """; - var verifier = CompileAndVerify(new[] { (source, "Program.cs"), s_attributesSource }, parseOptions: RegularWithInterceptors, expectedOutput: "1"); + var verifier = CompileAndVerify([source, interceptor, s_attributesSource], parseOptions: RegularWithInterceptors, expectedOutput: "1"); verifier.VerifyDiagnostics(); } @@ -4734,19 +5119,14 @@ class D : C public void InterceptorInterface() { var source = """ - using System.Runtime.CompilerServices; using System; I i = new C(); i.M(); - interface I + partial interface I { - public void M(); - - [InterceptsLocation("Program.cs", 5, 3)] - void Interceptor(); } class C : I @@ -4756,7 +5136,18 @@ class C : I } """; - var verifier = CompileAndVerify(new[] { (source, "Program.cs"), s_attributesSource }, parseOptions: RegularWithInterceptors, expectedOutput: "1"); + var location = GetInterceptableLocations(source)[0]!; + var interceptor = $$""" + using System.Runtime.CompilerServices; + + partial interface I + { + [InterceptsLocation({{GetAttributeArgs(location)}})] + void Interceptor(); + } + """; + + var verifier = CompileAndVerify([source, interceptor, s_attributesSource], parseOptions: RegularWithInterceptors, expectedOutput: "1"); verifier.VerifyDiagnostics(); } @@ -4786,6 +5177,9 @@ static class MyEnumerableExt var comp = CreateCompilation(new[] { (source, "Program.cs"), s_attributesSource }, parseOptions: RegularWithInterceptors); comp.VerifyEmitDiagnostics( + // Program.cs(16,6): warning CS9270: 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) + // [InterceptsLocation("Program.cs", 5, 22)] // 1 + Diagnostic(ErrorCode.WRN_InterceptsLocationAttributeUnsupportedSignature, @"InterceptsLocation(""Program.cs"", 5, 22)").WithLocation(16, 6), // Program.cs(16,6): error CS9151: Possible method name 'myEnumerable' cannot be intercepted because it is not being invoked. // [InterceptsLocation("Program.cs", 5, 22)] // 1 Diagnostic(ErrorCode.ERR_InterceptorNameNotInvoked, @"InterceptsLocation(""Program.cs"", 5, 22)").WithArguments("myEnumerable").WithLocation(16, 6)); @@ -4817,6 +5211,9 @@ static class MyDisposeExt var comp = CreateCompilation(new[] { (source, "Program.cs"), s_attributesSource }, parseOptions: RegularWithInterceptors); comp.VerifyEmitDiagnostics( + // Program.cs(16,6): warning CS9270: 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) + // [InterceptsLocation("Program.cs", 5, 8)] // 1 + Diagnostic(ErrorCode.WRN_InterceptsLocationAttributeUnsupportedSignature, @"InterceptsLocation(""Program.cs"", 5, 8)").WithLocation(16, 6), // Program.cs(16,6): error CS9151: Possible method name 'myDisposable' cannot be intercepted because it is not being invoked. // [InterceptsLocation("Program.cs", 5, 8)] // 1 Diagnostic(ErrorCode.ERR_InterceptorNameNotInvoked, @"InterceptsLocation(""Program.cs"", 5, 8)").WithArguments("myDisposable").WithLocation(16, 6) @@ -4847,12 +5244,55 @@ static class MyDeconstructableExt var comp = CreateCompilation(new[] { (source, "Program.cs"), s_attributesSource }, parseOptions: RegularWithInterceptors); comp.VerifyEmitDiagnostics( + // Program.cs(14,6): warning CS9270: 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) + // [InterceptsLocation("Program.cs", 5, 14)] // 1 + Diagnostic(ErrorCode.WRN_InterceptsLocationAttributeUnsupportedSignature, @"InterceptsLocation(""Program.cs"", 5, 14)").WithLocation(14, 6), // Program.cs(14,6): error CS9151: Possible method name 'myDeconstructable' cannot be intercepted because it is not being invoked. // [InterceptsLocation("Program.cs", 5, 14)] // 1 Diagnostic(ErrorCode.ERR_InterceptorNameNotInvoked, @"InterceptsLocation(""Program.cs"", 5, 14)").WithArguments("myDeconstructable").WithLocation(14, 6) ); } + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/76126")] + public void DisplayPathMapping_01() + { + var pathPrefix = PlatformInformation.IsWindows ? """C:\My\Machine\Specific\Path\""" : "/My/Machine/Specific/Path/"; + var path = pathPrefix + "Program.cs"; + var resolver = new SourceFileResolver([], null, [new KeyValuePair(pathPrefix, "/_/")]); + var options = TestOptions.DebugExe.WithSourceReferenceResolver(resolver); + + var source = (""" + C c = new C(); + c.M(); + """, path); + var comp = CreateCompilation(source, options: options); + var tree = comp.SyntaxTrees[0]; + var model = comp.GetSemanticModel(tree); + var node = tree.GetRoot().DescendantNodes().OfType().Single(); + var location = model.GetInterceptableLocation(node)!; + Assert.Equal("/_/Program.cs(2,3)", location.GetDisplayLocation()); + + var interceptors = $$""" + using System.Runtime.CompilerServices; + using System; + + class C + { + public void M() => throw null!; + + [InterceptsLocation({{GetAttributeArgs(location)}})] + public void Interceptor() => Console.Write(1); + } + """; + + var verifier = CompileAndVerify( + [source, interceptors, s_attributesSource], + parseOptions: RegularWithInterceptors, + options: options, + expectedOutput: "1"); + verifier.VerifyDiagnostics(); + } + [Fact] public void PathMapping_01() { @@ -4881,7 +5321,10 @@ class C options: TestOptions.DebugExe.WithSourceReferenceResolver( new SourceFileResolver(ImmutableArray.Empty, null, pathMap)), expectedOutput: "1"); - verifier.VerifyDiagnostics(); + verifier.VerifyDiagnostics( + // C:\My\Machine\Specific\Path\Program.cs(11,6): warning CS9270: 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) + // [InterceptsLocation("/_/Program.cs", 5, 3)] + Diagnostic(ErrorCode.WRN_InterceptsLocationAttributeUnsupportedSignature, @"InterceptsLocation(""/_/Program.cs"", 5, 3)").WithLocation(11, 6)); } [Fact] @@ -4914,7 +5357,10 @@ class C options: TestOptions.DebugExe.WithSourceReferenceResolver( new SourceFileResolver(ImmutableArray.Empty, null, pathMap)), expectedOutput: "1"); - verifier.VerifyDiagnostics(); + verifier.VerifyDiagnostics( + // C:\My\Machine\Specific\Path\Program.cs(11,6): warning CS9270: 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) + // [InterceptsLocation(@"C:\My\Machine\Specific\Path\Program.cs", 5, 3)] + Diagnostic(ErrorCode.WRN_InterceptsLocationAttributeUnsupportedSignature, $@"InterceptsLocation(@""{path}"", 5, 3)").WithLocation(11, 6)); } [Fact] @@ -4944,14 +5390,19 @@ class C parseOptions: RegularWithInterceptors, options: TestOptions.DebugExe.WithSourceReferenceResolver( new SourceFileResolver(ImmutableArray.Empty, null, pathMap))); - comp.VerifyEmitDiagnostics(PlatformInformation.IsWindows - // C:\My\Machine\Specific\Path\Program.cs(11,25): error CS9139: Cannot intercept: compilation does not contain a file with path 'C:\_\Program.cs'. + comp.VerifyEmitDiagnostics([ + // C:\My\Machine\Specific\Path\Program.cs(11,6): warning CS9270: 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) // [InterceptsLocation(@"\_\Program.cs", 5, 3)] - ? Diagnostic(ErrorCode.ERR_InterceptorPathNotInCompilation, @"@""\_\Program.cs""").WithArguments(@"C:\_\Program.cs").WithLocation(11, 25) + Diagnostic(ErrorCode.WRN_InterceptsLocationAttributeUnsupportedSignature, @"InterceptsLocation(@""\_\Program.cs"", 5, 3)").WithLocation(11, 6), + ..(ReadOnlySpan)[PlatformInformation.IsWindows + // C:\My\Machine\Specific\Path\Program.cs(11,25): error CS9139: Cannot intercept: compilation does not contain a file with path 'C:\_\Program.cs'. + // [InterceptsLocation(@"\_\Program.cs", 5, 3)] + ? Diagnostic(ErrorCode.ERR_InterceptorPathNotInCompilation, @"@""\_\Program.cs""").WithArguments(@"C:\_\Program.cs").WithLocation(11, 25) - // /My/Machine/Specific/Path/Program.cs(11,25): error CS9139: Cannot intercept: compilation does not contain a file with path '/My/Machine/Specific/Path/\_\Program.cs'. - // [InterceptsLocation(@"\_\Program.cs", 5, 3)] - : Diagnostic(ErrorCode.ERR_InterceptorPathNotInCompilation, @"@""\_\Program.cs""").WithArguments(@"/My/Machine/Specific/Path/\_\Program.cs").WithLocation(11, 25)); + // /My/Machine/Specific/Path/Program.cs(11,25): error CS9139: Cannot intercept: compilation does not contain a file with path '/My/Machine/Specific/Path/\_\Program.cs'. + // [InterceptsLocation(@"\_\Program.cs", 5, 3)] + : Diagnostic(ErrorCode.ERR_InterceptorPathNotInCompilation, @"@""\_\Program.cs""").WithArguments(@"/My/Machine/Specific/Path/\_\Program.cs").WithLocation(11, 25)] + ]); } [Fact] @@ -5012,6 +5463,9 @@ public static void M0() options: TestOptions.DebugDll.WithSourceReferenceResolver( new SourceFileResolver(ImmutableArray.Empty, null, pathMap))); comp.VerifyEmitDiagnostics( + // C:\My\Machine\Specific\Path1\Program.cs(16,6): warning CS9270: 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) + // [InterceptsLocation(@"/_/Program.cs", 11, 9)] + Diagnostic(ErrorCode.WRN_InterceptsLocationAttributeUnsupportedSignature, @"InterceptsLocation(@""/_/Program.cs"", 11, 9)").WithLocation(16, 6), // C:\My\Machine\Specific\Path1\Program.cs(16,25): error CS9152: Cannot intercept a call in file with path '/_/Program.cs' because multiple files in the compilation have this path. // [InterceptsLocation(@"/_/Program.cs", 11, 9)] Diagnostic(ErrorCode.ERR_InterceptorNonUniquePath, @"@""/_/Program.cs""").WithArguments("/_/Program.cs").WithLocation(16, 25)); @@ -5046,7 +5500,10 @@ class C options: TestOptions.DebugExe.WithSourceReferenceResolver( new SourceFileResolver(ImmutableArray.Empty, null, pathMap)), expectedOutput: "1"); - verifier.VerifyDiagnostics(); + verifier.VerifyDiagnostics( + // C:\My\Machine\Specific\Path\Program.cs(11,6): warning CS9270: 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) + // [InterceptsLocation(@"\_\Program.cs", 5, 3)] + Diagnostic(ErrorCode.WRN_InterceptsLocationAttributeUnsupportedSignature, @"InterceptsLocation(@""\_\Program.cs"", 5, 3)").WithLocation(11, 6)); } [Fact] @@ -5077,15 +5534,18 @@ class C parseOptions: RegularWithInterceptors, options: TestOptions.DebugExe.WithSourceReferenceResolver( new SourceFileResolver(ImmutableArray.Empty, null, pathMap))); - comp.VerifyEmitDiagnostics( - PlatformInformation.IsWindows + comp.VerifyEmitDiagnostics([ + // C:\My\Machine\Specific\Path\Program.cs(11,6): warning CS9270: 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) + // [InterceptsLocation(@"/_/Program.cs", 5, 3)] + Diagnostic(ErrorCode.WRN_InterceptsLocationAttributeUnsupportedSignature, @"InterceptsLocation(@""/_/Program.cs"", 5, 3)").WithLocation(11, 6), + ..(ReadOnlySpan)[PlatformInformation.IsWindows // C:\My\Machine\Specific\Path\Program.cs(11,25): error CS9139: Cannot intercept: compilation does not contain a file with path 'C:\_\Program.cs'. // [InterceptsLocation(@"/_/Program.cs", 5, 3)] ? Diagnostic(ErrorCode.ERR_InterceptorPathNotInCompilation, @"@""/_/Program.cs""").WithArguments(PlatformInformation.IsWindows ? @"C:\_\Program.cs" : "/_/Program.cs").WithLocation(11, 25) // /My/Machine/Specific/Path/Program.cs(11,25): error CS9139: Cannot intercept: compilation does not contain a file with path '/_/Program.cs'. // [InterceptsLocation(@"/_/Program.cs", 5, 3)] - : Diagnostic(ErrorCode.ERR_InterceptorPathNotInCompilation, @"@""/_/Program.cs""").WithArguments("/_/Program.cs").WithLocation(11, 25)); + : Diagnostic(ErrorCode.ERR_InterceptorPathNotInCompilation, @"@""/_/Program.cs""").WithArguments("/_/Program.cs").WithLocation(11, 25)]]); } [Fact] @@ -5117,7 +5577,10 @@ class C options: TestOptions.DebugExe.WithSourceReferenceResolver( new SourceFileResolver(ImmutableArray.Empty, null, pathMap)), expectedOutput: "1"); - verifier.VerifyDiagnostics(); + verifier.VerifyDiagnostics( + // C:\My\Machine\Specific\Path\Program.cs(11,6): warning CS9270: 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) + // [InterceptsLocation(@"\_/Program.cs", 5, 3)] + Diagnostic(ErrorCode.WRN_InterceptsLocationAttributeUnsupportedSignature, @"InterceptsLocation(@""\_/Program.cs"", 5, 3)").WithLocation(11, 6)); } [Fact] @@ -5147,7 +5610,10 @@ public static void Main() new[] { (source, "src/Program.cs"), s_attributesSource }, parseOptions: RegularWithInterceptors, expectedOutput: "1"); - verifier.VerifyDiagnostics(); + verifier.VerifyDiagnostics( + // src/Program.cs(14,6): warning CS9270: 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) + // [InterceptsLocation("src/Program.cs", 9, 11)] + Diagnostic(ErrorCode.WRN_InterceptsLocationAttributeUnsupportedSignature, @"InterceptsLocation(""src/Program.cs"", 9, 11)").WithLocation(14, 6)); } [Fact] @@ -5177,7 +5643,10 @@ public static void Main() new[] { (source, @"src\Program.cs"), s_attributesSource }, parseOptions: RegularWithInterceptors, expectedOutput: "1"); - verifier.VerifyDiagnostics(); + verifier.VerifyDiagnostics( + // src\Program.cs(14,6): warning CS9270: 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) + // [InterceptsLocation(@"src\Program.cs", 9, 11)] + Diagnostic(ErrorCode.WRN_InterceptsLocationAttributeUnsupportedSignature, @"InterceptsLocation(@""src\Program.cs"", 9, 11)").WithLocation(14, 6)); } [Fact] @@ -5205,6 +5674,9 @@ public static void Main() var comp = CreateCompilation(new[] { (source, @"src\Program.cs"), s_attributesSource }, parseOptions: RegularWithInterceptors); comp.VerifyEmitDiagnostics( + // src\Program.cs(14,6): warning CS9270: 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) + // [InterceptsLocation(@"src/Program.cs", 9, 11)] + Diagnostic(ErrorCode.WRN_InterceptsLocationAttributeUnsupportedSignature, @"InterceptsLocation(@""src/Program.cs"", 9, 11)").WithLocation(14, 6), // src\Program.cs(14,25): error CS9140: Cannot intercept: compilation does not contain a file with path 'src/Program.cs'. Did you mean to use path 'src\Program.cs'? // [InterceptsLocation(@"src/Program.cs", 9, 11)] Diagnostic(ErrorCode.ERR_InterceptorPathNotInCompilationWithCandidate, @"@""src/Program.cs""").WithArguments("src/Program.cs", @"src\Program.cs").WithLocation(14, 25)); @@ -5235,12 +5707,18 @@ public static void Main() if (PlatformInformation.IsWindows) { var verifier = CompileAndVerify(new[] { (source, @"C:\src\Program.cs"), s_attributesSource }, parseOptions: RegularWithInterceptors, expectedOutput: "1"); - verifier.VerifyDiagnostics(); + verifier.VerifyDiagnostics( + // C:\src\Program.cs(14,6): warning CS9270: 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) + // [InterceptsLocation("C:/src/Program.cs", 9, 11)] + Diagnostic(ErrorCode.WRN_InterceptsLocationAttributeUnsupportedSignature, @"InterceptsLocation(""C:/src/Program.cs"", 9, 11)").WithLocation(14, 6)); } else { var comp = CreateCompilation(new[] { (source, @"/src/Program.cs"), s_attributesSource }, parseOptions: RegularWithInterceptors); comp.VerifyEmitDiagnostics( + // C:\src\Program.cs(14,6): warning CS9270: 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) + // [InterceptsLocation("C:/src/Program.cs", 9, 11)] + Diagnostic(ErrorCode.WRN_InterceptsLocationAttributeUnsupportedSignature, @"InterceptsLocation(""C:/src/Program.cs"", 9, 11)").WithLocation(14, 6), // /src/Program.cs(14,25): error CS9139: Cannot intercept: compilation does not contain a file with path '/src/C:/src/Program.cs'. // [InterceptsLocation("C:/src/Program.cs", 9, 11)] Diagnostic(ErrorCode.ERR_InterceptorPathNotInCompilation, @"""C:/src/Program.cs""").WithArguments("/src/C:/src/Program.cs").WithLocation(14, 25)); @@ -5273,12 +5751,18 @@ public static void Main() if (PlatformInformation.IsWindows) { var verifier = CompileAndVerify(new[] { (source, @"C:/src\Program.cs"), s_attributesSource }, parseOptions: RegularWithInterceptors, expectedOutput: "1"); - verifier.VerifyDiagnostics(); + verifier.VerifyDiagnostics( + // C:/src\Program.cs(14,6): warning CS9270: 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) + // [InterceptsLocation(@"C:\src/Program.cs", 9, 11)] + Diagnostic(ErrorCode.WRN_InterceptsLocationAttributeUnsupportedSignature, @"InterceptsLocation(@""C:\src/Program.cs"", 9, 11)").WithLocation(14, 6)); } else { - var comp = CreateCompilation(new[] { (source, @"/src/Program.cs"), s_attributesSource }, parseOptions: RegularWithInterceptors); + var comp = CreateCompilation(new[] { (source, @"/src/Program.`cs"), s_attributesSource }, parseOptions: RegularWithInterceptors); comp.VerifyEmitDiagnostics( + // C:/src\Program.cs(14,6): warning CS9270: 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) + // [InterceptsLocation(@"C:\src/Program.cs", 9, 11)] + Diagnostic(ErrorCode.WRN_InterceptsLocationAttributeUnsupportedSignature, @"InterceptsLocation(@""C:\src/Program.cs"", 9, 11)").WithLocation(14, 6), // /src/Program.cs(14,25): error CS9139: Cannot intercept: compilation does not contain a file with path '/src/C:\src/Program.cs'. // [InterceptsLocation(@"C:\src/Program.cs", 9, 11)] Diagnostic(ErrorCode.ERR_InterceptorPathNotInCompilation, @"@""C:\src/Program.cs""").WithArguments(@"/src/C:\src/Program.cs").WithLocation(14, 25)); @@ -5313,7 +5797,10 @@ static class Interceptors """; var verifier = CompileAndVerify(new[] { (source, PlatformInformation.IsWindows ? @"C:\src\Program.cs" : "/src/Program.cs"), (source2, PlatformInformation.IsWindows ? @"C:\obj\Generated.cs" : "/obj/Generated.cs"), s_attributesSource }, parseOptions: RegularWithInterceptors, expectedOutput: "1"); - verifier.VerifyDiagnostics(); + verifier.VerifyDiagnostics( + // C:\obj\Generated.cs(6,6): warning CS9270: 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) + // [InterceptsLocation("../src/Program.cs", 6, 11)] + Diagnostic(ErrorCode.WRN_InterceptsLocationAttributeUnsupportedSignature, @"InterceptsLocation(""../src/Program.cs"", 6, 11)").WithLocation(6, 6)); } [Fact] @@ -5347,6 +5834,9 @@ static class Interceptors var comp = CreateCompilation(new[] { (source, PlatformInformation.IsWindows ? @"C:\src\Program.cs" : "/src/Program.cs"), (source2, PlatformInformation.IsWindows ? @"Generator\Generated.cs" : "Generator/Generated.cs"), s_attributesSource }, parseOptions: RegularWithInterceptors); comp.VerifyEmitDiagnostics( + // Generator\Generated.cs(6,6): warning CS9270: 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) + // [InterceptsLocation("../src/Program.cs", 6, 11)] + Diagnostic(ErrorCode.WRN_InterceptsLocationAttributeUnsupportedSignature, @"InterceptsLocation(""../src/Program.cs"", 6, 11)").WithLocation(6, 6), // Generator\Generated.cs(6,25): error CS9139: Cannot intercept: compilation does not contain a file with path '../src/Program.cs'. // [InterceptsLocation("../src/Program.cs", 6, 11)] Diagnostic(ErrorCode.ERR_InterceptorPathNotInCompilation, @"""../src/Program.cs""").WithArguments("../src/Program.cs").WithLocation(6, 25)); @@ -5382,6 +5872,9 @@ static class Interceptors var comp = CreateCompilation(new[] { (source, PlatformInformation.IsWindows ? @"src\Program.cs" : "src/Program.cs"), (source2, PlatformInformation.IsWindows ? @"C:\obj\Generated.cs" : "/obj/Generated.cs"), s_attributesSource }, parseOptions: RegularWithInterceptors); comp.VerifyEmitDiagnostics( + // C:\obj\Generated.cs(6,6): warning CS9270: 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) + // [InterceptsLocation("../src/Program.cs", 6, 11)] + Diagnostic(ErrorCode.WRN_InterceptsLocationAttributeUnsupportedSignature, @"InterceptsLocation(""../src/Program.cs"", 6, 11)").WithLocation(6, 6), // C:\obj\Generated.cs(6,25): error CS9139: Cannot intercept: compilation does not contain a file with path 'C:\src\Program.cs'. // [InterceptsLocation("../src/Program.cs", 6, 11)] Diagnostic(ErrorCode.ERR_InterceptorPathNotInCompilation, @"""../src/Program.cs""").WithArguments(PlatformInformation.IsWindows ? @"C:\src\Program.cs" : "/src/Program.cs").WithLocation(6, 25) @@ -5417,7 +5910,10 @@ static class Interceptors """; var comp = CreateCompilation(new[] { (source, PlatformInformation.IsWindows ? @"C:\src\Program.cs" : "/src/Program.cs"), (source2, PlatformInformation.IsWindows ? @"C:\obj\Generated.cs" : "/obj/Generated.cs"), s_attributesSource }, parseOptions: RegularWithInterceptors); - comp.VerifyEmitDiagnostics(); + comp.VerifyEmitDiagnostics( + // C:\obj\Generated.cs(6,6): warning CS9270: 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) + // [InterceptsLocation("../../src/Program.cs", 6, 11)] + Diagnostic(ErrorCode.WRN_InterceptsLocationAttributeUnsupportedSignature, @"InterceptsLocation(""../../src/Program.cs"", 6, 11)").WithLocation(6, 6)); } [Fact] @@ -5448,7 +5944,10 @@ static class Interceptors """; var comp = CreateCompilation(new[] { (source, PlatformInformation.IsWindows ? @"C:\src\Program.cs" : "/src/Program.cs"), (source2, PlatformInformation.IsWindows ? @"C:\obj\Generated.cs" : "/obj/Generated.cs"), s_attributesSource }, parseOptions: RegularWithInterceptors); - comp.VerifyEmitDiagnostics(); + comp.VerifyEmitDiagnostics( + // C:\obj\Generated.cs(6,6): warning CS9270: 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) + // [InterceptsLocation("../src/./Program.cs", 6, 11)] + Diagnostic(ErrorCode.WRN_InterceptsLocationAttributeUnsupportedSignature, @"InterceptsLocation(""../src/./Program.cs"", 6, 11)").WithLocation(6, 6)); } [Fact] @@ -5479,7 +5978,10 @@ static class Interceptors """; var comp = CreateCompilation(new[] { (source, PlatformInformation.IsWindows ? @"C:\src\Program.cs" : "/src/Program.cs"), (source2, PlatformInformation.IsWindows ? @"C:\obj\Generated.cs" : "/obj/Generated.cs"), s_attributesSource }, parseOptions: RegularWithInterceptors); - comp.VerifyEmitDiagnostics(); + comp.VerifyEmitDiagnostics( + // C:\obj\Generated.cs(6,6): warning CS9270: 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) + // [InterceptsLocation("../src/Program.cs/.", 6, 11)] + Diagnostic(ErrorCode.WRN_InterceptsLocationAttributeUnsupportedSignature, @"InterceptsLocation(""../src/Program.cs/."", 6, 11)").WithLocation(6, 6)); } [Fact] @@ -5516,7 +6018,10 @@ static class Interceptors options: TestOptions.DebugExe.WithSourceReferenceResolver( new SourceFileResolver(ImmutableArray.Empty, null, pathMap)), expectedOutput: "1"); - verifier.VerifyDiagnostics(); + verifier.VerifyDiagnostics( + // C:\My\Machine\Specific\Path\obj/Generated.cs(6,6): warning CS9270: 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) + // [InterceptsLocation("../src/Program.cs", 2, 3)] + Diagnostic(ErrorCode.WRN_InterceptsLocationAttributeUnsupportedSignature, @"InterceptsLocation(""../src/Program.cs"", 2, 3)").WithLocation(6, 6)); } [Fact] @@ -5554,6 +6059,9 @@ static class Interceptors options: TestOptions.DebugExe.WithSourceReferenceResolver( new SourceFileResolver(ImmutableArray.Empty, null, pathMap))); comp.VerifyEmitDiagnostics( + // My\Machine\Specific\Path\obj/Generated.cs(6,6): warning CS9270: 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) + // [InterceptsLocation("../src/Program.cs", 2, 3)] + Diagnostic(ErrorCode.WRN_InterceptsLocationAttributeUnsupportedSignature, @"InterceptsLocation(""../src/Program.cs"", 2, 3)").WithLocation(6, 6), // My\Machine\Specific\Path\obj/Generated.cs(6,25): error CS9139: Cannot intercept: compilation does not contain a file with path '../src/Program.cs'. // [InterceptsLocation("../src/Program.cs", 2, 3)] Diagnostic(ErrorCode.ERR_InterceptorPathNotInCompilation, @"""../src/Program.cs""").WithArguments("../src/Program.cs").WithLocation(6, 25)); @@ -5611,6 +6119,9 @@ class Interceptors options: TestOptions.DebugExe.WithSourceReferenceResolver( new SourceFileResolver(ImmutableArray.Empty, null, pathMap))); comp.VerifyEmitDiagnostics( + // C:\src1\interceptors.cs(6,6): warning CS9270: 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) + // [InterceptsLocation("./file1.cs", 6, 15)] // 1 + Diagnostic(ErrorCode.WRN_InterceptsLocationAttributeUnsupportedSignature, @"InterceptsLocation(""./file1.cs"", 6, 15)").WithLocation(6, 6), // C:\src1\interceptors.cs(6,6): error CS9151: Possible method name 'Interceptable' cannot be intercepted because it is not being invoked. // [InterceptsLocation("./file1.cs", 6, 15)] // 1 Diagnostic(ErrorCode.ERR_InterceptorNameNotInvoked, @"InterceptsLocation(""./file1.cs"", 6, 15)").WithArguments("Interceptable").WithLocation(6, 6)); @@ -5621,37 +6132,41 @@ class Interceptors options: TestOptions.DebugExe.WithSourceReferenceResolver( new SourceFileResolver(ImmutableArray.Empty, null, pathMap)), expectedOutput: "1"); - verifier.VerifyDiagnostics(); + verifier.VerifyDiagnostics( + // C:\src1\interceptors.cs(6,6): warning CS9270: 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) + // [InterceptsLocation("./file1.cs", 6, 15)] // 1 + Diagnostic(ErrorCode.WRN_InterceptsLocationAttributeUnsupportedSignature, @"InterceptsLocation(""./file1.cs"", 6, 15)").WithLocation(6, 6)); } [Fact] public void InterceptorUnmanagedCallersOnly() { var source = """ - using System.Runtime.CompilerServices; - using System.Runtime.InteropServices; - using System; - C.Interceptable(); class C { public static void Interceptable() { } } + """; + var locations = GetInterceptableLocations(source); + var interceptors = $$""" + using System.Runtime.CompilerServices; + using System.Runtime.InteropServices; static class D { - [InterceptsLocation("Program.cs", 5, 3)] + [InterceptsLocation({{GetAttributeArgs(locations[0]!)}})] [UnmanagedCallersOnly] public static void Interceptor() { } } """; - var comp = CreateCompilation(new[] { (source, "Program.cs"), s_attributesSource, (UnmanagedCallersOnlyAttributeDefinition, "UnmanagedCallersOnlyAttribute.cs") }, parseOptions: RegularWithInterceptors); + var comp = CreateCompilation([source, interceptors, s_attributesSource, UnmanagedCallersOnlyAttributeDefinition], parseOptions: RegularWithInterceptors); comp.VerifyEmitDiagnostics( - // Program.cs(14,6): error CS9161: An interceptor cannot be marked with 'UnmanagedCallersOnlyAttribute'. - // [InterceptsLocation("Program.cs", 5, 3)] - Diagnostic(ErrorCode.ERR_InterceptorCannotUseUnmanagedCallersOnly, @"InterceptsLocation(""Program.cs"", 5, 3)").WithLocation(14, 6)); + // (6,6): error CS9161: An interceptor cannot be marked with 'UnmanagedCallersOnlyAttribute'. + // [InterceptsLocation(1, "5P8UiY8bLUVHhLVapnhynAIAAAA=")] + Diagnostic(ErrorCode.ERR_InterceptorCannotUseUnmanagedCallersOnly, "InterceptsLocation").WithLocation(6, 6)); } [Fact] @@ -5708,15 +6223,15 @@ public enum MyEnum Second, } """, "Program.cs"); - - var interceptor = (""" + var locations = GetInterceptableLocations(program); + var interceptor = ($$""" using System.Runtime.CompilerServices; namespace MyInterceptors { public static class Interceptors { - [InterceptsLocation(@"Program.cs", 4, 25)] + [InterceptsLocation({{GetAttributeArgs(locations[1]!)}})] public static string OtherToString(this System.Enum value) => "Wrong Value" + value; } @@ -5766,15 +6281,15 @@ public void InterceptorStructBaseMethod() public struct MyStruct { } """, "Program.cs"); - - var interceptor = (""" + var locations = GetInterceptableLocations(program); + var interceptor = ($$""" using System.Runtime.CompilerServices; namespace MyInterceptors { public static class Interceptors { - [InterceptsLocation(@"Program.cs", 4, 25)] + [InterceptsLocation({{GetAttributeArgs(locations[1]!)}})] public static bool Equals(this System.ValueType value, object other) => true; } } @@ -5834,20 +6349,23 @@ void M(T value) public struct MyStruct { } """, "Program.cs"); - var interceptor = (""" + var locations = GetInterceptableLocations(program); + var location = locations[2]!; + + var interceptor = ($$""" using System.Runtime.CompilerServices; namespace MyInterceptors { public static class Interceptors { - [InterceptsLocation(@"Program.cs", 6, 29)] + [InterceptsLocation({{GetAttributeArgs(location)}})] public static new bool Equals(this object value, object other) => true; } } """, "Interceptor.cs"); - var verifier = CompileAndVerify(new[] { program, s_attributesSource }, parseOptions: RegularWithInterceptors, expectedOutput: "False"); + var verifier = CompileAndVerify([program, s_attributesSource], parseOptions: RegularWithInterceptors, expectedOutput: "False"); verifier.VerifyDiagnostics(); verifier.VerifyIL("Program.<
$>g__M|0_0(T)", """ { @@ -5863,7 +6381,7 @@ .maxstack 2 } """); - verifier = CompileAndVerify(new[] { program, interceptor, s_attributesSource }, parseOptions: RegularWithInterceptors, expectedOutput: "True"); + verifier = CompileAndVerify([program, interceptor, s_attributesSource], parseOptions: RegularWithInterceptors, expectedOutput: "True"); verifier.VerifyDiagnostics(); verifier.VerifyIL("Program.<
$>g__M|0_0(T)", """ { @@ -5912,8 +6430,8 @@ public interface I void IM(); } """, "Program.cs"); - - var interceptor = (""" + var locations = GetInterceptableLocations(program); + var interceptor = ($$""" using System.Runtime.CompilerServices; using System; @@ -5921,7 +6439,7 @@ namespace MyInterceptors { public static class Interceptors { - [InterceptsLocation(@"Program.cs", 9, 11)] + [InterceptsLocation({{GetAttributeArgs(locations[1]!)}})] public static void IM(this I @this) { Console.Write("Interceptor"); } } } @@ -5977,14 +6495,14 @@ public static void Main() } } """, "Program.cs"); - - var interceptor = (""" + var locations = GetInterceptableLocations(source); + var interceptor = ($$""" #nullable enable using System.Runtime.CompilerServices; static class D { - [InterceptsLocation("Program.cs", 16, 25)] + [InterceptsLocation({{GetAttributeArgs(locations[1]!)}})] public static string Generic(this C s, T arg) => "Interceptor"; } """, "Interceptor.cs"); @@ -6019,14 +6537,14 @@ public static void Main() } } """, "Program.cs"); - - var interceptor = (""" + var locations = GetInterceptableLocations(source); + var interceptor = ($$""" #nullable enable using System.Runtime.CompilerServices; static class D { - [InterceptsLocation("Program.cs", 16, 25)] + [InterceptsLocation({{GetAttributeArgs(locations[1]!)}})] public static string Generic(this C s, U arg) => "Interceptor"; } """, "Interceptor.cs"); @@ -6060,14 +6578,14 @@ public static void Main() } } """, "Program.cs"); - - var interceptor = (""" + var locations = GetInterceptableLocations(source); + var interceptor = ($$""" #nullable enable using System.Runtime.CompilerServices; static class D { - [InterceptsLocation("Program.cs", 15, 11)] + [InterceptsLocation({{GetAttributeArgs(locations[0]!)}})] public static string? Generic(this T s, U arg) => arg?.ToString(); } """, "Interceptor.cs"); @@ -6078,8 +6596,9 @@ static class D comp = CreateCompilation(new[] { source, interceptor, s_attributesSource }, parseOptions: RegularWithInterceptors); comp.VerifyEmitDiagnostics( // Interceptor.cs(6,6): error CS9144: Cannot intercept method 'C.Method1(string)' with interceptor 'D.Generic(int, string)' because the signatures do not match. - // [InterceptsLocation("Program.cs", 15, 11)] - Diagnostic(ErrorCode.ERR_InterceptorSignatureMismatch, @"InterceptsLocation(""Program.cs"", 15, 11)").WithArguments("C.Method1(string)", "D.Generic(int, string)").WithLocation(6, 6)); + // [InterceptsLocation(1, "F9njcAIQ5lvPC9SOXWAkgtwAAABQcm9ncmFtLmNz")] + Diagnostic(ErrorCode.ERR_InterceptorSignatureMismatch, "InterceptsLocation").WithArguments("C.Method1(string)", "D.Generic(int, string)").WithLocation(6, 6) + ); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/70311")] @@ -6106,13 +6625,14 @@ public static void Main() } """, "Program.cs"); - var interceptor = (""" + var locations = GetInterceptableLocations(source); + var interceptor = ($$""" #nullable enable using System.Runtime.CompilerServices; static class D { - [InterceptsLocation("Program.cs", 15, 11)] + [InterceptsLocation({{GetAttributeArgs(locations[0]!)}})] public static string? Generic(this C s, U arg) where T : struct => arg?.ToString(); } """, "Interceptor.cs"); @@ -6147,14 +6667,14 @@ public static void Main() } } """, "Program.cs"); - - var interceptor = (""" + var locations = GetInterceptableLocations(source); + var interceptor = ($$""" #nullable enable using System.Runtime.CompilerServices; static class D { - [InterceptsLocation("Program.cs", 15, 11)] + [InterceptsLocation({{GetAttributeArgs(locations[0]!)}})] public static string? Generic(this C s, U arg) where T : class => arg?.ToString(); } """, "Interceptor.cs"); @@ -6165,8 +6685,8 @@ static class D comp = CreateCompilation(new[] { source, interceptor, s_attributesSource }, parseOptions: RegularWithInterceptors); comp.VerifyEmitDiagnostics( // Interceptor.cs(6,6): error CS0452: The type 'int' must be a reference type in order to use it as parameter 'T' in the generic type or method 'D.Generic(C, U)' - // [InterceptsLocation("Program.cs", 15, 11)] - Diagnostic(ErrorCode.ERR_RefConstraintNotSatisfied, @"InterceptsLocation(""Program.cs"", 15, 11)").WithArguments("D.Generic(C, U)", "T", "int").WithLocation(6, 6)); + // [InterceptsLocation(1, "F9njcAIQ5lvPC9SOXWAkgtwAAABQcm9ncmFtLmNz")] + Diagnostic(ErrorCode.ERR_RefConstraintNotSatisfied, "InterceptsLocation").WithArguments("D.Generic(C, U)", "T", "int").WithLocation(6, 6)); } [Theory] @@ -6181,14 +6701,14 @@ class C public static void M() => throw null; } """, "Program.cs"); - - var interceptorSource = (""" + var locations = GetInterceptableLocations(source); + var interceptorSource = ($$""" using System; using System.Runtime.CompilerServices; static class D { - [InterceptsLocation("Program.cs", 1, 3)] + [InterceptsLocation({{GetAttributeArgs(locations[0]!)}})] public static void Interceptor() => Console.Write(1); } """, "Interceptor.cs"); @@ -6230,14 +6750,14 @@ class C public static void M(T t) => throw null; } """, "Program.cs"); - - var interceptorSource = (""" + var locations = GetInterceptableLocations(source); + var interceptorSource = ($$""" using System; using System.Runtime.CompilerServices; static class D { - [InterceptsLocation("Program.cs", 1, 3)] + [InterceptsLocation({{GetAttributeArgs(locations[0]!)}})] public static void Interceptor(T t) => Console.Write(t); } """, "Interceptor.cs"); @@ -6279,8 +6799,8 @@ class C public static void M() => throw null; } """, "Program.cs"); - - var interceptorSource = (""" + var locations = GetInterceptableLocations(source); + var interceptorSource = ($$""" using System; using System.Runtime.CompilerServices; @@ -6288,7 +6808,7 @@ namespace Interceptors { static class D { - [InterceptsLocation("Program.cs", 1, 3)] + [InterceptsLocation({{GetAttributeArgs(locations[0]!)}})] public static void Interceptor() => Console.Write(1); } } @@ -6333,7 +6853,9 @@ class C } """, "Program.cs"); - var interceptorSource = (""" + var location = GetInterceptableLocations(source)[0]!; + + var interceptorSource = ($$""" using System; using System.Runtime.CompilerServices; @@ -6341,7 +6863,7 @@ namespace NotInterceptors { static class D { - [InterceptsLocation("Program.cs", 1, 3)] + [InterceptsLocation({{GetAttributeArgs(location)}})] public static void Interceptor() => Console.Write(1); } } @@ -6358,9 +6880,9 @@ static class D Assert.Null(interceptor); comp.VerifyEmitDiagnostics( - // Interceptor.cs(8,10): error CS9137: The 'interceptors' experimental feature is not enabled in this namespace. Add '$(InterceptorsNamespaces);NotInterceptors' to your project. - // [InterceptsLocation("Program.cs", 1, 3)] - Diagnostic(ErrorCode.ERR_InterceptorsFeatureNotEnabled, @"InterceptsLocation(""Program.cs"", 1, 3)").WithArguments("$(InterceptorsNamespaces);NotInterceptors").WithLocation(8, 10)); + // Interceptor.cs(8,10): error CS9137: The 'interceptors' feature is not enabled in this namespace. Add '$(InterceptorsNamespaces);NotInterceptors' to your project. + // [InterceptsLocation(1, "NnwjYrJAcjZ/s0+OSiPXqwIAAABQcm9ncmFtLmNz")] + Diagnostic(ErrorCode.ERR_InterceptorsFeatureNotEnabled, "InterceptsLocation").WithArguments("$(InterceptorsNamespaces);NotInterceptors").WithLocation(8, 10)); interceptor = model.GetInterceptorMethod(call); Assert.Null(interceptor); @@ -6377,8 +6899,8 @@ class C public static void M() => throw null; } """, "Program.cs"); - - var interceptorSource = (""" + var locations = GetInterceptableLocations(source); + var interceptorSource = ($$""" using System; using System.Runtime.CompilerServices; @@ -6386,7 +6908,7 @@ namespace Interceptors { class D { - [InterceptsLocation("Program.cs", 1, 3)] + [InterceptsLocation({{GetAttributeArgs(locations[0]!)}})] public static void Interceptor() => Console.Write(1); } @@ -6431,8 +6953,8 @@ class C public static void M() => throw null; } """, "Program.cs"); - - var interceptorSource = (""" + var location = GetInterceptableLocations(source)[0]!; + var interceptorSource = ($$""" using System; using System.Runtime.CompilerServices; @@ -6440,10 +6962,10 @@ namespace Interceptors { static class D { - [InterceptsLocation("Program.cs", 1, 3)] + [InterceptsLocation({{GetAttributeArgs(location)}})] public static void Interceptor1(int i) => Console.Write(i); - [InterceptsLocation("Program.cs", 1, 3)] + [InterceptsLocation({{GetAttributeArgs(location)}})] public static void Interceptor2() => Console.Write(2); } } @@ -6460,11 +6982,11 @@ static class D comp.VerifyEmitDiagnostics( // Interceptor.cs(8,10): error CS9153: The indicated call is intercepted multiple times. - // [InterceptsLocation("Program.cs", 1, 3)] - Diagnostic(ErrorCode.ERR_DuplicateInterceptor, @"InterceptsLocation(""Program.cs"", 1, 3)").WithLocation(8, 10), + // [InterceptsLocation(1, "NnwjYrJAcjZ/s0+OSiPXqwIAAABQcm9ncmFtLmNz")] + Diagnostic(ErrorCode.ERR_DuplicateInterceptor, "InterceptsLocation").WithLocation(8, 10), // Interceptor.cs(11,10): error CS9153: The indicated call is intercepted multiple times. - // [InterceptsLocation("Program.cs", 1, 3)] - Diagnostic(ErrorCode.ERR_DuplicateInterceptor, @"InterceptsLocation(""Program.cs"", 1, 3)").WithLocation(11, 10)); + // [InterceptsLocation(1, "NnwjYrJAcjZ/s0+OSiPXqwIAAABQcm9ncmFtLmNz")] + Diagnostic(ErrorCode.ERR_DuplicateInterceptor, "InterceptsLocation").WithLocation(11, 10)); interceptor = model.GetInterceptorMethod(call); Assert.Null(interceptor); @@ -6481,8 +7003,8 @@ class C public static void M() => throw null; } """, "Program.cs"); - - var interceptorSource = (""" + var locations = GetInterceptableLocations(source); + var interceptorSource = ($$""" using System; using System.Runtime.CompilerServices; @@ -6490,16 +7012,16 @@ namespace Interceptors { static class D { - [InterceptsLocation("Program.cs", 1, 3)] + [InterceptsLocation({{GetAttributeArgs(locations[0]!)}})] public static void Interceptor1() => Console.Write(1); } } - + namespace NotInterceptors { static class D { - [InterceptsLocation("Program.cs", 1, 3)] + [InterceptsLocation({{GetAttributeArgs(locations[0]!)}})] public static void Interceptor2() => Console.Write(2); } } @@ -6515,9 +7037,9 @@ static class D Assert.Equal("void Interceptors.D.Interceptor1()", interceptor.ToTestDisplayString()); comp.VerifyEmitDiagnostics( - // Interceptor.cs(17,10): error CS9137: The 'interceptors' experimental feature is not enabled in this namespace. Add '$(InterceptorsNamespaces);NotInterceptors' to your project. - // [InterceptsLocation("Program.cs", 1, 3)] - Diagnostic(ErrorCode.ERR_InterceptorsFeatureNotEnabled, @"InterceptsLocation(""Program.cs"", 1, 3)").WithArguments("$(InterceptorsNamespaces);NotInterceptors").WithLocation(17, 10)); + // Interceptor.cs(17,10): error CS9137: The 'interceptors' feature is not enabled in this namespace. Add '$(InterceptorsNamespaces);NotInterceptors' to your project. + // [InterceptsLocation(1, "NnwjYrJAcjZ/s0+OSiPXqwIAAABQcm9ncmFtLmNz")] + Diagnostic(ErrorCode.ERR_InterceptorsFeatureNotEnabled, "InterceptsLocation").WithArguments("$(InterceptorsNamespaces);NotInterceptors").WithLocation(17, 10)); interceptor = model.GetInterceptorMethod(call); Assert.Equal("void Interceptors.D.Interceptor1()", interceptor.ToTestDisplayString()); @@ -6535,8 +7057,8 @@ class C public static void M() => throw null; } """, "Program.cs"); - - var interceptorSource = (""" + var locations = GetInterceptableLocations(source); + var interceptorSource = ($$""" using System; using System.Runtime.CompilerServices; @@ -6546,7 +7068,7 @@ static class Outer { public static class D { - [InterceptsLocation("Program.cs", 1, 3)] + [InterceptsLocation({{GetAttributeArgs(locations[0]!)}})] public static void Interceptor1() => Console.Write(1); } } @@ -6582,7 +7104,8 @@ class C } """, "Program.cs"); - var interceptorSource = (""" + var location = GetInterceptableLocations(source)[0]!; + var interceptorSource = ($$""" using System; using System.Runtime.CompilerServices; @@ -6592,7 +7115,7 @@ static class Outer { public static class D { - [InterceptsLocation("Program.cs", 1, 3)] + [InterceptsLocation({{GetAttributeArgs(location)}})] public static void Interceptor1() => Console.Write(1); } } @@ -6607,9 +7130,9 @@ public static class D Assert.Null(model.GetInterceptorMethod(call)); comp.VerifyEmitDiagnostics( - // Interceptor.cs(10,14): error CS9137: The 'interceptors' experimental feature is not enabled in this namespace. Add '$(InterceptorsNamespaces);Interceptors' to your project. - // [InterceptsLocation("Program.cs", 1, 3)] - Diagnostic(ErrorCode.ERR_InterceptorsFeatureNotEnabled, @"InterceptsLocation(""Program.cs"", 1, 3)").WithArguments("$(InterceptorsNamespaces);Interceptors").WithLocation(10, 14)); + // Interceptor.cs(10,14): error CS9137: The 'interceptors' feature is not enabled in this namespace. Add '$(InterceptorsNamespaces);Interceptors' to your project. + // [InterceptsLocation(1, "NnwjYrJAcjZ/s0+OSiPXqwIAAABQcm9ncmFtLmNz")] + Diagnostic(ErrorCode.ERR_InterceptorsFeatureNotEnabled, "InterceptsLocation").WithArguments("$(InterceptorsNamespaces);Interceptors").WithLocation(10, 14)); Assert.Null(model.GetInterceptorMethod(call)); } @@ -6625,8 +7148,8 @@ class C public static void M() => throw null; } """, "Program.cs"); - - var interceptorSource = (""" + var locations = GetInterceptableLocations(source); + var interceptorSource = ($$""" using System; using System.Runtime.CompilerServices; @@ -6636,7 +7159,7 @@ static class Outer { public static class D { - [InterceptsLocation("Program.cs", 1, 3)] + [InterceptsLocation({{GetAttributeArgs(locations[0]!)}})] public static void Interceptor1() => Console.Write(1); } } @@ -6712,8 +7235,8 @@ class C public static void M() => throw null; } """, "Program.cs"); - - var interceptorSource = (""" + var locations = GetInterceptableLocations(source); + var interceptorSource = ($$""" using System; using System.Runtime.CompilerServices; @@ -6723,7 +7246,7 @@ namespace Nested { public static class D { - [InterceptsLocation("Program.cs", 1, 3)] + [InterceptsLocation({{GetAttributeArgs(locations[0]!)}})] public static void Interceptor1() => Console.Write(1); } } @@ -6758,7 +7281,8 @@ class C } """, "Program.cs"); - var interceptorSource = (""" + var locations = GetInterceptableLocations(source); + var interceptorSource = ($$""" using System; using System.Runtime.CompilerServices; @@ -6766,13 +7290,13 @@ namespace Interceptors { public static class D { - [InterceptsLocation("Program.cs", 1, 3)] + [InterceptsLocation({{GetAttributeArgs(locations[0]!)}})] public static void Interceptor1() => Console.Write(1); } } """, "Interceptor.cs"); - var comp = CreateCompilation(new[] { source, interceptorSource, s_attributesSource }, parseOptions: TestOptions.Regular.WithFeature("InterceptorsNamespaces", "Interceptors.Nested")); + var comp = CreateCompilation([source, interceptorSource, s_attributesSource], parseOptions: TestOptions.Regular.WithFeature("InterceptorsNamespaces", "Interceptors.Nested")); var tree = comp.SyntaxTrees[0]; var model = comp.GetSemanticModel(tree); @@ -6781,9 +7305,9 @@ public static class D Assert.Null(model.GetInterceptorMethod(call)); comp.VerifyEmitDiagnostics( - // Interceptor.cs(8,10): error CS9137: The 'interceptors' experimental feature is not enabled in this namespace. Add '$(InterceptorsNamespaces);Interceptors' to your project. - // [InterceptsLocation("Program.cs", 1, 3)] - Diagnostic(ErrorCode.ERR_InterceptorsFeatureNotEnabled, @"InterceptsLocation(""Program.cs"", 1, 3)").WithArguments("$(InterceptorsNamespaces);Interceptors").WithLocation(8, 10)); + // Interceptor.cs(8,10): error CS9137: The 'interceptors' feature is not enabled in this namespace. Add '$(InterceptorsNamespaces);Interceptors' to your project. + // [InterceptsLocation(1, "NnwjYrJAcjZ/s0+OSiPXqwIAAABQcm9ncmFtLmNz")] + Diagnostic(ErrorCode.ERR_InterceptorsFeatureNotEnabled, "InterceptsLocation").WithArguments("$(InterceptorsNamespaces);Interceptors").WithLocation(8, 10)); Assert.Null(model.GetInterceptorMethod(call)); } @@ -6876,7 +7400,7 @@ static void Main() Assert.Equal(locationSpecifier.GetHashCode(), model.GetInterceptableLocation(node)!.GetHashCode()); // If Data changes it might be the case that 'SourceText.GetContentHash()' has changed algorithms. - // In this case we need to adjust the SourceMethodSymbolWithAttributes.DecodeInterceptsLocationAttribute impl to remain compatible with v1 and consider introducing a v2 which uses the new content hash algorithm. + // In this case we need to adjust the SourceMethodSymbol.DecodeInterceptsLocationAttribute impl to remain compatible with v1 and consider introducing a v2 which uses the new content hash algorithm. AssertEx.Equal("xRCCFCvTOZMORzSr/fZQFlIAAABQcm9ncmFtLmNz", locationSpecifier.Data); AssertEx.Equal("""[global::System.Runtime.CompilerServices.InterceptsLocationAttribute(1, "xRCCFCvTOZMORzSr/fZQFlIAAABQcm9ncmFtLmNz")]""", locationSpecifier.GetInterceptsLocationAttributeSyntax()); diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/IteratorTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/IteratorTests.cs index 170096bd82075..379986f86a708 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/IteratorTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/IteratorTests.cs @@ -661,5 +661,89 @@ public IEnumerator> GetEnumerator(KeyValuePair..ctor(TKey key, TValue value)", symbolInfo.CandidateSymbols.Select(c => c.ToTestDisplayString())); Assert.Equal(CandidateReason.OverloadResolutionFailure, symbolInfo.CandidateReason); } + + [Fact] + public void CompilerLoweringPreserveAttribute_01() + { + string source1 = @" +using System; +using System.Runtime.CompilerServices; + +[CompilerLoweringPreserve] +[AttributeUsage(AttributeTargets.GenericParameter)] +public class Preserve1Attribute : Attribute { } + +[AttributeUsage(AttributeTargets.GenericParameter)] +public class Preserve2Attribute : Attribute { } +"; + + string source2 = @" +using System.Collections.Generic; + +class Test1 +{ + IEnumerable M2<[Preserve1][Preserve2]T>(T x) + { + yield return x; + } +} +"; + var comp1 = CreateCompilation([source1, source2, CompilerLoweringPreserveAttributeDefinition]); + CompileAndVerify(comp1, symbolValidator: validate).VerifyDiagnostics(); + + static void validate(ModuleSymbol m) + { + AssertEx.SequenceEqual( + ["Preserve1Attribute"], + m.GlobalNamespace.GetMember("Test1.d__0").TypeParameters.Single().GetAttributes().Select(a => a.ToString())); + } + } + + [Fact] + public void CompilerLoweringPreserveAttribute_02() + { + string source1 = @" +using System; +using System.Runtime.CompilerServices; + +[CompilerLoweringPreserve] +[AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter)] +public class Preserve1Attribute : Attribute { } + +[CompilerLoweringPreserve] +[AttributeUsage(AttributeTargets.Parameter)] +public class Preserve2Attribute : Attribute { } + +[AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter)] +public class Preserve3Attribute : Attribute { } +"; + + string source2 = @" +using System.Collections.Generic; + +class Test1 +{ + IEnumerable M2([Preserve1][Preserve2][Preserve3]int x) + { + yield return x; + } +} +"; + var comp1 = CreateCompilation( + [source1, source2, CompilerLoweringPreserveAttributeDefinition], + options: TestOptions.DebugDll.WithMetadataImportOptions(MetadataImportOptions.All)); + CompileAndVerify(comp1, symbolValidator: validate).VerifyDiagnostics(); + + static void validate(ModuleSymbol m) + { + AssertEx.SequenceEqual( + ["Preserve1Attribute"], + m.GlobalNamespace.GetMember("Test1.d__0.x").GetAttributes().Select(a => a.ToString())); + + AssertEx.SequenceEqual( + ["Preserve1Attribute"], + m.GlobalNamespace.GetMember("Test1.d__0.<>3__x").GetAttributes().Select(a => a.ToString())); + } + } } } diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/LambdaTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/LambdaTests.cs index fd8620a66a1e8..eb2b674266f78 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/LambdaTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/LambdaTests.cs @@ -8553,5 +8553,81 @@ public void ParamsArray_ThisModifier_02() // var lam = (params this int[] xs) => xs.Length; Diagnostic(ErrorCode.ERR_ThisInBadContext, "this").WithLocation(1, 19)); } + + [Fact] + public void CompilerLoweringPreserveAttribute_01() + { + string source1 = @" +using System; +using System.Runtime.CompilerServices; + +[CompilerLoweringPreserve] +[AttributeUsage(AttributeTargets.GenericParameter)] +public class Preserve1Attribute : Attribute { } + +[AttributeUsage(AttributeTargets.GenericParameter)] +public class Preserve2Attribute : Attribute { } +"; + + string source2 = @" +class Test1 +{ + System.Func M2<[Preserve1][Preserve2]T>(T x) + { + return () => x; + } +} +"; + var comp1 = CreateCompilation([source1, source2, CompilerLoweringPreserveAttributeDefinition]); + CompileAndVerify(comp1, symbolValidator: validate).VerifyDiagnostics(); + + static void validate(ModuleSymbol m) + { + AssertEx.SequenceEqual( + ["Preserve1Attribute"], + m.GlobalNamespace.GetMember("Test1.<>c__DisplayClass0_0").TypeParameters.Single().GetAttributes().Select(a => a.ToString())); + } + } + + [Fact] + public void CompilerLoweringPreserveAttribute_02() + { + string source1 = @" +using System; +using System.Runtime.CompilerServices; + +[CompilerLoweringPreserve] +[AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter)] +public class Preserve1Attribute : Attribute { } + +[CompilerLoweringPreserve] +[AttributeUsage(AttributeTargets.Parameter)] +public class Preserve2Attribute : Attribute { } + +[AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter)] +public class Preserve3Attribute : Attribute { } +"; + + string source2 = @" +class Test1 +{ + System.Func M2([Preserve1][Preserve2][Preserve3]int x) + { + return () => x; + } +} +"; + var comp1 = CreateCompilation( + [source1, source2, CompilerLoweringPreserveAttributeDefinition], + options: TestOptions.DebugDll.WithMetadataImportOptions(MetadataImportOptions.All)); + CompileAndVerify(comp1, symbolValidator: validate).VerifyDiagnostics(); + + static void validate(ModuleSymbol m) + { + AssertEx.SequenceEqual( + ["Preserve1Attribute"], + m.GlobalNamespace.GetMember("Test1.<>c__DisplayClass0_0.x").GetAttributes().Select(a => a.ToString())); + } + } } } diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/NullableReferenceTypesTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/NullableReferenceTypesTests.cs index 3a4c805f23882..7315a2e033e0d 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/NullableReferenceTypesTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/NullableReferenceTypesTests.cs @@ -9439,7 +9439,7 @@ namespace Microsoft.CodeAnalysis { [Embedded] [System.Obsolete(""obsolete"")] - class EmbeddedAttribute : System.Attribute + internal sealed class EmbeddedAttribute : System.Attribute { public EmbeddedAttribute() { } } diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/RefEscapingTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/RefEscapingTests.cs index c0c092edba74b..79326aa71c089 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/RefEscapingTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/RefEscapingTests.cs @@ -4192,6 +4192,70 @@ static void Test() ); } + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/76277")] + public void ObjectInitializer_ImplicitIndexerAccess_Span() + { + var source = """ + using System; + + class Program + { + static void M(ref S s) + { + s = new S() + { + F = + { + [^1] = 5, + }, + }; + } + } + + ref struct S + { + public Span F; + } + """; + CreateCompilationWithIndexAndRangeAndSpan(source).VerifyDiagnostics(); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/76277")] + public void ObjectInitializer_ImplicitIndexerAccess_CustomRefStruct() + { + var source = """ + class Program + { + static void M(ref S s) + { + s = new S() + { + F = + { + [^1] = 5, + }, + }; + } + } + + ref struct S + { + public R F; + } + + ref struct R + { + public int Count => 0; + public int this[int index] + { + get => 0; + set { } + } + } + """; + CreateCompilationWithIndex(source).VerifyDiagnostics(); + } + [Theory] [InlineData(LanguageVersion.CSharp10)] [InlineData(LanguageVersion.CSharp11)] @@ -4899,7 +4963,10 @@ public void TryGet2(out Span result) Diagnostic(ErrorCode.ERR_CallArgMixing, "new SW().TryGet(out value1)").WithArguments("SW.TryGet(out System.Span)", "result").WithLocation(14, 13), // (14,33): error CS8352: Cannot use variable 'value1' in this context because it may expose referenced variables outside of their declaration scope // new SW().TryGet(out value1); - Diagnostic(ErrorCode.ERR_EscapeVariable, "value1").WithArguments("value1").WithLocation(14, 33) + Diagnostic(ErrorCode.ERR_EscapeVariable, "value1").WithArguments("value1").WithLocation(14, 33), + // (37,10): warning CS9269: UnscopedRefAttribute is only valid in C# 11 or later or when targeting net7.0 or later. + // [UnscopedRef] + Diagnostic(ErrorCode.WRN_UnscopedRefAttributeOldRules, "UnscopedRef").WithLocation(37, 10) ); } @@ -5982,6 +6049,459 @@ public static class Extensions Diagnostic(ErrorCode.ERR_EscapeVariable, "local2").WithArguments("local2").WithLocation(11, 18)); } + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75484")] + public void Deconstruction_UnscopedRef() + { + var source = """ + using System.Diagnostics.CodeAnalysis; + class C + { + R M1() + { + new S().Deconstruct(out var x, out _); + return x; // 1 + } + R M2() + { + (var x, _) = new S(); + return x; // 2 + } + R M3() + { + if (new S() is (var x, _)) + return x; // 3 + return default; + } + } + struct S + { + [UnscopedRef] public void Deconstruct(out R x, out int y) => throw null; + } + ref struct R { } + """; + CreateCompilation([source, UnscopedRefAttributeDefinition]).VerifyDiagnostics( + // (7,16): error CS8352: Cannot use variable 'x' in this context because it may expose referenced variables outside of their declaration scope + // return x; // 1 + Diagnostic(ErrorCode.ERR_EscapeVariable, "x").WithArguments("x").WithLocation(7, 16), + // (12,16): error CS8352: Cannot use variable 'x' in this context because it may expose referenced variables outside of their declaration scope + // return x; // 2 + Diagnostic(ErrorCode.ERR_EscapeVariable, "x").WithArguments("x").WithLocation(12, 16), + // (17,20): error CS8352: Cannot use variable 'x' in this context because it may expose referenced variables outside of their declaration scope + // return x; // 3 + Diagnostic(ErrorCode.ERR_EscapeVariable, "x").WithArguments("x").WithLocation(17, 20)); + + // Old ref safety rules mean the [UnscopedRef] has no effect, so the Deconstruct receiver is scoped. + CreateCompilation([source, UnscopedRefAttributeDefinition], parseOptions: TestOptions.Regular10).VerifyDiagnostics( + // (23,6): warning CS9269: UnscopedRefAttribute is only valid in C# 11 or later or when targeting net7.0 or later. + // [UnscopedRef] public void Deconstruct(out R x, out int y) => throw null; + Diagnostic(ErrorCode.WRN_UnscopedRefAttributeOldRules, "UnscopedRef").WithLocation(23, 6)); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75484")] + public void Deconstruction_UnscopedRef_ReturnInt() + { + var source = """ + using System.Diagnostics.CodeAnalysis; + class C + { + int M1() + { + new S().Deconstruct(out var x, out var y); + return y; // 1 + } + int M2() + { + (var x, var y) = new S(); + return y; // 2 + } + int M3() + { + if (new S() is (var x, var y)) + return y; // 3 + return default; + } + } + struct S + { + [UnscopedRef] public void Deconstruct(out R x, out int y) => throw null; + } + ref struct R; + """; + CreateCompilation([source, UnscopedRefAttributeDefinition]).VerifyDiagnostics(); + } + + [Fact] + public void Deconstruction_ScopedRef() + { + var source = """ + class C + { + R M1() + { + new S().Deconstruct(out var x, out _); + return x; + } + R M2() + { + (var x, _) = new S(); + return x; + } + R M3() + { + if (new S() is (var x, _)) + return x; + return default; + } + } + struct S + { + public void Deconstruct(out R x, out int y) => throw null; + } + ref struct R { } + """; + CreateCompilation(source).VerifyDiagnostics(); + CreateCompilation(source, parseOptions: TestOptions.Regular10).VerifyDiagnostics(); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75484")] + public void Deconstruction_UnscopedRef_ExtensionMethod() + { + var source = """ + class C + { + R M1() + { + new S().Deconstruct(out var x, out _); + return x; // 1 + } + R M2() + { + (var x, _) = new S(); + return x; // 2 + } + R M3() + { + if (new S() is (var x, _)) + return x; // 3 + return default; + } + } + struct S; + ref struct R; + static class E + { + public static void Deconstruct(this in S s, out R x, out int y) => throw null; + } + """; + CreateCompilation(source).VerifyDiagnostics( + // (6,16): error CS8352: Cannot use variable 'x' in this context because it may expose referenced variables outside of their declaration scope + // return x; // 1 + Diagnostic(ErrorCode.ERR_EscapeVariable, "x").WithArguments("x").WithLocation(6, 16), + // (11,16): error CS8352: Cannot use variable 'x' in this context because it may expose referenced variables outside of their declaration scope + // return x; // 2 + Diagnostic(ErrorCode.ERR_EscapeVariable, "x").WithArguments("x").WithLocation(11, 16), + // (16,20): error CS8352: Cannot use variable 'x' in this context because it may expose referenced variables outside of their declaration scope + // return x; // 3 + Diagnostic(ErrorCode.ERR_EscapeVariable, "x").WithArguments("x").WithLocation(16, 20)); + } + + [Fact] + public void Deconstruction_ScopedRef_ExtensionMethod() + { + var source = """ + class C + { + R M1() + { + new S().Deconstruct(out var x, out _); + return x; + } + R M2() + { + (var x, _) = new S(); + return x; + } + R M3() + { + if (new S() is (var x, _)) + return x; + return default; + } + } + struct S; + ref struct R; + static class E + { + public static void Deconstruct(this scoped in S s, out R x, out int y) => throw null; + } + """; + CreateCompilation(source).VerifyDiagnostics(); + } + + [Fact] + [WorkItem("https://github.com/dotnet/roslyn/issues/75484")] + public void Deconstruction_UnscopedRef_RefReturnableReceiver() + { + var source = """ + using System.Diagnostics.CodeAnalysis; + class C + { + R M1(ref S s) + { + s.Deconstruct(out var x, out _); + return x; + } + R M2(ref S s) + { + (var x, _) = s; + return x; // 1 + } + R M3(ref S s) + { + if (s is (var x, _)) + return x; // 2 + return default; + } + } + struct S + { + [UnscopedRef] public void Deconstruct(out R x, out int y) => throw null; + } + ref struct R; + """; + // M2 and M3 copy the receiver `s`, so the ref safety errors are expected. + CreateCompilation([source, UnscopedRefAttributeDefinition]).VerifyDiagnostics( + // (12,16): error CS8352: Cannot use variable 'x' in this context because it may expose referenced variables outside of their declaration scope + // return x; // 1 + Diagnostic(ErrorCode.ERR_EscapeVariable, "x").WithArguments("x").WithLocation(12, 16), + // (17,20): error CS8352: Cannot use variable 'x' in this context because it may expose referenced variables outside of their declaration scope + // return x; // 2 + Diagnostic(ErrorCode.ERR_EscapeVariable, "x").WithArguments("x").WithLocation(17, 20)); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75484")] + public void Deconstruction_UnscopedRef_PatternMatching_BinaryPattern_01() + { + var source = """ + using System.Diagnostics.CodeAnalysis; + class C + { + R M() + { + if (new S() is (var x and { F: 0 }, _)) + return x; + return default; + } + } + struct S + { + [UnscopedRef] public void Deconstruct(out R x, out int y) => throw null; + } + ref struct R(int f) + { + public int F = f; + } + """; + CreateCompilation([source, UnscopedRefAttributeDefinition]).VerifyDiagnostics( + // (7,20): error CS8352: Cannot use variable 'x' in this context because it may expose referenced variables outside of their declaration scope + // return x; + Diagnostic(ErrorCode.ERR_EscapeVariable, "x").WithArguments("x").WithLocation(7, 20)); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75484")] + public void Deconstruction_UnscopedRef_PatternMatching_BinaryPattern_02() + { + var source = """ + using System.Diagnostics.CodeAnalysis; + class C + { + R M() + { + if (new S() is (var x and var y, _)) + return y; + return default; + } + } + struct S + { + [UnscopedRef] public void Deconstruct(out R x, out int y) => throw null; + } + ref struct R; + """; + CreateCompilation([source, UnscopedRefAttributeDefinition]).VerifyDiagnostics( + // (7,20): error CS8352: Cannot use variable 'y' in this context because it may expose referenced variables outside of their declaration scope + // return y; + Diagnostic(ErrorCode.ERR_EscapeVariable, "y").WithArguments("y").WithLocation(7, 20)); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75484")] + public void Deconstruction_ScopedRef_PatternMatching_BinaryPattern_01() + { + var source = """ + class C + { + R M() + { + if (new S() is (var x and { F: 0 }, _)) + return x; + return default; + } + } + struct S + { + public void Deconstruct(out R x, out int y) => throw null; + } + ref struct R(int f) + { + public int F = f; + } + """; + CreateCompilation(source).VerifyDiagnostics(); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75484")] + public void Deconstruction_ScopedRef_PatternMatching_BinaryPattern_02() + { + var source = """ + class C + { + R M() + { + if (new S() is (var x and var y, _)) + return y; + return default; + } + } + struct S + { + public void Deconstruct(out R x, out int y) => throw null; + } + ref struct R; + """; + CreateCompilation(source).VerifyDiagnostics(); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75484")] + public void Deconstruction_UnscopedRef_PatternMatching_NestedDeconstruction() + { + var source = """ + using System.Diagnostics.CodeAnalysis; + class C + { + R M() + { + if (new S() is ((var x, var y), var z)) + return x; + return default; + } + } + struct S + { + public void Deconstruct(out T x, out int y) => throw null; + } + struct T + { + [UnscopedRef] public void Deconstruct(out R x, out int y) => throw null; + } + ref struct R; + """; + CreateCompilation([source, UnscopedRefAttributeDefinition]).VerifyDiagnostics( + // (7,20): error CS8352: Cannot use variable 'x' in this context because it may expose referenced variables outside of their declaration scope + // return x; + Diagnostic(ErrorCode.ERR_EscapeVariable, "x").WithArguments("x").WithLocation(7, 20)); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75484")] + public void Deconstruction_ScopedRef_PatternMatching_NestedDeconstruction() + { + var source = """ + class C + { + R M() + { + if (new S() is ((var x, var y), var z)) + return x; + return default; + } + } + struct S + { + public void Deconstruct(out T x, out int y) => throw null; + } + struct T + { + public void Deconstruct(out R x, out int y) => throw null; + } + ref struct R; + """; + CreateCompilation(source).VerifyDiagnostics(); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75484")] + public void Deconstruction_UnscopedRef_PatternMatching_NestedProp() + { + var source = """ + using System.Diagnostics.CodeAnalysis; + class C + { + S Prop { get; set; } + R M() + { + if (new C() is { Prop: (var x, _) }) + return x; + return default; + } + } + struct S + { + [UnscopedRef] public void Deconstruct(out R x, out int y) => throw null; + } + ref struct R; + """; + CreateCompilation([source, UnscopedRefAttributeDefinition]).VerifyDiagnostics( + // (8,20): error CS8352: Cannot use variable 'x' in this context because it may expose referenced variables outside of their declaration scope + // return x; + Diagnostic(ErrorCode.ERR_EscapeVariable, "x").WithArguments("x").WithLocation(8, 20)); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75484")] + public void Deconstruction_UnscopedRef_PatternMatching_NestedPattern() + { + var source = """ + using System.Diagnostics.CodeAnalysis; + class C + { + R M1() + { + if (new S() is ({ Prop: (var x2, _) } x, _)) + return x; + return default; + } + R M2() + { + if (new S() is ({ Prop: (var x2, _) } x, _)) + return x2; + return default; + } + } + struct S + { + [UnscopedRef] public void Deconstruct(out R x, out int y) => throw null; + } + ref struct R + { + public S Prop { get; set; } + } + """; + CreateCompilation([source, UnscopedRefAttributeDefinition]).VerifyDiagnostics( + // (7,20): error CS8352: Cannot use variable 'x' in this context because it may expose referenced variables outside of their declaration scope + // return x; + Diagnostic(ErrorCode.ERR_EscapeVariable, "x").WithArguments("x").WithLocation(7, 20), + // (13,20): error CS8352: Cannot use variable 'x2' in this context because it may expose referenced variables outside of their declaration scope + // return x2; + Diagnostic(ErrorCode.ERR_EscapeVariable, "x2").WithArguments("x2").WithLocation(13, 20)); + } + [Theory] [InlineData(LanguageVersion.CSharp10)] [InlineData(LanguageVersion.CSharp11)] @@ -10358,5 +10878,341 @@ public static void M([UnscopedRef] ref S s) """; CreateCompilation(source, targetFramework: TargetFramework.Net70).VerifyDiagnostics(); } + + [Theory, CombinatorialData, WorkItem("https://github.com/dotnet/roslyn/issues/76100")] + public void SelfAssignment_ScopeVariance_UnscopedRef_Disallowed_ImplicitInterface( + [CombinatorialValues("ref", "out")] string modifier) + { + var source = $$""" + using System.Diagnostics.CodeAnalysis; + + interface I + { + void M({{modifier}} R r); + } + + class C : I + { + public void M([UnscopedRef] {{modifier}} R r) { } + } + + ref struct R; + """; + + var expectedDiagnostics = new[] + { + // (10,17): error CS8987: The 'scoped' modifier of parameter 'r' doesn't match overridden or implemented member. + // public void M([UnscopedRef] ref R r) { } + Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfOverrideOrImplementation, "M").WithArguments("r").WithLocation(10, 17) + }; + + CreateCompilation([source, UnscopedRefAttributeDefinition]).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation([source, UnscopedRefAttributeDefinition], parseOptions: TestOptions.Regular13).VerifyDiagnostics(expectedDiagnostics); + + CreateCompilation([source, UnscopedRefAttributeDefinition], parseOptions: TestOptions.Regular12).VerifyDiagnostics( + // (10,17): warning CS9074: The 'scoped' modifier of parameter 'r' doesn't match overridden or implemented member. + // public void M([UnscopedRef] ref R r) { } + Diagnostic(ErrorCode.WRN_ScopedMismatchInParameterOfOverrideOrImplementation, "M").WithArguments("r").WithLocation(10, 17)); + } + + [Theory, CombinatorialData, WorkItem("https://github.com/dotnet/roslyn/issues/76100")] + public void SelfAssignment_ScopeVariance_UnscopedRef_Disallowed_ExplicitInterface( + [CombinatorialValues("ref", "out")] string modifier) + { + var source = $$""" + using System.Diagnostics.CodeAnalysis; + + interface I + { + void M({{modifier}} R r); + } + + class C : I + { + void I.M([UnscopedRef] {{modifier}} R r) { } + } + + ref struct R; + """; + CreateCompilation([source, UnscopedRefAttributeDefinition]).VerifyDiagnostics( + // (10,12): error CS8987: The 'scoped' modifier of parameter 'r' doesn't match overridden or implemented member. + // void I.M([UnscopedRef] ref R r) { } + Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfOverrideOrImplementation, "M").WithArguments("r").WithLocation(10, 12)); + } + + [Theory, CombinatorialData, WorkItem("https://github.com/dotnet/roslyn/issues/76100")] + public void SelfAssignment_ScopeVariance_UnscopedRef_Disallowed_Override( + [CombinatorialValues("ref", "out")] string modifier) + { + var source = $$""" + using System.Diagnostics.CodeAnalysis; + + abstract class B + { + public abstract void M({{modifier}} R r); + } + + class C : B + { + public override void M([UnscopedRef] {{modifier}} R r) { } + } + + ref struct R; + """; + CreateCompilation([source, UnscopedRefAttributeDefinition]).VerifyDiagnostics( + // (10,26): error CS8987: The 'scoped' modifier of parameter 'r' doesn't match overridden or implemented member. + // public override void M([UnscopedRef] ref R r) { } + Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfOverrideOrImplementation, "M").WithArguments("r").WithLocation(10, 26)); + } + + [Theory, CombinatorialData, WorkItem("https://github.com/dotnet/roslyn/issues/76100")] + public void SelfAssignment_ScopeVariance_UnscopedRef_Disallowed_DelegateConversion( + [CombinatorialValues("ref", "out")] string modifier) + { + var source = $$""" + using System.Diagnostics.CodeAnalysis; + + D d = C.M; + + delegate void D({{modifier}} R r); + + static class C + { + public static void M([UnscopedRef] {{modifier}} R r) { } + } + + ref struct R; + """; + CreateCompilation([source, UnscopedRefAttributeDefinition]).VerifyDiagnostics( + // (3,7): error CS8986: The 'scoped' modifier of parameter 'r' doesn't match target 'D'. + // D d = C.M; + Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "C.M").WithArguments("r", "D").WithLocation(3, 7)); + } + + [Theory, WorkItem("https://github.com/dotnet/roslyn/issues/76100")] + [InlineData("[System.Diagnostics.CodeAnalysis.UnscopedRef]", "")] + [InlineData("[System.Diagnostics.CodeAnalysis.UnscopedRef]", "[System.Diagnostics.CodeAnalysis.UnscopedRef]")] + [InlineData("", "")] + public void SelfAssignment_ScopeVariance_UnscopedRef_Allowed_ImplicitInterface(string attr1, string attr2) + { + var source = $$""" + interface I + { + void M({{attr1}} ref R r); + } + + class C : I + { + public void M({{attr2}} ref R r) { } + } + + ref struct R; + """; + CreateCompilation([source, UnscopedRefAttributeDefinition]).VerifyDiagnostics(); + } + + [Theory, CombinatorialData, WorkItem("https://github.com/dotnet/roslyn/issues/76100")] + public void SelfAssignment_ScopeVariance_ScopedRef_ImplicitInterface( + [CombinatorialValues("scoped", "")] string scoped1, + [CombinatorialValues("scoped", "")] string scoped2, + [CombinatorialValues("ref", "out")] string modifier) + { + var source = $$""" + interface I + { + void M({{scoped1}} {{modifier}} R r); + } + + class C : I + { + public void M({{scoped2}} {{modifier}} R r) { } + } + + ref struct R; + """; + + var comp = CreateCompilation(source); + + if (scoped1 == "scoped" && scoped2 == "" && modifier == "ref") + { + comp.VerifyDiagnostics( + // (8,17): error CS8987: The 'scoped' modifier of parameter 'r' doesn't match overridden or implemented member. + // public void M( ref R r) { } + Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfOverrideOrImplementation, "M").WithArguments("r").WithLocation(8, 17)); + } + else + { + comp.VerifyDiagnostics(); + } + } + + [Theory, WorkItem("https://github.com/dotnet/roslyn/issues/76100")] + [InlineData("[System.Diagnostics.CodeAnalysis.UnscopedRef]", "")] + [InlineData("[System.Diagnostics.CodeAnalysis.UnscopedRef]", "[System.Diagnostics.CodeAnalysis.UnscopedRef]")] + [InlineData("", "")] + public void SelfAssignment_ScopeVariance_UnscopedRef_Allowed_ExplicitInterface(string attr1, string attr2) + { + var source = $$""" + interface I + { + void M({{attr1}} ref R r); + } + + class C : I + { + void I.M({{attr2}} ref R r) { } + } + + ref struct R; + """; + CreateCompilation([source, UnscopedRefAttributeDefinition]).VerifyDiagnostics(); + } + + [Theory, CombinatorialData, WorkItem("https://github.com/dotnet/roslyn/issues/76100")] + public void SelfAssignment_ScopeVariance_ScopedRef_ExplicitInterface( + [CombinatorialValues("scoped", "")] string scoped1, + [CombinatorialValues("scoped", "")] string scoped2, + [CombinatorialValues("ref", "out")] string modifier) + { + var source = $$""" + interface I + { + void M({{scoped1}} {{modifier}} R r); + } + + class C : I + { + void I.M({{scoped2}} {{modifier}} R r) { } + } + + ref struct R; + """; + + var comp = CreateCompilation(source); + + if (scoped1 == "scoped" && scoped2 == "" && modifier == "ref") + { + comp.VerifyDiagnostics( + // (8,12): error CS8987: The 'scoped' modifier of parameter 'r' doesn't match overridden or implemented member. + // void I.M( ref R r) { } + Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfOverrideOrImplementation, "M").WithArguments("r").WithLocation(8, 12)); + } + else + { + comp.VerifyDiagnostics(); + } + } + + [Theory, WorkItem("https://github.com/dotnet/roslyn/issues/76100")] + [InlineData("[System.Diagnostics.CodeAnalysis.UnscopedRef]", "")] + [InlineData("[System.Diagnostics.CodeAnalysis.UnscopedRef]", "[System.Diagnostics.CodeAnalysis.UnscopedRef]")] + [InlineData("", "")] + public void SelfAssignment_ScopeVariance_UnscopedRef_Allowed_Override(string attr1, string attr2) + { + var source = $$""" + abstract class B + { + public abstract void M({{attr1}} ref R r); + } + + class C : B + { + public override void M({{attr2}} ref R r) { } + } + + ref struct R; + """; + CreateCompilation([source, UnscopedRefAttributeDefinition]).VerifyDiagnostics(); + } + + [Theory, CombinatorialData, WorkItem("https://github.com/dotnet/roslyn/issues/76100")] + public void SelfAssignment_ScopeVariance_ScopedRef_Override( + [CombinatorialValues("scoped", "")] string scoped1, + [CombinatorialValues("scoped", "")] string scoped2, + [CombinatorialValues("ref", "out")] string modifier) + { + var source = $$""" + abstract class B + { + public abstract void M({{scoped1}} {{modifier}} R r); + } + + class C : B + { + public override void M({{scoped2}} {{modifier}} R r) { } + } + + ref struct R; + """; + + var comp = CreateCompilation(source); + + if (scoped1 == "scoped" && scoped2 == "" && modifier == "ref") + { + comp.VerifyDiagnostics( + // (8,26): error CS8987: The 'scoped' modifier of parameter 'r' doesn't match overridden or implemented member. + // public override void M( ref R r) { } + Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfOverrideOrImplementation, "M").WithArguments("r").WithLocation(8, 26)); + } + else + { + comp.VerifyDiagnostics(); + } + } + + [Theory, WorkItem("https://github.com/dotnet/roslyn/issues/76100")] + [InlineData("[System.Diagnostics.CodeAnalysis.UnscopedRef]", "")] + [InlineData("[System.Diagnostics.CodeAnalysis.UnscopedRef]", "[System.Diagnostics.CodeAnalysis.UnscopedRef]")] + [InlineData("", "")] + public void SelfAssignment_ScopeVariance_UnscopedRef_Allowed_DelegateConversion(string attr1, string attr2) + { + var source = $$""" + D d = C.M; + + delegate void D({{attr1}} ref R r); + + static class C + { + public static void M({{attr2}} ref R r) { } + } + + ref struct R; + """; + CreateCompilation([source, UnscopedRefAttributeDefinition]).VerifyDiagnostics(); + } + + [Theory, CombinatorialData, WorkItem("https://github.com/dotnet/roslyn/issues/76100")] + public void SelfAssignment_ScopeVariance_ScopedRef_DelegateConversion( + [CombinatorialValues("scoped", "")] string scoped1, + [CombinatorialValues("scoped", "")] string scoped2, + [CombinatorialValues("ref", "out")] string modifier) + { + var source = $$""" + D d = C.M; + + delegate void D({{scoped1}} {{modifier}} R r); + + static class C + { + public static void M({{scoped2}} {{modifier}} R r) { } + } + + ref struct R; + """; + + var comp = CreateCompilation(source); + + if (scoped1 == "scoped" && scoped2 == "" && modifier == "ref") + { + comp.VerifyDiagnostics( + // (1,7): error CS8986: The 'scoped' modifier of parameter 'r' doesn't match target 'D'. + // D d = C.M; + Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "C.M").WithArguments("r", "D").WithLocation(1, 7)); + } + else + { + comp.VerifyDiagnostics(); + } + } } } diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/RefFieldTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/RefFieldTests.cs index 5e094ed174443..8c8f24c91e07e 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/RefFieldTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/RefFieldTests.cs @@ -9747,9 +9747,9 @@ static ref S F2(S x2) if (languageVersion == LanguageVersion.CSharp10) { comp.VerifyEmitDiagnostics( - // (8,28): error CS9063: UnscopedRefAttribute cannot be applied to this parameter because it is unscoped by default. + // (8,28): warning CS9269: UnscopedRefAttribute is only valid in C# 11 or later or when targeting net7.0 or later. // static ref S F1([UnscopedRef] ref S x1) - Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedTarget, "UnscopedRef").WithLocation(8, 28), + Diagnostic(ErrorCode.WRN_UnscopedRefAttributeOldRules, "UnscopedRef").WithLocation(8, 28), // (15,20): error CS8157: Cannot return 'y2' by reference because it was initialized to a value that cannot be returned by reference // return ref y2; // 1 Diagnostic(ErrorCode.ERR_RefReturnNonreturnableLocal, "y2").WithArguments("y2").WithLocation(15, 20)); @@ -11071,12 +11071,15 @@ static void Main() // (8,30): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater. // var f3 = (in int x3, scoped in int y3) => { }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "scoped").WithArguments("ref fields", "11.0").WithLocation(8, 30), + // (9,18): warning CS9073: The 'scoped' modifier of parameter 'z4' doesn't match target ''. + // var f4 = (out int x4, scoped out int y4, [System.Diagnostics.CodeAnalysis.UnscopedRefAttribute] out int z4) => { x4 = 0; y4 = 0; z4 = 0; }; + Diagnostic(ErrorCode.WRN_ScopedMismatchInParameterOfTarget, "(out int x4, scoped out int y4, [System.Diagnostics.CodeAnalysis.UnscopedRefAttribute] out int z4) => { x4 = 0; y4 = 0; z4 = 0; }").WithArguments("z4", "").WithLocation(9, 18), // (9,31): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater. // var f4 = (out int x4, scoped out int y4, [System.Diagnostics.CodeAnalysis.UnscopedRefAttribute] out int z4) => { x4 = 0; y4 = 0; z4 = 0; }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "scoped").WithArguments("ref fields", "11.0").WithLocation(9, 31), - // (9,51): error CS9063: UnscopedRefAttribute cannot be applied to this item because it is unscoped by default. + // (9,51): warning CS9269: UnscopedRefAttribute is only valid in C# 11 or later or when targeting net7.0 or later. // var f4 = (out int x4, scoped out int y4, [System.Diagnostics.CodeAnalysis.UnscopedRefAttribute] out int z4) => { x4 = 0; y4 = 0; z4 = 0; }; - Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedTarget, "System.Diagnostics.CodeAnalysis.UnscopedRefAttribute").WithLocation(9, 51), + Diagnostic(ErrorCode.WRN_UnscopedRefAttributeOldRules, "System.Diagnostics.CodeAnalysis.UnscopedRefAttribute").WithLocation(9, 51), // (10,29): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater. // var f5 = (ref R x5, scoped ref R y5) => { }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "scoped").WithArguments("ref fields", "11.0").WithLocation(10, 29), @@ -11098,27 +11101,27 @@ static void verify(CSharpCompilation comp, bool useUpdatedEscapeRules) var model = comp.GetSemanticModel(tree); var delegateTypesAndLambdas = tree.GetRoot().DescendantNodes().OfType().Select(d => getDelegateTypeAndLambda(model, d)).ToArray(); - verifyParameter(delegateTypesAndLambdas[0], 0, "R", "x1", RefKind.None, ScopedKind.None, false); - verifyParameter(delegateTypesAndLambdas[0], 1, "scoped R", "y1", RefKind.None, ScopedKind.ScopedValue, false); - verifyParameter(delegateTypesAndLambdas[1], 0, "ref System.Int32", "x2", RefKind.Ref, ScopedKind.None, false); - verifyParameter(delegateTypesAndLambdas[1], 1, "scoped ref System.Int32", "y2", RefKind.Ref, ScopedKind.ScopedRef, false); - verifyParameter(delegateTypesAndLambdas[2], 0, "in System.Int32", "x3", RefKind.In, ScopedKind.None, false); - verifyParameter(delegateTypesAndLambdas[2], 1, "scoped in System.Int32", "y3", RefKind.In, ScopedKind.ScopedRef, false); - verifyParameter(delegateTypesAndLambdas[3], 0, "out System.Int32", "x4", RefKind.Out, useUpdatedEscapeRules ? ScopedKind.ScopedRef : ScopedKind.None, false); - verifyParameter(delegateTypesAndLambdas[3], 1, "out System.Int32", "y4", RefKind.Out, ScopedKind.ScopedRef, false); - verifyParameter(delegateTypesAndLambdas[3], 2, "out System.Int32", "z4", RefKind.Out, ScopedKind.None, true); - verifyParameter(delegateTypesAndLambdas[4], 0, "ref R", "x5", RefKind.Ref, ScopedKind.None, false); - verifyParameter(delegateTypesAndLambdas[4], 1, "scoped ref R", "y5", RefKind.Ref, ScopedKind.ScopedRef, false); - verifyParameter(delegateTypesAndLambdas[5], 0, "in R", "x6", RefKind.In, ScopedKind.None, false); - verifyParameter(delegateTypesAndLambdas[5], 1, "scoped in R", "y6", RefKind.In, ScopedKind.ScopedRef, false); - verifyParameter(delegateTypesAndLambdas[6], 0, "out R", "x7", RefKind.Out, useUpdatedEscapeRules ? ScopedKind.ScopedRef : ScopedKind.None, false); - verifyParameter(delegateTypesAndLambdas[6], 1, "out R", "y7", RefKind.Out, ScopedKind.ScopedRef, false); + verifyParameter(delegateTypesAndLambdas[0], 0, "R", "x1", RefKind.None, ScopedKind.None, false, false); + verifyParameter(delegateTypesAndLambdas[0], 1, "scoped R", "y1", RefKind.None, ScopedKind.ScopedValue, false, false); + verifyParameter(delegateTypesAndLambdas[1], 0, "ref System.Int32", "x2", RefKind.Ref, ScopedKind.None, false, false); + verifyParameter(delegateTypesAndLambdas[1], 1, "scoped ref System.Int32", "y2", RefKind.Ref, ScopedKind.ScopedRef, false, false); + verifyParameter(delegateTypesAndLambdas[2], 0, "in System.Int32", "x3", RefKind.In, ScopedKind.None, false, false); + verifyParameter(delegateTypesAndLambdas[2], 1, "scoped in System.Int32", "y3", RefKind.In, ScopedKind.ScopedRef, false, false); + verifyParameter(delegateTypesAndLambdas[3], 0, "out System.Int32", "x4", RefKind.Out, useUpdatedEscapeRules ? ScopedKind.ScopedRef : ScopedKind.None, false, false); + verifyParameter(delegateTypesAndLambdas[3], 1, "out System.Int32", "y4", RefKind.Out, ScopedKind.ScopedRef, false, false); + verifyParameter(delegateTypesAndLambdas[3], 2, "out System.Int32", "z4", RefKind.Out, ScopedKind.None, true, useUpdatedEscapeRules); + verifyParameter(delegateTypesAndLambdas[4], 0, "ref R", "x5", RefKind.Ref, ScopedKind.None, false, false); + verifyParameter(delegateTypesAndLambdas[4], 1, "scoped ref R", "y5", RefKind.Ref, ScopedKind.ScopedRef, false, false); + verifyParameter(delegateTypesAndLambdas[5], 0, "in R", "x6", RefKind.In, ScopedKind.None, false, false); + verifyParameter(delegateTypesAndLambdas[5], 1, "scoped in R", "y6", RefKind.In, ScopedKind.ScopedRef, false, false); + verifyParameter(delegateTypesAndLambdas[6], 0, "out R", "x7", RefKind.Out, useUpdatedEscapeRules ? ScopedKind.ScopedRef : ScopedKind.None, false, false); + verifyParameter(delegateTypesAndLambdas[6], 1, "out R", "y7", RefKind.Out, ScopedKind.ScopedRef, false, false); } - static void verifyParameter((NamedTypeSymbol, LambdaSymbol) delegateTypeAndLambda, int parameterIndex, string expectedDisplayType, string expectedDisplayName, RefKind expectedRefKind, ScopedKind expectedScope, bool expectedHasUnscopedRefAttribute) + static void verifyParameter((NamedTypeSymbol, LambdaSymbol) delegateTypeAndLambda, int parameterIndex, string expectedDisplayType, string expectedDisplayName, RefKind expectedRefKind, ScopedKind expectedScope, bool expectedHasUnscopedRefAttribute, bool expectedHasUnscopedRefAttributeInDelegate) { var (delegateType, lambda) = delegateTypeAndLambda; - VerifyParameterSymbol(delegateType.DelegateInvokeMethod.Parameters[parameterIndex], $"{expectedDisplayType} arg{parameterIndex + 1}", expectedRefKind, expectedScope, expectedHasUnscopedRefAttribute); + VerifyParameterSymbol(delegateType.DelegateInvokeMethod.Parameters[parameterIndex], $"{expectedDisplayType} arg{parameterIndex + 1}", expectedRefKind, expectedScope, expectedHasUnscopedRefAttributeInDelegate); VerifyParameterSymbol(lambda.Parameters[parameterIndex], $"{expectedDisplayType} {expectedDisplayName}", expectedRefKind, expectedScope, expectedHasUnscopedRefAttribute); } @@ -16249,21 +16252,27 @@ static void Main() {{ D0 d0 = ({refModifier} int i) => {{ }}; D1 d1 = ({refModifier} int i) => F(); - D2 d2 = ({refModifier} int i) => ref F(); // 1 - D3 d3 = ({refModifier} int i) => ref F(); // 2 - D4 d4 = ({refModifier} int i) => new R(); // 3 + D2 d2 = ({refModifier} int i) => ref F(); + D3 d3 = ({refModifier} int i) => ref F(); + D4 d4 = ({refModifier} int i) => new R(); }} }}"; var comp = CreateCompilation(source); comp.VerifyDiagnostics( + // (12,22): error CS8986: The 'scoped' modifier of parameter 'i' doesn't match target 'D0'. + // D0 d0 = (ref int i) => { }; + Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, $"({refModifier} int i) => {{ }}").WithArguments("i", "D0").WithLocation(12, 22), + // (13,22): error CS8986: The 'scoped' modifier of parameter 'i' doesn't match target 'D1'. + // D1 d1 = (ref int i) => F(); + Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, $"({refModifier} int i) => F()").WithArguments("i", "D1").WithLocation(13, 22), // (14,22): error CS8986: The 'scoped' modifier of parameter 'i' doesn't match target 'D2'. - // D2 d2 = (ref int i) => ref F(); // 1 + // D2 d2 = (ref int i) => ref F(); Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, $"({refModifier} int i) => ref F()").WithArguments("i", "D2").WithLocation(14, 22), // (15,22): error CS8986: The 'scoped' modifier of parameter 'i' doesn't match target 'D3'. - // D3 d3 = (ref int i) => ref F(); // 2 + // D3 d3 = (ref int i) => ref F(); Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, $"({refModifier} int i) => ref F()").WithArguments("i", "D3").WithLocation(15, 22), // (16,22): error CS8986: The 'scoped' modifier of parameter 'i' doesn't match target 'D4'. - // D4 d4 = (ref int i) => new R(); // 3 + // D4 d4 = (ref int i) => new R(); Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, $"({refModifier} int i) => new R()").WithArguments("i", "D4").WithLocation(16, 22)); } @@ -16284,18 +16293,24 @@ class Program static void Main() {{ D0 d0 = ({refModifier} int i, R r) => {{ }}; - D1 d1 = ({refModifier} int i, ref R r) => {{ }}; // 1 + D1 d1 = ({refModifier} int i, ref R r) => {{ }}; D2 d2 = ({refModifier} int i, in R r) => {{ }}; - D3 d3 = ({refModifier} int i, out R r) => {{ r = default; }}; // 2 + D3 d3 = ({refModifier} int i, out R r) => {{ r = default; }}; }} }}"; var comp = CreateCompilation(source); comp.VerifyDiagnostics( + // (11,22): error CS8986: The 'scoped' modifier of parameter 'i' doesn't match target 'D0'. + // D0 d0 = (ref int i, R r) => { }; + Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, $"({refModifier} int i, R r) => {{ }}").WithArguments("i", "D0").WithLocation(11, 22), // (12,22): error CS8986: The 'scoped' modifier of parameter 'i' doesn't match target 'D1'. - // D1 d1 = (ref int i, ref R r) => { }; // 1 + // D1 d1 = (ref int i, ref R r) => { }; Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, $"({refModifier} int i, ref R r) => {{ }}").WithArguments("i", "D1").WithLocation(12, 22), + // (13,22): error CS8986: The 'scoped' modifier of parameter 'i' doesn't match target 'D2'. + // D2 d2 = (ref int i, in R r) => { }; + Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, $"({refModifier} int i, in R r) => {{ }}").WithArguments("i", "D2").WithLocation(13, 22), // (14,22): error CS8986: The 'scoped' modifier of parameter 'i' doesn't match target 'D3'. - // D3 d3 = (ref int i, out R r) => { r = default; }; // 2 + // D3 d3 = (ref int i, out R r) => { r = default; }; Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, $"({refModifier} int i, out R r) => {{ r = default; }}").WithArguments("i", "D3").WithLocation(14, 22)); } @@ -16765,7 +16780,10 @@ public static void M(object? o) comp.VerifyDiagnostics( // (3,17): error CS9048: The 'scoped' modifier can be used for refs and ref struct values only. // delegate R D(scoped T t); - Diagnostic(ErrorCode.ERR_ScopedRefAndRefStructOnly, "scoped T t").WithLocation(3, 17) + Diagnostic(ErrorCode.ERR_ScopedRefAndRefStructOnly, "scoped T t").WithLocation(3, 17), + // (14,27): error CS8986: The 'scoped' modifier of parameter 'o2' doesn't match target 'D'. + // D d = o2 => throw null!; + Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "o2 => throw null!").WithArguments("o2", "D").WithLocation(14, 27) ); var syntaxTree = comp.SyntaxTrees[0]; @@ -17388,7 +17406,10 @@ public class C : Base Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfOverrideOrImplementation, "get").WithArguments("rs").WithLocation(11, 38), // (12,45): error CS8987: The 'scoped' modifier of parameter 'rs' doesn't match overridden or implemented member. // public override RS this[RS rs, int _] { get => default; set { } } // 2 - Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfOverrideOrImplementation, "get").WithArguments("rs").WithLocation(12, 45)); + Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfOverrideOrImplementation, "get").WithArguments("rs").WithLocation(12, 45), + // (12,61): error CS8987: The 'scoped' modifier of parameter 'rs' doesn't match overridden or implemented member. + // public override RS this[RS rs, int _] { get => default; set { } } // 2 + Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfOverrideOrImplementation, "set").WithArguments("rs").WithLocation(12, 61)); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/73384")] @@ -17417,7 +17438,10 @@ public class C : I Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfOverrideOrImplementation, "get").WithArguments("rs").WithLocation(11, 29), // (12,36): error CS8987: The 'scoped' modifier of parameter 'rs' doesn't match overridden or implemented member. // public RS this[RS rs, int _] { get => default; set { } } // 2 - Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfOverrideOrImplementation, "get").WithArguments("rs").WithLocation(12, 36)); + Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfOverrideOrImplementation, "get").WithArguments("rs").WithLocation(12, 36), + // (12,52): error CS8987: The 'scoped' modifier of parameter 'rs' doesn't match overridden or implemented member. + // public RS this[RS rs, int _] { get => default; set { } } // 2 + Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfOverrideOrImplementation, "set").WithArguments("rs").WithLocation(12, 52)); } [CombinatorialData] @@ -22323,6 +22347,566 @@ public void ScopedReserved_Alias_Escaped() ); } + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75828")] + public void UnscopedRefAttribute_RefSafetyRules_ThisParameter() + { + var source = """ + using System.Diagnostics.CodeAnalysis; + struct S + { + public int F; + + [UnscopedRef] public ref int Ref() => ref F; + } + """; + CreateCompilation([source, UnscopedRefAttributeDefinition], + parseOptions: TestOptions.Regular10).VerifyDiagnostics( + // (6,6): warning CS9269: UnscopedRefAttribute is only valid in C# 11 or later or when targeting net7.0 or later. + // [UnscopedRef] public ref int Ref() => ref F; + Diagnostic(ErrorCode.WRN_UnscopedRefAttributeOldRules, "UnscopedRef").WithLocation(6, 6), + // (6,47): error CS8170: Struct members cannot return 'this' or other instance members by reference + // [UnscopedRef] public ref int Ref() => ref F; + Diagnostic(ErrorCode.ERR_RefReturnStructThis, "F").WithLocation(6, 47)); + + CreateCompilation(source, + parseOptions: TestOptions.Regular10, + targetFramework: TargetFramework.Net70).VerifyDiagnostics(); + CreateCompilation([source, UnscopedRefAttributeDefinition], + parseOptions: TestOptions.Regular11).VerifyDiagnostics(); + CreateCompilation([source, UnscopedRefAttributeDefinition]).VerifyDiagnostics(); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75828")] + public void UnscopedRefAttribute_RefSafetyRules_ThisParameter_Property() + { + var source = """ + using System.Diagnostics.CodeAnalysis; + struct S + { + public int F; + + [UnscopedRef] public ref int Ref => ref F; + } + """; + CreateCompilation([source, UnscopedRefAttributeDefinition], + parseOptions: TestOptions.Regular10).VerifyDiagnostics( + // (6,6): warning CS9269: UnscopedRefAttribute is only valid in C# 11 or later or when targeting net7.0 or later. + // [UnscopedRef] public ref int Ref => ref F; + Diagnostic(ErrorCode.WRN_UnscopedRefAttributeOldRules, "UnscopedRef").WithLocation(6, 6), + // (6,45): error CS8170: Struct members cannot return 'this' or other instance members by reference + // [UnscopedRef] public ref int Ref => ref F; + Diagnostic(ErrorCode.ERR_RefReturnStructThis, "F").WithLocation(6, 45)); + + CreateCompilation(source, + parseOptions: TestOptions.Regular10, + targetFramework: TargetFramework.Net70).VerifyDiagnostics(); + CreateCompilation([source, UnscopedRefAttributeDefinition], + parseOptions: TestOptions.Regular11).VerifyDiagnostics(); + CreateCompilation([source, UnscopedRefAttributeDefinition]).VerifyDiagnostics(); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75828")] + public void UnscopedRefAttribute_RefSafetyRules_RefParameter() + { + var source = """ + using System.Diagnostics.CodeAnalysis; + class C + { + void M([UnscopedRef] ref int x, out int y) + { + y = default; + x = ref y; + } + } + """; + CreateCompilation([source, UnscopedRefAttributeDefinition], + parseOptions: TestOptions.Regular10).VerifyDiagnostics( + // (4,13): warning CS9269: UnscopedRefAttribute is only valid in C# 11 or later or when targeting net7.0 or later. + // void M([UnscopedRef] ref int x, out int y) + Diagnostic(ErrorCode.WRN_UnscopedRefAttributeOldRules, "UnscopedRef").WithLocation(4, 13)); + + var expectedDiagnostics = new[] + { + // (7,9): error CS8374: Cannot ref-assign 'y' to 'x' because 'y' has a narrower escape scope than 'x'. + // x = ref y; + Diagnostic(ErrorCode.ERR_RefAssignNarrower, "x = ref y").WithArguments("x", "y").WithLocation(7, 9) + }; + + CreateCompilation(source, + parseOptions: TestOptions.Regular10, + targetFramework: TargetFramework.Net70).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation([source, UnscopedRefAttributeDefinition], + parseOptions: TestOptions.Regular11).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation([source, UnscopedRefAttributeDefinition]).VerifyDiagnostics(expectedDiagnostics); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75828")] + public void UnscopedRefAttribute_RefSafetyRules_OutParameter() + { + var source = """ + using System.Diagnostics.CodeAnalysis; + struct S + { + public int F; + + public static ref int Ref([UnscopedRef] out S s) + { + s = default; + return ref s.F; + } + } + """; + CreateCompilation([source, UnscopedRefAttributeDefinition], + parseOptions: TestOptions.Regular10).VerifyDiagnostics( + // (6,32): warning CS9269: UnscopedRefAttribute is only valid in C# 11 or later or when targeting net7.0 or later. + // public static ref int Ref([UnscopedRef] out S s) + Diagnostic(ErrorCode.WRN_UnscopedRefAttributeOldRules, "UnscopedRef").WithLocation(6, 32)); + CreateCompilation(source, + parseOptions: TestOptions.Regular10, + targetFramework: TargetFramework.Net70).VerifyDiagnostics(); + CreateCompilation([source, UnscopedRefAttributeDefinition], + parseOptions: TestOptions.Regular11).VerifyDiagnostics(); + CreateCompilation([source, UnscopedRefAttributeDefinition]).VerifyDiagnostics(); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75828")] + public void UnscopedRefAttribute_RefSafetyRules_ScopedParameter() + { + var source = """ + using System.Diagnostics.CodeAnalysis; + struct S + { + public int F; + + public static ref int Ref([UnscopedRef] scoped ref S s) => ref s.F; + } + """; + CreateCompilation([source, UnscopedRefAttributeDefinition], + parseOptions: TestOptions.Regular10).VerifyDiagnostics( + // (6,32): warning CS9269: UnscopedRefAttribute is only valid in C# 11 or later or when targeting net7.0 or later. + // public static ref int Ref([UnscopedRef] scoped ref S s) => ref s.F; + Diagnostic(ErrorCode.WRN_UnscopedRefAttributeOldRules, "UnscopedRef").WithLocation(6, 32), + // (6,32): error CS9066: UnscopedRefAttribute cannot be applied to parameters that have a 'scoped' modifier. + // public static ref int Ref([UnscopedRef] scoped ref S s) => ref s.F; + Diagnostic(ErrorCode.ERR_UnscopedScoped, "UnscopedRef").WithLocation(6, 32), + // (6,45): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater. + // public static ref int Ref([UnscopedRef] scoped ref S s) => ref s.F; + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "scoped").WithArguments("ref fields", "11.0").WithLocation(6, 45), + // (6,68): error CS9076: Cannot return by reference a member of parameter 's' because it is scoped to the current method + // public static ref int Ref([UnscopedRef] scoped ref S s) => ref s.F; + Diagnostic(ErrorCode.ERR_RefReturnScopedParameter2, "s").WithArguments("s").WithLocation(6, 68)); + + CreateCompilation(source, + parseOptions: TestOptions.Regular10, + targetFramework: TargetFramework.Net70).VerifyDiagnostics( + // (6,32): error CS9066: UnscopedRefAttribute cannot be applied to parameters that have a 'scoped' modifier. + // public static ref int Ref([UnscopedRef] scoped ref S s) => ref s.F; + Diagnostic(ErrorCode.ERR_UnscopedScoped, "UnscopedRef").WithLocation(6, 32), + // (6,45): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater. + // public static ref int Ref([UnscopedRef] scoped ref S s) => ref s.F; + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "scoped").WithArguments("ref fields", "11.0").WithLocation(6, 45)); + + var expectedDiagnostics = new[] + { + // (6,32): error CS9066: UnscopedRefAttribute cannot be applied to parameters that have a 'scoped' modifier. + // public static ref int Ref([UnscopedRef] scoped ref S s) => ref s.F; + Diagnostic(ErrorCode.ERR_UnscopedScoped, "UnscopedRef").WithLocation(6, 32) + }; + + CreateCompilation([source, UnscopedRefAttributeDefinition], + parseOptions: TestOptions.Regular11).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation([source, UnscopedRefAttributeDefinition]).VerifyDiagnostics(expectedDiagnostics); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75828")] + public void UnscopedRefAttribute_RefSafetyRules_Reference() + { + var source1 = """ + using System.Diagnostics.CodeAnalysis; + public struct S + { + [UnscopedRef] public ref int Ref() => throw null; + } + """; + var ref1a = CreateCompilation([source1, UnscopedRefAttributeDefinition], + parseOptions: TestOptions.Regular10).VerifyDiagnostics( + // (4,6): warning CS9269: UnscopedRefAttribute is only valid in C# 11 or later or when targeting net7.0 or later. + // [UnscopedRef] public ref int Ref() => throw null; + Diagnostic(ErrorCode.WRN_UnscopedRefAttributeOldRules, "UnscopedRef").WithLocation(4, 6)).EmitToImageReference(); + var ref1b = CreateCompilation(source1, + parseOptions: TestOptions.Regular10, + targetFramework: TargetFramework.Net70).VerifyDiagnostics().EmitToImageReference(); + var ref1c = CreateCompilation([source1, UnscopedRefAttributeDefinition], + parseOptions: TestOptions.Regular11).VerifyDiagnostics().EmitToImageReference(); + var ref1d = CreateCompilation([source1, UnscopedRefAttributeDefinition]).VerifyDiagnostics().EmitToImageReference(); + + var source2 = """ + static class C + { + static ref int M() + { + S s = default; + return ref s.Ref(); + } + } + """; + CreateCompilation(source2, [ref1a], parseOptions: TestOptions.Regular10).VerifyDiagnostics(); + CreateCompilation(source2, [ref1a], parseOptions: TestOptions.Regular10, targetFramework: TargetFramework.Net70).VerifyDiagnostics(); + CreateCompilation(source2, [ref1a], parseOptions: TestOptions.Regular11).VerifyDiagnostics(); + CreateCompilation(source2, [ref1a]).VerifyDiagnostics(); + + foreach (var ref1 in new[] { ref1b, ref1c, ref1d }) + { + var expectedDiagnostics = new[] + { + // (6,20): error CS8168: Cannot return local 's' by reference because it is not a ref local + // return ref s.Ref(); + Diagnostic(ErrorCode.ERR_RefReturnLocal, "s").WithArguments("s").WithLocation(6, 20) + }; + + CreateCompilation(source2, [ref1], parseOptions: TestOptions.Regular10).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(source2, [ref1], parseOptions: TestOptions.Regular10, targetFramework: TargetFramework.Net70).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(source2, [ref1], parseOptions: TestOptions.Regular11).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(source2, [ref1]).VerifyDiagnostics(expectedDiagnostics); + } + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75828")] + public void UnscopedRefAttribute_RefSafetyRules_Reference_Property() + { + var source1 = """ + using System.Diagnostics.CodeAnalysis; + public struct S + { + [UnscopedRef] public ref int Ref => throw null; + } + """; + var ref1a = CreateCompilation([source1, UnscopedRefAttributeDefinition], + parseOptions: TestOptions.Regular10).VerifyDiagnostics( + // (4,6): warning CS9269: UnscopedRefAttribute is only valid in C# 11 or later or when targeting net7.0 or later. + // [UnscopedRef] public ref int Ref => throw null; + Diagnostic(ErrorCode.WRN_UnscopedRefAttributeOldRules, "UnscopedRef").WithLocation(4, 6)).EmitToImageReference(); + var ref1b = CreateCompilation(source1, + parseOptions: TestOptions.Regular10, + targetFramework: TargetFramework.Net70).VerifyDiagnostics().EmitToImageReference(); + var ref1c = CreateCompilation([source1, UnscopedRefAttributeDefinition], + parseOptions: TestOptions.Regular11).VerifyDiagnostics().EmitToImageReference(); + var ref1d = CreateCompilation([source1, UnscopedRefAttributeDefinition]).VerifyDiagnostics().EmitToImageReference(); + + var source2 = """ + static class C + { + static ref int M() + { + S s = default; + return ref s.Ref; + } + } + """; + CreateCompilation(source2, [ref1a], parseOptions: TestOptions.Regular10).VerifyDiagnostics(); + CreateCompilation(source2, [ref1a], parseOptions: TestOptions.Regular10, targetFramework: TargetFramework.Net70).VerifyDiagnostics(); + CreateCompilation(source2, [ref1a], parseOptions: TestOptions.Regular11).VerifyDiagnostics(); + CreateCompilation(source2, [ref1a]).VerifyDiagnostics(); + + foreach (var ref1 in new[] { ref1b, ref1c, ref1d }) + { + var expectedDiagnostics = new[] + { + // (6,20): error CS8168: Cannot return local 's' by reference because it is not a ref local + // return ref s.Ref(); + Diagnostic(ErrorCode.ERR_RefReturnLocal, "s").WithArguments("s").WithLocation(6, 20) + }; + + CreateCompilation(source2, [ref1], parseOptions: TestOptions.Regular10).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(source2, [ref1], parseOptions: TestOptions.Regular10, targetFramework: TargetFramework.Net70).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(source2, [ref1], parseOptions: TestOptions.Regular11).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(source2, [ref1]).VerifyDiagnostics(expectedDiagnostics); + } + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75828")] + public void UnscopedRefAttribute_RefSafetyRules_Reference_SynthesizedDelegate_01() + { + var source1 = """ + using System.Diagnostics.CodeAnalysis; + public static class C + { + public static void M([UnscopedRef] ref int x) { } + } + """; + var ref1 = CreateCompilation([source1, UnscopedRefAttributeDefinition]) + .VerifyDiagnostics().EmitToImageReference(); + + var source2 = """ + using System; + + Delegate d = C.M; + Console.WriteLine(d.GetType()); + """; + + var expectedOutput = "<>f__AnonymousDelegate0"; + + CompileAndVerify(source2, [ref1], + parseOptions: TestOptions.Regular10, + symbolValidator: validate, + expectedOutput: expectedOutput).VerifyDiagnostics(); + + CompileAndVerify(source2, [ref1], + symbolValidator: validate, + expectedOutput: expectedOutput).VerifyDiagnostics(); + + static void validate(ModuleSymbol module) + { + var m = module.GlobalNamespace.GetMember("<>f__AnonymousDelegate0.Invoke"); + AssertEx.Equal("void <>f__AnonymousDelegate0.Invoke(ref System.Int32 arg)", m.ToTestDisplayString()); + var a = m.Parameters[0].GetAttributes().Single().AttributeClass.ToTestDisplayString(); + AssertEx.Equal("System.Diagnostics.CodeAnalysis.UnscopedRefAttribute", a); + } + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75828")] + public void UnscopedRefAttribute_RefSafetyRules_Reference_SynthesizedDelegate_02() + { + var source1 = """ + using System.Diagnostics.CodeAnalysis; + public static class C + { + public static void M([UnscopedRef] ref int x) { } + } + """; + var ref1 = CreateCompilation([source1, UnscopedRefAttributeDefinition], + parseOptions: TestOptions.Regular10) + .VerifyDiagnostics( + // (4,27): warning CS9269: UnscopedRefAttribute is only valid in C# 11 or later or when targeting net7.0 or later. + // public static void M([UnscopedRef] ref int x) { } + Diagnostic(ErrorCode.WRN_UnscopedRefAttributeOldRules, "UnscopedRef").WithLocation(4, 27)) + .EmitToImageReference(); + + var source2 = """ + using System; + + Delegate d = C.M; + Console.WriteLine(d.GetType()); + """; + + var expectedOutput = "<>A{00000001}`1[System.Int32]"; + + var expectedDiagnostics = new[] + { + // (3,14): warning CS9073: The 'scoped' modifier of parameter 'x' doesn't match target ''. + // Delegate d = C.M; + Diagnostic(ErrorCode.WRN_ScopedMismatchInParameterOfTarget, "C.M").WithArguments("x", "").WithLocation(3, 14) + }; + + CompileAndVerify(source2, [ref1], + parseOptions: TestOptions.Regular10, + symbolValidator: validate, + expectedOutput: expectedOutput).VerifyDiagnostics(expectedDiagnostics); + + CompileAndVerify(source2, [ref1], + symbolValidator: validate, + expectedOutput: expectedOutput).VerifyDiagnostics(expectedDiagnostics); + + static void validate(ModuleSymbol module) + { + var m = module.GlobalNamespace.GetMember("<>A{00000001}.Invoke"); + AssertEx.Equal("void <>A{00000001}.Invoke(ref T1 arg)", m.ToTestDisplayString()); + Assert.Empty(m.Parameters[0].GetAttributes()); + } + } + + [Fact] + [WorkItem("https://github.com/dotnet/roslyn/issues/75828")] + [WorkItem("https://github.com/dotnet/roslyn/issues/76087")] + public void UnscopedRefAttribute_RefSafetyRules_Reference_SynthesizedDelegate_03() + { + var source1 = """ + using System.Diagnostics.CodeAnalysis; + public static class C + { + public static void M([UnscopedRef] ref int x, ref R r) + { + r.F = ref x; + } + } + public ref struct R + { + public ref int F; + } + """; + var ref1 = CreateCompilation(source1, targetFramework: TargetFramework.Net70) + .VerifyDiagnostics().EmitToImageReference(); + + var source2 = """ + int x = 1; + R r = default; + C.M(ref x, ref r); + var d = C.M; + d(ref x, ref r); + """; + // Should the delegate invocation be an error as well? https://github.com/dotnet/roslyn/issues/76087 + CreateCompilation([source2, UnscopedRefAttributeDefinition], [ref1], + parseOptions: TestOptions.Regular10).VerifyDiagnostics( + // (3,1): error CS8350: This combination of arguments to 'C.M(ref int, ref R)' is disallowed because it may expose variables referenced by parameter 'x' outside of their declaration scope + // C.M(ref x, ref r); + Diagnostic(ErrorCode.ERR_CallArgMixing, "C.M(ref x, ref r)").WithArguments("C.M(ref int, ref R)", "x").WithLocation(3, 1), + // (3,9): error CS8168: Cannot return local 'x' by reference because it is not a ref local + // C.M(ref x, ref r); + Diagnostic(ErrorCode.ERR_RefReturnLocal, "x").WithArguments("x").WithLocation(3, 9)); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75828")] + public void UnscopedRefAttribute_InvalidLocation_Parameter() + { + var source = """ + using System.Diagnostics.CodeAnalysis; + class C + { + ref T F1([UnscopedRef] R r) => throw null; + ref T F2([UnscopedRef] T r) => throw null; + } + ref struct R { } + """; + + CreateCompilation([source, UnscopedRefAttributeDefinition], + parseOptions: TestOptions.Regular10).VerifyDiagnostics( + // (4,18): warning CS9269: UnscopedRefAttribute is only valid in C# 11 or later or when targeting net7.0 or later. + // ref T F1([UnscopedRef] R r) => throw null; + Diagnostic(ErrorCode.WRN_UnscopedRefAttributeOldRules, "UnscopedRef").WithLocation(4, 18), + // (4,18): error CS9063: UnscopedRefAttribute cannot be applied to this parameter because it is unscoped by default. + // ref T F1([UnscopedRef] R r) => throw null; + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedTarget, "UnscopedRef").WithLocation(4, 18), + // (5,18): warning CS9269: UnscopedRefAttribute is only valid in C# 11 or later or when targeting net7.0 or later. + // ref T F2([UnscopedRef] T r) => throw null; + Diagnostic(ErrorCode.WRN_UnscopedRefAttributeOldRules, "UnscopedRef").WithLocation(5, 18), + // (5,18): error CS9063: UnscopedRefAttribute cannot be applied to this parameter because it is unscoped by default. + // ref T F2([UnscopedRef] T r) => throw null; + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedTarget, "UnscopedRef").WithLocation(5, 18)); + + var expectedDiagnostics = new[] + { + // (4,18): error CS9063: UnscopedRefAttribute cannot be applied to this parameter because it is unscoped by default. + // ref T F1([UnscopedRef] R r) => throw null; + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedTarget, "UnscopedRef").WithLocation(4, 18), + // (5,18): error CS9063: UnscopedRefAttribute cannot be applied to this parameter because it is unscoped by default. + // ref T F2([UnscopedRef] T r) => throw null; + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedTarget, "UnscopedRef").WithLocation(5, 18) + }; + + CreateCompilation(source, + parseOptions: TestOptions.Regular10, + targetFramework: TargetFramework.Net70).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation([source, UnscopedRefAttributeDefinition], + parseOptions: TestOptions.Regular11).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation([source, UnscopedRefAttributeDefinition]).VerifyDiagnostics(expectedDiagnostics); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75828")] + public void UnscopedRefAttribute_InvalidLocation_Method() + { + var source = """ + using System.Diagnostics.CodeAnalysis; + class C + { + [UnscopedRef] object F() => null; + } + """; + + CreateCompilation([source, UnscopedRefAttributeDefinition], + parseOptions: TestOptions.Regular10).VerifyDiagnostics( + // (4,6): warning CS9269: UnscopedRefAttribute is only valid in C# 11 or later or when targeting net7.0 or later. + // [UnscopedRef] object F() => null; + Diagnostic(ErrorCode.WRN_UnscopedRefAttributeOldRules, "UnscopedRef").WithLocation(4, 6), + // (4,6): error CS9101: UnscopedRefAttribute can only be applied to struct or virtual interface instance methods and properties, and cannot be applied to constructors or init-only members. + // [UnscopedRef] object F() => null; + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(4, 6)); + + var expectedDiagnostics = new[] + { + // (4,6): error CS9101: UnscopedRefAttribute can only be applied to struct or virtual interface instance methods and properties, and cannot be applied to constructors or init-only members. + // [UnscopedRef] object F() => null; + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(4, 6) + }; + + CreateCompilation(source, + parseOptions: TestOptions.Regular10, + targetFramework: TargetFramework.Net70).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation([source, UnscopedRefAttributeDefinition], + parseOptions: TestOptions.Regular11).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation([source, UnscopedRefAttributeDefinition]).VerifyDiagnostics(expectedDiagnostics); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75828")] + public void UnscopedRefAttribute_InvalidLocation_Property() + { + var source = """ + using System.Diagnostics.CodeAnalysis; + struct S + { + [UnscopedRef] object P { get; init; } + } + """; + + CreateCompilation([source, UnscopedRefAttributeDefinition, IsExternalInitTypeDefinition], + parseOptions: TestOptions.Regular10).VerifyDiagnostics( + // (4,6): warning CS9269: UnscopedRefAttribute is only valid in C# 11 or later or when targeting net7.0 or later. + // [UnscopedRef] object P { get; init; } + Diagnostic(ErrorCode.WRN_UnscopedRefAttributeOldRules, "UnscopedRef").WithLocation(4, 6), + // (4,6): error CS9101: UnscopedRefAttribute can only be applied to struct or virtual interface instance methods and properties, and cannot be applied to constructors or init-only members. + // [UnscopedRef] object P { get; init; } + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(4, 6)); + + var expectedDiagnostics = new[] + { + // (4,6): error CS9101: UnscopedRefAttribute can only be applied to struct or virtual interface instance methods and properties, and cannot be applied to constructors or init-only members. + // [UnscopedRef] object P { get; init; } + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(4, 6) + }; + + CreateCompilation(source, + parseOptions: TestOptions.Regular10, + targetFramework: TargetFramework.Net70).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation([source, UnscopedRefAttributeDefinition, IsExternalInitTypeDefinition], + parseOptions: TestOptions.Regular11).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation([source, UnscopedRefAttributeDefinition, IsExternalInitTypeDefinition]).VerifyDiagnostics(expectedDiagnostics); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/76087")] + public void RefSafetyRules_SynthesizedDelegate() + { + var source1 = """ + public static class C + { + public static R M(ref int x) => new R { F = ref x }; + } + public ref struct R + { + public ref int F; + } + """; + var ref1 = CreateCompilation(source1, targetFramework: TargetFramework.Net70) + .VerifyDiagnostics().EmitToImageReference(); + + var source2 = """ + R r; + { + int x = 1; + r = C.M(ref x); + + var d = C.M; + r = d(ref x); + } + """; + // Should the delegate invocation be an error as well? https://github.com/dotnet/roslyn/issues/76087 + CreateCompilation(source2, [ref1], parseOptions: TestOptions.Regular10).VerifyDiagnostics( + // (4,9): error CS8347: Cannot use a result of 'C.M(ref int)' in this context because it may expose variables referenced by parameter 'x' outside of their declaration scope + // r = C.M(ref x); + Diagnostic(ErrorCode.ERR_EscapeCall, "C.M(ref x)").WithArguments("C.M(ref int)", "x").WithLocation(4, 9), + // (4,17): error CS8168: Cannot return local 'x' by reference because it is not a ref local + // r = C.M(ref x); + Diagnostic(ErrorCode.ERR_RefReturnLocal, "x").WithArguments("x").WithLocation(4, 17)); + } + [Theory] [InlineData("struct")] [InlineData("ref struct")] @@ -24835,25 +25419,35 @@ static void F5([UnscopedRef] out R r5) { } else { comp.VerifyEmitDiagnostics( - // (10,21): error CS9063: UnscopedRefAttribute cannot be applied to this parameter because it is unscoped by default. + // (5,6): warning CS9269: UnscopedRefAttribute is only valid in C# 11 or later or when targeting net7.0 or later. + // [UnscopedRef] ref int F() => throw null; + Diagnostic(ErrorCode.WRN_UnscopedRefAttributeOldRules, "UnscopedRef").WithLocation(5, 6), + // (6,6): warning CS9269: UnscopedRefAttribute is only valid in C# 11 or later or when targeting net7.0 or later. + // [UnscopedRef] ref int P => throw null; + Diagnostic(ErrorCode.WRN_UnscopedRefAttributeOldRules, "UnscopedRef").WithLocation(6, 6), + // (10,21): warning CS9269: UnscopedRefAttribute is only valid in C# 11 or later or when targeting net7.0 or later. // static void F1([UnscopedRef] out int i1) { i1 = 0; } - Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedTarget, "UnscopedRef").WithLocation(10, 21), + Diagnostic(ErrorCode.WRN_UnscopedRefAttributeOldRules, "UnscopedRef").WithLocation(10, 21), + // (11,21): warning CS9269: UnscopedRefAttribute is only valid in C# 11 or later or when targeting net7.0 or later. + // static void F2([UnscopedRef] R r2) { } + Diagnostic(ErrorCode.WRN_UnscopedRefAttributeOldRules, "UnscopedRef").WithLocation(11, 21), // (11,21): error CS9063: UnscopedRefAttribute cannot be applied to this parameter because it is unscoped by default. // static void F2([UnscopedRef] R r2) { } Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedTarget, "UnscopedRef").WithLocation(11, 21), - // (12,21): error CS9063: UnscopedRefAttribute cannot be applied to this parameter because it is unscoped by default. + // (12,21): warning CS9269: UnscopedRefAttribute is only valid in C# 11 or later or when targeting net7.0 or later. // static void F3([UnscopedRef] ref R r3) { } - Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedTarget, "UnscopedRef").WithLocation(12, 21), - // (13,21): error CS9063: UnscopedRefAttribute cannot be applied to this parameter because it is unscoped by default. + Diagnostic(ErrorCode.WRN_UnscopedRefAttributeOldRules, "UnscopedRef").WithLocation(12, 21), + // (13,21): warning CS9269: UnscopedRefAttribute is only valid in C# 11 or later or when targeting net7.0 or later. // static void F4([UnscopedRef] in R r4) { } - Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedTarget, "UnscopedRef").WithLocation(13, 21), - // (14,21): error CS9063: UnscopedRefAttribute cannot be applied to this parameter because it is unscoped by default. + Diagnostic(ErrorCode.WRN_UnscopedRefAttributeOldRules, "UnscopedRef").WithLocation(13, 21), + // (14,21): warning CS9269: UnscopedRefAttribute is only valid in C# 11 or later or when targeting net7.0 or later. // static void F5([UnscopedRef] out R r5) { } - Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedTarget, "UnscopedRef").WithLocation(14, 21)); + Diagnostic(ErrorCode.WRN_UnscopedRefAttributeOldRules, "UnscopedRef").WithLocation(14, 21)); } - VerifyParameterSymbol(comp.GetMember("S.F").ThisParameter, "ref S this", RefKind.Ref, ScopedKind.None, expectedHasUnscopedRefAttribute: true); - VerifyParameterSymbol(comp.GetMember("S.P").GetMethod.ThisParameter, "ref S this", RefKind.Ref, ScopedKind.None, expectedHasUnscopedRefAttribute: true); + var scopedRefInCSharp10 = languageVersion == LanguageVersion.CSharp11 ? ScopedKind.None : ScopedKind.ScopedRef; + VerifyParameterSymbol(comp.GetMember("S.F").ThisParameter, "ref S this", RefKind.Ref, scopedRefInCSharp10, expectedHasUnscopedRefAttribute: true); + VerifyParameterSymbol(comp.GetMember("S.P").GetMethod.ThisParameter, "ref S this", RefKind.Ref, scopedRefInCSharp10, expectedHasUnscopedRefAttribute: true); VerifyParameterSymbol(comp.GetMember("Program.F1").Parameters[0], "out System.Int32 i1", RefKind.Out, ScopedKind.None, expectedHasUnscopedRefAttribute: true); VerifyParameterSymbol(comp.GetMember("Program.F2").Parameters[0], "R r2", RefKind.None, ScopedKind.None, expectedHasUnscopedRefAttribute: true); VerifyParameterSymbol(comp.GetMember("Program.F3").Parameters[0], "ref R r3", RefKind.Ref, ScopedKind.None, expectedHasUnscopedRefAttribute: true); @@ -25608,9 +26202,12 @@ [UnscopedRef] void I.F2() { } comp.VerifyEmitDiagnostics(); } - [Fact] + [Theory] + [InlineData(LanguageVersion.Preview)] + [InlineData(LanguageVersion.CSharp13)] + [InlineData(LanguageVersion.CSharp12)] [WorkItem(64508, "https://github.com/dotnet/roslyn/issues/64508")] - public void UnscopedRefAttribute_InterfaceImplementation_03() + public void UnscopedRefAttribute_InterfaceImplementation_03(LanguageVersion langVersion) { string source = """ using System.Diagnostics.CodeAnalysis; @@ -25642,7 +26239,7 @@ struct S3 : I2, I3 public int P3 { [UnscopedRef] set { } } // 7 } """; - var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70); + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular.WithLanguageVersion(langVersion), targetFramework: TargetFramework.Net70); comp.VerifyEmitDiagnostics( // (16,40): error CS9102: UnscopedRefAttribute cannot be applied to an interface implementation because implemented member 'I1.P1.get' doesn't have this attribute. // [UnscopedRef] public ref int P1 => throw null; // 1 diff --git a/src/Compilers/CSharp/Test/Symbol/DocumentationComments/CrefTests.cs b/src/Compilers/CSharp/Test/Symbol/DocumentationComments/CrefTests.cs index 68e18c40b7ee3..660bdec42dad4 100644 --- a/src/Compilers/CSharp/Test/Symbol/DocumentationComments/CrefTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/DocumentationComments/CrefTests.cs @@ -5564,7 +5564,7 @@ class C Assert.IsType(crefTypeParam.GetSymbol()); var sourceTypeParam = referencedType.TypeParameters.Single(); - Assert.IsType(sourceTypeParam.GetSymbol()); + Assert.IsType(sourceTypeParam.GetSymbol()); Assert.NotEqual(crefTypeParam, sourceTypeParam); Assert.NotEqual(sourceTypeParam, crefTypeParam); diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/LocalFunctionTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/LocalFunctionTests.cs index fc44f296c1a3d..06ba893283b7c 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/LocalFunctionTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/LocalFunctionTests.cs @@ -524,5 +524,153 @@ public static void M() { } Assert.Equal("void C.M()", symbol.ToTestDisplayString()); Assert.Equal("C", symbol.ContainingSymbol.ToTestDisplayString()); } + + [Fact] + public void CompilerLoweringPreserveAttribute_01() + { + string source1 = @" +using System; +using System.Runtime.CompilerServices; + +[CompilerLoweringPreserve] +[AttributeUsage(AttributeTargets.GenericParameter)] +public class Preserve1Attribute : Attribute { } + +[AttributeUsage(AttributeTargets.GenericParameter)] +public class Preserve2Attribute : Attribute { } +"; + + string source2 = @" +class Test1 +{ + System.Func M2<[Preserve1][Preserve2]T>(T x) + { + return local; + T local() => x; + } +} +"; + var comp1 = CreateCompilation([source1, source2, CompilerLoweringPreserveAttributeDefinition]); + CompileAndVerify(comp1, symbolValidator: validate).VerifyDiagnostics(); + + static void validate(ModuleSymbol m) + { + AssertEx.SequenceEqual( + ["Preserve1Attribute"], + m.GlobalNamespace.GetMember("Test1.<>c__DisplayClass0_0").TypeParameters.Single().GetAttributes().Select(a => a.ToString())); + } + } + + [Fact] + public void CompilerLoweringPreserveAttribute_02() + { + string source1 = @" +using System; + +[AttributeUsage(AttributeTargets.GenericParameter)] +public class Preserve1Attribute : Attribute { } +"; + + string source2 = @" +class Test1 +{ + System.Func M2() + { + return local; + T local<[Preserve1]T>(T x) => x; + } +} +"; + var comp1 = CreateCompilation([source1, source2], options: TestOptions.DebugDll.WithMetadataImportOptions(MetadataImportOptions.All)); + CompileAndVerify(comp1, symbolValidator: validate).VerifyDiagnostics(); + + static void validate(ModuleSymbol m) + { + AssertEx.SequenceEqual( + ["Preserve1Attribute"], + m.GlobalNamespace.GetMember("Test1.g__local|0_0").TypeParameters.Single().GetAttributes().Select(a => a.ToString())); + } + } + + [Fact] + public void CompilerLoweringPreserveAttribute_03() + { + string source1 = @" +using System; +using System.Runtime.CompilerServices; + +[CompilerLoweringPreserve] +[AttributeUsage(AttributeTargets.GenericParameter)] +public class Preserve1Attribute : Attribute { } + +[AttributeUsage(AttributeTargets.GenericParameter)] +public class Preserve2Attribute : Attribute { } +"; + + string source2 = @" +class Test1 +{ + void M2<[Preserve1][Preserve2]T>(T x) + { + local(); + void local() => x.ToString(); + } +} +"; + var comp1 = CreateCompilation([source1, source2, CompilerLoweringPreserveAttributeDefinition], options: TestOptions.DebugDll.WithMetadataImportOptions(MetadataImportOptions.All)); + CompileAndVerify(comp1, symbolValidator: validate).VerifyDiagnostics(); + + static void validate(ModuleSymbol m) + { + AssertEx.SequenceEqual( + ["Preserve1Attribute"], + m.GlobalNamespace.GetMember("Test1.<>c__DisplayClass0_0").TypeParameters.Single().GetAttributes().Select(a => a.ToString())); + AssertEx.SequenceEqual( + ["Preserve1Attribute", "Preserve2Attribute"], + m.GlobalNamespace.GetMember("Test1.g__local|0_0").TypeParameters.Single().GetAttributes().Select(a => a.ToString())); + } + } + + [Fact] + public void CompilerLoweringPreserveAttribute_04() + { + string source1 = @" +using System; +using System.Runtime.CompilerServices; + +[CompilerLoweringPreserve] +[AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter)] +public class Preserve1Attribute : Attribute { } + +[CompilerLoweringPreserve] +[AttributeUsage(AttributeTargets.Parameter)] +public class Preserve2Attribute : Attribute { } + +[AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter)] +public class Preserve3Attribute : Attribute { } +"; + + string source2 = @" +class Test1 +{ + System.Func M2([Preserve1][Preserve2][Preserve3]int x) + { + return local; + int local() => x; + } +} +"; + var comp1 = CreateCompilation( + [source1, source2, CompilerLoweringPreserveAttributeDefinition], + options: TestOptions.DebugDll.WithMetadataImportOptions(MetadataImportOptions.All)); + CompileAndVerify(comp1, symbolValidator: validate).VerifyDiagnostics(); + + static void validate(ModuleSymbol m) + { + AssertEx.SequenceEqual( + ["Preserve1Attribute"], + m.GlobalNamespace.GetMember("Test1.<>c__DisplayClass0_0.x").GetAttributes().Select(a => a.ToString())); + } + } } } diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/MockNamedTypeSymbol.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/MockNamedTypeSymbol.cs index d4b933a157acd..854eed416473e 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/MockNamedTypeSymbol.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/MockNamedTypeSymbol.cs @@ -265,6 +265,8 @@ internal override ImmutableArray GetDeclaredInterfaces(ConsList internal override bool HasCodeAnalysisEmbeddedAttribute => false; + internal override bool HasCompilerLoweringPreserveAttribute => false; + internal sealed override ManagedKind GetManagedKind(ref CompoundUseSiteInfo useSiteInfo) => ManagedKind.Managed; internal override bool ShouldAddWinRTMembers diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/RequiredMembersTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/RequiredMembersTests.cs index 4f68a2f3315f3..996ecaa302bdd 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/RequiredMembersTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/RequiredMembersTests.cs @@ -5820,6 +5820,697 @@ public Derived() : base() { } ); } + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/74423")] + public void SetsRequiredMembersHonoredForPropertyOverride_01() + { + var code = """ + #nullable enable + using System.Diagnostics.CodeAnalysis; + + public abstract class Base + { + [SetsRequiredMembers] + public Base(string str) + { + this.Str = str; + } + + public required abstract string Str { get; set; } + } + + public class Derived : Base + { + [SetsRequiredMembers] + public Derived(string str) : base(str) + { + } + + public override required string Str { get; set; } + } + """; + + var comp = CreateCompilationWithRequiredMembers(code); + comp.VerifyDiagnostics(); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/74423")] + public void SetsRequiredMembersHonoredForPropertyOverride_02() + { + var code = """ + #nullable enable + using System.Diagnostics.CodeAnalysis; + + public abstract class Base + { + [SetsRequiredMembers] + public Base(string str) + { + } + + public required virtual string Str { get; set; } = ""; + } + + public class Derived : Base + { + [SetsRequiredMembers] + public Derived(string str) : base(str) + { + } + + public override required string Str { get; set; } + } + """; + + var comp = CreateCompilationWithRequiredMembers(code); + comp.VerifyDiagnostics( + // (17,12): warning CS8618: Non-nullable property 'Str' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the property as nullable. + // public Derived(string str) : base(str) + Diagnostic(ErrorCode.WRN_UninitializedNonNullableField, "Derived").WithArguments("property", "Str").WithLocation(17, 12) + ); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/74423")] + public void SetsRequiredMembersHonoredForPropertyOverride_03() + { + var code = """ + #nullable enable + using System.Diagnostics.CodeAnalysis; + + public abstract class Base + { + [SetsRequiredMembers] + public Base(string str) + { + } + + public required abstract string Str { get; set; } + } + + public class Derived : Base + { + [SetsRequiredMembers] + public Derived(string str) : base(str) + { + } + + public override required string Str { get; set; } + } + """; + + var comp = CreateCompilationWithRequiredMembers(code); + comp.VerifyDiagnostics( + // (7,12): warning CS8618: Non-nullable property 'Str' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the property as nullable. + // public Base(string str) + Diagnostic(ErrorCode.WRN_UninitializedNonNullableField, "Base").WithArguments("property", "Str").WithLocation(7, 12) + ); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/74423")] + public void SetsRequiredMembersHonoredForPropertyOverride_04() + { + var code = """ + #nullable enable + using System.Diagnostics.CodeAnalysis; + + public abstract class Base + { + public Base(string str) + { + } + + public required abstract string Str { get; set; } + } + + public class Derived : Base + { + [SetsRequiredMembers] + public Derived(string str) : base(str) + { + } + + public override required string Str { get; set; } + } + """; + + var comp = CreateCompilationWithRequiredMembers(code); + comp.VerifyDiagnostics( + // (16,12): warning CS8618: Non-nullable property 'Str' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the property as nullable. + // public Derived(string str) : base(str) + Diagnostic(ErrorCode.WRN_UninitializedNonNullableField, "Derived").WithArguments("property", "Str").WithLocation(16, 12) + ); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/74423")] + public void SetsRequiredMembersHonoredForPropertyOverride_05() + { + var code = """ + #nullable enable + using System.Diagnostics.CodeAnalysis; + + public abstract class Base + { + public Base() + { + } + + public required abstract string Str { get; set; } + } + + public class Derived : Base + { + [SetsRequiredMembers] + public Derived(string str) : base() + { + this.Str = str; + } + + public override required string Str { get; set; } + } + """; + + var comp = CreateCompilationWithRequiredMembers(code); + comp.VerifyDiagnostics(); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/74423")] + public void SetsRequiredMembersHonoredForPropertyOverride_06() + { + var code = """ + #nullable enable + using System.Diagnostics.CodeAnalysis; + + public abstract class Base + { + public Base() + { + } + + public required abstract string Str { get; set; } + } + + public class Derived : Base + { + public Derived() : base() + { + } + + public override required string Str { get; set; } + } + + public class DerivedDerived : Derived + { + [SetsRequiredMembers] + public DerivedDerived(string str) : base() + { + } + + public override required string Str { get; set; } + } + """; + + var comp = CreateCompilationWithRequiredMembers(code); + comp.VerifyDiagnostics( + // (25,12): warning CS8618: Non-nullable property 'Str' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the property as nullable. + // public DerivedDerived(string str) : base() + Diagnostic(ErrorCode.WRN_UninitializedNonNullableField, "DerivedDerived").WithArguments("property", "Str").WithLocation(25, 12), + // (25,12): warning CS8618: Non-nullable property 'Str' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the property as nullable. + // public DerivedDerived(string str) : base() + Diagnostic(ErrorCode.WRN_UninitializedNonNullableField, "DerivedDerived").WithArguments("property", "Str").WithLocation(25, 12) + ); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/74423")] + public void SetsRequiredMembersHonoredForPropertyOverride_07() + { + var code = """ + #nullable enable + using System.Diagnostics.CodeAnalysis; + + public abstract class Base + { + public Base() + { + } + + public required abstract string Str { get; set; } + } + + public class Derived : Base + { + public Derived() : base() + { + } + + public override required string Str { get; set; } + } + + public class DerivedDerived : Derived + { + [SetsRequiredMembers] + public DerivedDerived(string str) : base() + { + } + } + """; + + var comp = CreateCompilationWithRequiredMembers(code); + comp.VerifyDiagnostics( + // (25,12): warning CS8618: Non-nullable property 'Str' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the property as nullable. + // public DerivedDerived(string str) : base() + Diagnostic(ErrorCode.WRN_UninitializedNonNullableField, "DerivedDerived").WithArguments("property", "Str").WithLocation(25, 12) + ); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/74423")] + public void SetsRequiredMembersHonoredForPropertyOverride_08() + { + var code = """ + #nullable enable + using System.Diagnostics.CodeAnalysis; + + public abstract class Base + { + [SetsRequiredMembers] + public Base(string str) + { + this.Str = str; + } + + public required abstract string? Str { get; set; } + } + + public class Derived : Base + { + [SetsRequiredMembers] + public Derived(string str) : base(str) + { + } + + public override required string Str { get; set; } + } + """; + + var comp = CreateCompilationWithRequiredMembers([code, NotNullAttributeDefinition, DisallowNullAttributeDefinition]); + comp.VerifyDiagnostics( + // (18,12): warning CS8618: Non-nullable property 'Str' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the property as nullable. + // public Derived(string str) : base(str) + Diagnostic(ErrorCode.WRN_UninitializedNonNullableField, "Derived").WithArguments("property", "Str").WithLocation(18, 12), + // (22,48): warning CS8765: Nullability of type of parameter 'value' doesn't match overridden member (possibly because of nullability attributes). + // public override required string Str { get; set; } + Diagnostic(ErrorCode.WRN_TopLevelNullabilityMismatchInParameterTypeOnOverride, "set").WithArguments("value").WithLocation(22, 48) + ); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/74423")] + public void SetsRequiredMembersHonoredForPropertyOverride_09() + { + var code = """ + #nullable enable + using System.Diagnostics.CodeAnalysis; + + public abstract class Base + { + [SetsRequiredMembers] + public Base(string str) + { + this.Str = str; + } + + public required abstract string Str { get; set; } + } + + public class Derived : Base + { + [SetsRequiredMembers] + public Derived(string str) : base(str) + { + } + + public override required string? Str { get; set; } + } + """; + + var comp = CreateCompilationWithRequiredMembers([code, MaybeNullAttributeDefinition, AllowNullAttributeDefinition]); + comp.VerifyDiagnostics( + // (22,44): warning CS8764: Nullability of return type doesn't match overridden member (possibly because of nullability attributes). + // public override required string Str { get; set; } + Diagnostic(ErrorCode.WRN_TopLevelNullabilityMismatchInReturnTypeOnOverride, "get").WithLocation(22, 44) + ); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/74423")] + public void SetsRequiredMembersHonoredForPropertyOverride_10() + { + var code = """ + #nullable enable + using System.Diagnostics.CodeAnalysis; + + public abstract class Base + { + [SetsRequiredMembers] + public Base(string str) + { + this.Str = str; + } + + public required abstract string? Str { get; set; } + } + + public class Derived : Base + { + [SetsRequiredMembers] + public Derived(string str) : base(str) + { + } + + [NotNull, DisallowNull] + public override required string? Str { get; set; } + } + """; + + var comp = CreateCompilationWithRequiredMembers([code, NotNullAttributeDefinition, DisallowNullAttributeDefinition]); + comp.VerifyDiagnostics( + // (18,12): warning CS8618: Non-nullable property 'Str' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the property as nullable. + // public Derived(string str) : base(str) + Diagnostic(ErrorCode.WRN_UninitializedNonNullableField, "Derived").WithArguments("property", "Str").WithLocation(18, 12), + // (23,49): warning CS8765: Nullability of type of parameter 'value' doesn't match overridden member (possibly because of nullability attributes). + // public override required string? Str { get; set; } + Diagnostic(ErrorCode.WRN_TopLevelNullabilityMismatchInParameterTypeOnOverride, "set").WithArguments("value").WithLocation(23, 49) + ); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/74423")] + public void SetsRequiredMembersHonoredForPropertyOverride_11() + { + var code = """ + #nullable enable + using System.Diagnostics.CodeAnalysis; + + public abstract class Base + { + [SetsRequiredMembers] + public Base(string str) + { + this.Str = str; + } + + public required abstract string Str { get; set; } + } + + public class Derived : Base + { + [SetsRequiredMembers] + public Derived(string str) : base(str) + { + } + + [MaybeNull, AllowNull] + public override required string Str { get; set; } + } + """; + + var comp = CreateCompilationWithRequiredMembers([code, MaybeNullAttributeDefinition, AllowNullAttributeDefinition]); + comp.VerifyDiagnostics( + // (23,43): warning CS8764: Nullability of return type doesn't match overridden member (possibly because of nullability attributes). + // public override required string Str { get; set; } + Diagnostic(ErrorCode.WRN_TopLevelNullabilityMismatchInReturnTypeOnOverride, "get").WithLocation(23, 43) + ); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/74423")] + public void SetsRequiredMembersHonoredForPropertyOverride_12() + { + var code = """ + #nullable enable + using System.Diagnostics.CodeAnalysis; + + public abstract class Base + { + public required abstract string Str { get; set; } + } + + public abstract class Derived : Base + { + [SetsRequiredMembers] + public Derived(string str) + { + Str = str; + } + + public abstract override required string Str { get; set; } + } + + public class DerivedDerived : Derived + { + [SetsRequiredMembers] + public DerivedDerived(string str) : base(str) + { + } + + public override required string Str { get; set; } + } + """; + + var comp = CreateCompilationWithRequiredMembers([code, MaybeNullAttributeDefinition, AllowNullAttributeDefinition]); + comp.VerifyDiagnostics( + ); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/74423")] + public void SetsRequiredMembersHonoredForPropertyOverride_13() + { + var code = """ + #nullable enable + using System.Diagnostics.CodeAnalysis; + + public abstract class Base + { + public required virtual string Str { get; set; } + } + + public class Derived : Base + { + [SetsRequiredMembers] + public Derived(string str) + { + } + + public override required string Str { get; set; } + } + """; + + var comp = CreateCompilationWithRequiredMembers(code); + comp.VerifyDiagnostics( + // (12,12): warning CS8618: Non-nullable property 'Str' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the property as nullable. + // public Derived(string str) + Diagnostic(ErrorCode.WRN_UninitializedNonNullableField, "Derived").WithArguments("property", "Str").WithLocation(12, 12), + // (12,12): warning CS8618: Non-nullable property 'Str' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the property as nullable. + // public Derived(string str) + Diagnostic(ErrorCode.WRN_UninitializedNonNullableField, "Derived").WithArguments("property", "Str").WithLocation(12, 12) + ); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/74423")] + public void SetsRequiredMembersHonoredForPropertyOverride_13A() + { + var code = """ + #nullable enable + using System.Diagnostics.CodeAnalysis; + + public abstract class Base + { + public required virtual string Str { get; set; } + } + + public class Derived : Base + { + [SetsRequiredMembers] + public Derived(string str) + { + Str = str; + base.Str = str; + } + + public override required string Str { get; set; } + } + """; + + var comp = CreateCompilationWithRequiredMembers(code); + comp.VerifyDiagnostics(); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/74423")] + public void SetsRequiredMembersHonoredForPropertyOverride_14() + { + var code = """ + #nullable enable + using System.Diagnostics.CodeAnalysis; + + public abstract class Base + { + public virtual string Str { get; set; } + } + + public class Derived : Base + { + [SetsRequiredMembers] + public Derived(string str) + { + } + + public override required string Str { get; set; } + } + """; + + var comp = CreateCompilationWithRequiredMembers(code); + comp.VerifyDiagnostics( + // (6,27): warning CS8618: Non-nullable property 'Str' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the property as nullable. + // public virtual string Str { get; set; } + Diagnostic(ErrorCode.WRN_UninitializedNonNullableField, "Str").WithArguments("property", "Str").WithLocation(6, 27), + // (12,12): warning CS8618: Non-nullable property 'Str' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the property as nullable. + // public Derived(string str) + Diagnostic(ErrorCode.WRN_UninitializedNonNullableField, "Derived").WithArguments("property", "Str").WithLocation(12, 12) + ); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/74423")] + public void SetsRequiredMembersHonoredForPropertyOverride_15() + { + var code = """ + #nullable enable + using System.Diagnostics.CodeAnalysis; + + public abstract class Base + { + public abstract string Str { get; set; } + } + + public class Derived : Base + { + [SetsRequiredMembers] + public Derived(string str) + { + } + + public override required string Str { get; set; } + } + """; + + var comp = CreateCompilationWithRequiredMembers(code); + comp.VerifyDiagnostics( + // (12,12): warning CS8618: Non-nullable property 'Str' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the property as nullable. + // public Derived(string str) + Diagnostic(ErrorCode.WRN_UninitializedNonNullableField, "Derived").WithArguments("property", "Str").WithLocation(12, 12) + ); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/74423")] + public void SetsRequiredMembersHonoredForPropertyOverride_16() + { + var code = """ + #nullable enable + using System.Diagnostics.CodeAnalysis; + + public abstract class Base + { + [SetsRequiredMembers] + public Base(string str) + { + } + + public virtual string Str { get; set; } + } + + public class Derived : Base + { + [SetsRequiredMembers] + public Derived(string str) : base(str) + { + } + + public override required string Str { get; set; } + } + """; + + var comp = CreateCompilationWithRequiredMembers(code); + comp.VerifyDiagnostics( + // (7,12): warning CS8618: Non-nullable property 'Str' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the property as nullable. + // public Base(string str) + Diagnostic(ErrorCode.WRN_UninitializedNonNullableField, "Base").WithArguments("property", "Str").WithLocation(7, 12), + // (17,12): warning CS8618: Non-nullable property 'Str' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the property as nullable. + // public Derived(string str) : base(str) + Diagnostic(ErrorCode.WRN_UninitializedNonNullableField, "Derived").WithArguments("property", "Str").WithLocation(17, 12) + ); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/74423")] + public void SetsRequiredMembersHonoredForPropertyOverride_17() + { + var code = """ + #nullable enable + using System.Diagnostics.CodeAnalysis; + + public abstract class Base + { + [SetsRequiredMembers] + public Base(string str) + { + } + + public abstract string Str { get; set; } + } + + public class Derived : Base + { + [SetsRequiredMembers] + public Derived(string str) : base(str) + { + } + + public override required string Str { get; set; } + } + """; + + var comp = CreateCompilationWithRequiredMembers(code); + comp.VerifyDiagnostics( + ); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/74423")] + public void SetsRequiredMembersHonoredForPropertyOverride_18() + { + var code = """ + #nullable enable + using System.Diagnostics.CodeAnalysis; + + public abstract class Base + { + [SetsRequiredMembers] + public Base(string str) + { + this.Str = str; + } + + public required abstract string? Str { get; set; } + } + + public class Derived : Base + { + [SetsRequiredMembers] + public Derived(string str) : base(str) + { + } + + [AllowNull] + public override required string Str { get; set; } + } + """; + + var comp = CreateCompilationWithRequiredMembers([code, AllowNullAttributeDefinition]); + comp.VerifyDiagnostics( + ); + } + [Fact] public void SetsRequiredMembersAppliedToRecordCopyConstructor_DeclaredInType() { diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/Retargeting/RetargetingTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/Retargeting/RetargetingTests.cs index 4cef4ac1db904..7132b52637a15 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/Retargeting/RetargetingTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/Retargeting/RetargetingTests.cs @@ -666,7 +666,7 @@ public void RetargetingUnmanagedTypeParameters(string code, bool isUnmanaged) var compilation = CreateCompilation(code).VerifyDiagnostics(); var sourceAssembly = (SourceAssemblySymbol)compilation.Assembly; - SourceTypeParameterSymbol sourceTypeParameter = (SourceTypeParameterSymbol)sourceAssembly.GlobalNamespace.GetTypeMember("Test").TypeParameters.Single(); + SourceTypeTypeParameterSymbol sourceTypeParameter = (SourceTypeTypeParameterSymbol)sourceAssembly.GlobalNamespace.GetTypeMember("Test").TypeParameters.Single(); Assert.Equal(isUnmanaged, sourceTypeParameter.HasUnmanagedTypeConstraint); var retargetingAssembly = new RetargetingAssemblySymbol(sourceAssembly, isLinked: false); diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/Source/EventTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/Source/EventTests.cs index d94401d821679..36851ee503cf4 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/Source/EventTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/Source/EventTests.cs @@ -2487,5 +2487,283 @@ class Test } #endregion + + [Fact] + public void CompilerLoweringPreserveAttribute_01() + { + string source1 = @" +using System; +using System.Runtime.CompilerServices; + +[CompilerLoweringPreserve] +[AttributeUsage(AttributeTargets.Field | AttributeTargets.Event)] +public class Preserve1Attribute : Attribute { } +"; + + string source2 = @" +public class Test1 +{ +#pragma warning disable CS0067 // The event 'Test1.E1' is never used + [Preserve1] + public event System.Action E1; +} +"; + var comp1 = CreateCompilation( + [source1, source2, CompilerLoweringPreserveAttributeDefinition], + options: TestOptions.DebugDll.WithMetadataImportOptions(MetadataImportOptions.All)); + var verifier = CompileAndVerify(comp1).VerifyDiagnostics(); + + verifier.VerifyTypeIL("Test1", @" +.class public auto ansi beforefieldinit Test1 + extends [netstandard]System.Object +{ + // Fields + .field private class [netstandard]System.Action E1 + .custom instance void [netstandard]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( + 01 00 00 00 + ) + .custom instance void [netstandard]System.Diagnostics.DebuggerBrowsableAttribute::.ctor(valuetype [netstandard]System.Diagnostics.DebuggerBrowsableState) = ( + 01 00 00 00 00 00 00 00 + ) + // Methods + .method public hidebysig specialname + instance void add_E1 ( + class [netstandard]System.Action 'value' + ) cil managed + { + .custom instance void [netstandard]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( + 01 00 00 00 + ) + // Method begins at RVA 0x206c + // Code size 41 (0x29) + .maxstack 3 + .locals init ( + [0] class [netstandard]System.Action, + [1] class [netstandard]System.Action, + [2] class [netstandard]System.Action + ) + IL_0000: ldarg.0 + IL_0001: ldfld class [netstandard]System.Action Test1::E1 + IL_0006: stloc.0 + // loop start (head: IL_0007) + IL_0007: ldloc.0 + IL_0008: stloc.1 + IL_0009: ldloc.1 + IL_000a: ldarg.1 + IL_000b: call class [netstandard]System.Delegate [netstandard]System.Delegate::Combine(class [netstandard]System.Delegate, class [netstandard]System.Delegate) + IL_0010: castclass [netstandard]System.Action + IL_0015: stloc.2 + IL_0016: ldarg.0 + IL_0017: ldflda class [netstandard]System.Action Test1::E1 + IL_001c: ldloc.2 + IL_001d: ldloc.1 + IL_001e: call !!0 [netstandard]System.Threading.Interlocked::CompareExchange(!!0&, !!0, !!0) + IL_0023: stloc.0 + IL_0024: ldloc.0 + IL_0025: ldloc.1 + IL_0026: bne.un.s IL_0007 + // end loop + IL_0028: ret + } // end of method Test1::add_E1 + .method public hidebysig specialname + instance void remove_E1 ( + class [netstandard]System.Action 'value' + ) cil managed + { + .custom instance void [netstandard]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( + 01 00 00 00 + ) + // Method begins at RVA 0x20a4 + // Code size 41 (0x29) + .maxstack 3 + .locals init ( + [0] class [netstandard]System.Action, + [1] class [netstandard]System.Action, + [2] class [netstandard]System.Action + ) + IL_0000: ldarg.0 + IL_0001: ldfld class [netstandard]System.Action Test1::E1 + IL_0006: stloc.0 + // loop start (head: IL_0007) + IL_0007: ldloc.0 + IL_0008: stloc.1 + IL_0009: ldloc.1 + IL_000a: ldarg.1 + IL_000b: call class [netstandard]System.Delegate [netstandard]System.Delegate::Remove(class [netstandard]System.Delegate, class [netstandard]System.Delegate) + IL_0010: castclass [netstandard]System.Action + IL_0015: stloc.2 + IL_0016: ldarg.0 + IL_0017: ldflda class [netstandard]System.Action Test1::E1 + IL_001c: ldloc.2 + IL_001d: ldloc.1 + IL_001e: call !!0 [netstandard]System.Threading.Interlocked::CompareExchange(!!0&, !!0, !!0) + IL_0023: stloc.0 + IL_0024: ldloc.0 + IL_0025: ldloc.1 + IL_0026: bne.un.s IL_0007 + // end loop + IL_0028: ret + } // end of method Test1::remove_E1 + .method public hidebysig specialname rtspecialname + instance void .ctor () cil managed + { + // Method begins at RVA 0x20d9 + // Code size 8 (0x8) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: call instance void [netstandard]System.Object::.ctor() + IL_0006: nop + IL_0007: ret + } // end of method Test1::.ctor + // Events + .event [netstandard]System.Action E1 + { + .custom instance void Preserve1Attribute::.ctor() = ( + 01 00 00 00 + ) + .addon instance void Test1::add_E1(class [netstandard]System.Action) + .removeon instance void Test1::remove_E1(class [netstandard]System.Action) + } +} // end of class Test1 +".Replace("[netstandard]", ExecutionConditionUtil.IsDesktop ? "[mscorlib]" : "[netstandard]")); + } + + [Fact] + public void CompilerLoweringPreserveAttribute_02() + { + string source1 = @" +using System; + +[AttributeUsage(AttributeTargets.Field)] +public class Preserve1Attribute : Attribute { } +"; + + string source2 = @" +public class Test1 +{ +#pragma warning disable CS0067 // The event 'Test1.E1' is never used + [field: Preserve1] + public event System.Action E1; +} +"; + var comp1 = CreateCompilation( + [source1, source2], + options: TestOptions.DebugDll.WithMetadataImportOptions(MetadataImportOptions.All)); + var verifier = CompileAndVerify(comp1).VerifyDiagnostics(); + + verifier.VerifyTypeIL("Test1", @" +.class public auto ansi beforefieldinit Test1 + extends [netstandard]System.Object +{ + // Fields + .field private class [netstandard]System.Action E1 + .custom instance void [netstandard]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( + 01 00 00 00 + ) + .custom instance void [netstandard]System.Diagnostics.DebuggerBrowsableAttribute::.ctor(valuetype [netstandard]System.Diagnostics.DebuggerBrowsableState) = ( + 01 00 00 00 00 00 00 00 + ) + .custom instance void Preserve1Attribute::.ctor() = ( + 01 00 00 00 + ) + // Methods + .method public hidebysig specialname + instance void add_E1 ( + class [netstandard]System.Action 'value' + ) cil managed + { + .custom instance void [netstandard]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( + 01 00 00 00 + ) + // Method begins at RVA 0x206c + // Code size 41 (0x29) + .maxstack 3 + .locals init ( + [0] class [netstandard]System.Action, + [1] class [netstandard]System.Action, + [2] class [netstandard]System.Action + ) + IL_0000: ldarg.0 + IL_0001: ldfld class [netstandard]System.Action Test1::E1 + IL_0006: stloc.0 + // loop start (head: IL_0007) + IL_0007: ldloc.0 + IL_0008: stloc.1 + IL_0009: ldloc.1 + IL_000a: ldarg.1 + IL_000b: call class [netstandard]System.Delegate [netstandard]System.Delegate::Combine(class [netstandard]System.Delegate, class [netstandard]System.Delegate) + IL_0010: castclass [netstandard]System.Action + IL_0015: stloc.2 + IL_0016: ldarg.0 + IL_0017: ldflda class [netstandard]System.Action Test1::E1 + IL_001c: ldloc.2 + IL_001d: ldloc.1 + IL_001e: call !!0 [netstandard]System.Threading.Interlocked::CompareExchange(!!0&, !!0, !!0) + IL_0023: stloc.0 + IL_0024: ldloc.0 + IL_0025: ldloc.1 + IL_0026: bne.un.s IL_0007 + // end loop + IL_0028: ret + } // end of method Test1::add_E1 + .method public hidebysig specialname + instance void remove_E1 ( + class [netstandard]System.Action 'value' + ) cil managed + { + .custom instance void [netstandard]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( + 01 00 00 00 + ) + // Method begins at RVA 0x20a4 + // Code size 41 (0x29) + .maxstack 3 + .locals init ( + [0] class [netstandard]System.Action, + [1] class [netstandard]System.Action, + [2] class [netstandard]System.Action + ) + IL_0000: ldarg.0 + IL_0001: ldfld class [netstandard]System.Action Test1::E1 + IL_0006: stloc.0 + // loop start (head: IL_0007) + IL_0007: ldloc.0 + IL_0008: stloc.1 + IL_0009: ldloc.1 + IL_000a: ldarg.1 + IL_000b: call class [netstandard]System.Delegate [netstandard]System.Delegate::Remove(class [netstandard]System.Delegate, class [netstandard]System.Delegate) + IL_0010: castclass [netstandard]System.Action + IL_0015: stloc.2 + IL_0016: ldarg.0 + IL_0017: ldflda class [netstandard]System.Action Test1::E1 + IL_001c: ldloc.2 + IL_001d: ldloc.1 + IL_001e: call !!0 [netstandard]System.Threading.Interlocked::CompareExchange(!!0&, !!0, !!0) + IL_0023: stloc.0 + IL_0024: ldloc.0 + IL_0025: ldloc.1 + IL_0026: bne.un.s IL_0007 + // end loop + IL_0028: ret + } // end of method Test1::remove_E1 + .method public hidebysig specialname rtspecialname + instance void .ctor () cil managed + { + // Method begins at RVA 0x20d9 + // Code size 8 (0x8) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: call instance void [netstandard]System.Object::.ctor() + IL_0006: nop + IL_0007: ret + } // end of method Test1::.ctor + // Events + .event [netstandard]System.Action E1 + { + .addon instance void Test1::add_E1(class [netstandard]System.Action) + .removeon instance void Test1::remove_E1(class [netstandard]System.Action) + } +} // end of class Test1 +".Replace("[netstandard]", ExecutionConditionUtil.IsDesktop ? "[mscorlib]" : "[netstandard]")); + } } } diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/Source/PropertyTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/Source/PropertyTests.cs index fc17e45995e8a..cccb6ac427a14 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/Source/PropertyTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/Source/PropertyTests.cs @@ -3026,5 +3026,74 @@ class C var property = compilation.GetMember("C.P"); Assert.True(property.RequiresInstanceReceiver); } + + [Fact] + public void CompilerLoweringPreserveAttribute_01() + { + string source1 = @" +using System; +using System.Runtime.CompilerServices; + +[CompilerLoweringPreserve] +[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)] +public class Preserve1Attribute : Attribute { } +"; + + string source2 = @" +public class Test1 +{ + [Preserve1] + int P1 {get; set;} +} +"; + var comp1 = CreateCompilation( + [source1, source2, CompilerLoweringPreserveAttributeDefinition], + options: TestOptions.DebugDll.WithMetadataImportOptions(MetadataImportOptions.All)); + CompileAndVerify(comp1, symbolValidator: validate).VerifyDiagnostics(); + + static void validate(ModuleSymbol m) + { + AssertEx.SequenceEqual( + [ + "System.Runtime.CompilerServices.CompilerGeneratedAttribute", + "System.Diagnostics.DebuggerBrowsableAttribute(System.Diagnostics.DebuggerBrowsableState.Never)" + ], + m.GlobalNamespace.GetMember("Test1.k__BackingField").GetAttributes().Select(a => a.ToString())); + } + } + + [Fact] + public void CompilerLoweringPreserveAttribute_02() + { + string source1 = @" +using System; + +[AttributeUsage(AttributeTargets.Field)] +public class Preserve1Attribute : Attribute { } +"; + + string source2 = @" +public class Test1 +{ + [field: Preserve1] + int P1 {get; set;} +} +"; + var comp1 = CreateCompilation( + [source1, source2], + options: TestOptions.DebugDll.WithMetadataImportOptions(MetadataImportOptions.All)); + CompileAndVerify(comp1, symbolValidator: validate).VerifyDiagnostics(); + + static void validate(ModuleSymbol m) + { + AssertEx.SequenceEqual( + [ + "System.Runtime.CompilerServices.CompilerGeneratedAttribute", + "System.Diagnostics.DebuggerBrowsableAttribute(System.Diagnostics.DebuggerBrowsableState.Never)", + "Preserve1Attribute" + ], + m.GlobalNamespace.GetMember("Test1.k__BackingField").GetAttributes().Select(a => a.ToString())); + } + } } } diff --git a/src/Compilers/CSharp/Test/Syntax/Diagnostics/DiagnosticTest.cs b/src/Compilers/CSharp/Test/Syntax/Diagnostics/DiagnosticTest.cs index da572570c48fb..e2c7ddb41920c 100644 --- a/src/Compilers/CSharp/Test/Syntax/Diagnostics/DiagnosticTest.cs +++ b/src/Compilers/CSharp/Test/Syntax/Diagnostics/DiagnosticTest.cs @@ -322,8 +322,10 @@ public void WarningLevel_2() case ErrorCode.WRN_TargetDifferentRefness: case ErrorCode.WRN_RefReadonlyParameterDefaultValue: case ErrorCode.WRN_Experimental: + case ErrorCode.WRN_ExperimentalWithMessage: case ErrorCode.WRN_ConvertingLock: case ErrorCode.WRN_PartialPropertySignatureDifference: + case ErrorCode.WRN_UnscopedRefAttributeOldRules: Assert.Equal(1, ErrorFacts.GetWarningLevel(errorCode)); break; case ErrorCode.WRN_MainIgnored: @@ -472,6 +474,10 @@ public void WarningLevel_2() // These are the warnings introduced with the warning "wave" shipped with dotnet 8 and C# 12. Assert.Equal(8, ErrorFacts.GetWarningLevel(errorCode)); break; + case ErrorCode.WRN_InterceptsLocationAttributeUnsupportedSignature: + // These are the warnings introduced with the warning "wave" shipped with dotnet 9 and C# 13. + Assert.Equal(9, ErrorFacts.GetWarningLevel(errorCode)); + break; case ErrorCode.WRN_UnassignedInternalRefField: // These are the warnings introduced with the warning "wave" shipped with dotnet 10 and C# 14. Assert.Equal(10, ErrorFacts.GetWarningLevel(errorCode)); diff --git a/src/Compilers/CSharp/Test/Syntax/IncrementalParsing/IncrementalParsingTests.cs b/src/Compilers/CSharp/Test/Syntax/IncrementalParsing/IncrementalParsingTests.cs index 4d4ed05966982..9b02ce60e8227 100644 --- a/src/Compilers/CSharp/Test/Syntax/IncrementalParsing/IncrementalParsingTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/IncrementalParsing/IncrementalParsingTests.cs @@ -3666,6 +3666,43 @@ enum VirtualKey WalkTreeAndVerify(tree.GetCompilationUnitRoot(), fullTree.GetCompilationUnitRoot()); } + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/76439")] + public void InKeywordInsideAForBlock() + { + var source = """ + void Main() + { + for (int i = 0; i < n; i++) + { + } + } + """; + var tree = SyntaxFactory.ParseSyntaxTree(source); + var text = tree.GetText(); + + // Update all the 'i's in the for-loop to be 'in' instead. + var position1 = source.IndexOf("i =") + 1; + var position2 = source.IndexOf("i <") + 1; + var position3 = source.IndexOf("i++") + 1; + text = text.WithChanges( + new TextChange(new TextSpan(position1, 0), "n"), + new TextChange(new TextSpan(position2, 0), "n"), + new TextChange(new TextSpan(position3, 0), "n")); + + Assert.Equal(""" + void Main() + { + for (int in = 0; in < n; in++) + { + } + } + """, text.ToString()); + + tree = tree.WithChangedText(text); + var fullTree = SyntaxFactory.ParseSyntaxTree(text.ToString()); + WalkTreeAndVerify(tree.GetCompilationUnitRoot(), fullTree.GetCompilationUnitRoot()); + } + #endregion #region Helper functions diff --git a/src/Compilers/CSharp/Test/Syntax/Parsing/FileModifierParsingTests.cs b/src/Compilers/CSharp/Test/Syntax/Parsing/FileModifierParsingTests.cs index b70593980a8b5..4043dbe639c76 100644 --- a/src/Compilers/CSharp/Test/Syntax/Parsing/FileModifierParsingTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/Parsing/FileModifierParsingTests.cs @@ -6,12 +6,13 @@ using System.Linq; using Microsoft.CodeAnalysis.CSharp.Test.Utilities; using Microsoft.CodeAnalysis.Test.Utilities; +using Roslyn.Test.Utilities; using Xunit; using Xunit.Abstractions; namespace Microsoft.CodeAnalysis.CSharp.UnitTests; -public class FileModifierParsingTests : ParsingTests +public sealed class FileModifierParsingTests : ParsingTests { public FileModifierParsingTests(ITestOutputHelper output) : base(output) { } @@ -3598,4 +3599,106 @@ void M(file x) { } } EOF(); } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75992")] + public void TestFileModifierAfterIncompleteBaseList1() + { + UsingTree(""" + class C : B + file class D + { + } + """, + // (1,12): error CS1514: { expected + // class C : B + Diagnostic(ErrorCode.ERR_LbraceExpected, "").WithLocation(1, 12), + // (1,12): error CS1513: } expected + // class C : B + Diagnostic(ErrorCode.ERR_RbraceExpected, "").WithLocation(1, 12)); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.BaseList); + { + N(SyntaxKind.ColonToken); + N(SyntaxKind.SimpleBaseType); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "B"); + } + } + } + M(SyntaxKind.OpenBraceToken); + M(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.FileKeyword); + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "D"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75992")] + public void TestFileModifierAfterIncompleteBaseList2() + { + UsingTree(""" + class C : B, file + { + } + + class file + { + } + """); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.BaseList); + { + N(SyntaxKind.ColonToken); + N(SyntaxKind.SimpleBaseType); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "B"); + } + } + N(SyntaxKind.CommaToken); + N(SyntaxKind.SimpleBaseType); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "file"); + } + } + } + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "file"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } } diff --git a/src/Compilers/CSharp/Test/Syntax/Syntax/SyntaxNodeTests.cs b/src/Compilers/CSharp/Test/Syntax/Syntax/SyntaxNodeTests.cs index f9c4a90d8d350..645ee0ad29ad3 100644 --- a/src/Compilers/CSharp/Test/Syntax/Syntax/SyntaxNodeTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/Syntax/SyntaxNodeTests.cs @@ -2802,6 +2802,44 @@ class C }); } + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/19613")] + public void TestRemove_KeepUnbalancedDirectives_Indented() + { + var inputText = """ + class C + { + // before + #region Fred + // more before + void M() + { + } // after + #endregion + } + """; + + var expectedText = """ + class C + { + + #region Fred + #endregion + } + """; + + TestWithWindowsAndUnixEndOfLines(inputText, expectedText, (cu, expected) => + { + var m = cu.DescendantNodes().OfType().FirstOrDefault(); + Assert.NotNull(m); + + var cu2 = cu.RemoveNode(m, SyntaxRemoveOptions.KeepUnbalancedDirectives); + + var text = cu2.ToFullString(); + + Assert.Equal(expected, text); + }); + } + [Fact] public void TestRemove_KeepDirectives() { diff --git a/src/Compilers/Core/CodeAnalysisTest/AnalyzerAssemblyLoaderTests.cs b/src/Compilers/Core/CodeAnalysisTest/AnalyzerAssemblyLoaderTests.cs index 69e3d9cde5e70..e1aac8fc9057e 100644 --- a/src/Compilers/Core/CodeAnalysisTest/AnalyzerAssemblyLoaderTests.cs +++ b/src/Compilers/Core/CodeAnalysisTest/AnalyzerAssemblyLoaderTests.cs @@ -1458,7 +1458,7 @@ public void AssemblyLoading_CompilerDependencyDuplicated(AnalyzerTestKind kind) loader.AddDependencyLocation(destFile); var copiedAssembly = loader.LoadFromPath(destFile); - Assert.Single(AppDomain.CurrentDomain.GetAssemblies().Where(x => x.FullName == assembly.FullName)); + Assert.Single(AppDomain.CurrentDomain.GetAssemblies(), x => x.FullName == assembly.FullName); Assert.Same(copiedAssembly, assembly); }); } diff --git a/src/Compilers/Core/MSBuildTask/Microsoft.CSharp.Core.targets b/src/Compilers/Core/MSBuildTask/Microsoft.CSharp.Core.targets index f11e8b1adcf90..e595f62d2c33a 100644 --- a/src/Compilers/Core/MSBuildTask/Microsoft.CSharp.Core.targets +++ b/src/Compilers/Core/MSBuildTask/Microsoft.CSharp.Core.targets @@ -18,9 +18,10 @@ - Pattern: .NET 5.0 uses C# 9.0, .NET 6.0 uses C# 10.0, and so on. - Starting from C# 9.0 for .NET 5.0, we add the difference between the major .NET version and 5 to determine the correct language version. + NOTE: `.Split('.')[0]` needed due to https://github.com/dotnet/msbuild/issues/9757. --> <_MaxSupportedLangVersion Condition="'$(TargetFrameworkIdentifier)' == '.NETCoreApp' AND - '$(_MaxSupportedLangVersion)' == ''">$([MSBuild]::Add(9, $([MSBuild]::Subtract($(_TargetFrameworkVersionWithoutV), 5)))).0 + '$(_MaxSupportedLangVersion)' == ''">$([MSBuild]::Add(9, $([MSBuild]::Subtract($(_TargetFrameworkVersionWithoutV.Split('.')[0]), 5)))).0 <_MaxAvailableLangVersion>13.0 diff --git a/src/Compilers/Core/Portable/Collections/ImmutableArrayExtensions.cs b/src/Compilers/Core/Portable/Collections/ImmutableArrayExtensions.cs index 6778fcbd7310b..d85a96967c326 100644 --- a/src/Compilers/Core/Portable/Collections/ImmutableArrayExtensions.cs +++ b/src/Compilers/Core/Portable/Collections/ImmutableArrayExtensions.cs @@ -296,6 +296,28 @@ public static ImmutableArray SelectManyAsArray(this Imm return builder.ToImmutableAndFree(); } + /// + /// Maps and flattens a subset of immutable array to another immutable array. + /// + /// Type of the source array items + /// Type of the transformed array items + /// The array to transform + /// A transform function to apply to each element. + /// If the items's length is 0, this will return an empty immutable array. + public static ImmutableArray SelectManyAsArray(this ImmutableArray array, Func> selector) + { + if (array.Length == 0) + return ImmutableArray.Empty; + + var builder = ArrayBuilder.GetInstance(); + foreach (var item in array) + { + selector(item).AddRangeTo(builder); + } + + return builder.ToImmutableAndFree(); + } + /// /// Maps and flattens a subset of immutable array to another immutable array. /// @@ -344,6 +366,55 @@ public static ImmutableArray SelectManyAsArray(this Imm return builder.ToImmutableAndFree(); } + /// + /// Maps and flattens a subset of immutable array to another immutable array. + /// + /// Type of the source array items + /// Type of the transformed array items + /// The array to transform + /// The condition to use for filtering the array content. + /// A transform function to apply to each element that is not filtered out by . + /// If the items's length is 0, this will return an empty immutable array. + public static ImmutableArray SelectManyAsArray(this ImmutableArray array, Func predicate, Func> selector) + { + if (array.Length == 0) + return ImmutableArray.Empty; + + var builder = ArrayBuilder.GetInstance(); + foreach (var item in array) + { + if (predicate(item)) + selector(item).AddRangeTo(builder); + } + + return builder.ToImmutableAndFree(); + } + + /// + /// Maps and flattens a subset of immutable array to another immutable array. + /// + /// Type of the source array items + /// Type of the argument to pass to the predicate and selector + /// Type of the transformed array items + /// The array to transform + /// The condition to use for filtering the array content. + /// A transform function to apply to each element that is not filtered out by . + /// If the items's length is 0, this will return an empty immutable array. + public static ImmutableArray SelectManyAsArray(this ImmutableArray array, Func predicate, Func> selector, TArg arg) + { + if (array.Length == 0) + return ImmutableArray.Empty; + + var builder = ArrayBuilder.GetInstance(); + foreach (var item in array) + { + if (predicate(item, arg)) + selector(item, arg).AddRangeTo(builder); + } + + return builder.ToImmutableAndFree(); + } + /// /// Maps an immutable array through a function that returns ValueTasks, returning the new ImmutableArray. /// diff --git a/src/Compilers/Core/Portable/InternalUtilities/EnumerableExtensions.cs b/src/Compilers/Core/Portable/InternalUtilities/EnumerableExtensions.cs index c16746b542170..a1ffcde92687b 100644 --- a/src/Compilers/Core/Portable/InternalUtilities/EnumerableExtensions.cs +++ b/src/Compilers/Core/Portable/InternalUtilities/EnumerableExtensions.cs @@ -397,6 +397,22 @@ public static ImmutableArray SelectAsArray(this IRead return ImmutableCollectionsMarshal.AsImmutableArray(builder); } + public static ImmutableArray SelectAsArray(this IReadOnlyCollection? source, Func selector, TArg arg) + { + if (source == null) + return ImmutableArray.Empty; + + var builder = new TResult[source.Count]; + var index = 0; + foreach (var item in source) + { + builder[index] = selector(item, arg); + index++; + } + + return ImmutableCollectionsMarshal.AsImmutableArray(builder); + } + public static ImmutableArray SelectManyAsArray(this IEnumerable? source, Func> selector) { if (source == null) @@ -447,6 +463,18 @@ public static ImmutableArray SelectManyAsArray(th return builder.ToImmutableAndFree(); } + public static ImmutableArray SelectManyAsArray(this IEnumerable? source, Func> selector) + { + if (source == null) + return ImmutableArray.Empty; + + var builder = ArrayBuilder.GetInstance(); + foreach (var item in source) + selector(item).AddRangeTo(builder); + + return builder.ToImmutableAndFree(); + } + /// /// Maps an immutable array through a function that returns ValueTask, returning the new ImmutableArray. /// diff --git a/src/Compilers/Core/Portable/InternalUtilities/RoslynExperiments.cs b/src/Compilers/Core/Portable/InternalUtilities/RoslynExperiments.cs index fd954a5664fdc..9394f13b21c30 100644 --- a/src/Compilers/Core/Portable/InternalUtilities/RoslynExperiments.cs +++ b/src/Compilers/Core/Portable/InternalUtilities/RoslynExperiments.cs @@ -12,9 +12,6 @@ internal static class RoslynExperiments internal const string NullableDisabledSemanticModel = "RSEXPERIMENTAL001"; internal const string NullableDisabledSemanticModel_Url = "https://github.com/dotnet/roslyn/issues/70609"; - internal const string Interceptors = "RSEXPERIMENTAL002"; - internal const string Interceptors_Url = "https://github.com/dotnet/csharplang/issues/7009"; - internal const string SyntaxTokenParser = "RSEXPERIMENTAL003"; internal const string SyntaxTokenParser_Url = "https://github.com/dotnet/roslyn/issues/73002"; diff --git a/src/Compilers/Core/Portable/MetadataReader/PEModule.cs b/src/Compilers/Core/Portable/MetadataReader/PEModule.cs index 53d2b58105ff2..7e2c6a5eae7f6 100644 --- a/src/Compilers/Core/Portable/MetadataReader/PEModule.cs +++ b/src/Compilers/Core/Portable/MetadataReader/PEModule.cs @@ -1022,6 +1022,11 @@ internal bool HasCodeAnalysisEmbeddedAttribute(EntityHandle token) return FindTargetAttribute(token, AttributeDescription.CodeAnalysisEmbeddedAttribute).HasValue; } + internal bool HasCompilerLoweringPreserveAttribute(EntityHandle token) + { + return FindTargetAttribute(token, AttributeDescription.CompilerLoweringPreserveAttribute).HasValue; + } + internal bool HasInterpolatedStringHandlerAttribute(EntityHandle token) { return FindTargetAttribute(token, AttributeDescription.InterpolatedStringHandlerAttribute).HasValue; @@ -1294,17 +1299,18 @@ internal static bool IsMoreImportantObsoleteKind(ObsoleteAttributeKind firstKind diagnosticId = null; } - string? urlFormat = crackUrlFormat(decoder, ref sig); - return new ObsoleteAttributeData(ObsoleteAttributeKind.Experimental, message: null, isError: false, diagnosticId, urlFormat); + (string? urlFormat, string? message) = crackUrlFormatAndMessage(decoder, ref sig); + return new ObsoleteAttributeData(ObsoleteAttributeKind.Experimental, message: message, isError: false, diagnosticId, urlFormat); - static string? crackUrlFormat(IAttributeNamedArgumentDecoder decoder, ref BlobReader sig) + static (string? urlFormat, string? message) crackUrlFormatAndMessage(IAttributeNamedArgumentDecoder decoder, ref BlobReader sig) { if (sig.RemainingBytes <= 0) { - return null; + return default; } string? urlFormat = null; + string? message = null; try { @@ -1313,7 +1319,7 @@ internal static bool IsMoreImportantObsoleteKind(ObsoleteAttributeKind firstKind // Next is a description of the optional “named” fields and properties. // This starts with NumNamed– an unsigned int16 giving the number of “named” properties or fields that follow. var numNamed = sig.ReadUInt16(); - for (int i = 0; i < numNamed && urlFormat is null; i++) + for (int i = 0; i < numNamed && (urlFormat is null || message is null); i++) { var ((name, value), isProperty, typeCode, /* elementTypeCode */ _) = decoder.DecodeCustomAttributeNamedArgumentOrThrow(ref sig); if (typeCode == SerializationTypeCode.String && isProperty && value.ValueInternal is string stringValue) @@ -1322,13 +1328,17 @@ internal static bool IsMoreImportantObsoleteKind(ObsoleteAttributeKind firstKind { urlFormat = stringValue; } + else if (message is null && name == ObsoleteAttributeData.MessagePropertyName) + { + message = stringValue; + } } } } catch (BadImageFormatException) { } catch (UnsupportedSignatureContent) { } - return urlFormat; + return (urlFormat, message); } } diff --git a/src/Compilers/Core/Portable/Symbols/Attributes/AttributeDescription.cs b/src/Compilers/Core/Portable/Symbols/Attributes/AttributeDescription.cs index 7a6618dcf3f05..6b16eac1db4e2 100644 --- a/src/Compilers/Core/Portable/Symbols/Attributes/AttributeDescription.cs +++ b/src/Compilers/Core/Portable/Symbols/Attributes/AttributeDescription.cs @@ -490,5 +490,6 @@ static AttributeDescription() internal static readonly AttributeDescription InlineArrayAttribute = new AttributeDescription("System.Runtime.CompilerServices", "InlineArrayAttribute", s_signatures_HasThis_Void_Int32_Only); internal static readonly AttributeDescription CollectionBuilderAttribute = new AttributeDescription("System.Runtime.CompilerServices", "CollectionBuilderAttribute", s_signaturesOfCollectionBuilderAttribute); internal static readonly AttributeDescription OverloadResolutionPriorityAttribute = new AttributeDescription("System.Runtime.CompilerServices", "OverloadResolutionPriorityAttribute", s_signatures_HasThis_Void_Int32_Only); + internal static readonly AttributeDescription CompilerLoweringPreserveAttribute = new AttributeDescription("System.Runtime.CompilerServices", "CompilerLoweringPreserveAttribute", s_signatures_HasThis_Void_Only); } } diff --git a/src/Compilers/Core/Portable/Symbols/Attributes/CommonAttributeData.cs b/src/Compilers/Core/Portable/Symbols/Attributes/CommonAttributeData.cs index 4a89d1b0de44c..36f3d0be8743c 100644 --- a/src/Compilers/Core/Portable/Symbols/Attributes/CommonAttributeData.cs +++ b/src/Compilers/Core/Portable/Symbols/Attributes/CommonAttributeData.cs @@ -281,6 +281,8 @@ internal ObsoleteAttributeData DecodeExperimentalAttribute() } string? urlFormat = null; + string? message = null; + foreach (var (name, value) in this.CommonNamedArguments) { if (urlFormat is null && name == ObsoleteAttributeData.UrlFormatPropertyName && IsStringProperty(ObsoleteAttributeData.UrlFormatPropertyName)) @@ -288,13 +290,18 @@ internal ObsoleteAttributeData DecodeExperimentalAttribute() urlFormat = value.ValueInternal as string; } - if (urlFormat is not null) + if (message is null && name == ObsoleteAttributeData.MessagePropertyName && IsStringProperty(ObsoleteAttributeData.MessagePropertyName)) + { + message = value.ValueInternal as string; + } + + if (urlFormat is not null && message is not null) { break; } } - return new ObsoleteAttributeData(ObsoleteAttributeKind.Experimental, message: null, isError: false, diagnosticId, urlFormat); + return new ObsoleteAttributeData(ObsoleteAttributeKind.Experimental, message: message, isError: false, diagnosticId, urlFormat); } /// diff --git a/src/Compilers/Core/Portable/Symbols/Attributes/CommonTypeWellKnownAttributeData.cs b/src/Compilers/Core/Portable/Symbols/Attributes/CommonTypeWellKnownAttributeData.cs index 913611d1009ed..3e5ae5edd8958 100644 --- a/src/Compilers/Core/Portable/Symbols/Attributes/CommonTypeWellKnownAttributeData.cs +++ b/src/Compilers/Core/Portable/Symbols/Attributes/CommonTypeWellKnownAttributeData.cs @@ -250,5 +250,23 @@ public bool HasExcludeFromCodeCoverageAttribute } #endregion + + #region CompilerLoweringPreserveAttribute + private bool _hasCompilerLoweringPreserveAttribute; + public bool HasCompilerLoweringPreserveAttribute + { + get + { + VerifySealed(expected: true); + return _hasCompilerLoweringPreserveAttribute; + } + set + { + VerifySealed(expected: false); + _hasCompilerLoweringPreserveAttribute = value; + SetDataStored(); + } + } + #endregion } } diff --git a/src/Compilers/Core/Portable/Symbols/Attributes/ObsoleteAttributeData.cs b/src/Compilers/Core/Portable/Symbols/Attributes/ObsoleteAttributeData.cs index 67d7d4da7c831..c9a96a4de5065 100644 --- a/src/Compilers/Core/Portable/Symbols/Attributes/ObsoleteAttributeData.cs +++ b/src/Compilers/Core/Portable/Symbols/Attributes/ObsoleteAttributeData.cs @@ -26,6 +26,7 @@ internal sealed class ObsoleteAttributeData public const string DiagnosticIdPropertyName = "DiagnosticId"; public const string UrlFormatPropertyName = "UrlFormat"; + public const string MessagePropertyName = "Message"; public ObsoleteAttributeData(ObsoleteAttributeKind kind, string? message, bool isError, string? diagnosticId, string? urlFormat) { diff --git a/src/Compilers/Core/Portable/Syntax/SyntaxTree.cs b/src/Compilers/Core/Portable/Syntax/SyntaxTree.cs index 6e9655d6fcf14..0f51cba9942bd 100644 --- a/src/Compilers/Core/Portable/Syntax/SyntaxTree.cs +++ b/src/Compilers/Core/Portable/Syntax/SyntaxTree.cs @@ -10,6 +10,7 @@ using System.Text; using System.Threading; using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Collections; using Microsoft.CodeAnalysis.Text; using Roslyn.Utilities; @@ -369,11 +370,11 @@ internal int GetDisplayLineNumber(TextSpan span) /// internal Cci.DebugSourceInfo GetDebugSourceInfo() { - if (_lazyChecksum.IsDefault) + if (RoslynImmutableInterlocked.VolatileRead(ref _lazyChecksum).IsDefault) { var text = this.GetText(); - _lazyChecksum = text.GetChecksum(); _lazyHashAlgorithm = text.ChecksumAlgorithm; + ImmutableInterlocked.InterlockedInitialize(ref _lazyChecksum, text.GetChecksum()); } Debug.Assert(!_lazyChecksum.IsDefault); diff --git a/src/Compilers/Core/RebuildTest/BasicDeterministicKeyBuilderTests.cs b/src/Compilers/Core/RebuildTest/BasicDeterministicKeyBuilderTests.cs index f6977a5e218fd..42b612cc64108 100644 --- a/src/Compilers/Core/RebuildTest/BasicDeterministicKeyBuilderTests.cs +++ b/src/Compilers/Core/RebuildTest/BasicDeterministicKeyBuilderTests.cs @@ -356,7 +356,7 @@ public void FeatureFlag() ""features"": {{ ""debug-determinism"": ""true"" }}, - ""languageVersion"": ""VisualBasic16_9"", + ""languageVersion"": ""VisualBasic17_13"", ""specifiedLanguageVersion"": ""Default"", ""preprocessorSymbols"": {{ ""TARGET"": ""library"", @@ -381,7 +381,7 @@ public void FeatureFlag() ""features"": {{ ""debug-determinism"": ""true"" }}, - ""languageVersion"": ""VisualBasic16_9"", + ""languageVersion"": ""VisualBasic17_13"", ""specifiedLanguageVersion"": ""Default"", ""preprocessorSymbols"": {{ ""TARGET"": ""library"", diff --git a/src/Compilers/Test/Core/Assert/ConditionalFactAttribute.cs b/src/Compilers/Test/Core/Assert/ConditionalFactAttribute.cs index 34c52322212ed..49ff8af979590 100644 --- a/src/Compilers/Test/Core/Assert/ConditionalFactAttribute.cs +++ b/src/Compilers/Test/Core/Assert/ConditionalFactAttribute.cs @@ -165,6 +165,7 @@ public static class ExecutionConditionUtil public static bool IsCoreClr => !IsDesktop; public static bool IsCoreClrUnix => IsCoreClr && IsUnix; public static bool IsMonoOrCoreClr => IsMonoDesktop || IsCoreClr; + public static bool IsBitness64 => IntPtr.Size == 8; public static bool RuntimeSupportsCovariantReturnsOfClasses => Type.GetType("System.Runtime.CompilerServices.RuntimeFeature")?.GetField("CovariantReturnsOfClasses") != null; private static readonly Lazy s_operatingSystemRestrictsFileNames = new Lazy(() => diff --git a/src/Compilers/Test/Core/CompilationVerifier.cs b/src/Compilers/Test/Core/CompilationVerifier.cs index ebc1cd681856e..c709948406117 100644 --- a/src/Compilers/Test/Core/CompilationVerifier.cs +++ b/src/Compilers/Test/Core/CompilationVerifier.cs @@ -224,7 +224,7 @@ private static string FixupCodeSizeComments(string output) /// An action to invoke with the emitted IL. public void VerifyTypeIL(string typeName, Action validateExpected) { - var output = new ICSharpCode.Decompiler.PlainTextOutput(); + var output = new ICSharpCode.Decompiler.PlainTextOutput() { IndentationString = " " }; using (var testEnvironment = RuntimeEnvironmentFactory.Create(_dependencies)) { string mainModuleFullName = Emit(testEnvironment, manifestResources: null, EmitOptions.Default); diff --git a/src/Compilers/Test/Core/Microsoft.CodeAnalysis.Test.Utilities.csproj b/src/Compilers/Test/Core/Microsoft.CodeAnalysis.Test.Utilities.csproj index 3d2b74a3c7ca2..712aaca60659f 100644 --- a/src/Compilers/Test/Core/Microsoft.CodeAnalysis.Test.Utilities.csproj +++ b/src/Compilers/Test/Core/Microsoft.CodeAnalysis.Test.Utilities.csproj @@ -99,7 +99,6 @@ - diff --git a/src/Compilers/Test/Core/Traits/Traits.cs b/src/Compilers/Test/Core/Traits/Traits.cs index cced8ae0268cd..f15d2ed986d08 100644 --- a/src/Compilers/Test/Core/Traits/Traits.cs +++ b/src/Compilers/Test/Core/Traits/Traits.cs @@ -172,6 +172,7 @@ public static class Features public const string CodeActionsSimplifyConditional = "CodeActions.SimplifyConditional"; public const string CodeActionsSimplifyInterpolation = "CodeActions.SimplifyInterpolation"; public const string CodeActionsSimplifyLinqExpression = "CodeActions.SimplifyLinqExpression"; + public const string CodeActionsSimplifyLinqTypeCheckAndCast = "CodeActions.SimplifyLinqTypeCheckAndCast"; public const string CodeActionsSimplifyPropertyPattern = "CodeActions.SimplifyPropertyPattern"; public const string CodeActionsSimplifyThisOrMe = "CodeActions.SimplifyThisOrMe"; public const string CodeActionsSimplifyTypeNames = "CodeActions.SimplifyTypeNames"; @@ -192,6 +193,7 @@ public static class Features public const string CodeActionsUseConditionalExpression = "CodeActions.UseConditionalExpression"; public const string CodeActionsUseDeconstruction = "CodeActions.UseDeconstruction"; public const string CodeActionsUseDefaultLiteral = "CodeActions.UseDefaultLiteral"; + public const string CodeActionsUseExplicitArrayInExpressionTree = "CodeActions.UseExplicitArrayInExpressionTree"; public const string CodeActionsUseExplicitTupleName = "CodeActions.UseExplicitTupleName"; public const string CodeActionsUseExplicitType = "CodeActions.UseExplicitType"; public const string CodeActionsUseExplicitTypeForConst = "CodeActions.UseExplicitTypeForConst"; diff --git a/src/Compilers/Test/Utilities/CSharp/CSharpTestBase.cs b/src/Compilers/Test/Utilities/CSharp/CSharpTestBase.cs index a2d5397815847..166457fffd27e 100644 --- a/src/Compilers/Test/Utilities/CSharp/CSharpTestBase.cs +++ b/src/Compilers/Test/Utilities/CSharp/CSharpTestBase.cs @@ -764,6 +764,20 @@ .property instance int32 Priority() } """; + /// + /// The shape of the attribute comes from https://github.com/dotnet/runtime/issues/103430 + /// + internal const string CompilerLoweringPreserveAttributeDefinition = """ + namespace System.Runtime.CompilerServices + { + [AttributeUsage(AttributeTargets.Class, Inherited = false)] + public class CompilerLoweringPreserveAttribute : Attribute + { + public CompilerLoweringPreserveAttribute() { } + } + } + """; + protected static T GetSyntax(SyntaxTree tree, string text) { return GetSyntaxes(tree, text).Single(); diff --git a/src/Compilers/Test/Utilities/VisualBasic/BasicTestBase.vb b/src/Compilers/Test/Utilities/VisualBasic/BasicTestBase.vb index a1514aa50417d..7fe5035e6b888 100644 --- a/src/Compilers/Test/Utilities/VisualBasic/BasicTestBase.vb +++ b/src/Compilers/Test/Utilities/VisualBasic/BasicTestBase.vb @@ -12,6 +12,18 @@ Imports Xunit Public MustInherit Class BasicTestBase Inherits CommonTestBase + Public Const CompilerLoweringPreserveAttributeDefinition As String = " +Namespace System.Runtime.CompilerServices + + Public Class CompilerLoweringPreserveAttribute + Inherits Attribute + + Sub New() + End Sub + End Class +End Namespace +" + Public Function XCDataToString(Optional data As XCData = Nothing) As String Return data?.Value.Replace(vbLf, Environment.NewLine) End Function diff --git a/src/Compilers/Test/Utilities/VisualBasic/MockSymbols.vb b/src/Compilers/Test/Utilities/VisualBasic/MockSymbols.vb index ef58a60eb2802..37798a724c3b4 100644 --- a/src/Compilers/Test/Utilities/VisualBasic/MockSymbols.vb +++ b/src/Compilers/Test/Utilities/VisualBasic/MockSymbols.vb @@ -310,6 +310,12 @@ Friend Class MockNamedTypeSymbol End Get End Property + Friend Overrides ReadOnly Property HasCompilerLoweringPreserveAttribute As Boolean + Get + Throw New NotImplementedException() + End Get + End Property + Friend Overrides ReadOnly Property IsExtensibleInterfaceNoUseSiteDiagnostics As Boolean Get Throw New NotImplementedException() @@ -509,6 +515,10 @@ Friend Class MockMethodSymbol End Get End Property + Public Overrides Function GetOverloadResolutionPriority() As Integer + Return 0 + End Function + Public Overrides ReadOnly Property IsOverridable As Boolean Get Return False diff --git a/src/Compilers/VisualBasic/Portable/Binding/Binder_XmlLiterals.vb b/src/Compilers/VisualBasic/Portable/Binding/Binder_XmlLiterals.vb index 02b4d1fb55803..e760ab679b286 100644 --- a/src/Compilers/VisualBasic/Portable/Binding/Binder_XmlLiterals.vb +++ b/src/Compilers/VisualBasic/Portable/Binding/Binder_XmlLiterals.vb @@ -1636,6 +1636,10 @@ Namespace Microsoft.CodeAnalysis.VisualBasic End Get End Property + Public Overrides Function GetOverloadResolutionPriority() As Integer + Return _originalDefinition.GetOverloadResolutionPriority() + End Function + Public Overrides ReadOnly Property IsOverridable As Boolean Get Return False @@ -1853,6 +1857,10 @@ Namespace Microsoft.CodeAnalysis.VisualBasic End Get End Property + Public Overrides Function GetOverloadResolutionPriority() As Integer + Return _originalDefinition.GetOverloadResolutionPriority() + End Function + Public Overrides ReadOnly Property IsOverridable As Boolean Get Return False diff --git a/src/Compilers/VisualBasic/Portable/BoundTree/BoundMethodGroup.vb b/src/Compilers/VisualBasic/Portable/BoundTree/BoundMethodGroup.vb index 973c68d5ce6b4..c9f0bab9b7d3a 100644 --- a/src/Compilers/VisualBasic/Portable/BoundTree/BoundMethodGroup.vb +++ b/src/Compilers/VisualBasic/Portable/BoundTree/BoundMethodGroup.vb @@ -8,6 +8,7 @@ Imports Microsoft.CodeAnalysis.VisualBasic.Symbols Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Imports System.Runtime.InteropServices Imports System.Threading +Imports Microsoft.CodeAnalysis.Collections Namespace Microsoft.CodeAnalysis.VisualBasic @@ -55,7 +56,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic Debug.Assert(group.PendingExtensionMethodsOpt Is Me) Debug.Assert(Not useSiteInfo.AccumulatesDependencies OrElse _withDependencies) - If _lazyMethods.IsDefault Then + If RoslynImmutableInterlocked.VolatileRead(_lazyMethods).IsDefault Then Dim receiverOpt As BoundExpression = group.ReceiverOpt Dim methods As ImmutableArray(Of MethodSymbol) = ImmutableArray(Of MethodSymbol).Empty Dim localUseSiteInfo = If(_withDependencies, New CompoundUseSiteInfo(Of AssemblySymbol)(_lookupBinder.Compilation.Assembly), CompoundUseSiteInfo(Of AssemblySymbol).DiscardedDependencies) diff --git a/src/Compilers/VisualBasic/Portable/Emit/MethodSymbolAdapter.vb b/src/Compilers/VisualBasic/Portable/Emit/MethodSymbolAdapter.vb index 83fc610227c06..178c0a426d08f 100644 --- a/src/Compilers/VisualBasic/Portable/Emit/MethodSymbolAdapter.vb +++ b/src/Compilers/VisualBasic/Portable/Emit/MethodSymbolAdapter.vb @@ -411,7 +411,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols CheckDefinitionInvariant() Dim userDefined As ImmutableArray(Of VisualBasicAttributeData) - Dim synthesized As ArrayBuilder(Of SynthesizedAttributeData) = Nothing + Dim synthesized As ArrayBuilder(Of VisualBasicAttributeData) = Nothing userDefined = AdaptedMethodSymbol.GetReturnTypeAttributes() AdaptedMethodSymbol.AddSynthesizedReturnTypeAttributes(synthesized) diff --git a/src/Compilers/VisualBasic/Portable/Emit/PEModuleBuilder.vb b/src/Compilers/VisualBasic/Portable/Emit/PEModuleBuilder.vb index 37bc77ab98fe6..c8a52432fcef3 100644 --- a/src/Compilers/VisualBasic/Portable/Emit/PEModuleBuilder.vb +++ b/src/Compilers/VisualBasic/Portable/Emit/PEModuleBuilder.vb @@ -386,9 +386,9 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Emit Debug.Assert(HaveDeterminedTopLevelTypes) If _lazyExportedTypes.IsDefault Then - _lazyExportedTypes = CalculateExportedTypes() + Dim initialized = ImmutableInterlocked.InterlockedInitialize(_lazyExportedTypes, CalculateExportedTypes()) - If _lazyExportedTypes.Length > 0 Then + If initialized AndAlso _lazyExportedTypes.Length > 0 Then ReportExportedTypeNameCollisions(_lazyExportedTypes, diagnostics) End If End If diff --git a/src/Compilers/VisualBasic/Portable/Emit/SourceAssemblySymbolAdapter.vb b/src/Compilers/VisualBasic/Portable/Emit/SourceAssemblySymbolAdapter.vb index 3eda631743f52..bc53b3c6ce35c 100644 --- a/src/Compilers/VisualBasic/Portable/Emit/SourceAssemblySymbolAdapter.vb +++ b/src/Compilers/VisualBasic/Portable/Emit/SourceAssemblySymbolAdapter.vb @@ -12,7 +12,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols emittingRefAssembly As Boolean, emittingAssemblyAttributesInNetModule As Boolean) As IEnumerable(Of VisualBasicAttributeData) - Dim synthesized As ArrayBuilder(Of SynthesizedAttributeData) = Nothing + Dim synthesized As ArrayBuilder(Of VisualBasicAttributeData) = Nothing AddSynthesizedAttributes(moduleBuilder, synthesized) If emittingRefAssembly AndAlso Not HasReferenceAssemblyAttribute Then diff --git a/src/Compilers/VisualBasic/Portable/Emit/SymbolAdapter.vb b/src/Compilers/VisualBasic/Portable/Emit/SymbolAdapter.vb index aa07f6ef3a194..c7c9551f017da 100644 --- a/src/Compilers/VisualBasic/Portable/Emit/SymbolAdapter.vb +++ b/src/Compilers/VisualBasic/Portable/Emit/SymbolAdapter.vb @@ -79,7 +79,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic Friend Function GetCustomAttributesToEmit(moduleBuilder As PEModuleBuilder, emittingAssemblyAttributesInNetModule As Boolean) As IEnumerable(Of VisualBasicAttributeData) Debug.Assert(Me.Kind <> SymbolKind.Assembly) - Dim synthesized As ArrayBuilder(Of SynthesizedAttributeData) = Nothing + Dim synthesized As ArrayBuilder(Of VisualBasicAttributeData) = Nothing AddSynthesizedAttributes(moduleBuilder, synthesized) Return GetCustomAttributesToEmit(Me.GetAttributes(), synthesized, isReturnType:=False, emittingAssemblyAttributesInNetModule:=emittingAssemblyAttributesInNetModule) End Function @@ -88,7 +88,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic ''' Returns a list of attributes to emit to CustomAttribute table. ''' Friend Function GetCustomAttributesToEmit(userDefined As ImmutableArray(Of VisualBasicAttributeData), - synthesized As ArrayBuilder(Of SynthesizedAttributeData), + synthesized As ArrayBuilder(Of VisualBasicAttributeData), isReturnType As Boolean, emittingAssemblyAttributesInNetModule As Boolean) As IEnumerable(Of VisualBasicAttributeData) @@ -101,7 +101,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic End Function Private Iterator Function GetCustomAttributesToEmitIterator(userDefined As ImmutableArray(Of VisualBasicAttributeData), - synthesized As ArrayBuilder(Of SynthesizedAttributeData), + synthesized As ArrayBuilder(Of VisualBasicAttributeData), isReturnType As Boolean, emittingAssemblyAttributesInNetModule As Boolean) As IEnumerable(Of VisualBasicAttributeData) diff --git a/src/Compilers/VisualBasic/Portable/Errors/ErrorFacts.vb b/src/Compilers/VisualBasic/Portable/Errors/ErrorFacts.vb index 48fe778a53989..0ceb29c88e20a 100644 --- a/src/Compilers/VisualBasic/Portable/Errors/ErrorFacts.vb +++ b/src/Compilers/VisualBasic/Portable/Errors/ErrorFacts.vb @@ -1367,6 +1367,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic ERRID.ERR_UnsupportedRefReturningCallInWithStatement, ERRID.ERR_TypeReserved, ERRID.ERR_UnmanagedConstraintNotSatisfied, + ERRID.ERR_CannotApplyOverloadResolutionPriorityToOverride, + ERRID.ERR_CannotApplyOverloadResolutionPriorityToMember, ERRID.ERR_NextAvailable, ERRID.WRN_UseOfObsoleteSymbol2, ERRID.WRN_InvalidOverrideDueToTupleNames2, @@ -1532,6 +1534,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic ERRID.WRN_UnableToLoadAnalyzer, ERRID.WRN_AttributeIgnoredWhenPublicSigning, ERRID.WRN_Experimental, + ERRID.WRN_ExperimentalWithMessage, ERRID.WRN_AttributeNotSupportedInVB, ERRID.WRN_GeneratorFailedDuringInitialization, ERRID.WRN_GeneratorFailedDuringGeneration, @@ -1542,7 +1545,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic ERRID.WRN_DuplicateAnalyzerReference, ERRID.ERR_InvalidExperimentalDiagID, ERRID.ERR_LockTypeUnsupported, - ERRID.WRN_ConvertingLock + ERRID.WRN_ConvertingLock, + ERRID.ERR_EmbeddedAttributeMustFollowPattern Return False Case Else ' NOTE: All error codes must be explicitly handled in the below select case statement diff --git a/src/Compilers/VisualBasic/Portable/Errors/Errors.vb b/src/Compilers/VisualBasic/Portable/Errors/Errors.vb index 7a1f4efecbec3..2c425f89a3c2b 100644 --- a/src/Compilers/VisualBasic/Portable/Errors/Errors.vb +++ b/src/Compilers/VisualBasic/Portable/Errors/Errors.vb @@ -1783,7 +1783,12 @@ Namespace Microsoft.CodeAnalysis.VisualBasic ERR_TypeReserved = 37331 ERR_UnmanagedConstraintNotSatisfied = 37332 - ERR_NextAvailable = 37333 + ERR_CannotApplyOverloadResolutionPriorityToOverride = 37333 + ERR_CannotApplyOverloadResolutionPriorityToMember = 37334 + + ERR_EmbeddedAttributeMustFollowPattern = 37335 + + ERR_NextAvailable = 37336 '// WARNINGS BEGIN HERE WRN_UseOfObsoleteSymbol2 = 40000 @@ -2018,6 +2023,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic WRN_ConvertingLock = 42508 + WRN_ExperimentalWithMessage = 42509 + ' // AVAILABLE 42600 - 49998 WRN_NextAvailable = 42600 @@ -2083,5 +2090,6 @@ Namespace Microsoft.CodeAnalysis.VisualBasic FEATURE_InitOnlySettersUsage FEATURE_CallerArgumentExpression FEATURE_UnmanagedConstraint + FEATURE_OverloadResolutionPriority End Enum End Namespace diff --git a/src/Compilers/VisualBasic/Portable/Generated/ErrorFacts.Generated.vb b/src/Compilers/VisualBasic/Portable/Generated/ErrorFacts.Generated.vb index a325413f92031..746fccc4750a1 100644 --- a/src/Compilers/VisualBasic/Portable/Generated/ErrorFacts.Generated.vb +++ b/src/Compilers/VisualBasic/Portable/Generated/ErrorFacts.Generated.vb @@ -178,7 +178,8 @@ ERRID.WRN_CallerArgumentExpressionAttributeHasInvalidParameterName, ERRID.WRN_AnalyzerReferencesNewerCompiler, ERRID.WRN_DuplicateAnalyzerReference, - ERRID.WRN_ConvertingLock + ERRID.WRN_ConvertingLock, + ERRID.WRN_ExperimentalWithMessage Return True Case Else Return False diff --git a/src/Compilers/VisualBasic/Portable/LanguageVersion.vb b/src/Compilers/VisualBasic/Portable/LanguageVersion.vb index 1a6aac70c9f81..2a1b696e73956 100644 --- a/src/Compilers/VisualBasic/Portable/LanguageVersion.vb +++ b/src/Compilers/VisualBasic/Portable/LanguageVersion.vb @@ -93,7 +93,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic Case LanguageVersion.Latest Return LanguageVersion.VisualBasic17_13 Case LanguageVersion.Default - Return LanguageVersion.VisualBasic16_9 + Return LanguageVersion.VisualBasic17_13 Case Else Return version End Select diff --git a/src/Compilers/VisualBasic/Portable/Lowering/IteratorRewriter/IteratorRewriter.IteratorMethodToClassRewriter.vb b/src/Compilers/VisualBasic/Portable/Lowering/IteratorRewriter/IteratorRewriter.IteratorMethodToClassRewriter.vb index 0c1489a25069c..f317c0a22a6a1 100644 --- a/src/Compilers/VisualBasic/Portable/Lowering/IteratorRewriter/IteratorRewriter.IteratorMethodToClassRewriter.vb +++ b/src/Compilers/VisualBasic/Portable/Lowering/IteratorRewriter/IteratorRewriter.IteratorMethodToClassRewriter.vb @@ -111,10 +111,14 @@ Namespace Microsoft.CodeAnalysis.VisualBasic F.Assignment(F.Field(F.Me, Me.StateField, True), F.Literal(StateMachineState.NotStartedOrRunningState)), F.Label(breakLabel), F.ExpressionStatement(F.Call(F.Me, moveNextMethod)), + F.Assignment(F.Field(F.Me, Me.StateField, True), F.Literal(StateMachineState.FinishedState)), F.Return() )) Else - F.CloseMethod(F.Return()) + F.CloseMethod(F.Block( + F.Assignment(F.Field(F.Me, Me.StateField, True), F.Literal(StateMachineState.FinishedState)), + F.Return() + )) End If End Sub diff --git a/src/Compilers/VisualBasic/Portable/Lowering/LambdaRewriter/LambdaFrameConstructor.vb b/src/Compilers/VisualBasic/Portable/Lowering/LambdaRewriter/LambdaFrameConstructor.vb index cf680d2d5bc01..62bd7edda8415 100644 --- a/src/Compilers/VisualBasic/Portable/Lowering/LambdaRewriter/LambdaFrameConstructor.vb +++ b/src/Compilers/VisualBasic/Portable/Lowering/LambdaRewriter/LambdaFrameConstructor.vb @@ -46,7 +46,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic Return False End Function - Friend Overrides Sub AddSynthesizedAttributes(moduleBuilder As PEModuleBuilder, ByRef attributes As ArrayBuilder(Of SynthesizedAttributeData)) + Friend Overrides Sub AddSynthesizedAttributes(moduleBuilder As PEModuleBuilder, ByRef attributes As ArrayBuilder(Of VisualBasicAttributeData)) MyBase.AddSynthesizedAttributes(moduleBuilder, attributes) ' Dev11 adds DebuggerNonUserCode; there is no reason to do so since: diff --git a/src/Compilers/VisualBasic/Portable/Lowering/LambdaRewriter/SynthesizedLambdaMethod.vb b/src/Compilers/VisualBasic/Portable/Lowering/LambdaRewriter/SynthesizedLambdaMethod.vb index 919fa2fddbabb..76a50c638854d 100644 --- a/src/Compilers/VisualBasic/Portable/Lowering/LambdaRewriter/SynthesizedLambdaMethod.vb +++ b/src/Compilers/VisualBasic/Portable/Lowering/LambdaRewriter/SynthesizedLambdaMethod.vb @@ -196,7 +196,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic Return DirectCast(substituted.GetMemberForDefinition(Me), MethodSymbol) End Function - Friend Overrides Sub AddSynthesizedAttributes(moduleBuilder As PEModuleBuilder, ByRef attributes As ArrayBuilder(Of SynthesizedAttributeData)) + Friend Overrides Sub AddSynthesizedAttributes(moduleBuilder As PEModuleBuilder, ByRef attributes As ArrayBuilder(Of VisualBasicAttributeData)) MyBase.AddSynthesizedAttributes(moduleBuilder, attributes) ' Lambda that doesn't contain user code may still call to a user code (e.g. delegate relaxation stubs). We want the stack frame to be hidden. diff --git a/src/Compilers/VisualBasic/Portable/Lowering/MethodToClassRewriter/MethodToClassRewriter.MyBaseMyClassWrapper.vb b/src/Compilers/VisualBasic/Portable/Lowering/MethodToClassRewriter/MethodToClassRewriter.MyBaseMyClassWrapper.vb index 70ab036306a71..174623ee6fe97 100644 --- a/src/Compilers/VisualBasic/Portable/Lowering/MethodToClassRewriter/MethodToClassRewriter.MyBaseMyClassWrapper.vb +++ b/src/Compilers/VisualBasic/Portable/Lowering/MethodToClassRewriter/MethodToClassRewriter.MyBaseMyClassWrapper.vb @@ -211,7 +211,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic End Get End Property - Friend Overrides Sub AddSynthesizedAttributes(moduleBuilder As PEModuleBuilder, ByRef attributes As ArrayBuilder(Of SynthesizedAttributeData)) + Friend Overrides Sub AddSynthesizedAttributes(moduleBuilder As PEModuleBuilder, ByRef attributes As ArrayBuilder(Of VisualBasicAttributeData)) MyBase.AddSynthesizedAttributes(moduleBuilder, attributes) Dim compilation = Me.DeclaringCompilation diff --git a/src/Compilers/VisualBasic/Portable/Lowering/StateMachineRewriter/StateMachineRewriter.vb b/src/Compilers/VisualBasic/Portable/Lowering/StateMachineRewriter/StateMachineRewriter.vb index ab4a83cc72470..8caf9757131ab 100644 --- a/src/Compilers/VisualBasic/Portable/Lowering/StateMachineRewriter/StateMachineRewriter.vb +++ b/src/Compilers/VisualBasic/Portable/Lowering/StateMachineRewriter/StateMachineRewriter.vb @@ -241,7 +241,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic proxy = CreateParameterCapture( F.StateMachineField( paramType, - Me.Method, + parameter, GeneratedNames.MakeStateMachineParameterName(parameter.Name), Accessibility.Friend), parameter) @@ -252,7 +252,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic CreateParameterCapture( Me.F.StateMachineField( paramType, - Me.Method, + parameter, GeneratedNames.MakeIteratorParameterProxyName(parameter.Name), Accessibility.Friend), parameter)) diff --git a/src/Compilers/VisualBasic/Portable/Lowering/StateMachineRewriter/SynthesizedContainer.vb b/src/Compilers/VisualBasic/Portable/Lowering/StateMachineRewriter/SynthesizedContainer.vb index 3a42c6e41a647..3b60139908050 100644 --- a/src/Compilers/VisualBasic/Portable/Lowering/StateMachineRewriter/SynthesizedContainer.vb +++ b/src/Compilers/VisualBasic/Portable/Lowering/StateMachineRewriter/SynthesizedContainer.vb @@ -145,6 +145,12 @@ Namespace Microsoft.CodeAnalysis.VisualBasic End Get End Property + Friend Overrides ReadOnly Property HasCompilerLoweringPreserveAttribute As Boolean + Get + Return False + End Get + End Property + Friend NotOverridable Overrides ReadOnly Property IsExtensibleInterfaceNoUseSiteDiagnostics As Boolean Get Return False @@ -305,7 +311,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic End Get End Property - Friend Overrides Sub AddSynthesizedAttributes(moduleBuilder As PEModuleBuilder, ByRef attributes As ArrayBuilder(Of SynthesizedAttributeData)) + Friend Overrides Sub AddSynthesizedAttributes(moduleBuilder As PEModuleBuilder, ByRef attributes As ArrayBuilder(Of VisualBasicAttributeData)) MyBase.AddSynthesizedAttributes(moduleBuilder, attributes) Dim compilation = Me.DeclaringCompilation diff --git a/src/Compilers/VisualBasic/Portable/Lowering/StateMachineRewriter/SynthesizedStateMachineMethod.vb b/src/Compilers/VisualBasic/Portable/Lowering/StateMachineRewriter/SynthesizedStateMachineMethod.vb index 834f5888839d1..922db9730a3ab 100644 --- a/src/Compilers/VisualBasic/Portable/Lowering/StateMachineRewriter/SynthesizedStateMachineMethod.vb +++ b/src/Compilers/VisualBasic/Portable/Lowering/StateMachineRewriter/SynthesizedStateMachineMethod.vb @@ -191,7 +191,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic MyBase.New(stateMachineType, WellKnownMemberNames.MoveNextMethodName, interfaceMethod, syntax, declaredAccessibility, generateDebugInfo:=True, hasMethodBodyDependency:=True) End Sub - Friend Overrides Sub AddSynthesizedAttributes(moduleBuilder As PEModuleBuilder, ByRef attributes As ArrayBuilder(Of SynthesizedAttributeData)) + Friend Overrides Sub AddSynthesizedAttributes(moduleBuilder As PEModuleBuilder, ByRef attributes As ArrayBuilder(Of VisualBasicAttributeData)) MyBase.AddSynthesizedAttributes(moduleBuilder, attributes) Debug.Assert(WellKnownMembers.IsSynthesizedAttributeOptional(WellKnownMember.System_Runtime_CompilerServices_CompilerGeneratedAttribute__ctor)) @@ -247,7 +247,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic hasMethodBodyDependency:=hasMethodBodyDependency, associatedProperty:=associatedProperty) End Sub - Friend Overrides Sub AddSynthesizedAttributes(moduleBuilder As PEModuleBuilder, ByRef attributes As ArrayBuilder(Of SynthesizedAttributeData)) + Friend Overrides Sub AddSynthesizedAttributes(moduleBuilder As PEModuleBuilder, ByRef attributes As ArrayBuilder(Of VisualBasicAttributeData)) MyBase.AddSynthesizedAttributes(moduleBuilder, attributes) Debug.Assert(WellKnownMembers.IsSynthesizedAttributeOptional(WellKnownMember.System_Diagnostics_DebuggerNonUserCodeAttribute__ctor)) diff --git a/src/Compilers/VisualBasic/Portable/Parser/ParserFeature.vb b/src/Compilers/VisualBasic/Portable/Parser/ParserFeature.vb index 9235e57dd1710..f9d99710a2e35 100644 --- a/src/Compilers/VisualBasic/Portable/Parser/ParserFeature.vb +++ b/src/Compilers/VisualBasic/Portable/Parser/ParserFeature.vb @@ -42,6 +42,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Syntax.InternalSyntax CommentsAfterLineContinuation InitOnlySettersUsage UnmanagedConstraint + OverloadResolutionPriority End Enum Friend Module FeatureExtensions @@ -107,7 +108,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Syntax.InternalSyntax Case Feature.InitOnlySettersUsage Return LanguageVersion.VisualBasic16_9 - Case Feature.UnmanagedConstraint + Case Feature.UnmanagedConstraint, + Feature.OverloadResolutionPriority Return LanguageVersion.VisualBasic17_13 Case Else @@ -185,6 +187,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Syntax.InternalSyntax Return ERRID.FEATURE_InitOnlySettersUsage Case Feature.UnmanagedConstraint Return ERRID.FEATURE_UnmanagedConstraint + Case Feature.OverloadResolutionPriority + Return ERRID.FEATURE_OverloadResolutionPriority Case Else Throw ExceptionUtilities.UnexpectedValue(feature) End Select diff --git a/src/Compilers/VisualBasic/Portable/Semantics/Operators.vb b/src/Compilers/VisualBasic/Portable/Semantics/Operators.vb index 802f9c7b10876..c37d590d70d7d 100644 --- a/src/Compilers/VisualBasic/Portable/Semantics/Operators.vb +++ b/src/Compilers/VisualBasic/Portable/Semantics/Operators.vb @@ -3164,6 +3164,8 @@ Next_i: Dim liftOperators As Boolean = nullableOfT.GetUseSiteInfo().DiagnosticInfo Is Nothing Dim candidates = ArrayBuilder(Of CandidateAnalysisResult).GetInstance() + Dim someCandidatesHaveOverloadResolutionPriority As Boolean = InternalSyntax.Parser.CheckFeatureAvailability(binder.Compilation.LanguageVersion, InternalSyntax.Feature.OverloadResolutionPriority) AndAlso + opSet.Any(Function(candidate) candidate.OverloadResolutionPriority <> 0) For Each method In opSet Debug.Assert(method.ParameterCount = If(argument2 Is Nothing, 1, 2)) @@ -3189,7 +3191,10 @@ Next_i: Continue For End If - CombineCandidates(candidates, New CandidateAnalysisResult(New OperatorCandidate(method)), method.ParameterCount, Nothing, useSiteInfo) + CombineCandidates(candidates, New CandidateAnalysisResult(New OperatorCandidate(method)), method.ParameterCount, + argumentNames:=Nothing, + someCandidatesHaveOverloadResolutionPriority, + useSiteInfo) If liftOperators Then Dim param1 As ParameterSymbol = method.Parameters(0) @@ -3230,7 +3235,10 @@ Next_i: ImmutableArray.Create(param1), ImmutableArray.Create(Of ParameterSymbol)(param1, param2)), returnType)), - method.ParameterCount, Nothing, useSiteInfo) + method.ParameterCount, + argumentNames:=Nothing, + someCandidatesHaveOverloadResolutionPriority, + useSiteInfo) End If End If Next @@ -3242,7 +3250,10 @@ Next_i: If(argument2 Is Nothing, ImmutableArray.Create(argument1), ImmutableArray.Create(Of BoundExpression)(argument1, argument2)), - Nothing, Nothing, lateBindingIsAllowed, binder:=binder, + argumentNames:=Nothing, + someCandidatesHaveOverloadResolutionPriority, + delegateReturnType:=Nothing, + lateBindingIsAllowed, binder:=binder, asyncLambdaSubToFunctionMismatch:=Nothing, callerInfoOpt:=Nothing, forceExpandedForm:=False, useSiteInfo:=useSiteInfo) diff --git a/src/Compilers/VisualBasic/Portable/Semantics/OverloadResolution.vb b/src/Compilers/VisualBasic/Portable/Semantics/OverloadResolution.vb index 6d69e5c4ce84c..254d6b2603a58 100644 --- a/src/Compilers/VisualBasic/Portable/Semantics/OverloadResolution.vb +++ b/src/Compilers/VisualBasic/Portable/Semantics/OverloadResolution.vb @@ -88,6 +88,10 @@ Namespace Microsoft.CodeAnalysis.VisualBasic Public MustOverride ReadOnly Property Arity As Integer Public MustOverride ReadOnly Property TypeParameters As ImmutableArray(Of TypeParameterSymbol) + Public MustOverride ReadOnly Property OverloadResolutionPriority As Integer + + Public MustOverride Function GetOverloadResolutionPriorityInfo() As (Source As NamedTypeSymbol, Priority As Integer) + Friend Sub GetAllParameterCounts( ByRef requiredCount As Integer, ByRef maxCount As Integer, @@ -227,6 +231,28 @@ Namespace Microsoft.CodeAnalysis.VisualBasic Return False End Function + + Public Overrides ReadOnly Property OverloadResolutionPriority As Integer + Get + Return m_Method.OriginalDefinition.OverloadResolutionPriority + End Get + End Property + + Public Overrides Function GetOverloadResolutionPriorityInfo() As (Source As NamedTypeSymbol, Priority As Integer) + Dim leastOverriddenDefinition As MethodSymbol = m_Method.OriginalDefinition + + While leastOverriddenDefinition.IsOverrides + Dim overridden As MethodSymbol = leastOverriddenDefinition.OverriddenMethod + + If overridden Is Nothing Then + Exit While + End If + + leastOverriddenDefinition = overridden.OriginalDefinition + End While + + Return (leastOverriddenDefinition.ContainingType, leastOverriddenDefinition.OverloadResolutionPriority) + End Function End Class ''' @@ -444,6 +470,28 @@ Namespace Microsoft.CodeAnalysis.VisualBasic Return False End Function + + Public Overrides ReadOnly Property OverloadResolutionPriority As Integer + Get + Return _property.OriginalDefinition.OverloadResolutionPriority + End Get + End Property + + Public Overrides Function GetOverloadResolutionPriorityInfo() As (Source As NamedTypeSymbol, Priority As Integer) + Dim leastOverriddenDefinition As PropertySymbol = _property.OriginalDefinition + + While leastOverriddenDefinition.IsOverrides + Dim overridden As PropertySymbol = leastOverriddenDefinition.OverriddenProperty + + If overridden Is Nothing Then + Exit While + End If + + leastOverriddenDefinition = overridden.OriginalDefinition + End While + + Return (leastOverriddenDefinition.ContainingType, leastOverriddenDefinition.OverloadResolutionPriority) + End Function End Class Private Const s_stateSize = 8 ' bit size of the following enum @@ -915,13 +963,32 @@ Namespace Microsoft.CodeAnalysis.VisualBasic Dim applicableNarrowingCandidateCount As Integer = 0 Dim applicableInstanceCandidateCount As Integer = 0 + Dim someCandidatesHaveOverloadResolutionPriority As Boolean = False + Dim respectOverloadResolutionPriority As Boolean = InternalSyntax.Parser.CheckFeatureAvailability(binder.Compilation.LanguageVersion, InternalSyntax.Feature.OverloadResolutionPriority) + + If respectOverloadResolutionPriority AndAlso binder.IsEarlyAttributeBinder Then + Dim possiblyConstructor = TryCast(binder.ContainingMember, MethodSymbol) + If possiblyConstructor IsNot Nothing AndAlso + possiblyConstructor.MethodKind = MethodKind.Constructor AndAlso + possiblyConstructor.ContainingType.Name = AttributeDescription.OverloadResolutionPriorityAttribute.Name AndAlso + possiblyConstructor.ContainingType.IsCompilerServicesTopLevelType() Then + ' Avoid possible cycle during attribute binding + respectOverloadResolutionPriority = False + End If + End If ' First collect instance methods. If instanceCandidates.Count > 0 Then + ' Given the way VB name lookup works, the least derived forms are also among the candidates and are getting filtered out by CombineCandidates. + ' Therefore, this simple check gets to them as well without explicitly traversing the overrides hierarchy. + someCandidatesHaveOverloadResolutionPriority = respectOverloadResolutionPriority AndAlso instanceCandidates.Any(Function(candidate) candidate.OverloadResolutionPriority <> 0) + CollectOverloadedCandidates( binder, candidates, instanceCandidates, typeArguments, - arguments, argumentNames, delegateReturnType, delegateReturnTypeReferenceBoundNode, + arguments, argumentNames, + someCandidatesHaveOverloadResolutionPriority, + delegateReturnType, delegateReturnTypeReferenceBoundNode, includeEliminatedCandidates, isQueryOperatorInvocation, forceExpandedForm, asyncLambdaSubToFunctionMismatch, useSiteInfo) @@ -939,6 +1006,10 @@ Namespace Microsoft.CodeAnalysis.VisualBasic Dim addedExtensionMethods As Boolean = False If ShouldConsiderExtensionMethods(candidates) Then + Debug.Assert(candidates.All(Function(candidate) candidate.State <> CandidateAnalysisResultState.Applicable OrElse + candidate.RequiresNarrowingConversion OrElse + candidate.MaxDelegateRelaxationLevel = ConversionKind.DelegateRelaxationLevelNarrowing)) + ' Request additional extension methods, if any available. If methodGroup.ResultKind = LookupResultKind.Good Then methods = methodGroup.AdditionalExtensionMethods(useSiteInfo) @@ -951,9 +1022,14 @@ Namespace Microsoft.CodeAnalysis.VisualBasic If curriedCandidates.Count > 0 Then addedExtensionMethods = True + someCandidatesHaveOverloadResolutionPriority = someCandidatesHaveOverloadResolutionPriority OrElse + (respectOverloadResolutionPriority AndAlso curriedCandidates.Any(Function(candidate) candidate.OverloadResolutionPriority <> 0)) + CollectOverloadedCandidates( binder, candidates, curriedCandidates, typeArguments, - arguments, argumentNames, delegateReturnType, delegateReturnTypeReferenceBoundNode, + arguments, argumentNames, + someCandidatesHaveOverloadResolutionPriority, + delegateReturnType, delegateReturnTypeReferenceBoundNode, includeEliminatedCandidates, isQueryOperatorInvocation, forceExpandedForm, asyncLambdaSubToFunctionMismatch, useSiteInfo) End If @@ -965,7 +1041,9 @@ Namespace Microsoft.CodeAnalysis.VisualBasic If applicableInstanceCandidateCount = 0 AndAlso Not addedExtensionMethods Then result = ReportOverloadResolutionFailedOrLateBound(candidates, applicableInstanceCandidateCount, lateBindingIsAllowed AndAlso binder.OptionStrict <> OptionStrict.On, asyncLambdaSubToFunctionMismatch) Else - result = ResolveOverloading(methodGroup, candidates, arguments, argumentNames, delegateReturnType, lateBindingIsAllowed, binder, asyncLambdaSubToFunctionMismatch, callerInfoOpt, forceExpandedForm, + result = ResolveOverloading(methodGroup, candidates, arguments, argumentNames, + someCandidatesHaveOverloadResolutionPriority, + delegateReturnType, lateBindingIsAllowed, binder, asyncLambdaSubToFunctionMismatch, callerInfoOpt, forceExpandedForm, useSiteInfo) End If @@ -977,6 +1055,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic applicableNarrowingCandidateCount As Integer, lateBindingIsAllowed As Boolean, asyncLambdaSubToFunctionMismatch As HashSet(Of BoundExpression)) As OverloadResolutionResult + Debug.Assert(applicableNarrowingCandidateCount = 0) Dim isLateBound As Boolean = False If lateBindingIsAllowed Then @@ -1022,14 +1101,25 @@ Namespace Microsoft.CodeAnalysis.VisualBasic Dim asyncLambdaSubToFunctionMismatch As HashSet(Of BoundExpression) = Nothing + ' Given the way VB name lookup works, the least derived forms are also among the candidates and are getting filtered out by CombineCandidates. + ' Therefore, this simple check gets to them as well without explicitly traversing the overrides hierarchy. + Dim someCandidatesHaveOverloadResolutionPriority As Boolean = + binder.BindingLocation <> BindingLocation.Attribute AndAlso + InternalSyntax.Parser.CheckFeatureAvailability(binder.Compilation.LanguageVersion, InternalSyntax.Feature.OverloadResolutionPriority) AndAlso + candidates.Any(Function(candidate) candidate.OverloadResolutionPriority <> 0) + CollectOverloadedCandidates(binder, results, candidates, ImmutableArray(Of TypeSymbol).Empty, - arguments, argumentNames, Nothing, Nothing, includeEliminatedCandidates, + arguments, argumentNames, + someCandidatesHaveOverloadResolutionPriority, + Nothing, Nothing, includeEliminatedCandidates, isQueryOperatorInvocation:=False, forceExpandedForm:=False, asyncLambdaSubToFunctionMismatch:=asyncLambdaSubToFunctionMismatch, useSiteInfo:=useSiteInfo) Debug.Assert(asyncLambdaSubToFunctionMismatch Is Nothing) candidates.Free() - Dim result = ResolveOverloading(propertyGroup, results, arguments, argumentNames, delegateReturnType:=Nothing, lateBindingIsAllowed:=True, binder:=binder, + Dim result = ResolveOverloading(propertyGroup, results, arguments, argumentNames, + someCandidatesHaveOverloadResolutionPriority, + delegateReturnType:=Nothing, lateBindingIsAllowed:=True, binder:=binder, asyncLambdaSubToFunctionMismatch:=asyncLambdaSubToFunctionMismatch, callerInfoOpt:=callerInfoOpt, forceExpandedForm:=False, useSiteInfo:=useSiteInfo) results.Free() @@ -1064,6 +1154,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic candidates As ArrayBuilder(Of CandidateAnalysisResult), arguments As ImmutableArray(Of BoundExpression), argumentNames As ImmutableArray(Of String), + someCandidatesHaveOverloadResolutionPriority As Boolean, delegateReturnType As TypeSymbol, lateBindingIsAllowed As Boolean, binder As Binder, @@ -1101,6 +1192,20 @@ Namespace Microsoft.CodeAnalysis.VisualBasic GoTo ResolutionComplete End If + If someCandidatesHaveOverloadResolutionPriority Then + RemoveLowerPriorityMembers(candidates, applicableCandidates, applicableNarrowingCandidates) + If applicableCandidates < 2 Then + narrowingCandidatesRemainInTheSet = (applicableNarrowingCandidates > 0) + GoTo ResolutionComplete + End If + + ApplyTieBreakingRulesSkippedByCombineCandidates(candidates, applicableCandidates, applicableNarrowingCandidates, arguments.Length, argumentNames, useSiteInfo) + If applicableCandidates < 2 Then + narrowingCandidatesRemainInTheSet = (applicableNarrowingCandidates > 0) + GoTo ResolutionComplete + End If + End If + ' §11.8.1 Overloaded Method Resolution. ' 7.8. If one or more arguments are AddressOf or lambda expressions, and all of the corresponding ' delegate types in M match exactly, but not all do in N, eliminate N from the set. @@ -1187,6 +1292,261 @@ ResolutionComplete: Return New OverloadResolutionResult(candidates.ToImmutable(), resolutionIsLateBound, narrowingCandidatesRemainInTheSet, asyncLambdaSubToFunctionMismatch) End Function + Private Shared ReadOnly s_poolInstance As ObjectPool(Of PooledDictionary(Of NamedTypeSymbol, OneOrMany(Of (Index As Integer, Priority As Integer)))) = + PooledDictionary(Of NamedTypeSymbol, OneOrMany(Of (Index As Integer, Priority As Integer))).CreatePool(SymbolEqualityComparer.IgnoreAll) + + Private Shared Sub RemoveLowerPriorityMembers( + candidates As ArrayBuilder(Of CandidateAnalysisResult), + ByRef applicableCandidates As Integer, + ByRef applicableNarrowingCandidates As Integer + ) + Dim candidateInfoByDeclaringType As PooledDictionary(Of NamedTypeSymbol, OneOrMany(Of (Index As Integer, Priority As Integer))) = s_poolInstance.Allocate() + + For i As Integer = 0 To candidates.Count - 1 Step 1 + + Dim current As CandidateAnalysisResult = candidates(i) + + If current.State <> CandidateAnalysisResultState.Applicable Then + Continue For + End If + + Dim priorityInfo As (Source As NamedTypeSymbol, Priority As Integer) = current.Candidate.GetOverloadResolutionPriorityInfo() + + Dim siblings As OneOrMany(Of (Index As Integer, Priority As Integer)) = Nothing + + If candidateInfoByDeclaringType.TryGetValue(priorityInfo.Source, siblings) Then + candidateInfoByDeclaringType(priorityInfo.Source) = siblings.Add((i, priorityInfo.Priority)) + Else + candidateInfoByDeclaringType.Add(priorityInfo.Source, OneOrMany.Create((i, priorityInfo.Priority))) + End If + Next + + For Each siblings In candidateInfoByDeclaringType.Values + If siblings.Count = 1 Then + Continue For + End If + + Dim maxPriority = Integer.MinValue + + For Each info In siblings + Dim candidate = candidates(info.Index) + + If candidate.RequiresNarrowingConversion OrElse candidate.MaxDelegateRelaxationLevel = ConversionKind.DelegateRelaxationLevelNarrowing Then + Continue For + End If + + If maxPriority < info.Priority Then + maxPriority = info.Priority + End If + Next + + If maxPriority = Integer.MinValue Then + Continue For + End If + + For Each info In siblings + If maxPriority > info.Priority Then + Dim toDeprioritize = candidates(info.Index) + applicableCandidates -= 1 + If toDeprioritize.RequiresNarrowingConversion Then + applicableNarrowingCandidates -= 1 + End If + toDeprioritize.State = CandidateAnalysisResultState.LessApplicable + candidates(info.Index) = toDeprioritize + End If + Next + Next + + candidateInfoByDeclaringType.Free() + End Sub + + Private Shared Sub ApplyTieBreakingRulesSkippedByCombineCandidates( + candidates As ArrayBuilder(Of CandidateAnalysisResult), + ByRef applicableCandidates As Integer, + ByRef applicableNarrowingCandidates As Integer, + argumentCount As Integer, + argumentNames As ImmutableArray(Of String), + <[In], Out> ByRef useSiteInfo As CompoundUseSiteInfo(Of AssemblySymbol) + ) + For i As Integer = 0 To candidates.Count - 1 Step 1 + + Dim existingCandidate As CandidateAnalysisResult = candidates(i) + + ' Skip over some eliminated candidates, which we will be unable to match signature against. + If existingCandidate.State = CandidateAnalysisResultState.ArgumentCountMismatch OrElse + existingCandidate.State = CandidateAnalysisResultState.BadGenericArity OrElse + existingCandidate.State = CandidateAnalysisResultState.Ambiguous OrElse + existingCandidate.State = CandidateAnalysisResultState.TypeInferenceFailed OrElse existingCandidate.SomeInferenceFailed OrElse + existingCandidate.State = CandidateAnalysisResultState.HasUseSiteError OrElse + existingCandidate.State = CandidateAnalysisResultState.HasUnsupportedMetadata OrElse + existingCandidate.State = CandidateAnalysisResultState.LessApplicable OrElse + existingCandidate.State = CandidateAnalysisResultState.Shadowed Then + Continue For + End If + + For j As Integer = i + 1 To candidates.Count - 1 Step 1 + + Dim newCandidate As CandidateAnalysisResult = candidates(j) + + If newCandidate.State <> CandidateAnalysisResultState.Applicable Then + Continue For + End If + + ' Candidate can't hide another form of itself + If existingCandidate.Candidate Is newCandidate.Candidate Then + Continue For + End If + + Dim existingWins As Boolean = False + Dim newWins As Boolean = False + + If ApplyTieBreakingRulesSkippedByCombineCandidates(existingCandidate, newCandidate, argumentCount, argumentNames, useSiteInfo, existingWins, newWins) Then + Debug.Assert(existingWins Xor newWins) ' Both cannot win! + Dim lost As Integer = If(existingWins, j, i) + + Dim toShadow = candidates(lost) + + If toShadow.State = CandidateAnalysisResultState.Applicable Then + applicableCandidates -= 1 + If toShadow.RequiresNarrowingConversion Then + applicableNarrowingCandidates -= 1 + End If + End If + + toShadow.State = CandidateAnalysisResultState.Shadowed + candidates(lost) = toShadow + + If lost = i Then + Exit For + End If + End If + Next + Next + End Sub + + Private Shared Function ApplyTieBreakingRulesSkippedByCombineCandidates( + existingCandidate As CandidateAnalysisResult, newCandidate As CandidateAnalysisResult, + argumentCount As Integer, + argumentNames As ImmutableArray(Of String), + <[In], Out> ByRef useSiteInfo As CompoundUseSiteInfo(Of AssemblySymbol), + ByRef existingWins As Boolean, ByRef newWins As Boolean + ) As Boolean + Debug.Assert(newCandidate.State = CandidateAnalysisResultState.Applicable) + + Dim operatorResolution As Boolean = newCandidate.Candidate.IsOperator + + Debug.Assert(newCandidate.Candidate.ParameterCount >= argumentCount OrElse newCandidate.IsExpandedParamArrayForm) + Debug.Assert(argumentNames.IsDefault OrElse argumentNames.Length > 0) + Debug.Assert(Not operatorResolution OrElse argumentNames.IsDefault) + + ' It looks like the following code is applying some tie-breaking rules from section 7 of + ' §11.8.1 Overloaded Method Resolution, but not all of them and even skips ParamArrays tie-breaking + ' rule in some scenarios. I couldn't find an explanation of this behavior in the spec and + ' simply tried to keep this code close to Dev10. + + ' Spec says that the tie-breaking rules should be applied only for members equally applicable to the argument list. + ' [§11.8.1.1 Applicability] defines equally applicable members as follows: + ' A member M is considered equally applicable as N if + ' 1) their signatures are the same or + ' 2) if each parameter type in M is the same as the corresponding parameter type in N. + + ' We can always check if signature is the same, but we cannot check the second condition in presence + ' of named arguments because for them we don't know yet which parameter in M corresponds to which + ' parameter in N. + + Debug.Assert(existingCandidate.Candidate.ParameterCount >= argumentCount OrElse existingCandidate.IsExpandedParamArrayForm) + + ' Check if the shadowing below can be applied in theory + If Not existingCandidate.IsExpandedParamArrayForm AndAlso Not newCandidate.IsExpandedParamArrayForm AndAlso + Not argumentNames.IsDefault AndAlso + (existingCandidate.Candidate.IsExtensionMethod OrElse newCandidate.Candidate.IsExtensionMethod) Then + Return False + End If + + If argumentNames.IsDefault Then + If Not CombineCandidatesCompareVirtualSignature(newCandidate, existingCandidate, argumentCount) Then + ' Signatures are different, shadowing rules do not apply + Return False + End If + Else + Debug.Assert(Not operatorResolution) + End If + + Dim signatureMatch As Boolean + + ' Compare complete signature, with no regard to arguments + If existingCandidate.Candidate.ParameterCount <> newCandidate.Candidate.ParameterCount Then + Debug.Assert(Not operatorResolution) + signatureMatch = False + ElseIf operatorResolution Then + Debug.Assert(argumentNames.IsDefault) ' We matched the virtual signature above + Debug.Assert(argumentCount = existingCandidate.Candidate.ParameterCount) + signatureMatch = True + + ' Not lifted operators are preferred over lifted. + If ShadowBasedOnLiftedState(existingCandidate, newCandidate, existingWins, newWins) Then + Return True + End If + Else + signatureMatch = CombineCandidatesCompareDeclaredSignature(newCandidate, existingCandidate) + End If + + If Not argumentNames.IsDefault AndAlso Not signatureMatch Then + ' Signatures are different, shadowing rules do not apply + Return False + End If + + If Not signatureMatch Then + Debug.Assert(argumentNames.IsDefault) ' We matched the virtual signature above + + ' If we have gotten to this point it means that the 2 procedures have equal specificity, + ' but signatures that do not match exactly (after generic substitution). This + ' implies that we are dealing with differences in shape due to param arrays + ' or optional arguments. + ' So we look and see if one procedure maps fewer arguments to the + ' param array than the other. The one using more, is then shadowed by the one using less. + + '• If M has fewer parameters from an expanded paramarray than N, eliminate N from the set. + If ShadowBasedOnParamArrayUsage(existingCandidate, newCandidate, existingWins, newWins) Then + Return True + End If + + Else + ' The signatures of the two methods match (after generic parameter substitution). + ' This means that param array shadowing doesn't come into play. + ' !!! Why? Where is this mentioned in the spec? + End If + + Debug.Assert(argumentNames.IsDefault OrElse signatureMatch) + + ' In presence of named arguments, the following shadowing rules + ' cannot be applied if any candidate is extension method because + ' full signature match doesn't guarantee equal applicability (in presence of named arguments) + ' and instance methods hide by signature regardless applicability rules do not apply to extension methods. + If argumentNames.IsDefault OrElse + Not (existingCandidate.Candidate.IsExtensionMethod OrElse newCandidate.Candidate.IsExtensionMethod) Then + + '7.1. If M is defined in a more derived type than N, eliminate N from the set. + ' This rule also applies to the types that extension methods are defined on. + '7.2. If M and N are extension methods and the target type of M is a class or + ' structure and the target type of N is an interface, eliminate N from the set. + If (Not signatureMatch OrElse existingCandidate.Candidate.IsExtensionMethod OrElse newCandidate.Candidate.IsExtensionMethod) AndAlso + ShadowBasedOnReceiverType(existingCandidate, newCandidate, existingWins, newWins, useSiteInfo) Then + Return True + End If + + '7.3. If M and N are extension methods and the target type of M has fewer type + ' parameters than the target type of N, eliminate N from the set. + ' !!! Note that spec talks about "fewer type parameters", but it is not really about count. + ' !!! It is about one refers to a type parameter and the other one doesn't. + If ShadowBasedOnExtensionMethodTargetTypeGenericity(existingCandidate, newCandidate, existingWins, newWins) Then + Return True + End If + End If + + Return False + End Function + Private Shared Function EliminateNarrowingCandidates( candidates As ArrayBuilder(Of CandidateAnalysisResult) ) As Integer @@ -3490,6 +3850,7 @@ Bailout: typeArguments As ImmutableArray(Of TypeSymbol), arguments As ImmutableArray(Of BoundExpression), argumentNames As ImmutableArray(Of String), + someCandidatesHaveOverloadResolutionPriority As Boolean, delegateReturnType As TypeSymbol, delegateReturnTypeReferenceBoundNode As BoundNode, includeEliminatedCandidates As Boolean, @@ -3519,6 +3880,7 @@ Bailout: If info.Candidate.UnderlyingSymbol.ContainingModule Is sourceModule OrElse info.Candidate.IsExtensionMethod Then CollectOverloadedCandidate(results, info, typeArguments, arguments, argumentNames, + someCandidatesHaveOverloadResolutionPriority, delegateReturnType, delegateReturnTypeReferenceBoundNode, includeEliminatedCandidates, binder, asyncLambdaSubToFunctionMismatch, useSiteInfo) @@ -3635,11 +3997,13 @@ Bailout: If info.State <> CandidateAnalysisResultState.Ambiguous Then CollectOverloadedCandidate(results, info, typeArguments, arguments, argumentNames, + someCandidatesHaveOverloadResolutionPriority, delegateReturnType, delegateReturnTypeReferenceBoundNode, includeEliminatedCandidates, binder, asyncLambdaSubToFunctionMismatch, useSiteInfo) ElseIf includeEliminatedCandidates Then CollectOverloadedCandidate(results, info, typeArguments, arguments, argumentNames, + someCandidatesHaveOverloadResolutionPriority, delegateReturnType, delegateReturnTypeReferenceBoundNode, includeEliminatedCandidates, binder, asyncLambdaSubToFunctionMismatch, useSiteInfo) @@ -3650,6 +4014,7 @@ Bailout: If info2.Candidate IsNot Nothing AndAlso info2.State = CandidateAnalysisResultState.Ambiguous Then quickInfo(l) = Nothing CollectOverloadedCandidate(results, info2, typeArguments, arguments, argumentNames, + someCandidatesHaveOverloadResolutionPriority, delegateReturnType, delegateReturnTypeReferenceBoundNode, includeEliminatedCandidates, binder, asyncLambdaSubToFunctionMismatch, useSiteInfo) @@ -3780,6 +4145,7 @@ Bailout: typeArguments As ImmutableArray(Of TypeSymbol), arguments As ImmutableArray(Of BoundExpression), argumentNames As ImmutableArray(Of String), + someCandidatesHaveOverloadResolutionPriority As Boolean, delegateReturnType As TypeSymbol, delegateReturnTypeReferenceBoundNode As BoundNode, includeEliminatedCandidates As Boolean, @@ -3835,7 +4201,7 @@ Bailout: triedToAddSomething = True #End If InferTypeArgumentsIfNeedToAndCombineWithExistingCandidates(results, candidateAnalysis, typeArguments, - arguments, argumentNames, + arguments, argumentNames, someCandidatesHaveOverloadResolutionPriority, delegateReturnType, delegateReturnTypeReferenceBoundNode, binder, asyncLambdaSubToFunctionMismatch, useSiteInfo) @@ -3851,7 +4217,7 @@ Bailout: candidateAnalysis.SetIsExpandedParamArrayForm() candidateAnalysis.ExpandedParamArrayArgumentsUsed = Math.Max(arguments.Length - candidate.Candidate.ParameterCount + 1, 0) InferTypeArgumentsIfNeedToAndCombineWithExistingCandidates(results, candidateAnalysis, typeArguments, - arguments, argumentNames, + arguments, argumentNames, someCandidatesHaveOverloadResolutionPriority, delegateReturnType, delegateReturnTypeReferenceBoundNode, binder, asyncLambdaSubToFunctionMismatch, useSiteInfo) @@ -3877,6 +4243,7 @@ Bailout: typeArguments As ImmutableArray(Of TypeSymbol), arguments As ImmutableArray(Of BoundExpression), argumentNames As ImmutableArray(Of String), + someCandidatesHaveOverloadResolutionPriority As Boolean, delegateReturnType As TypeSymbol, delegateReturnTypeReferenceBoundNode As BoundNode, binder As Binder, @@ -3900,7 +4267,7 @@ Bailout: End If End If - CombineCandidates(results, newCandidate, arguments.Length, argumentNames, useSiteInfo) + CombineCandidates(results, newCandidate, arguments.Length, argumentNames, someCandidatesHaveOverloadResolutionPriority, useSiteInfo) End Sub ''' @@ -3913,6 +4280,7 @@ Bailout: newCandidate As CandidateAnalysisResult, argumentCount As Integer, argumentNames As ImmutableArray(Of String), + someCandidatesHaveOverloadResolutionPriority As Boolean, <[In], Out> ByRef useSiteInfo As CompoundUseSiteInfo(Of AssemblySymbol) ) Debug.Assert(newCandidate.State = CandidateAnalysisResultState.Applicable) @@ -3981,33 +4349,15 @@ Bailout: Debug.Assert(existingCandidate.Candidate.ParameterCount >= argumentCount OrElse existingCandidate.IsExpandedParamArrayForm) If argumentNames.IsDefault Then - Dim existingParamIndex As Integer = 0 - Dim newParamIndex As Integer = 0 - - 'CONSIDER: Can we somehow merge this with the complete signature comparison? - For j As Integer = 0 To argumentCount - 1 Step 1 - - Dim existingType As TypeSymbol = GetParameterTypeFromVirtualSignature(existingCandidate, existingParamIndex) - Dim newType As TypeSymbol = GetParameterTypeFromVirtualSignature(newCandidate, newParamIndex) - - If Not existingType.IsSameTypeIgnoringAll(newType) Then - ' Signatures are different, shadowing rules do not apply - GoTo ContinueCandidatesLoop - End If - - ' Advance to the next parameter in the existing candidate, - ' unless we are on the expanded ParamArray parameter. - AdvanceParameterInVirtualSignature(existingCandidate, existingParamIndex) - - ' Advance to the next parameter in the new candidate, - ' unless we are on the expanded ParamArray parameter. - AdvanceParameterInVirtualSignature(newCandidate, newParamIndex) - Next + If Not CombineCandidatesCompareVirtualSignature(newCandidate, existingCandidate, argumentCount) Then + ' Signatures are different, shadowing rules do not apply + GoTo ContinueCandidatesLoop + End If Else Debug.Assert(Not operatorResolution) End If - Dim signatureMatch As Boolean = True + Dim signatureMatch As Boolean ' Compare complete signature, with no regard to arguments If existingCandidate.Candidate.ParameterCount <> newCandidate.Candidate.ParameterCount Then @@ -4015,30 +4365,19 @@ Bailout: signatureMatch = False ElseIf operatorResolution Then Debug.Assert(argumentCount = existingCandidate.Candidate.ParameterCount) - Debug.Assert(signatureMatch) + Debug.Assert(argumentNames.IsDefault) ' We matched the virtual signature above + signatureMatch = True ' Not lifted operators are preferred over lifted. - If existingCandidate.Candidate.IsLifted Then - If Not newCandidate.Candidate.IsLifted Then - newWins = True + If ShadowBasedOnLiftedState(existingCandidate, newCandidate, existingWins, newWins) Then + If someCandidatesHaveOverloadResolutionPriority Then + GoTo ContinueCandidatesLoop + Else GoTo DeterminedTheWinner End If - ElseIf newCandidate.Candidate.IsLifted Then - Debug.Assert(Not existingCandidate.Candidate.IsLifted) - existingWins = True - GoTo DeterminedTheWinner End If Else - For j As Integer = 0 To existingCandidate.Candidate.ParameterCount - 1 Step 1 - - Dim existingType As TypeSymbol = existingCandidate.Candidate.Parameters(j).Type - Dim newType As TypeSymbol = newCandidate.Candidate.Parameters(j).Type - - If Not existingType.IsSameTypeIgnoringAll(newType) Then - signatureMatch = False - Exit For - End If - Next + signatureMatch = CombineCandidatesCompareDeclaredSignature(newCandidate, existingCandidate) End If If Not argumentNames.IsDefault AndAlso Not signatureMatch Then @@ -4047,7 +4386,7 @@ Bailout: End If If Not signatureMatch Then - Debug.Assert(argumentNames.IsDefault) + Debug.Assert(argumentNames.IsDefault) ' We matched the virtual signature above ' If we have gotten to this point it means that the 2 procedures have equal specificity, ' but signatures that do not match exactly (after generic substitution). This @@ -4057,7 +4396,7 @@ Bailout: ' param array than the other. The one using more, is then shadowed by the one using less. '• If M has fewer parameters from an expanded paramarray than N, eliminate N from the set. - If ShadowBasedOnParamArrayUsage(existingCandidate, newCandidate, existingWins, newWins) Then + If Not someCandidatesHaveOverloadResolutionPriority AndAlso ShadowBasedOnParamArrayUsage(existingCandidate, newCandidate, existingWins, newWins) Then GoTo DeterminedTheWinner End If @@ -4080,7 +4419,9 @@ Bailout: ' This rule also applies to the types that extension methods are defined on. '7.2. If M and N are extension methods and the target type of M is a class or ' structure and the target type of N is an interface, eliminate N from the set. - If ShadowBasedOnReceiverType(existingCandidate, newCandidate, existingWins, newWins, useSiteInfo) Then + If (Not someCandidatesHaveOverloadResolutionPriority OrElse + (signatureMatch AndAlso Not (existingCandidate.Candidate.IsExtensionMethod OrElse newCandidate.Candidate.IsExtensionMethod))) AndAlso + ShadowBasedOnReceiverType(existingCandidate, newCandidate, existingWins, newWins, useSiteInfo) Then GoTo DeterminedTheWinner End If @@ -4088,7 +4429,7 @@ Bailout: ' parameters than the target type of N, eliminate N from the set. ' !!! Note that spec talks about "fewer type parameters", but it is not really about count. ' !!! It is about one refers to a type parameter and the other one doesn't. - If ShadowBasedOnExtensionMethodTargetTypeGenericity(existingCandidate, newCandidate, existingWins, newWins) Then + If Not someCandidatesHaveOverloadResolutionPriority AndAlso ShadowBasedOnExtensionMethodTargetTypeGenericity(existingCandidate, newCandidate, existingWins, newWins) Then GoTo DeterminedTheWinner End If End If @@ -4118,6 +4459,65 @@ ContinueCandidatesLoop: results.Add(newCandidate) End Sub + Private Shared Function CombineCandidatesCompareVirtualSignature(newCandidate As CandidateAnalysisResult, existingCandidate As CandidateAnalysisResult, argumentCount As Integer) As Boolean + Dim existingParamIndex As Integer = 0 + Dim newParamIndex As Integer = 0 + + 'CONSIDER: Can we somehow merge this with the complete signature comparison? + For j As Integer = 0 To argumentCount - 1 Step 1 + + Dim existingType As TypeSymbol = GetParameterTypeFromVirtualSignature(existingCandidate, existingParamIndex) + Dim newType As TypeSymbol = GetParameterTypeFromVirtualSignature(newCandidate, newParamIndex) + + If Not existingType.IsSameTypeIgnoringAll(newType) Then + ' Signatures are different, shadowing rules do not apply + Return False + End If + + ' Advance to the next parameter in the existing candidate, + ' unless we are on the expanded ParamArray parameter. + AdvanceParameterInVirtualSignature(existingCandidate, existingParamIndex) + + ' Advance to the next parameter in the new candidate, + ' unless we are on the expanded ParamArray parameter. + AdvanceParameterInVirtualSignature(newCandidate, newParamIndex) + Next + + Return True + End Function + + Private Shared Function CombineCandidatesCompareDeclaredSignature(newCandidate As CandidateAnalysisResult, existingCandidate As CandidateAnalysisResult) As Boolean + For j As Integer = 0 To existingCandidate.Candidate.ParameterCount - 1 Step 1 + + Dim existingType As TypeSymbol = existingCandidate.Candidate.Parameters(j).Type + Dim newType As TypeSymbol = newCandidate.Candidate.Parameters(j).Type + + If Not existingType.IsSameTypeIgnoringAll(newType) Then + Return False + End If + Next + + Return True + End Function + + Private Shared Function ShadowBasedOnLiftedState( + existingCandidate As CandidateAnalysisResult, newCandidate As CandidateAnalysisResult, + ByRef existingWins As Boolean, ByRef newWins As Boolean + ) As Boolean + If existingCandidate.Candidate.IsLifted Then + If Not newCandidate.Candidate.IsLifted Then + newWins = True + Return True + End If + ElseIf newCandidate.Candidate.IsLifted Then + Debug.Assert(Not existingCandidate.Candidate.IsLifted) + existingWins = True + Return True + End If + + Return False + End Function + Private Shared Function ShadowBasedOnOverriding( existingCandidate As CandidateAnalysisResult, newCandidate As CandidateAnalysisResult, ByRef existingWins As Boolean, ByRef newWins As Boolean diff --git a/src/Compilers/VisualBasic/Portable/Symbols/AnonymousTypes/PublicSymbols/AnonymousTypeOrDelegatePublicSymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/AnonymousTypes/PublicSymbols/AnonymousTypeOrDelegatePublicSymbol.vb index 81adf8fd26991..bc857323df126 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/AnonymousTypes/PublicSymbols/AnonymousTypeOrDelegatePublicSymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/AnonymousTypes/PublicSymbols/AnonymousTypeOrDelegatePublicSymbol.vb @@ -104,6 +104,12 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols End Get End Property + Friend Overrides ReadOnly Property HasCompilerLoweringPreserveAttribute As Boolean + Get + Return False + End Get + End Property + Friend Overrides ReadOnly Property IsExtensibleInterfaceNoUseSiteDiagnostics As Boolean Get Return False diff --git a/src/Compilers/VisualBasic/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousDelegate_TemplateSymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousDelegate_TemplateSymbol.vb index ea3003ae95ce7..886a32095f454 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousDelegate_TemplateSymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousDelegate_TemplateSymbol.vb @@ -169,7 +169,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols End Get End Property - Friend Overrides Sub AddSynthesizedAttributes(moduleBuilder As PEModuleBuilder, ByRef attributes As ArrayBuilder(Of SynthesizedAttributeData)) + Friend Overrides Sub AddSynthesizedAttributes(moduleBuilder As PEModuleBuilder, ByRef attributes As ArrayBuilder(Of VisualBasicAttributeData)) MyBase.AddSynthesizedAttributes(moduleBuilder, attributes) ' Attribute: System.Runtime.CompilerServices.CompilerGeneratedAttribute() diff --git a/src/Compilers/VisualBasic/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousTypeOrDelegateTemplateSymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousTypeOrDelegateTemplateSymbol.vb index 7dbea7df36c15..5ded985e98464 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousTypeOrDelegateTemplateSymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousTypeOrDelegateTemplateSymbol.vb @@ -161,6 +161,12 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols End Get End Property + Friend Overrides ReadOnly Property HasCompilerLoweringPreserveAttribute As Boolean + Get + Return False + End Get + End Property + Friend Overrides ReadOnly Property IsExtensibleInterfaceNoUseSiteDiagnostics As Boolean Get Return False diff --git a/src/Compilers/VisualBasic/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType_ConstructorSymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType_ConstructorSymbol.vb index b4c623cc8ee70..94c77c2625f94 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType_ConstructorSymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType_ConstructorSymbol.vb @@ -40,7 +40,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols End Get End Property - Friend Overrides Sub AddSynthesizedAttributes(moduleBuilder As PEModuleBuilder, ByRef attributes As ArrayBuilder(Of SynthesizedAttributeData)) + Friend Overrides Sub AddSynthesizedAttributes(moduleBuilder As PEModuleBuilder, ByRef attributes As ArrayBuilder(Of VisualBasicAttributeData)) MyBase.AddSynthesizedAttributes(moduleBuilder, attributes) Dim compilation = DirectCast(Me.ContainingType, AnonymousTypeTemplateSymbol).Manager.Compilation diff --git a/src/Compilers/VisualBasic/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType_EqualsMethodSymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType_EqualsMethodSymbol.vb index 8d99035cf5b03..05f5e9db19d1b 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType_EqualsMethodSymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType_EqualsMethodSymbol.vb @@ -83,7 +83,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols End Get End Property - Friend Overrides Sub AddSynthesizedAttributes(moduleBuilder As PEModuleBuilder, ByRef attributes As ArrayBuilder(Of SynthesizedAttributeData)) + Friend Overrides Sub AddSynthesizedAttributes(moduleBuilder As PEModuleBuilder, ByRef attributes As ArrayBuilder(Of VisualBasicAttributeData)) MyBase.AddSynthesizedAttributes(moduleBuilder, attributes) Dim compilation = DirectCast(Me.ContainingType, AnonymousTypeTemplateSymbol).Manager.Compilation diff --git a/src/Compilers/VisualBasic/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType_GetHashCodeMethodSymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType_GetHashCodeMethodSymbol.vb index 17edaba998aa9..e17cdfe77df42 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType_GetHashCodeMethodSymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType_GetHashCodeMethodSymbol.vb @@ -52,7 +52,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols End Get End Property - Friend Overrides Sub AddSynthesizedAttributes(moduleBuilder As PEModuleBuilder, ByRef attributes As ArrayBuilder(Of SynthesizedAttributeData)) + Friend Overrides Sub AddSynthesizedAttributes(moduleBuilder As PEModuleBuilder, ByRef attributes As ArrayBuilder(Of VisualBasicAttributeData)) MyBase.AddSynthesizedAttributes(moduleBuilder, attributes) Dim compilation = DirectCast(Me.ContainingType, AnonymousTypeTemplateSymbol).Manager.Compilation diff --git a/src/Compilers/VisualBasic/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType_IEquatable_EqualsMethodSymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType_IEquatable_EqualsMethodSymbol.vb index 9bbba28d771d9..0d41d57cd7c00 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType_IEquatable_EqualsMethodSymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType_IEquatable_EqualsMethodSymbol.vb @@ -89,7 +89,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols End Get End Property - Friend Overrides Sub AddSynthesizedAttributes(moduleBuilder As PEModuleBuilder, ByRef attributes As ArrayBuilder(Of SynthesizedAttributeData)) + Friend Overrides Sub AddSynthesizedAttributes(moduleBuilder As PEModuleBuilder, ByRef attributes As ArrayBuilder(Of VisualBasicAttributeData)) MyBase.AddSynthesizedAttributes(moduleBuilder, attributes) Dim compilation = DirectCast(Me.ContainingType, AnonymousTypeTemplateSymbol).Manager.Compilation diff --git a/src/Compilers/VisualBasic/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType_PropertyAccessors.vb b/src/Compilers/VisualBasic/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType_PropertyAccessors.vb index 8c162192daf50..c32e4ae3c5d70 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType_PropertyAccessors.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType_PropertyAccessors.vb @@ -38,7 +38,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols End Get End Property - Friend Overrides Sub AddSynthesizedAttributes(moduleBuilder As PEModuleBuilder, ByRef attributes As ArrayBuilder(Of SynthesizedAttributeData)) + Friend Overrides Sub AddSynthesizedAttributes(moduleBuilder As PEModuleBuilder, ByRef attributes As ArrayBuilder(Of VisualBasicAttributeData)) MyBase.AddSynthesizedAttributes(moduleBuilder, attributes) ' Dev11 adds DebuggerNonUserCode; there is no reason to do so since: diff --git a/src/Compilers/VisualBasic/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType_PropertySymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType_PropertySymbol.vb index 79941c6ffb76f..517062768a82c 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType_PropertySymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType_PropertySymbol.vb @@ -164,6 +164,10 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols End Get End Property + Public Overrides Function GetOverloadResolutionPriority() As Integer + Return 0 + End Function + Friend Overrides ReadOnly Property ShadowsExplicitly As Boolean Get Return False diff --git a/src/Compilers/VisualBasic/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType_TemplateSymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType_TemplateSymbol.vb index f8edc8f7e31c2..38f3505642b06 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType_TemplateSymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType_TemplateSymbol.vb @@ -143,7 +143,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols End Get End Property - Friend Overrides Sub AddSynthesizedAttributes(moduleBuilder As PEModuleBuilder, ByRef attributes As ArrayBuilder(Of SynthesizedAttributeData)) + Friend Overrides Sub AddSynthesizedAttributes(moduleBuilder As PEModuleBuilder, ByRef attributes As ArrayBuilder(Of VisualBasicAttributeData)) MyBase.AddSynthesizedAttributes(moduleBuilder, attributes) ' Attribute: System.Runtime.CompilerServices.CompilerGeneratedAttribute() diff --git a/src/Compilers/VisualBasic/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType_ToStringMethodSymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType_ToStringMethodSymbol.vb index d09e5a0359145..5179d03599421 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType_ToStringMethodSymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType_ToStringMethodSymbol.vb @@ -56,7 +56,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols End Get End Property - Friend Overrides Sub AddSynthesizedAttributes(moduleBuilder As PEModuleBuilder, ByRef attributes As ArrayBuilder(Of SynthesizedAttributeData)) + Friend Overrides Sub AddSynthesizedAttributes(moduleBuilder As PEModuleBuilder, ByRef attributes As ArrayBuilder(Of VisualBasicAttributeData)) MyBase.AddSynthesizedAttributes(moduleBuilder, attributes) ' May call user-defined method. diff --git a/src/Compilers/VisualBasic/Portable/Symbols/Attributes/PEAttributeData.vb b/src/Compilers/VisualBasic/Portable/Symbols/Attributes/PEAttributeData.vb index 49d368b35393f..16c6e01fcdfd1 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/Attributes/PEAttributeData.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/Attributes/PEAttributeData.vb @@ -120,7 +120,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols.Metadata.PE Private Sub EnsureLazyMembersAreLoaded() - If _lazyConstructorArguments Is Nothing Then + If Volatile.Read(_lazyConstructorArguments) Is Nothing Then Dim constructorArgs As TypedConstant() = Nothing Dim namedArgs As KeyValuePair(Of String, TypedConstant)() = Nothing diff --git a/src/Compilers/VisualBasic/Portable/Symbols/ErrorMethodSymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/ErrorMethodSymbol.vb index f67b1a089169d..59659fd3c1238 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/ErrorMethodSymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/ErrorMethodSymbol.vb @@ -147,6 +147,10 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols End Get End Property + Public Overrides Function GetOverloadResolutionPriority() As Integer + Return 0 + End Function + Public Overrides ReadOnly Property IsOverridable As Boolean Get Return False diff --git a/src/Compilers/VisualBasic/Portable/Symbols/ErrorTypeSymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/ErrorTypeSymbol.vb index 044392d3ad0ee..ba1990b07061d 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/ErrorTypeSymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/ErrorTypeSymbol.vb @@ -251,6 +251,12 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols End Get End Property + Friend Overrides ReadOnly Property HasCompilerLoweringPreserveAttribute As Boolean + Get + Return False + End Get + End Property + Friend Overrides ReadOnly Property IsExtensibleInterfaceNoUseSiteDiagnostics As Boolean Get Return False diff --git a/src/Compilers/VisualBasic/Portable/Symbols/Metadata/PE/PEGlobalNamespaceSymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/Metadata/PE/PEGlobalNamespaceSymbol.vb index 008058c1912b4..f8d33217132f5 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/Metadata/PE/PEGlobalNamespaceSymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/Metadata/PE/PEGlobalNamespaceSymbol.vb @@ -7,6 +7,7 @@ Imports Microsoft.CodeAnalysis.Text Imports Microsoft.CodeAnalysis.VisualBasic.Symbols Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Imports System.Reflection.Metadata +Imports System.Threading Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols.Metadata.PE @@ -61,7 +62,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols.Metadata.PE End Property Protected Overrides Sub EnsureAllMembersLoaded() - If m_lazyTypes Is Nothing OrElse m_lazyMembers Is Nothing Then + If Volatile.Read(m_lazyTypes) Is Nothing OrElse Volatile.Read(m_lazyMembers) Is Nothing Then Dim groups As IEnumerable(Of IGrouping(Of String, TypeDefinitionHandle)) Try diff --git a/src/Compilers/VisualBasic/Portable/Symbols/Metadata/PE/PEMethodSymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/Metadata/PE/PEMethodSymbol.vb index ab330becff378..fab30cfd986b8 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/Metadata/PE/PEMethodSymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/Metadata/PE/PEMethodSymbol.vb @@ -52,7 +52,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols.Metadata.PE Private Structure PackedFlags ' Flags are packed into a 32-bit int with the following layout: - ' | l|k|j|i|h|g|f|e|d|c|b|aaaaa| + ' | m|l|k|j|i|h|g|f|e|d|c|b|aaaaa| ' ' a = method kind. 5 bits ' b = method kind populated. 1 bit @@ -66,6 +66,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols.Metadata.PE ' j = is init-only populated. 1 bit. ' k = has SetsRequiredMembers. 1 bit. ' l = has SetsRequiredMembers populated. 1 bit. + ' m = OverloadResolutionPriority populated. 1 bit. Private _bits As Integer @@ -82,6 +83,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols.Metadata.PE Private Const s_isInitOnlyPopulatedBit = 1 << 13 Private Const s_hasSetsRequiredMembersBit = 1 << 14 Private Const s_hasSetsRequiredMembersPopulatedBit = 1 << 15 + Private Const s_OverloadResolutionPriorityIsPopulatedBit As Integer = 1 << 16 Public Property MethodKind As MethodKind Get @@ -113,25 +115,25 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols.Metadata.PE Public ReadOnly Property IsObsoleteAttributePopulated As Boolean Get - Return (_bits And s_isObsoleteAttributePopulatedBit) <> 0 + Return (Volatile.Read(_bits) And s_isObsoleteAttributePopulatedBit) <> 0 End Get End Property Public ReadOnly Property IsCustomAttributesPopulated As Boolean Get - Return (_bits And s_isCustomAttributesPopulatedBit) <> 0 + Return (Volatile.Read(_bits) And s_isCustomAttributesPopulatedBit) <> 0 End Get End Property Public ReadOnly Property IsUseSiteDiagnosticPopulated As Boolean Get - Return (_bits And s_isUseSiteDiagnosticPopulatedBit) <> 0 + Return (Volatile.Read(_bits) And s_isUseSiteDiagnosticPopulatedBit) <> 0 End Get End Property Public ReadOnly Property IsConditionalPopulated As Boolean Get - Return (_bits And s_isConditionalAttributePopulatedBit) <> 0 + Return (Volatile.Read(_bits) And s_isConditionalAttributePopulatedBit) <> 0 End Get End Property @@ -197,6 +199,16 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols.Metadata.PE Debug.Assert(BitsAreUnsetOrSame(_bits, bitsToSet)) ThreadSafeFlagOperations.Set(_bits, bitsToSet) End Sub + + Public ReadOnly Property OverloadResolutionPriorityPopulated As Boolean + Get + Return (Volatile.Read(_bits) And s_OverloadResolutionPriorityIsPopulatedBit) <> 0 + End Get + End Property + + Public Sub SetOverloadResolutionPriorityPopulated() + ThreadSafeFlagOperations.Set(_bits, s_OverloadResolutionPriorityIsPopulatedBit) + End Sub End Structure ''' @@ -209,6 +221,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols.Metadata.PE Public _lazyConditionalAttributeSymbols As ImmutableArray(Of String) Public _lazyObsoleteAttributeData As ObsoleteAttributeData Public _lazyCachedUseSiteInfo As CachedUseSiteInfo(Of AssemblySymbol) + Public _lazyOverloadResolutionPriority As Integer End Class Private Function CreateUncommonFields() As UncommonFields @@ -823,6 +836,26 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols.Metadata.PE End Get End Property + Public Overrides Function GetOverloadResolutionPriority() As Integer + If Not _packedFlags.OverloadResolutionPriorityPopulated Then + + Dim priority As Integer + If _containingType.ContainingPEModule.Module.TryGetOverloadResolutionPriorityValue(_handle, priority) AndAlso + priority <> 0 Then + Interlocked.CompareExchange(AccessUncommonFields()._lazyOverloadResolutionPriority, priority, 0) +#If DEBUG Then + Else + ' 0 is the default if nothing is present in metadata, and we don't care about preserving the difference between "not present" and "set to the default value". + Debug.Assert(_uncommonFields Is Nothing OrElse _uncommonFields._lazyOverloadResolutionPriority = 0) +#End If + End If + + _packedFlags.SetOverloadResolutionPriorityPopulated() + End If + + Return If(_uncommonFields?._lazyOverloadResolutionPriority, 0) + End Function + Friend Overrides ReadOnly Property IsHiddenBySignature As Boolean Get Return (_flags And MethodAttributes.HideBySig) <> 0 diff --git a/src/Compilers/VisualBasic/Portable/Symbols/Metadata/PE/PENamedTypeSymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/Metadata/PE/PENamedTypeSymbol.vb index 7f75caa280d6a..b512b6b7b84d0 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/Metadata/PE/PENamedTypeSymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/Metadata/PE/PENamedTypeSymbol.vb @@ -84,6 +84,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols.Metadata.PE Private _lazyHasVisualBasicEmbeddedAttribute As Integer = ThreeState.Unknown + Private _lazyHasCompilerLoweringPreserveAttribute As Integer = ThreeState.Unknown + Private _lazyObsoleteAttributeData As ObsoleteAttributeData = ObsoleteAttributeData.Uninitialized Private _lazyIsExtensibleInterface As ThreeState = ThreeState.Unknown @@ -649,7 +651,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols.Metadata.PE Private Sub EnsureNonTypeMembersAreLoaded() - If _lazyMembers Is Nothing Then + If Volatile.Read(_lazyMembers) Is Nothing Then ' A method may be referenced as an accessor by one or more properties. And, ' any of those properties may be "bogus" if one of the property accessors ' does not match the property signature. If the method is referenced by at @@ -963,6 +965,18 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols.Metadata.PE End Get End Property + Friend Overrides ReadOnly Property HasCompilerLoweringPreserveAttribute As Boolean + Get + If Me._lazyHasCompilerLoweringPreserveAttribute = ThreeState.Unknown Then + Interlocked.CompareExchange( + Me._lazyHasCompilerLoweringPreserveAttribute, + Me.ContainingPEModule.Module.HasCompilerLoweringPreserveAttribute(Me._handle).ToThreeState(), + ThreeState.Unknown) + End If + Return Me._lazyHasCompilerLoweringPreserveAttribute = ThreeState.True + End Get + End Property + Friend Overrides Sub BuildExtensionMethodsMap( map As Dictionary(Of String, ArrayBuilder(Of MethodSymbol)), appendThrough As NamespaceSymbol diff --git a/src/Compilers/VisualBasic/Portable/Symbols/Metadata/PE/PENestedNamespaceSymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/Metadata/PE/PENestedNamespaceSymbol.vb index 00c6f1ffb132a..606f94044b031 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/Metadata/PE/PENestedNamespaceSymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/Metadata/PE/PENestedNamespaceSymbol.vb @@ -118,10 +118,11 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols.Metadata.PE End Property Protected Overrides Sub EnsureAllMembersLoaded() - Dim typesByNS = _typesByNS + Dim typesByNS = Volatile.Read(_typesByNS) - If m_lazyTypes Is Nothing OrElse m_lazyMembers Is Nothing Then - Debug.Assert(typesByNS IsNot Nothing) + If typesByNS Is Nothing Then + Debug.Assert(m_lazyTypes IsNot Nothing AndAlso m_lazyMembers IsNot Nothing) + Else LoadAllMembers(typesByNS) Interlocked.Exchange(_typesByNS, Nothing) End If diff --git a/src/Compilers/VisualBasic/Portable/Symbols/Metadata/PE/PEPropertySymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/Metadata/PE/PEPropertySymbol.vb index e25261d5bdda6..5c7571f2bc81b 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/Metadata/PE/PEPropertySymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/Metadata/PE/PEPropertySymbol.vb @@ -11,6 +11,7 @@ Imports Microsoft.Cci Imports Microsoft.CodeAnalysis.PooledObjects Imports System.Reflection.Metadata.Ecma335 Imports Microsoft.CodeAnalysis.VisualBasic.Emit +Imports System.Runtime.CompilerServices Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols.Metadata.PE @@ -45,6 +46,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols.Metadata.PE Private _lazyObsoleteAttributeData As ObsoleteAttributeData = ObsoleteAttributeData.Uninitialized Private _lazyIsRequired As ThreeState = ThreeState.Unknown + Private _lazyOverloadResolutionPriority As StrongBox(Of Integer) Friend Shared Function Create( moduleSymbol As PEModuleSymbol, @@ -220,6 +222,20 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols.Metadata.PE End Get End Property + Public Overrides Function GetOverloadResolutionPriority() As Integer + If _lazyOverloadResolutionPriority Is Nothing Then + + Dim priority As Integer + If Not _containingType.ContainingPEModule.Module.TryGetOverloadResolutionPriorityValue(_handle, priority) Then + priority = 0 + End If + + Interlocked.CompareExchange(_lazyOverloadResolutionPriority, New StrongBox(Of Integer)(priority), Nothing) + End If + + Return _lazyOverloadResolutionPriority.Value + End Function + Public Overrides ReadOnly Property IsShared As Boolean Get Return (Me._getMethod Is Nothing OrElse Me._getMethod.IsShared) AndAlso diff --git a/src/Compilers/VisualBasic/Portable/Symbols/Metadata/PE/PETypeParameterSymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/Metadata/PE/PETypeParameterSymbol.vb index e1d387a2b4924..055fb569b2251 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/Metadata/PE/PETypeParameterSymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/Metadata/PE/PETypeParameterSymbol.vb @@ -13,6 +13,7 @@ Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Imports System.Reflection Imports System.Reflection.Metadata.Ecma335 Imports System.Runtime.InteropServices +Imports Microsoft.CodeAnalysis.Collections Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols.Metadata.PE @@ -312,7 +313,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols.Metadata.PE End Property Friend Overrides Sub EnsureAllConstraintsAreResolved() - If _lazyConstraintTypes.IsDefault Then + If RoslynImmutableInterlocked.VolatileRead(_lazyConstraintTypes).IsDefault Then Dim typeParameters = If(_containingSymbol.Kind = SymbolKind.Method, DirectCast(_containingSymbol, PEMethodSymbol).TypeParameters, DirectCast(_containingSymbol, PENamedTypeSymbol).TypeParameters) @@ -324,7 +325,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols.Metadata.PE Debug.Assert(Not inProgress.Contains(Me)) Debug.Assert(Not inProgress.Any() OrElse inProgress.Head.ContainingSymbol Is ContainingSymbol) - If _lazyConstraintTypes.IsDefault Then + If RoslynImmutableInterlocked.VolatileRead(_lazyConstraintTypes).IsDefault Then Dim diagnosticsBuilder = ArrayBuilder(Of TypeParameterDiagnosticInfo).GetInstance() Dim inherited = (_containingSymbol.Kind = SymbolKind.Method) AndAlso DirectCast(_containingSymbol, MethodSymbol).IsOverrides Dim hasUnmanagedModreqPattern As Boolean = False diff --git a/src/Compilers/VisualBasic/Portable/Symbols/MethodSymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/MethodSymbol.vb index 3101385966ebc..215b7105d69f8 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/MethodSymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/MethodSymbol.vb @@ -172,7 +172,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols ''' ''' Build and add synthesized return type attributes for this method symbol. ''' - Friend Overridable Sub AddSynthesizedReturnTypeAttributes(ByRef attributes As ArrayBuilder(Of SynthesizedAttributeData)) + Friend Overridable Sub AddSynthesizedReturnTypeAttributes(ByRef attributes As ArrayBuilder(Of VisualBasicAttributeData)) End Sub ''' @@ -437,6 +437,36 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols ''' Public MustOverride ReadOnly Property IsOverloads As Boolean + ''' + ''' Gets the resolution priority of this method, 0 if not set. + ''' + ''' + ''' Do not call this method from early attribute binding, cycles will occur. + ''' + Public ReadOnly Property OverloadResolutionPriority As Integer + Get + Return If(CanHaveOverloadResolutionPriority, GetOverloadResolutionPriority(), 0) + End Get + End Property + + Public MustOverride Function GetOverloadResolutionPriority() As Integer + + Public ReadOnly Property CanHaveOverloadResolutionPriority As Boolean + Get + Select Case MethodKind + Case MethodKind.Ordinary, + MethodKind.Constructor, + MethodKind.UserDefinedOperator, + MethodKind.ReducedExtension + + Return Not IsOverrides + + Case Else + Return False + End Select + End Get + End Property + ''' ''' True if the implementation of this method is supplied by the runtime. ''' diff --git a/src/Compilers/VisualBasic/Portable/Symbols/NamedTypeSymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/NamedTypeSymbol.vb index b983ef0e1e1e1..dc4e530696574 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/NamedTypeSymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/NamedTypeSymbol.vb @@ -286,6 +286,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols ''' Friend MustOverride ReadOnly Property HasVisualBasicEmbeddedAttribute As Boolean + Friend MustOverride ReadOnly Property HasCompilerLoweringPreserveAttribute As Boolean + ''' ''' A Named type is an extensible interface if both the following are true: ''' (a) It is an interface type and diff --git a/src/Compilers/VisualBasic/Portable/Symbols/ObsoleteAttributeHelpers.vb b/src/Compilers/VisualBasic/Portable/Symbols/ObsoleteAttributeHelpers.vb index a365857816ec6..690d292d318ab 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/ObsoleteAttributeHelpers.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/ObsoleteAttributeHelpers.vb @@ -142,15 +142,18 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols Debug.Assert(data.Message Is Nothing) Debug.Assert(Not data.IsError) ' Provide an explicit format for fully-qualified type names. - Return ErrorFactory.ErrorInfo(ERRID.WRN_Experimental, New FormattedSymbol(symbol, SymbolDisplayFormat.VisualBasicErrorMessageFormat)) + Return ErrorFactory.ErrorInfo(ERRID.WRN_Experimental, New FormattedSymbol(symbol, SymbolDisplayFormat.VisualBasicErrorMessageFormat), "", "") End If If data.Kind = ObsoleteAttributeKind.Experimental Then - Debug.Assert(data.Message Is Nothing) Debug.Assert(Not data.IsError) ' Provide an explicit format for fully-qualified type names. - Return New CustomObsoleteDiagnosticInfo(MessageProvider.Instance, ERRID.WRN_Experimental, - data, New FormattedSymbol(symbol, SymbolDisplayFormat.VisualBasicErrorMessageFormat)) + If String.IsNullOrEmpty(data.Message) Then + Return New CustomObsoleteDiagnosticInfo(MessageProvider.Instance, ERRID.WRN_Experimental, data, New FormattedSymbol(symbol, SymbolDisplayFormat.VisualBasicErrorMessageFormat)) + Else + Return New CustomObsoleteDiagnosticInfo(MessageProvider.Instance, ERRID.WRN_ExperimentalWithMessage, data, New FormattedSymbol(symbol, SymbolDisplayFormat.VisualBasicErrorMessageFormat), + data.Message) + End If End If ' For property accessors we report a special diagnostic which indicates whether the getter or setter is obsolete. diff --git a/src/Compilers/VisualBasic/Portable/Symbols/PropertySymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/PropertySymbol.vb index e88c3d0b985a6..29ecdc870a5fe 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/PropertySymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/PropertySymbol.vb @@ -301,6 +301,23 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols ''' Public MustOverride ReadOnly Property IsOverloads As Boolean + ''' + ''' Gets the resolution priority of this property, 0 if not set. + ''' + Public ReadOnly Property OverloadResolutionPriority As Integer + Get + Return If(CanHaveOverloadResolutionPriority, GetOverloadResolutionPriority(), 0) + End Get + End Property + + Public MustOverride Function GetOverloadResolutionPriority() As Integer + + Public ReadOnly Property CanHaveOverloadResolutionPriority As Boolean + Get + Return Not IsOverrides + End Get + End Property + ''' ''' If this property overrides another property (because it both had the Overrides modifier ''' and there correctly was a property to override), returns the overridden property. diff --git a/src/Compilers/VisualBasic/Portable/Symbols/ReducedExtensionMethodSymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/ReducedExtensionMethodSymbol.vb index bc1475beaed91..789c95170dc00 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/ReducedExtensionMethodSymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/ReducedExtensionMethodSymbol.vb @@ -444,6 +444,10 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols End Get End Property + Public Overrides Function GetOverloadResolutionPriority() As Integer + Return _curriedFromMethod.GetOverloadResolutionPriority() + End Function + Public Overrides ReadOnly Property IsShared As Boolean Get Return False diff --git a/src/Compilers/VisualBasic/Portable/Symbols/Retargeting/RetargetingMethodSymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/Retargeting/RetargetingMethodSymbol.vb index 00bd421bbaab5..cb8dbeac81ea4 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/Retargeting/RetargetingMethodSymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/Retargeting/RetargetingMethodSymbol.vb @@ -241,6 +241,10 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols.Retargeting End Get End Property + Public Overrides Function GetOverloadResolutionPriority() As Integer + Return _underlyingMethod.GetOverloadResolutionPriority() + End Function + Friend Overrides ReadOnly Property IsHiddenBySignature As Boolean Get Return _underlyingMethod.IsHiddenBySignature diff --git a/src/Compilers/VisualBasic/Portable/Symbols/Retargeting/RetargetingNamedTypeSymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/Retargeting/RetargetingNamedTypeSymbol.vb index dbfdad97cd702..e9c738c635bdd 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/Retargeting/RetargetingNamedTypeSymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/Retargeting/RetargetingNamedTypeSymbol.vb @@ -130,6 +130,12 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols.Retargeting End Get End Property + Friend Overrides ReadOnly Property HasCompilerLoweringPreserveAttribute As Boolean + Get + Return _underlyingType.HasCompilerLoweringPreserveAttribute + End Get + End Property + Friend Overrides ReadOnly Property IsExtensibleInterfaceNoUseSiteDiagnostics As Boolean Get Return _underlyingType.IsExtensibleInterfaceNoUseSiteDiagnostics diff --git a/src/Compilers/VisualBasic/Portable/Symbols/Retargeting/RetargetingPropertySymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/Retargeting/RetargetingPropertySymbol.vb index 308499a9c2c66..f2dc9d2a8dd06 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/Retargeting/RetargetingPropertySymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/Retargeting/RetargetingPropertySymbol.vb @@ -154,6 +154,10 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols.Retargeting End Get End Property + Public Overrides Function GetOverloadResolutionPriority() As Integer + Return _underlyingProperty.GetOverloadResolutionPriority() + End Function + Public Overrides ReadOnly Property IsShared As Boolean Get Return _underlyingProperty.IsShared diff --git a/src/Compilers/VisualBasic/Portable/Symbols/SignatureOnlyMethodSymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/SignatureOnlyMethodSymbol.vb index 5455c9e34853d..a7e55a7ce910a 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/SignatureOnlyMethodSymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/SignatureOnlyMethodSymbol.vb @@ -249,6 +249,10 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols End Get End Property + Public Overrides Function GetOverloadResolutionPriority() As Integer + Return 0 + End Function + Public Overrides ReadOnly Property IsExternalMethod As Boolean Get Throw ExceptionUtilities.Unreachable diff --git a/src/Compilers/VisualBasic/Portable/Symbols/SignatureOnlyPropertySymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/SignatureOnlyPropertySymbol.vb index ee362dfe262aa..998c8efb8f7b4 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/SignatureOnlyPropertySymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/SignatureOnlyPropertySymbol.vb @@ -187,6 +187,10 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols End Get End Property + Public Overrides Function GetOverloadResolutionPriority() As Integer + Return 0 + End Function + Public Overrides ReadOnly Property IsOverridable As Boolean Get Throw ExceptionUtilities.Unreachable diff --git a/src/Compilers/VisualBasic/Portable/Symbols/Source/ImplicitNamedTypeSymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/Source/ImplicitNamedTypeSymbol.vb index 7dfc25b44d9fb..b2b9c54651a72 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/Source/ImplicitNamedTypeSymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/Source/ImplicitNamedTypeSymbol.vb @@ -153,6 +153,12 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols End Get End Property + Friend Overrides ReadOnly Property HasCompilerLoweringPreserveAttribute As Boolean + Get + Return False + End Get + End Property + Friend Overrides ReadOnly Property CoClassType As TypeSymbol Get Return Nothing diff --git a/src/Compilers/VisualBasic/Portable/Symbols/Source/LambdaSymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/Source/LambdaSymbol.vb index 4e1db4d908905..65733f1a215e0 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/Source/LambdaSymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/Source/LambdaSymbol.vb @@ -208,6 +208,10 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols End Get End Property + Public Overrides Function GetOverloadResolutionPriority() As Integer + Return 0 + End Function + Public Overrides ReadOnly Property IsOverridable As Boolean Get Return False diff --git a/src/Compilers/VisualBasic/Portable/Symbols/Source/SourceAssemblySymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/Source/SourceAssemblySymbol.vb index 175b566f28210..998d7e2c78e25 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/Source/SourceAssemblySymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/Source/SourceAssemblySymbol.vb @@ -1508,7 +1508,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols Return guidString IsNot Nothing End Function - Friend Overrides Sub AddSynthesizedAttributes(moduleBuilder As PEModuleBuilder, ByRef attributes As ArrayBuilder(Of SynthesizedAttributeData)) + Friend Overrides Sub AddSynthesizedAttributes(moduleBuilder As PEModuleBuilder, ByRef attributes As ArrayBuilder(Of VisualBasicAttributeData)) MyBase.AddSynthesizedAttributes(moduleBuilder, attributes) Debug.Assert(_lazyEmitExtensionAttribute <> ThreeState.Unknown) diff --git a/src/Compilers/VisualBasic/Portable/Symbols/Source/SourceEventSymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/Source/SourceEventSymbol.vb index 8cf47f22d2330..6b24aaf8b729a 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/Source/SourceEventSymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/Source/SourceEventSymbol.vb @@ -775,7 +775,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols End Get End Property - Friend Overrides Sub AddSynthesizedAttributes(moduleBuilder As PEModuleBuilder, ByRef attributes As ArrayBuilder(Of SynthesizedAttributeData)) + Friend Overrides Sub AddSynthesizedAttributes(moduleBuilder As PEModuleBuilder, ByRef attributes As ArrayBuilder(Of VisualBasicAttributeData)) MyBase.AddSynthesizedAttributes(moduleBuilder, attributes) If Me.Type.ContainsTupleNames() Then diff --git a/src/Compilers/VisualBasic/Portable/Symbols/Source/SourceFieldSymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/Source/SourceFieldSymbol.vb index 9e7528edde223..d7b8ab2e9a071 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/Source/SourceFieldSymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/Source/SourceFieldSymbol.vb @@ -672,7 +672,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols _lazyCustomAttributesBag = attributeData End Sub - Friend Overrides Sub AddSynthesizedAttributes(moduleBuilder As PEModuleBuilder, ByRef attributes As ArrayBuilder(Of SynthesizedAttributeData)) + Friend Overrides Sub AddSynthesizedAttributes(moduleBuilder As PEModuleBuilder, ByRef attributes As ArrayBuilder(Of VisualBasicAttributeData)) MyBase.AddSynthesizedAttributes(moduleBuilder, attributes) If Me.IsConst Then diff --git a/src/Compilers/VisualBasic/Portable/Symbols/Source/SourceMemberContainerTypeSymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/Source/SourceMemberContainerTypeSymbol.vb index 5119595df0745..5f636c7163de5 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/Source/SourceMemberContainerTypeSymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/Source/SourceMemberContainerTypeSymbol.vb @@ -60,6 +60,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols ReportedVarianceDiagnostics = &H2 ' Set if variance diagnostics have been reported. ReportedBaseClassConstraintsDiagnostics = &H4 ' Set if base class constraints diagnostics have been reported. ReportedInterfacesConstraintsDiagnostics = &H8 ' Set if constraints diagnostics for base/implemented interfaces have been reported. + ReportedCodeAnalysisEmbeddedAttributeDiagnostics = &H10 ' Set if the symbol has been checked for Microsoft.CodeAnalysis.EmbeddedAttribute definition diagnostics. End Enum ' Containing symbol @@ -4034,7 +4035,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols End Get End Property - Friend Overrides Sub AddSynthesizedAttributes(moduleBuilder As PEModuleBuilder, ByRef attributes As ArrayBuilder(Of SynthesizedAttributeData)) + Friend Overrides Sub AddSynthesizedAttributes(moduleBuilder As PEModuleBuilder, ByRef attributes As ArrayBuilder(Of VisualBasicAttributeData)) MyBase.AddSynthesizedAttributes(moduleBuilder, attributes) If EmitExtensionAttribute Then diff --git a/src/Compilers/VisualBasic/Portable/Symbols/Source/SourceMemberMethodSymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/Source/SourceMemberMethodSymbol.vb index f490fba947be1..34d12ee3d5df0 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/Source/SourceMemberMethodSymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/Source/SourceMemberMethodSymbol.vb @@ -175,7 +175,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols End Get End Property - Friend Overrides Sub AddSynthesizedAttributes(moduleBuilder As PEModuleBuilder, ByRef attributes As ArrayBuilder(Of SynthesizedAttributeData)) + Friend Overrides Sub AddSynthesizedAttributes(moduleBuilder As PEModuleBuilder, ByRef attributes As ArrayBuilder(Of VisualBasicAttributeData)) MyBase.AddSynthesizedAttributes(moduleBuilder, attributes) If Me.IsAsync OrElse Me.IsIterator Then diff --git a/src/Compilers/VisualBasic/Portable/Symbols/Source/SourceMethodSymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/Source/SourceMethodSymbol.vb index bcf324bcc0325..a8ab13a0b9526 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/Source/SourceMethodSymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/Source/SourceMethodSymbol.vb @@ -1434,7 +1434,7 @@ lReportErrorOnTwoTokens: Return Me.GetAttributesBag().Attributes End Function - Friend Overrides Sub AddSynthesizedAttributes(moduleBuilder As PEModuleBuilder, ByRef attributes As ArrayBuilder(Of SynthesizedAttributeData)) + Friend Overrides Sub AddSynthesizedAttributes(moduleBuilder As PEModuleBuilder, ByRef attributes As ArrayBuilder(Of VisualBasicAttributeData)) MyBase.AddSynthesizedAttributes(moduleBuilder, attributes) ' Emit synthesized STAThreadAttribute for this method if both the following requirements are met: @@ -1454,7 +1454,7 @@ lReportErrorOnTwoTokens: End If End Sub - Friend Overrides Sub AddSynthesizedReturnTypeAttributes(ByRef attributes As ArrayBuilder(Of SynthesizedAttributeData)) + Friend Overrides Sub AddSynthesizedReturnTypeAttributes(ByRef attributes As ArrayBuilder(Of VisualBasicAttributeData)) MyBase.AddSynthesizedReturnTypeAttributes(attributes) If Me.ReturnType.ContainsTupleNames() Then @@ -1529,6 +1529,21 @@ lReportErrorOnTwoTokens: Else Return Nothing End If + ElseIf VisualBasicAttributeData.IsTargetEarlyAttribute(arguments.AttributeType, arguments.AttributeSyntax, AttributeDescription.OverloadResolutionPriorityAttribute) Then + + If Not CanHaveOverloadResolutionPriority Then + 'Cannot use 'OverloadResolutionPriorityAttribute' on this member. + Return Nothing + End If + + Dim attrdata = arguments.Binder.GetAttribute(arguments.AttributeSyntax, arguments.AttributeType, hasAnyDiagnostics) + If Not attrdata.HasErrors AndAlso attrdata.IsTargetAttribute(AttributeDescription.OverloadResolutionPriorityAttribute) Then + Dim priority As Integer = attrdata.GetConstructorArgument(Of Integer)(0, SpecialType.System_Int32) + arguments.GetOrCreateData(Of MethodEarlyWellKnownAttributeData)().OverloadResolutionPriority = priority + Return If(Not hasAnyDiagnostics, attrdata, Nothing) + Else + Return Nothing + End If Else Dim BoundAttribute As VisualBasicAttributeData = Nothing Dim obsoleteData As ObsoleteAttributeData = Nothing @@ -1566,6 +1581,11 @@ lReportErrorOnTwoTokens: Return If(data IsNot Nothing, data.ConditionalSymbols, ImmutableArray(Of String).Empty) End Function + Public NotOverridable Overrides Function GetOverloadResolutionPriority() As Integer + Dim data As MethodEarlyWellKnownAttributeData = Me.GetEarlyDecodedWellKnownAttributeData() + Return If(data?.OverloadResolutionPriority, 0) + End Function + Friend Overrides Sub DecodeWellKnownAttribute(ByRef arguments As DecodeWellKnownAttributeArguments(Of AttributeSyntax, VisualBasicAttributeData, AttributeLocation)) Dim attrData = arguments.Attribute Debug.Assert(Not attrData.HasErrors) @@ -1729,6 +1749,19 @@ lReportErrorOnTwoTokens: ElseIf VerifyObsoleteAttributeAppliedToMethod(arguments, AttributeDescription.DeprecatedAttribute) Then ElseIf arguments.Attribute.IsTargetAttribute(AttributeDescription.ModuleInitializerAttribute) Then diagnostics.Add(ERRID.WRN_AttributeNotSupportedInVB, arguments.AttributeSyntaxOpt.Location, AttributeDescription.ModuleInitializerAttribute.FullName) + ElseIf arguments.Attribute.IsTargetAttribute(AttributeDescription.OverloadResolutionPriorityAttribute) Then + + If Not CanHaveOverloadResolutionPriority Then + diagnostics.Add(If(IsOverrides, + ERRID.ERR_CannotApplyOverloadResolutionPriorityToOverride, + ERRID.ERR_CannotApplyOverloadResolutionPriorityToMember), + arguments.AttributeSyntaxOpt.GetLocation()) + Else + InternalSyntax.Parser.CheckFeatureAvailability(diagnostics, + arguments.AttributeSyntaxOpt.GetLocation(), + DirectCast(arguments.AttributeSyntaxOpt.SyntaxTree.Options, VisualBasicParseOptions).LanguageVersion, + InternalSyntax.Feature.OverloadResolutionPriority) + End If Else Dim methodImpl As MethodSymbol = If(Me.IsPartial, PartialImplementationPart, Me) diff --git a/src/Compilers/VisualBasic/Portable/Symbols/Source/SourceNamedTypeSymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/Source/SourceNamedTypeSymbol.vb index abd72dfff73ac..17bf9ed29de80 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/Source/SourceNamedTypeSymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/Source/SourceNamedTypeSymbol.vb @@ -120,6 +120,9 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols cancellationToken.ThrowIfCancellationRequested() CheckInterfacesConstraints() + + cancellationToken.ThrowIfCancellationRequested() + CheckEmbeddedAttributeImplementation() End Sub #End Region @@ -1687,16 +1690,52 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols End If End If + m_containingModule.AtomicSetFlagAndStoreDiagnostics(m_lazyState, StateFlags.ReportedInterfacesConstraintsDiagnostics, 0, diagnostics) + + If diagnostics IsNot Nothing Then + diagnostics.Free() + End If + End Sub + + Private Sub CheckEmbeddedAttributeImplementation() + If (m_lazyState And StateFlags.ReportedCodeAnalysisEmbeddedAttributeDiagnostics) <> 0 Then + Return + End If + + Dim diagnostics As BindingDiagnosticBag = Nothing + If Me.IsMicrosoftCodeAnalysisEmbeddedAttribute() Then + ' This is a user-defined implementation of the special attribute Microsoft.CodeAnalysis.EmbeddedAttribute. It needs to follow specific rules + ' 1. It must be Friend + ' 2. It must be a Class + ' 3. It must be NotInheritable + ' 4. It must not be a Module + ' 5. It must have a Public parameterless constructor. This is different from C#, because VB requires any attribute to have a Public parameterless constructor. + ' 6. It must inherit from System.Attribute + ' 7. It must be allowed on any type declaration (Class, Struct, Interface, Enum, or Delegate) + ' 8. It must be non-generic. Note that generic attributes are not supported in VB, and won't pass the `IsMicrosoftCodeAnalysisEmbeddedAttribute` check, it's just listed here for completeness. + + Const expectedTargets = AttributeTargets.Class Or AttributeTargets.Struct Or AttributeTargets.Interface Or AttributeTargets.Enum Or AttributeTargets.Delegate + + If DeclaredAccessibility <> Accessibility.Friend OrElse + TypeKind <> TypeKind.Class OrElse + (Not IsNotInheritable) OrElse + IsShared OrElse + (Not InstanceConstructors.Any(Function(c) c.ParameterCount = 0 AndAlso c.DeclaredAccessibility = Accessibility.Public)) OrElse + (Not DeclaringCompilation.IsAttributeType(Me)) OrElse + (GetAttributeUsageInfo().ValidTargets And expectedTargets) <> expectedTargets Then + diagnostics = BindingDiagnosticBag.GetInstance() + diagnostics.Add(ERRID.ERR_EmbeddedAttributeMustFollowPattern, TypeDeclaration.Declarations(0).Location) + End If + End If + If m_containingModule.AtomicSetFlagAndStoreDiagnostics(m_lazyState, - StateFlags.ReportedInterfacesConstraintsDiagnostics, + StateFlags.ReportedCodeAnalysisEmbeddedAttributeDiagnostics, 0, diagnostics) Then DeclaringCompilation.SymbolDeclaredEvent(Me) End If - If diagnostics IsNot Nothing Then - diagnostics.Free() - End If + diagnostics?.Free() End Sub ''' @@ -1870,7 +1909,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols Friend Overrides ReadOnly Property HasCodeAnalysisEmbeddedAttribute As Boolean Get Dim data As TypeEarlyWellKnownAttributeData = GetEarlyDecodedWellKnownAttributeData() - Return data IsNot Nothing AndAlso data.HasCodeAnalysisEmbeddedAttribute + ' We synthesize an application of Microsoft.CodeAnalysis.EmbeddedAttribute on Microsoft.CodeAnalysis.EmbeddedAttribute if one wasn't present + Return (data IsNot Nothing AndAlso data.HasCodeAnalysisEmbeddedAttribute) OrElse Me.IsMicrosoftCodeAnalysisEmbeddedAttribute() End Get End Property @@ -1881,6 +1921,14 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols End Get End Property + Friend Overrides ReadOnly Property HasCompilerLoweringPreserveAttribute As Boolean + Get + Dim attributesBag = GetAttributesBag() + Dim wellKnownAttributeData = DirectCast(attributesBag.DecodedWellKnownAttributeData, CommonTypeWellKnownAttributeData) + Return (wellKnownAttributeData IsNot Nothing) AndAlso wellKnownAttributeData.HasCompilerLoweringPreserveAttribute + End Get + End Property + Friend Overrides ReadOnly Property IsExtensibleInterfaceNoUseSiteDiagnostics As Boolean Get If _lazyIsExtensibleInterface = ThreeState.Unknown Then @@ -2304,6 +2352,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols ElseIf attrData.IsTargetAttribute(AttributeDescription.RequiredAttributeAttribute) Then Debug.Assert(arguments.AttributeSyntaxOpt IsNot Nothing) diagnostics.Add(ERRID.ERR_CantUseRequiredAttribute, arguments.AttributeSyntaxOpt.GetLocation(), Me) + ElseIf attrData.IsTargetAttribute(AttributeDescription.CompilerLoweringPreserveAttribute) Then + arguments.GetOrCreateData(Of CommonTypeWellKnownAttributeData)().HasCompilerLoweringPreserveAttribute = True End If End If @@ -2475,7 +2525,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols End Get End Property - Friend Overrides Sub AddSynthesizedAttributes(moduleBuilder As PEModuleBuilder, ByRef attributes As ArrayBuilder(Of SynthesizedAttributeData)) + Friend Overrides Sub AddSynthesizedAttributes(moduleBuilder As PEModuleBuilder, ByRef attributes As ArrayBuilder(Of VisualBasicAttributeData)) MyBase.AddSynthesizedAttributes(moduleBuilder, attributes) Dim compilation = Me.DeclaringCompilation @@ -2532,6 +2582,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols ImmutableArray.Create( New TypedConstant(GetSpecialType(SpecialType.System_String), TypedConstantKind.Primitive, eventInterfaceName)))) End If + End If Dim baseType As NamedTypeSymbol = Me.BaseTypeNoUseSiteDiagnostics @@ -2559,6 +2610,26 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols ImmutableArray.Create(New TypedConstant(compilation.GetWellKnownType(WellKnownType.System_Type), TypedConstantKind.Type, originalType)), isOptionalUse:=True)) End If + + If Me.IsMicrosoftCodeAnalysisEmbeddedAttribute() Then + Dim earlyAttributeData = GetEarlyDecodedWellKnownAttributeData() + + If earlyAttributeData Is Nothing OrElse Not earlyAttributeData.HasCodeAnalysisEmbeddedAttribute Then + ' Get the parameterless constructor and apply it to the current type. If there wasn't a parameterless constructor, we would have + ' issued a declaration diagnostic + + Dim parameterlessConstructor = InstanceConstructors.FirstOrDefault(Function(c) c.ParameterCount = 0) + If parameterlessConstructor IsNot Nothing Then + AddSynthesizedAttribute( + attributes, + New SynthesizedAttributeData( + DeclaringCompilation, + parameterlessConstructor, + arguments:=ImmutableArray(Of TypedConstant).Empty, + namedArgs:=ImmutableArray(Of KeyValuePair(Of String, TypedConstant)).Empty)) + End If + End If + End If End Sub Private Function HasDefaultMemberAttribute() As Boolean diff --git a/src/Compilers/VisualBasic/Portable/Symbols/Source/SourceNamedTypeSymbol_ComClass.vb b/src/Compilers/VisualBasic/Portable/Symbols/Source/SourceNamedTypeSymbol_ComClass.vb index 9e8e9f6386e99..16d84b989c8db 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/Source/SourceNamedTypeSymbol_ComClass.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/Source/SourceNamedTypeSymbol_ComClass.vb @@ -803,6 +803,12 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols End Get End Property + Friend Overrides ReadOnly Property HasCompilerLoweringPreserveAttribute As Boolean + Get + Throw ExceptionUtilities.Unreachable + End Get + End Property + Friend Overrides ReadOnly Property IsExtensibleInterfaceNoUseSiteDiagnostics As Boolean Get Return False @@ -981,7 +987,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols Return ImmutableArray(Of VisualBasicAttributeData).Empty End Function - Friend Overrides Sub AddSynthesizedAttributes(moduleBuilder As PEModuleBuilder, ByRef attributes As ArrayBuilder(Of SynthesizedAttributeData)) + Friend Overrides Sub AddSynthesizedAttributes(moduleBuilder As PEModuleBuilder, ByRef attributes As ArrayBuilder(Of VisualBasicAttributeData)) MyBase.AddSynthesizedAttributes(moduleBuilder, attributes) Dim compilation As VisualBasicCompilation = _comClass.DeclaringCompilation @@ -1166,6 +1172,10 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols End Get End Property + Public Overrides Function GetOverloadResolutionPriority() As Integer + Return 0 ' This symbol is used to produce a metadata artifact, it cannot be accessed by a user + End Function + Public Overrides ReadOnly Property IsOverridable As Boolean Get Return False @@ -1347,7 +1357,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols Return attributes.ToImmutableAndFree() End Function - Friend Overrides Sub AddSynthesizedAttributes(moduleBuilder As PEModuleBuilder, ByRef attributes As ArrayBuilder(Of SynthesizedAttributeData)) + Friend Overrides Sub AddSynthesizedAttributes(moduleBuilder As PEModuleBuilder, ByRef attributes As ArrayBuilder(Of VisualBasicAttributeData)) MyBase.AddSynthesizedAttributes(moduleBuilder, attributes) If _synthesizedDispId = ReservedDispId.None Then @@ -1629,14 +1639,14 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols Return _clonedFrom.GetAttributes() End Function - Friend Overrides Sub AddSynthesizedAttributes(moduleBuilder As PEModuleBuilder, ByRef attributes As ArrayBuilder(Of SynthesizedAttributeData)) + Friend Overrides Sub AddSynthesizedAttributes(moduleBuilder As PEModuleBuilder, ByRef attributes As ArrayBuilder(Of VisualBasicAttributeData)) MyBase.AddSynthesizedAttributes(moduleBuilder, attributes) If IsComEventParameter Then Return End If - Dim toClone As ArrayBuilder(Of SynthesizedAttributeData) = Nothing + Dim toClone As ArrayBuilder(Of VisualBasicAttributeData) = Nothing _clonedFrom.AddSynthesizedAttributes(moduleBuilder, toClone) Dim compilation = Me.DeclaringCompilation @@ -1779,6 +1789,10 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols End Get End Property + Public Overrides Function GetOverloadResolutionPriority() As Integer + Return 0 ' This symbol is used to produce a metadata artifact, it cannot be accessed by a user + End Function + Public Overrides ReadOnly Property IsOverridable As Boolean Get Return False @@ -1849,7 +1863,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols Return _clonedFrom.GetAttributes() End Function - Friend Overrides Sub AddSynthesizedAttributes(moduleBuilder As PEModuleBuilder, ByRef attributes As ArrayBuilder(Of SynthesizedAttributeData)) + Friend Overrides Sub AddSynthesizedAttributes(moduleBuilder As PEModuleBuilder, ByRef attributes As ArrayBuilder(Of VisualBasicAttributeData)) MyBase.AddSynthesizedAttributes(moduleBuilder, attributes) If _synthesizedDispId = ReservedDispId.None Then diff --git a/src/Compilers/VisualBasic/Portable/Symbols/Source/SourceParameterSymbolBase.vb b/src/Compilers/VisualBasic/Portable/Symbols/Source/SourceParameterSymbolBase.vb index a6b934d87984d..c69fb2eda03bb 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/Source/SourceParameterSymbolBase.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/Source/SourceParameterSymbolBase.vb @@ -39,7 +39,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols Friend MustOverride ReadOnly Property HasDefaultValueAttribute As Boolean - Friend NotOverridable Overrides Sub AddSynthesizedAttributes(moduleBuilder As PEModuleBuilder, ByRef attributes As ArrayBuilder(Of SynthesizedAttributeData)) + Friend NotOverridable Overrides Sub AddSynthesizedAttributes(moduleBuilder As PEModuleBuilder, ByRef attributes As ArrayBuilder(Of VisualBasicAttributeData)) MyBase.AddSynthesizedAttributes(moduleBuilder, attributes) ' Create the ParamArrayAttribute diff --git a/src/Compilers/VisualBasic/Portable/Symbols/Source/SourcePropertyAccessorSymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/Source/SourcePropertyAccessorSymbol.vb index 02addfd0ec070..8a25ddd38b2a2 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/Source/SourcePropertyAccessorSymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/Source/SourcePropertyAccessorSymbol.vb @@ -497,7 +497,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols End Get End Property - Friend Overrides Sub AddSynthesizedAttributes(moduleBuilder As PEModuleBuilder, ByRef attributes As ArrayBuilder(Of SynthesizedAttributeData)) + Friend Overrides Sub AddSynthesizedAttributes(moduleBuilder As PEModuleBuilder, ByRef attributes As ArrayBuilder(Of VisualBasicAttributeData)) MyBase.AddSynthesizedAttributes(moduleBuilder, attributes) If m_property.IsAutoProperty Then diff --git a/src/Compilers/VisualBasic/Portable/Symbols/Source/SourcePropertySymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/Source/SourcePropertySymbol.vb index 661fbf78934c2..163bad7cb3235 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/Source/SourcePropertySymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/Source/SourcePropertySymbol.vb @@ -548,6 +548,22 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols End If Return boundAttribute + ElseIf VisualBasicAttributeData.IsTargetEarlyAttribute(arguments.AttributeType, arguments.AttributeSyntax, AttributeDescription.OverloadResolutionPriorityAttribute) Then + + If Not CanHaveOverloadResolutionPriority Then + 'Cannot use 'OverloadResolutionPriorityAttribute' on this member. + Return Nothing + End If + + Dim hasAnyDiagnostics As Boolean = False + Dim attrdata = arguments.Binder.GetAttribute(arguments.AttributeSyntax, arguments.AttributeType, hasAnyDiagnostics) + If Not attrdata.HasErrors Then + Dim priority As Integer = attrdata.GetConstructorArgument(Of Integer)(0, SpecialType.System_Int32) + arguments.GetOrCreateData(Of CommonPropertyEarlyWellKnownAttributeData)().OverloadResolutionPriority = priority + Return If(Not hasAnyDiagnostics, attrdata, Nothing) + Else + Return Nothing + End If End If Return MyBase.EarlyDecodeWellKnownAttribute(arguments) @@ -594,6 +610,21 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols _setMethod IsNot Nothing AndAlso DirectCast(_setMethod, SourcePropertyAccessorSymbol).HasDebuggerHiddenAttribute) Then diagnostics.Add(ERRID.WRN_DebuggerHiddenIgnoredOnProperties, arguments.AttributeSyntaxOpt.GetLocation()) End If + Return + ElseIf arguments.Attribute.IsTargetAttribute(AttributeDescription.OverloadResolutionPriorityAttribute) Then + + If Not CanHaveOverloadResolutionPriority Then + diagnostics.Add(If(IsOverrides, + ERRID.ERR_CannotApplyOverloadResolutionPriorityToOverride, + ERRID.ERR_CannotApplyOverloadResolutionPriorityToMember), + arguments.AttributeSyntaxOpt.GetLocation()) + Else + InternalSyntax.Parser.CheckFeatureAvailability(diagnostics, + arguments.AttributeSyntaxOpt.GetLocation(), + DirectCast(arguments.AttributeSyntaxOpt.SyntaxTree.Options, VisualBasicParseOptions).LanguageVersion, + InternalSyntax.Feature.OverloadResolutionPriority) + End If + Return End If End If @@ -694,6 +725,20 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols End Get End Property + Public Overrides Function GetOverloadResolutionPriority() As Integer + Dim data As CommonPropertyEarlyWellKnownAttributeData = Me.GetEarlyDecodedWellKnownAttributeData() + Return If(data?.OverloadResolutionPriority, 0) + End Function + + Private Function GetEarlyDecodedWellKnownAttributeData() As CommonPropertyEarlyWellKnownAttributeData + Dim attributesBag As CustomAttributesBag(Of VisualBasicAttributeData) = Me._lazyCustomAttributesBag + If attributesBag Is Nothing OrElse Not attributesBag.IsEarlyDecodedWellKnownAttributeDataComputed Then + attributesBag = Me.GetAttributesBag() + End If + + Return DirectCast(attributesBag.EarlyDecodedWellKnownAttributeData, CommonPropertyEarlyWellKnownAttributeData) + End Function + Public Overrides ReadOnly Property IsWithEvents As Boolean Get Return (_flags And SourceMemberFlags.WithEvents) <> 0 @@ -1218,7 +1263,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols End Get End Property - Friend Overrides Sub AddSynthesizedAttributes(moduleBuilder As PEModuleBuilder, ByRef attributes As ArrayBuilder(Of SynthesizedAttributeData)) + Friend Overrides Sub AddSynthesizedAttributes(moduleBuilder As PEModuleBuilder, ByRef attributes As ArrayBuilder(Of VisualBasicAttributeData)) MyBase.AddSynthesizedAttributes(moduleBuilder, attributes) If Me.Type.ContainsTupleNames() Then diff --git a/src/Compilers/VisualBasic/Portable/Symbols/Source/SourceWithEventsBackingFieldSymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/Source/SourceWithEventsBackingFieldSymbol.vb index d6515c0da4534..ed74cfb64903e 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/Source/SourceWithEventsBackingFieldSymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/Source/SourceWithEventsBackingFieldSymbol.vb @@ -58,7 +58,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols End Get End Property - Friend Overrides Sub AddSynthesizedAttributes(moduleBuilder As PEModuleBuilder, ByRef attributes As ArrayBuilder(Of SynthesizedAttributeData)) + Friend Overrides Sub AddSynthesizedAttributes(moduleBuilder As PEModuleBuilder, ByRef attributes As ArrayBuilder(Of VisualBasicAttributeData)) MyBase.AddSynthesizedAttributes(moduleBuilder, attributes) Dim compilation = _property.DeclaringCompilation diff --git a/src/Compilers/VisualBasic/Portable/Symbols/Source/SynthesizedConstructorSymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/Source/SynthesizedConstructorSymbol.vb index 6c7ae1ef2531a..c68a131af3260 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/Source/SynthesizedConstructorSymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/Source/SynthesizedConstructorSymbol.vb @@ -37,7 +37,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols Me._debuggable = isDebuggable End Sub - Friend Overrides Sub AddSynthesizedAttributes(moduleBuilder As PEModuleBuilder, ByRef attributes As ArrayBuilder(Of SynthesizedAttributeData)) + Friend Overrides Sub AddSynthesizedAttributes(moduleBuilder As PEModuleBuilder, ByRef attributes As ArrayBuilder(Of VisualBasicAttributeData)) MyBase.AddSynthesizedAttributes(moduleBuilder, attributes) ' Dev11 emits DebuggerNonUserCodeAttribute. This attribute is not needed since we don't emit any debug info for the constructor. diff --git a/src/Compilers/VisualBasic/Portable/Symbols/Source/SynthesizedEventAccessorSymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/Source/SynthesizedEventAccessorSymbol.vb index 8abc1f2aa6642..39cf890613496 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/Source/SynthesizedEventAccessorSymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/Source/SynthesizedEventAccessorSymbol.vb @@ -489,7 +489,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols Dim unusedReturnType = Me.ReturnType End Sub - Friend Overrides Sub AddSynthesizedAttributes(moduleBuilder As PEModuleBuilder, ByRef attributes As ArrayBuilder(Of SynthesizedAttributeData)) + Friend Overrides Sub AddSynthesizedAttributes(moduleBuilder As PEModuleBuilder, ByRef attributes As ArrayBuilder(Of VisualBasicAttributeData)) MyBase.AddSynthesizedAttributes(moduleBuilder, attributes) Debug.Assert(Not ContainingType.IsImplicitlyDeclared) diff --git a/src/Compilers/VisualBasic/Portable/Symbols/Source/SynthesizedFieldSymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/Source/SynthesizedFieldSymbol.vb index d28f645f3c89d..fb29c72bde4b7 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/Source/SynthesizedFieldSymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/Source/SynthesizedFieldSymbol.vb @@ -55,7 +55,22 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols End Get End Property - Friend Overrides Sub AddSynthesizedAttributes(moduleBuilder As PEModuleBuilder, ByRef attributes As ArrayBuilder(Of SynthesizedAttributeData)) + Friend Overrides Sub AddSynthesizedAttributes(moduleBuilder As PEModuleBuilder, ByRef attributes As ArrayBuilder(Of VisualBasicAttributeData)) + If TypeOf Me Is LambdaCapturedVariable OrElse TypeOf Me Is StateMachineFieldSymbol Then + Dim definition = TryCast(_implicitlyDefinedBy.OriginalDefinition, SourceParameterSymbolBase) + + If definition IsNot Nothing AndAlso + ContainingModule = definition.ContainingModule Then + For Each attr In definition.GetAttributes() + Dim attributeType As NamedTypeSymbol = attr.AttributeClass + If attributeType IsNot Nothing AndAlso attributeType.HasCompilerLoweringPreserveAttribute AndAlso + (attributeType.GetAttributeUsageInfo().ValidTargets And System.AttributeTargets.Field) <> 0 Then + AddSynthesizedAttribute(attributes, attr) + End If + Next + End If + End If + MyBase.AddSynthesizedAttributes(moduleBuilder, attributes) ' enum fields do not need to be marked as generated diff --git a/src/Compilers/VisualBasic/Portable/Symbols/Source/SynthesizedMainTypeEntryPoint.vb b/src/Compilers/VisualBasic/Portable/Symbols/Source/SynthesizedMainTypeEntryPoint.vb index d81a4f6341a38..90074237c2507 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/Source/SynthesizedMainTypeEntryPoint.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/Source/SynthesizedMainTypeEntryPoint.vb @@ -82,7 +82,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols Return New BoundBlock(syntaxNode, Nothing, ImmutableArray(Of LocalSymbol).Empty, ImmutableArray.Create(statement, New BoundReturnStatement(syntaxNode, Nothing, Nothing, Nothing))) End Function - Friend Overrides Sub AddSynthesizedAttributes(moduleBuilder As PEModuleBuilder, ByRef attributes As ArrayBuilder(Of SynthesizedAttributeData)) + Friend Overrides Sub AddSynthesizedAttributes(moduleBuilder As PEModuleBuilder, ByRef attributes As ArrayBuilder(Of VisualBasicAttributeData)) MyBase.AddSynthesizedAttributes(moduleBuilder, attributes) AddSynthesizedAttribute(attributes, diff --git a/src/Compilers/VisualBasic/Portable/Symbols/Source/SynthesizedMyGroupCollectionPropertyAccessorSymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/Source/SynthesizedMyGroupCollectionPropertyAccessorSymbol.vb index 24055fd47a867..584ec9eea66ab 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/Source/SynthesizedMyGroupCollectionPropertyAccessorSymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/Source/SynthesizedMyGroupCollectionPropertyAccessorSymbol.vb @@ -36,7 +36,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols End Get End Property - Friend Overrides Sub AddSynthesizedAttributes(moduleBuilder As PEModuleBuilder, ByRef attributes As ArrayBuilder(Of SynthesizedAttributeData)) + Friend Overrides Sub AddSynthesizedAttributes(moduleBuilder As PEModuleBuilder, ByRef attributes As ArrayBuilder(Of VisualBasicAttributeData)) MyBase.AddSynthesizedAttributes(moduleBuilder, attributes) ' Note, Dev11 emits DebuggerNonUserCodeAttribute, but we are using DebuggerHiddenAttribute instead. diff --git a/src/Compilers/VisualBasic/Portable/Symbols/Source/SynthesizedMyGroupCollectionPropertyBackingFieldSymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/Source/SynthesizedMyGroupCollectionPropertyBackingFieldSymbol.vb index 492b19c9295ee..e02544afdf700 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/Source/SynthesizedMyGroupCollectionPropertyBackingFieldSymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/Source/SynthesizedMyGroupCollectionPropertyBackingFieldSymbol.vb @@ -33,7 +33,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols Return LexicalSortKey.NotInSource End Function - Friend Overrides Sub AddSynthesizedAttributes(moduleBuilder As PEModuleBuilder, ByRef attributes As ArrayBuilder(Of SynthesizedAttributeData)) + Friend Overrides Sub AddSynthesizedAttributes(moduleBuilder As PEModuleBuilder, ByRef attributes As ArrayBuilder(Of VisualBasicAttributeData)) AddSynthesizedAttribute(attributes, Me.DeclaringCompilation.SynthesizeEditorBrowsableNeverAttribute()) End Sub diff --git a/src/Compilers/VisualBasic/Portable/Symbols/Source/SynthesizedStaticLocalBackingField.vb b/src/Compilers/VisualBasic/Portable/Symbols/Source/SynthesizedStaticLocalBackingField.vb index f03d520929a21..feae529e93ff0 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/Source/SynthesizedStaticLocalBackingField.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/Source/SynthesizedStaticLocalBackingField.vb @@ -55,7 +55,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols End Get End Property - Friend Overrides Sub AddSynthesizedAttributes(moduleBuilder As PEModuleBuilder, ByRef attributes As ArrayBuilder(Of SynthesizedAttributeData)) + Friend Overrides Sub AddSynthesizedAttributes(moduleBuilder As PEModuleBuilder, ByRef attributes As ArrayBuilder(Of VisualBasicAttributeData)) ' no attributes on static backing fields - Dev12 behavior End Sub End Class diff --git a/src/Compilers/VisualBasic/Portable/Symbols/Source/SynthesizedWithEventsAccessorSymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/Source/SynthesizedWithEventsAccessorSymbol.vb index a0f8b38f79825..af18660b801e8 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/Source/SynthesizedWithEventsAccessorSymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/Source/SynthesizedWithEventsAccessorSymbol.vb @@ -87,7 +87,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols Protected MustOverride Function GetParameters() As ImmutableArray(Of ParameterSymbol) - Friend Overrides Sub AddSynthesizedAttributes(moduleBuilder As PEModuleBuilder, ByRef attributes As ArrayBuilder(Of SynthesizedAttributeData)) + Friend Overrides Sub AddSynthesizedAttributes(moduleBuilder As PEModuleBuilder, ByRef attributes As ArrayBuilder(Of VisualBasicAttributeData)) MyBase.AddSynthesizedAttributes(moduleBuilder, attributes) Debug.Assert(Not ContainingType.IsImplicitlyDeclared) diff --git a/src/Compilers/VisualBasic/Portable/Symbols/SubstitutedMethodSymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/SubstitutedMethodSymbol.vb index 944349b0db12c..142c6d977748e 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/SubstitutedMethodSymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/SubstitutedMethodSymbol.vb @@ -216,6 +216,10 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols End Get End Property + Public Overrides Function GetOverloadResolutionPriority() As Integer + Return OriginalDefinition.GetOverloadResolutionPriority() + End Function + Public Overrides ReadOnly Property IsOverridable As Boolean Get Return OriginalDefinition.IsOverridable diff --git a/src/Compilers/VisualBasic/Portable/Symbols/SubstitutedNamedType.vb b/src/Compilers/VisualBasic/Portable/Symbols/SubstitutedNamedType.vb index 036e58071ed43..d172520964eed 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/SubstitutedNamedType.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/SubstitutedNamedType.vb @@ -155,6 +155,12 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols End Get End Property + Friend NotOverridable Overrides ReadOnly Property HasCompilerLoweringPreserveAttribute As Boolean + Get + Return OriginalDefinition.HasCompilerLoweringPreserveAttribute + End Get + End Property + Friend Overrides ReadOnly Property IsExtensibleInterfaceNoUseSiteDiagnostics As Boolean Get Return OriginalDefinition.IsExtensibleInterfaceNoUseSiteDiagnostics diff --git a/src/Compilers/VisualBasic/Portable/Symbols/SubstitutedPropertySymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/SubstitutedPropertySymbol.vb index 1101d84b3197f..694bdb1b4781b 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/SubstitutedPropertySymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/SubstitutedPropertySymbol.vb @@ -181,6 +181,10 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols End Get End Property + Public Overrides Function GetOverloadResolutionPriority() As Integer + Return _originalDefinition.GetOverloadResolutionPriority() + End Function + Public Overrides ReadOnly Property IsImplicitlyDeclared As Boolean Get Return _originalDefinition.IsImplicitlyDeclared diff --git a/src/Compilers/VisualBasic/Portable/Symbols/Symbol_Attributes.vb b/src/Compilers/VisualBasic/Portable/Symbols/Symbol_Attributes.vb index d9422f9f8ec0d..afd1c8e664d0b 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/Symbol_Attributes.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/Symbol_Attributes.vb @@ -33,16 +33,16 @@ Namespace Microsoft.CodeAnalysis.VisualBasic ''' ''' Build and add synthesized attributes for this symbol. ''' - Friend Overridable Sub AddSynthesizedAttributes(moduleBuilder As PEModuleBuilder, ByRef attributes As ArrayBuilder(Of SynthesizedAttributeData)) + Friend Overridable Sub AddSynthesizedAttributes(moduleBuilder As PEModuleBuilder, ByRef attributes As ArrayBuilder(Of VisualBasicAttributeData)) End Sub ''' ''' Convenience helper called by subclasses to add a synthesized attribute to a collection of attributes. ''' - Friend Shared Sub AddSynthesizedAttribute(ByRef attributes As ArrayBuilder(Of SynthesizedAttributeData), attribute As SynthesizedAttributeData) + Friend Shared Sub AddSynthesizedAttribute(ByRef attributes As ArrayBuilder(Of VisualBasicAttributeData), attribute As VisualBasicAttributeData) If attribute IsNot Nothing Then If attributes Is Nothing Then - attributes = ArrayBuilder(Of SynthesizedAttributeData).GetInstance(4) + attributes = ArrayBuilder(Of VisualBasicAttributeData).GetInstance(4) End If attributes.Add(attribute) diff --git a/src/Compilers/VisualBasic/Portable/Symbols/SynthesizedSymbols/SynthesizedBackingFieldBase.vb b/src/Compilers/VisualBasic/Portable/Symbols/SynthesizedSymbols/SynthesizedBackingFieldBase.vb index 8fce0b2a282b2..5709a75903f7c 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/SynthesizedSymbols/SynthesizedBackingFieldBase.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/SynthesizedSymbols/SynthesizedBackingFieldBase.vb @@ -122,7 +122,15 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols End Get End Property - Friend Overrides Sub AddSynthesizedAttributes(moduleBuilder As PEModuleBuilder, ByRef attributes As ArrayBuilder(Of SynthesizedAttributeData)) + Friend Overrides Sub AddSynthesizedAttributes(moduleBuilder As PEModuleBuilder, ByRef attributes As ArrayBuilder(Of VisualBasicAttributeData)) + For Each attr In _propertyOrEvent.GetAttributes() + Dim attributeType As NamedTypeSymbol = attr.AttributeClass + If attributeType IsNot Nothing AndAlso attributeType.HasCompilerLoweringPreserveAttribute AndAlso + (attributeType.GetAttributeUsageInfo().ValidTargets And System.AttributeTargets.Field) <> 0 Then + AddSynthesizedAttribute(attributes, attr) + End If + Next + MyBase.AddSynthesizedAttributes(moduleBuilder, attributes) Dim compilation = Me.DeclaringCompilation diff --git a/src/Compilers/VisualBasic/Portable/Symbols/SynthesizedSymbols/SynthesizedDelegateMethodSymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/SynthesizedSymbols/SynthesizedDelegateMethodSymbol.vb index 3a04cf6b8ed57..1e3cdc7ac17a6 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/SynthesizedSymbols/SynthesizedDelegateMethodSymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/SynthesizedSymbols/SynthesizedDelegateMethodSymbol.vb @@ -206,6 +206,10 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols End Get End Property + Public Overrides Function GetOverloadResolutionPriority() As Integer + Return 0 + End Function + ''' ''' Gets a value indicating whether this instance is overridable. ''' @@ -432,7 +436,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols End Get End Property - Friend Overrides Sub AddSynthesizedAttributes(moduleBuilder As PEModuleBuilder, ByRef attributes As ArrayBuilder(Of SynthesizedAttributeData)) + Friend Overrides Sub AddSynthesizedAttributes(moduleBuilder As PEModuleBuilder, ByRef attributes As ArrayBuilder(Of VisualBasicAttributeData)) MyBase.AddSynthesizedAttributes(moduleBuilder, attributes) ' Dev11 emits DebuggerNonUserCodeAttribute on methods of anon delegates but not of user defined delegates. diff --git a/src/Compilers/VisualBasic/Portable/Symbols/SynthesizedSymbols/SynthesizedEventDelegateSymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/SynthesizedSymbols/SynthesizedEventDelegateSymbol.vb index 6554e1951e18b..d41acd9678ebb 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/SynthesizedSymbols/SynthesizedEventDelegateSymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/SynthesizedSymbols/SynthesizedEventDelegateSymbol.vb @@ -274,6 +274,12 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols End Get End Property + Friend Overrides ReadOnly Property HasCompilerLoweringPreserveAttribute As Boolean + Get + Return False + End Get + End Property + Friend Overrides ReadOnly Property IsExtensibleInterfaceNoUseSiteDiagnostics As Boolean Get Return False diff --git a/src/Compilers/VisualBasic/Portable/Symbols/SynthesizedSymbols/SynthesizedGlobalMethodBase.vb b/src/Compilers/VisualBasic/Portable/Symbols/SynthesizedSymbols/SynthesizedGlobalMethodBase.vb index 2b00368060a7e..134faedfe0fc5 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/SynthesizedSymbols/SynthesizedGlobalMethodBase.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/SynthesizedSymbols/SynthesizedGlobalMethodBase.vb @@ -92,6 +92,10 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols End Get End Property + Public Overrides Function GetOverloadResolutionPriority() As Integer + Return 0 + End Function + ''' ''' Gets a value indicating whether this instance is overridable. ''' diff --git a/src/Compilers/VisualBasic/Portable/Symbols/SynthesizedSymbols/SynthesizedHotReloadExceptionSymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/SynthesizedSymbols/SynthesizedHotReloadExceptionSymbol.vb index faa75fb2e647e..77abc86606a92 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/SynthesizedSymbols/SynthesizedHotReloadExceptionSymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/SynthesizedSymbols/SynthesizedHotReloadExceptionSymbol.vb @@ -179,6 +179,12 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols End Get End Property + Friend Overrides ReadOnly Property HasCompilerLoweringPreserveAttribute As Boolean + Get + Return False + End Get + End Property + Friend Overrides ReadOnly Property IsExtensibleInterfaceNoUseSiteDiagnostics As Boolean Get Return False diff --git a/src/Compilers/VisualBasic/Portable/Symbols/SynthesizedSymbols/SynthesizedInterfaceImplementationStubSymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/SynthesizedSymbols/SynthesizedInterfaceImplementationStubSymbol.vb index 75c743524cc64..ffb6929c8f4ca 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/SynthesizedSymbols/SynthesizedInterfaceImplementationStubSymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/SynthesizedSymbols/SynthesizedInterfaceImplementationStubSymbol.vb @@ -181,7 +181,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols End Get End Property - Friend Overrides Sub AddSynthesizedAttributes(moduleBuilder As PEModuleBuilder, ByRef attributes As ArrayBuilder(Of SynthesizedAttributeData)) + Friend Overrides Sub AddSynthesizedAttributes(moduleBuilder As PEModuleBuilder, ByRef attributes As ArrayBuilder(Of VisualBasicAttributeData)) MyBase.AddSynthesizedAttributes(moduleBuilder, attributes) Dim compilation = Me.DeclaringCompilation @@ -190,7 +190,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols AddSynthesizedAttribute(attributes, compilation.SynthesizeDebuggerHiddenAttribute()) End Sub - Friend Overrides Sub AddSynthesizedReturnTypeAttributes(ByRef attributes As ArrayBuilder(Of SynthesizedAttributeData)) + Friend Overrides Sub AddSynthesizedReturnTypeAttributes(ByRef attributes As ArrayBuilder(Of VisualBasicAttributeData)) MyBase.AddSynthesizedReturnTypeAttributes(attributes) Dim compilation = Me.DeclaringCompilation diff --git a/src/Compilers/VisualBasic/Portable/Symbols/SynthesizedSymbols/SynthesizedMethod.vb b/src/Compilers/VisualBasic/Portable/Symbols/SynthesizedSymbols/SynthesizedMethod.vb index ba5ca41da756e..15d463ec65d64 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/SynthesizedSymbols/SynthesizedMethod.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/SynthesizedSymbols/SynthesizedMethod.vb @@ -101,7 +101,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols End Get End Property - Friend Overrides Sub AddSynthesizedAttributes(moduleBuilder As PEModuleBuilder, ByRef attributes As ArrayBuilder(Of SynthesizedAttributeData)) + Friend Overrides Sub AddSynthesizedAttributes(moduleBuilder As PEModuleBuilder, ByRef attributes As ArrayBuilder(Of VisualBasicAttributeData)) MyBase.AddSynthesizedAttributes(moduleBuilder, attributes) Dim sourceType = TryCast(ContainingSymbol, SourceMemberContainerTypeSymbol) diff --git a/src/Compilers/VisualBasic/Portable/Symbols/SynthesizedSymbols/SynthesizedMethodBase.vb b/src/Compilers/VisualBasic/Portable/Symbols/SynthesizedSymbols/SynthesizedMethodBase.vb index 365f9b28a2581..54edc32d1a60d 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/SynthesizedSymbols/SynthesizedMethodBase.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/SynthesizedSymbols/SynthesizedMethodBase.vb @@ -221,6 +221,10 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols Return False End Get End Property + + Public Overrides Function GetOverloadResolutionPriority() As Integer + Return 0 + End Function End Class End Namespace diff --git a/src/Compilers/VisualBasic/Portable/Symbols/SynthesizedSymbols/SynthesizedOverridingWitheventsProperty.vb b/src/Compilers/VisualBasic/Portable/Symbols/SynthesizedSymbols/SynthesizedOverridingWitheventsProperty.vb index 57a4efd374c3b..152dd8376c63e 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/SynthesizedSymbols/SynthesizedOverridingWitheventsProperty.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/SynthesizedSymbols/SynthesizedOverridingWitheventsProperty.vb @@ -151,6 +151,10 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols End Get End Property + Public Overrides Function GetOverloadResolutionPriority() As Integer + Return 0 + End Function + Public Overrides ReadOnly Property IsOverridable As Boolean Get ' override is itself overridable diff --git a/src/Compilers/VisualBasic/Portable/Symbols/SynthesizedSymbols/SynthesizedParameterSymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/SynthesizedSymbols/SynthesizedParameterSymbol.vb index d21b88cf07993..c90f6d6166629 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/SynthesizedSymbols/SynthesizedParameterSymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/SynthesizedSymbols/SynthesizedParameterSymbol.vb @@ -244,7 +244,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols End Get End Property - Friend NotOverridable Overrides Sub AddSynthesizedAttributes(moduleBuilder As PEModuleBuilder, ByRef attributes As ArrayBuilder(Of SynthesizedAttributeData)) + Friend NotOverridable Overrides Sub AddSynthesizedAttributes(moduleBuilder As PEModuleBuilder, ByRef attributes As ArrayBuilder(Of VisualBasicAttributeData)) Dim compilation = Me.DeclaringCompilation If Type.ContainsTupleNames() AndAlso compilation.HasTupleNamesAttributes Then diff --git a/src/Compilers/VisualBasic/Portable/Symbols/SynthesizedSymbols/SynthesizedPropertyBase.vb b/src/Compilers/VisualBasic/Portable/Symbols/SynthesizedSymbols/SynthesizedPropertyBase.vb index 557a14555b8c6..ea564618a91b0 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/SynthesizedSymbols/SynthesizedPropertyBase.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/SynthesizedSymbols/SynthesizedPropertyBase.vb @@ -95,6 +95,10 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols End Get End Property + Public Overrides Function GetOverloadResolutionPriority() As Integer + Return 0 + End Function + Friend Overrides ReadOnly Property ShadowsExplicitly As Boolean Get Return False diff --git a/src/Compilers/VisualBasic/Portable/Symbols/Tuples/TupleMethodSymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/Tuples/TupleMethodSymbol.vb index 226ab68708a6a..7d18d7d044c6f 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/Tuples/TupleMethodSymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/Tuples/TupleMethodSymbol.vb @@ -152,5 +152,9 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols Return _underlyingMethod.HasSetsRequiredMembers End Get End Property + + Public Overrides Function GetOverloadResolutionPriority() As Integer + Return _underlyingMethod.GetOverloadResolutionPriority() + End Function End Class End Namespace diff --git a/src/Compilers/VisualBasic/Portable/Symbols/Tuples/TuplePropertySymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/Tuples/TuplePropertySymbol.vb index 2ddef7b5becac..da8b560210882 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/Tuples/TuplePropertySymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/Tuples/TuplePropertySymbol.vb @@ -95,6 +95,10 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols End Get End Property + Public Overrides Function GetOverloadResolutionPriority() As Integer + Return Me._underlyingProperty.GetOverloadResolutionPriority() + End Function + Friend Overrides ReadOnly Property IsMyGroupCollectionProperty As Boolean Get Return Me._underlyingProperty.IsMyGroupCollectionProperty diff --git a/src/Compilers/VisualBasic/Portable/Symbols/Tuples/TupleTypeSymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/Tuples/TupleTypeSymbol.vb index 8fdfed37c7355..8d7ccc0d74dfc 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/Tuples/TupleTypeSymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/Tuples/TupleTypeSymbol.vb @@ -107,6 +107,12 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols End Get End Property + Friend Overrides ReadOnly Property HasCompilerLoweringPreserveAttribute As Boolean + Get + Return Me._underlyingType.HasCompilerLoweringPreserveAttribute + End Get + End Property + ''' ''' Get the default fields for the tuple's elements (in order and cached). ''' diff --git a/src/Compilers/VisualBasic/Portable/Symbols/TypeSymbolExtensions.vb b/src/Compilers/VisualBasic/Portable/Symbols/TypeSymbolExtensions.vb index 80ccdad058a12..a343d5efb3799 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/TypeSymbolExtensions.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/TypeSymbolExtensions.vb @@ -1333,6 +1333,17 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols Return typeSymbol.ContainingType Is Nothing AndAlso IsContainedInNamespace(typeSymbol, "System", "Runtime", "CompilerServices") End Function + + Friend Function IsMicrosoftCodeAnalysisEmbeddedAttribute(typeSymbol As TypeSymbol) As Boolean + Dim namedTypeSymbol = TryCast(typeSymbol, NamedTypeSymbol) + + Return namedTypeSymbol IsNot Nothing AndAlso + namedTypeSymbol.Name = "EmbeddedAttribute" AndAlso + namedTypeSymbol.Arity = 0 AndAlso + typeSymbol.ContainingType Is Nothing AndAlso + IsContainedInNamespace(typeSymbol, "Microsoft", "CodeAnalysis") + End Function + Private Function IsContainedInNamespace(typeSymbol As TypeSymbol, outerNS As String, midNS As String, Optional innerNS As String = Nothing) As Boolean Dim midNamespace As NamespaceSymbol diff --git a/src/Compilers/VisualBasic/Portable/Symbols/UnboundGenericType.vb b/src/Compilers/VisualBasic/Portable/Symbols/UnboundGenericType.vb index f940c94ff9e52..935fa62812521 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/UnboundGenericType.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/UnboundGenericType.vb @@ -146,6 +146,12 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols End Get End Property + Friend Overrides ReadOnly Property HasCompilerLoweringPreserveAttribute As Boolean + Get + Return OriginalDefinition.HasCompilerLoweringPreserveAttribute + End Get + End Property + Friend Overrides ReadOnly Property IsExtensibleInterfaceNoUseSiteDiagnostics As Boolean Get Return OriginalDefinition.IsExtensibleInterfaceNoUseSiteDiagnostics diff --git a/src/Compilers/VisualBasic/Portable/Symbols/Wrapped/WrappedParameterSymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/Wrapped/WrappedParameterSymbol.vb index 56dd496553479..9ec7f8aa1f891 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/Wrapped/WrappedParameterSymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/Wrapped/WrappedParameterSymbol.vb @@ -175,7 +175,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols Return Me._underlyingParameter.GetAttributes() End Function - Friend Overrides Sub AddSynthesizedAttributes(moduleBuilder As PEModuleBuilder, ByRef attributes As ArrayBuilder(Of SynthesizedAttributeData)) + Friend Overrides Sub AddSynthesizedAttributes(moduleBuilder As PEModuleBuilder, ByRef attributes As ArrayBuilder(Of VisualBasicAttributeData)) Me._underlyingParameter.AddSynthesizedAttributes(moduleBuilder, attributes) End Sub diff --git a/src/Compilers/VisualBasic/Portable/Syntax/SyntaxFacts.vb b/src/Compilers/VisualBasic/Portable/Syntax/SyntaxFacts.vb index 9b13f20ecbe67..0ca91c9e69e0c 100644 --- a/src/Compilers/VisualBasic/Portable/Syntax/SyntaxFacts.vb +++ b/src/Compilers/VisualBasic/Portable/Syntax/SyntaxFacts.vb @@ -10,7 +10,7 @@ Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Namespace Microsoft.CodeAnalysis.VisualBasic - Partial Public Class SyntaxFacts + Partial Public NotInheritable Class SyntaxFacts ''' ''' Determine if the token instance represents a syntax trivia such as comment, whitespace, etc... diff --git a/src/Compilers/VisualBasic/Portable/Syntax/SyntaxNodeRemover.vb b/src/Compilers/VisualBasic/Portable/Syntax/SyntaxNodeRemover.vb index c0ce5c76d403f..c22eeccc6a74c 100644 --- a/src/Compilers/VisualBasic/Portable/Syntax/SyntaxNodeRemover.vb +++ b/src/Compilers/VisualBasic/Portable/Syntax/SyntaxNodeRemover.vb @@ -2,17 +2,12 @@ ' The .NET Foundation licenses this file to you under the MIT license. ' See the LICENSE file in the project root for more information. -Imports System -Imports System.Collections.Generic -Imports System.Linq Imports Microsoft.CodeAnalysis.Syntax Imports Microsoft.CodeAnalysis.Text -Imports Microsoft.CodeAnalysis.VisualBasic.Symbols -Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Namespace Microsoft.CodeAnalysis.VisualBasic.Syntax - Public Class SyntaxNodeRemover + Public NotInheritable Class SyntaxNodeRemover Friend Shared Function RemoveNodes(Of TRoot As SyntaxNode)(root As TRoot, nodes As IEnumerable(Of SyntaxNode), options As SyntaxRemoveOptions) As TRoot Dim nodesToRemove As SyntaxNode() = nodes.ToArray() @@ -32,7 +27,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Syntax Return DirectCast(result, TRoot) End Function - Private Class SyntaxRemover + Private NotInheritable Class SyntaxRemover Inherits VisualBasicSyntaxRewriter Private ReadOnly _nodesToRemove As HashSet(Of SyntaxNode) @@ -304,8 +299,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Syntax End If Dim directivesInSpan = node.DescendantTrivia(span, Function(n) n.ContainsDirectives, descendIntoTrivia:=True) _ - .Where(Function(tr) tr.IsDirective) _ - .Select(Function(tr) DirectCast(tr.GetStructure(), DirectiveTriviaSyntax)) + .Where(Function(tr) tr.IsDirective) _ + .Select(Function(tr) DirectCast(tr.GetStructure(), DirectiveTriviaSyntax)) For Each directive In directivesInSpan If (Me._options And SyntaxRemoveOptions.KeepDirectives) <> 0 Then @@ -324,12 +319,33 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Syntax End If If Me._directivesToKeep.Contains(directive) Then - AddResidualTrivia(SyntaxFactory.TriviaList(directive.ParentTrivia), requiresNewLine:=True) + Dim parentTrivia = directive.ParentTrivia + Dim triviaListAndIndex = GetTriviaListAndIndex(parentTrivia) + Dim triviaList = triviaListAndIndex.triviaList + Dim directiveTriviaListIndex = triviaListAndIndex.Index + + ' If we're keeping a directive, and it's not at the start of the line, keep the whitespace + ' that precedes it as well. + If directiveTriviaListIndex >= 1 AndAlso triviaList(directiveTriviaListIndex - 1).Kind() = SyntaxKind.WhitespaceTrivia Then + AddResidualTrivia(SyntaxFactory.TriviaList( + triviaList(directiveTriviaListIndex - 1), parentTrivia), requiresNewLine:=True) + Else + AddResidualTrivia(SyntaxFactory.TriviaList(parentTrivia), requiresNewLine:=True) + End If End If Next End If End Sub + Private Shared Function GetTriviaListAndIndex(trivia As SyntaxTrivia) As (triviaList As SyntaxTriviaList, Index As Integer) + Dim parentToken = trivia.Token + + Dim index = parentToken.LeadingTrivia.IndexOf(trivia) + Return If(index >= 0, + (parentToken.LeadingTrivia, index), + (parentToken.TrailingTrivia, parentToken.TrailingTrivia.IndexOf(trivia))) + End Function + Private Shared Function HasRelatedDirectives(directive As DirectiveTriviaSyntax) As Boolean Select Case directive.Kind Case SyntaxKind.IfDirectiveTrivia, diff --git a/src/Compilers/VisualBasic/Portable/VBResources.resx b/src/Compilers/VisualBasic/Portable/VBResources.resx index aa32f54bfc7c7..81ec12c060ab6 100644 --- a/src/Compilers/VisualBasic/Portable/VBResources.resx +++ b/src/Compilers/VisualBasic/Portable/VBResources.resx @@ -5543,6 +5543,12 @@ Type is for evaluation purposes only and is subject to change or removal in future updates. + + '{0}' is for evaluation purposes only and is subject to change or removal in future updates: '{1}'. + + + Type is for evaluation purposes only and is subject to change or removal in future updates. + Unable to read debug information of method '{0}' (token 0x{1:X8}) from assembly '{2}': {3} @@ -5716,4 +5722,16 @@ The type name '{0}' is reserved to be used by the compiler. - \ No newline at end of file + + Cannot use 'OverloadResolutionPriorityAttribute' on an overriding member. + + + Cannot use 'OverloadResolutionPriorityAttribute' on this member. + + + overload resolution priority + + + The type 'Microsoft.CodeAnalysis.EmbeddedAttribute' must be non-generic, Friend, NotInheritable, have a Public parameterless constructor, inherit from System.Attribute, and be able to be applied to any type + + diff --git a/src/Compilers/VisualBasic/Portable/xlf/VBResources.cs.xlf b/src/Compilers/VisualBasic/Portable/xlf/VBResources.cs.xlf index bd814e020e846..8b1bcd3130f0b 100644 --- a/src/Compilers/VisualBasic/Portable/xlf/VBResources.cs.xlf +++ b/src/Compilers/VisualBasic/Portable/xlf/VBResources.cs.xlf @@ -17,6 +17,16 @@ Chyba syntaxe příkazového řádku: {0} není platná hodnota možnosti {1}. Hodnota musí mít tvar {2}. + + Cannot use 'OverloadResolutionPriorityAttribute' on this member. + Cannot use 'OverloadResolutionPriorityAttribute' on this member. + + + + Cannot use 'OverloadResolutionPriorityAttribute' on an overriding member. + Cannot use 'OverloadResolutionPriorityAttribute' on an overriding member. + + Cannot inherit from '{0}' because it has required members. Z {0} nelze dědit, protože obsahuje požadované členy. @@ -97,6 +107,11 @@ Seznam požadovaných členů pro {0} má chybný formát a nelze ho interpretovat. + + The type 'Microsoft.CodeAnalysis.EmbeddedAttribute' must be non-generic, Friend, NotInheritable, have a Public parameterless constructor, inherit from System.Attribute, and be able to be applied to any type + The type 'Microsoft.CodeAnalysis.EmbeddedAttribute' must be non-generic, Friend, NotInheritable, have a Public parameterless constructor, inherit from System.Attribute, and be able to be applied to any type + + Target runtime doesn't support default interface implementation. Cílový modul runtime nepodporuje implementaci výchozího rozhraní. @@ -162,6 +177,11 @@ přiřazování do vlastností ByRef nebo jejich předávání pomocí metod setter init-only + + overload resolution priority + overload resolution priority + + unconstrained type parameters in binary conditional expressions parametry neomezeného typu v binárních podmíněných výrazech @@ -658,6 +678,16 @@ Odkaz analyzátoru byl zadán vícekrát + + '{0}' is for evaluation purposes only and is subject to change or removal in future updates: '{1}'. + '{0}' is for evaluation purposes only and is subject to change or removal in future updates: '{1}'. + + + + Type is for evaluation purposes only and is subject to change or removal in future updates. + Type is for evaluation purposes only and is subject to change or removal in future updates. + + Generator '{0}' failed to generate source. It will not contribute to the output and compilation errors may occur as a result. Exception was of type '{1}' with message '{2}'. {3} @@ -9323,7 +9353,7 @@ '{0}' is for evaluation purposes only and is subject to change or removal in future updates. - {0} slouží jen pro účely vyhodnocení a v budoucích aktualizacích může dojít ke změně nebo odebrání. + '{0}' is for evaluation purposes only and is subject to change or removal in future updates. diff --git a/src/Compilers/VisualBasic/Portable/xlf/VBResources.de.xlf b/src/Compilers/VisualBasic/Portable/xlf/VBResources.de.xlf index 23bcf204875eb..4dd5fd7fd5969 100644 --- a/src/Compilers/VisualBasic/Portable/xlf/VBResources.de.xlf +++ b/src/Compilers/VisualBasic/Portable/xlf/VBResources.de.xlf @@ -17,6 +17,16 @@ Fehler in der Befehlszeilensyntax: "{0}" ist kein gültiger Wert für die Option "{1}". Der Wert muss im Format "{2}" vorliegen. + + Cannot use 'OverloadResolutionPriorityAttribute' on this member. + Cannot use 'OverloadResolutionPriorityAttribute' on this member. + + + + Cannot use 'OverloadResolutionPriorityAttribute' on an overriding member. + Cannot use 'OverloadResolutionPriorityAttribute' on an overriding member. + + Cannot inherit from '{0}' because it has required members. Von "{0}" kann nicht geerbt werden, da er über erforderliche Member verfügt. @@ -97,6 +107,11 @@ Die erforderliche Mitgliederliste für '{0}' ist falsch formatiert und kann nicht interpretiert werden. + + The type 'Microsoft.CodeAnalysis.EmbeddedAttribute' must be non-generic, Friend, NotInheritable, have a Public parameterless constructor, inherit from System.Attribute, and be able to be applied to any type + The type 'Microsoft.CodeAnalysis.EmbeddedAttribute' must be non-generic, Friend, NotInheritable, have a Public parameterless constructor, inherit from System.Attribute, and be able to be applied to any type + + Target runtime doesn't support default interface implementation. Die Standardschnittstellenimplementierung wird von der Zielruntime nicht unterstützt. @@ -162,6 +177,11 @@ Die Zuweisung zu oder die Übergabe von ByRef-Eigenschaften erfolgt mit init-only-Settern. + + overload resolution priority + overload resolution priority + + unconstrained type parameters in binary conditional expressions Nicht eingeschränkte Typparameter in binären bedingten Ausdrücken @@ -658,6 +678,16 @@ Mehrfacher Verweis auf Analysetool + + '{0}' is for evaluation purposes only and is subject to change or removal in future updates: '{1}'. + '{0}' is for evaluation purposes only and is subject to change or removal in future updates: '{1}'. + + + + Type is for evaluation purposes only and is subject to change or removal in future updates. + Type is for evaluation purposes only and is subject to change or removal in future updates. + + Generator '{0}' failed to generate source. It will not contribute to the output and compilation errors may occur as a result. Exception was of type '{1}' with message '{2}'. {3} @@ -9323,7 +9353,7 @@ '{0}' is for evaluation purposes only and is subject to change or removal in future updates. - "{0}" dient nur zu Testzwecken und kann in zukünftigen Aktualisierungen geändert oder entfernt werden. + '{0}' is for evaluation purposes only and is subject to change or removal in future updates. diff --git a/src/Compilers/VisualBasic/Portable/xlf/VBResources.es.xlf b/src/Compilers/VisualBasic/Portable/xlf/VBResources.es.xlf index b0a0d61173178..de1c6e6f55067 100644 --- a/src/Compilers/VisualBasic/Portable/xlf/VBResources.es.xlf +++ b/src/Compilers/VisualBasic/Portable/xlf/VBResources.es.xlf @@ -17,6 +17,16 @@ Error de sintaxis de la línea de comandos: "{0}" no es un valor válido para la opción "{1}". El valor debe tener el formato "{2}". + + Cannot use 'OverloadResolutionPriorityAttribute' on this member. + Cannot use 'OverloadResolutionPriorityAttribute' on this member. + + + + Cannot use 'OverloadResolutionPriorityAttribute' on an overriding member. + Cannot use 'OverloadResolutionPriorityAttribute' on an overriding member. + + Cannot inherit from '{0}' because it has required members. No se puede heredar de '{0}' porque tiene miembros necesarios. @@ -97,6 +107,11 @@ La lista de miembros necesarios para '{0}' tiene un formato incorrecto y no se puede interpretar. + + The type 'Microsoft.CodeAnalysis.EmbeddedAttribute' must be non-generic, Friend, NotInheritable, have a Public parameterless constructor, inherit from System.Attribute, and be able to be applied to any type + The type 'Microsoft.CodeAnalysis.EmbeddedAttribute' must be non-generic, Friend, NotInheritable, have a Public parameterless constructor, inherit from System.Attribute, and be able to be applied to any type + + Target runtime doesn't support default interface implementation. El tiempo de ejecución de destino no admite la implementación de interfaz predeterminada. @@ -162,6 +177,11 @@ se asigna a propiedades "ByRef" o se pasa a estas con establecedores init-only + + overload resolution priority + overload resolution priority + + unconstrained type parameters in binary conditional expressions parámetros de tipo sin restricciones en expresiones condicionales binarias @@ -658,6 +678,16 @@ Referencia del analizador especificada varias veces + + '{0}' is for evaluation purposes only and is subject to change or removal in future updates: '{1}'. + '{0}' is for evaluation purposes only and is subject to change or removal in future updates: '{1}'. + + + + Type is for evaluation purposes only and is subject to change or removal in future updates. + Type is for evaluation purposes only and is subject to change or removal in future updates. + + Generator '{0}' failed to generate source. It will not contribute to the output and compilation errors may occur as a result. Exception was of type '{1}' with message '{2}'. {3} @@ -9323,7 +9353,7 @@ '{0}' is for evaluation purposes only and is subject to change or removal in future updates. - "{0}" se incluye con fines de evaluación y está sujeto a cambios o a que se elimine en próximas actualizaciones. + '{0}' is for evaluation purposes only and is subject to change or removal in future updates. diff --git a/src/Compilers/VisualBasic/Portable/xlf/VBResources.fr.xlf b/src/Compilers/VisualBasic/Portable/xlf/VBResources.fr.xlf index 11f4e764ce15e..bdffe5911d464 100644 --- a/src/Compilers/VisualBasic/Portable/xlf/VBResources.fr.xlf +++ b/src/Compilers/VisualBasic/Portable/xlf/VBResources.fr.xlf @@ -17,6 +17,16 @@ Erreur de syntaxe de ligne de commande : '{0}' est une valeur non valide pour l'option '{1}'. La valeur doit se présenter sous la forme '{2}'. + + Cannot use 'OverloadResolutionPriorityAttribute' on this member. + Cannot use 'OverloadResolutionPriorityAttribute' on this member. + + + + Cannot use 'OverloadResolutionPriorityAttribute' on an overriding member. + Cannot use 'OverloadResolutionPriorityAttribute' on an overriding member. + + Cannot inherit from '{0}' because it has required members. Impossible d'hériter de '{0}' car il a requis des membres. @@ -97,6 +107,11 @@ La liste des membres requis pour «{0}» est incorrecte et ne peut pas être interprétée. + + The type 'Microsoft.CodeAnalysis.EmbeddedAttribute' must be non-generic, Friend, NotInheritable, have a Public parameterless constructor, inherit from System.Attribute, and be able to be applied to any type + The type 'Microsoft.CodeAnalysis.EmbeddedAttribute' must be non-generic, Friend, NotInheritable, have a Public parameterless constructor, inherit from System.Attribute, and be able to be applied to any type + + Target runtime doesn't support default interface implementation. Le runtime cible ne prend pas en charge l'implémentation d'interface par défaut. @@ -162,6 +177,11 @@ affectation ou passage de propriétés 'ByRef' avec des méthodes setter d'initialisation uniquement + + overload resolution priority + overload resolution priority + + unconstrained type parameters in binary conditional expressions paramètres de type sans contrainte dans les expressions conditionnelles binaires @@ -658,6 +678,16 @@ Référence de l’analyseur spécifiée plusieurs fois + + '{0}' is for evaluation purposes only and is subject to change or removal in future updates: '{1}'. + '{0}' is for evaluation purposes only and is subject to change or removal in future updates: '{1}'. + + + + Type is for evaluation purposes only and is subject to change or removal in future updates. + Type is for evaluation purposes only and is subject to change or removal in future updates. + + Generator '{0}' failed to generate source. It will not contribute to the output and compilation errors may occur as a result. Exception was of type '{1}' with message '{2}'. {3} @@ -9323,7 +9353,7 @@ '{0}' is for evaluation purposes only and is subject to change or removal in future updates. - '{0}' est utilisé à des fins d'évaluation uniquement. Il sera peut-être changé ou supprimé au cours des prochaines mises à jour. + '{0}' is for evaluation purposes only and is subject to change or removal in future updates. diff --git a/src/Compilers/VisualBasic/Portable/xlf/VBResources.it.xlf b/src/Compilers/VisualBasic/Portable/xlf/VBResources.it.xlf index 6290b87240a9c..6b8f0af256805 100644 --- a/src/Compilers/VisualBasic/Portable/xlf/VBResources.it.xlf +++ b/src/Compilers/VisualBasic/Portable/xlf/VBResources.it.xlf @@ -17,6 +17,16 @@ Errore di sintassi della riga di comando: '{0}' non è un valore valido per l'opzione '{1}'. Il valore deve essere espresso nel formato '{2}'. + + Cannot use 'OverloadResolutionPriorityAttribute' on this member. + Cannot use 'OverloadResolutionPriorityAttribute' on this member. + + + + Cannot use 'OverloadResolutionPriorityAttribute' on an overriding member. + Cannot use 'OverloadResolutionPriorityAttribute' on an overriding member. + + Cannot inherit from '{0}' because it has required members. Non è possibile ereditare da '{0}' perché contiene membri obbligatori. @@ -97,6 +107,11 @@ L'elenco dei membri obbligatori per '{0}' non è valido e non può essere interpretato. + + The type 'Microsoft.CodeAnalysis.EmbeddedAttribute' must be non-generic, Friend, NotInheritable, have a Public parameterless constructor, inherit from System.Attribute, and be able to be applied to any type + The type 'Microsoft.CodeAnalysis.EmbeddedAttribute' must be non-generic, Friend, NotInheritable, have a Public parameterless constructor, inherit from System.Attribute, and be able to be applied to any type + + Target runtime doesn't support default interface implementation. Il runtime di destinazione non supporta l'implementazione di interfaccia predefinita. @@ -162,6 +177,11 @@ assegnazione o passaggio di proprietà 'ByRef' con i setter di sola inizializzazione + + overload resolution priority + overload resolution priority + + unconstrained type parameters in binary conditional expressions parametri di tipo non senza vincoli in espressioni condizionali binarie @@ -659,6 +679,16 @@ Riferimento analizzatore specificato più volte + + '{0}' is for evaluation purposes only and is subject to change or removal in future updates: '{1}'. + '{0}' is for evaluation purposes only and is subject to change or removal in future updates: '{1}'. + + + + Type is for evaluation purposes only and is subject to change or removal in future updates. + Type is for evaluation purposes only and is subject to change or removal in future updates. + + Generator '{0}' failed to generate source. It will not contribute to the output and compilation errors may occur as a result. Exception was of type '{1}' with message '{2}'. {3} @@ -9324,7 +9354,7 @@ '{0}' is for evaluation purposes only and is subject to change or removal in future updates. - '{0}' viene usato solo a scopo di valutazione e potrebbe essere modificato o rimosso in aggiornamenti futuri. + '{0}' is for evaluation purposes only and is subject to change or removal in future updates. diff --git a/src/Compilers/VisualBasic/Portable/xlf/VBResources.ja.xlf b/src/Compilers/VisualBasic/Portable/xlf/VBResources.ja.xlf index 38607bc0ce729..2905480c4eb12 100644 --- a/src/Compilers/VisualBasic/Portable/xlf/VBResources.ja.xlf +++ b/src/Compilers/VisualBasic/Portable/xlf/VBResources.ja.xlf @@ -17,6 +17,16 @@ コマンドライン構文エラー: '{0}' は、'{1}' オプションの有効な値ではありません。値は '{2}' の形式にする必要があります。 + + Cannot use 'OverloadResolutionPriorityAttribute' on this member. + Cannot use 'OverloadResolutionPriorityAttribute' on this member. + + + + Cannot use 'OverloadResolutionPriorityAttribute' on an overriding member. + Cannot use 'OverloadResolutionPriorityAttribute' on an overriding member. + + Cannot inherit from '{0}' because it has required members. 必要なメンバーがあるため、'{0}' から継承できません。 @@ -97,6 +107,11 @@ '{0}' に必要なメンバーの一覧の形式が正しくないため、解釈できません。 + + The type 'Microsoft.CodeAnalysis.EmbeddedAttribute' must be non-generic, Friend, NotInheritable, have a Public parameterless constructor, inherit from System.Attribute, and be able to be applied to any type + The type 'Microsoft.CodeAnalysis.EmbeddedAttribute' must be non-generic, Friend, NotInheritable, have a Public parameterless constructor, inherit from System.Attribute, and be able to be applied to any type + + Target runtime doesn't support default interface implementation. ターゲット ランタイムは、既定のインターフェイスの実装をサポートしていません。 @@ -162,6 +177,11 @@ 初期化専用セッターを使用して、'ByRef' プロパティに割り当てるか、そのプロパティを渡します + + overload resolution priority + overload resolution priority + + unconstrained type parameters in binary conditional expressions バイナリ条件式での非制約型パラメーター @@ -660,6 +680,16 @@ 複数回指定されたアナライザー参照 + + '{0}' is for evaluation purposes only and is subject to change or removal in future updates: '{1}'. + '{0}' is for evaluation purposes only and is subject to change or removal in future updates: '{1}'. + + + + Type is for evaluation purposes only and is subject to change or removal in future updates. + Type is for evaluation purposes only and is subject to change or removal in future updates. + + Generator '{0}' failed to generate source. It will not contribute to the output and compilation errors may occur as a result. Exception was of type '{1}' with message '{2}'. {3} @@ -9325,7 +9355,7 @@ '{0}' is for evaluation purposes only and is subject to change or removal in future updates. - '{0}' は、評価の目的でのみ提供されています。将来の更新で変更または削除されることがあります。 + '{0}' is for evaluation purposes only and is subject to change or removal in future updates. diff --git a/src/Compilers/VisualBasic/Portable/xlf/VBResources.ko.xlf b/src/Compilers/VisualBasic/Portable/xlf/VBResources.ko.xlf index 2ecf339ec30cb..6fcc6640362b8 100644 --- a/src/Compilers/VisualBasic/Portable/xlf/VBResources.ko.xlf +++ b/src/Compilers/VisualBasic/Portable/xlf/VBResources.ko.xlf @@ -17,6 +17,16 @@ 명령줄 구문 오류: '{0}'은(는) '{1}' 옵션에 유효한 값이 아닙니다. 값은 '{2}' 형식이어야 합니다. + + Cannot use 'OverloadResolutionPriorityAttribute' on this member. + Cannot use 'OverloadResolutionPriorityAttribute' on this member. + + + + Cannot use 'OverloadResolutionPriorityAttribute' on an overriding member. + Cannot use 'OverloadResolutionPriorityAttribute' on an overriding member. + + Cannot inherit from '{0}' because it has required members. 필요한 멤버가 있어 '{0}'에서 상속할 수 없습니다. @@ -97,6 +107,11 @@ '{0}'에 대한 필수 구성원 목록 형식이 잘못되어 해석할 수 없습니다. + + The type 'Microsoft.CodeAnalysis.EmbeddedAttribute' must be non-generic, Friend, NotInheritable, have a Public parameterless constructor, inherit from System.Attribute, and be able to be applied to any type + The type 'Microsoft.CodeAnalysis.EmbeddedAttribute' must be non-generic, Friend, NotInheritable, have a Public parameterless constructor, inherit from System.Attribute, and be able to be applied to any type + + Target runtime doesn't support default interface implementation. 대상 런타임이 기본 인터페이스 구현을 지원하지 않습니다. @@ -162,6 +177,11 @@ 초기값 전용 setter를 사용하여 'ByRef' 속성에 할당 또는 이 속성을 전달 + + overload resolution priority + overload resolution priority + + unconstrained type parameters in binary conditional expressions 이진 조건식의 비제한 형식 매개 변수 @@ -658,6 +678,16 @@ 여러 번 지정된 분석기 참조 + + '{0}' is for evaluation purposes only and is subject to change or removal in future updates: '{1}'. + '{0}' is for evaluation purposes only and is subject to change or removal in future updates: '{1}'. + + + + Type is for evaluation purposes only and is subject to change or removal in future updates. + Type is for evaluation purposes only and is subject to change or removal in future updates. + + Generator '{0}' failed to generate source. It will not contribute to the output and compilation errors may occur as a result. Exception was of type '{1}' with message '{2}'. {3} @@ -9323,7 +9353,7 @@ '{0}' is for evaluation purposes only and is subject to change or removal in future updates. - '{0}'은(는) 평가 목적으로 제공되며, 이후 업데이트에서 변경되거나 제거될 수 있습니다. + '{0}' is for evaluation purposes only and is subject to change or removal in future updates. diff --git a/src/Compilers/VisualBasic/Portable/xlf/VBResources.pl.xlf b/src/Compilers/VisualBasic/Portable/xlf/VBResources.pl.xlf index 579256899b55a..10a4d464c1254 100644 --- a/src/Compilers/VisualBasic/Portable/xlf/VBResources.pl.xlf +++ b/src/Compilers/VisualBasic/Portable/xlf/VBResources.pl.xlf @@ -17,6 +17,16 @@ Błąd składni wiersza polecenia: „{0}” nie jest prawidłową wartością dla opcji „{1}”. Wartość musi mieć postać „{2}”. + + Cannot use 'OverloadResolutionPriorityAttribute' on this member. + Cannot use 'OverloadResolutionPriorityAttribute' on this member. + + + + Cannot use 'OverloadResolutionPriorityAttribute' on an overriding member. + Cannot use 'OverloadResolutionPriorityAttribute' on an overriding member. + + Cannot inherit from '{0}' because it has required members. Nie można dziedziczyć z elementu „{0}”, ponieważ zawiera wymagane elementy członkowskie. @@ -97,6 +107,11 @@ Lista wymaganych składowych dla „{0}” jest źle sformułowana i nie można jej zinterpretować. + + The type 'Microsoft.CodeAnalysis.EmbeddedAttribute' must be non-generic, Friend, NotInheritable, have a Public parameterless constructor, inherit from System.Attribute, and be able to be applied to any type + The type 'Microsoft.CodeAnalysis.EmbeddedAttribute' must be non-generic, Friend, NotInheritable, have a Public parameterless constructor, inherit from System.Attribute, and be able to be applied to any type + + Target runtime doesn't support default interface implementation. Docelowe środowisko uruchomieniowe nie obsługuje domyślnej implementacji interfejsu. @@ -162,6 +177,11 @@ przypisywanie lub przekazywanie właściwości „ByRef” za pomocą metod ustawiających tylko do inicjowania + + overload resolution priority + overload resolution priority + + unconstrained type parameters in binary conditional expressions parametry typu bez ograniczeń w binarnych wyrażeniach warunkowych @@ -658,6 +678,16 @@ Odwołanie do analizatora określono wiele razy + + '{0}' is for evaluation purposes only and is subject to change or removal in future updates: '{1}'. + '{0}' is for evaluation purposes only and is subject to change or removal in future updates: '{1}'. + + + + Type is for evaluation purposes only and is subject to change or removal in future updates. + Type is for evaluation purposes only and is subject to change or removal in future updates. + + Generator '{0}' failed to generate source. It will not contribute to the output and compilation errors may occur as a result. Exception was of type '{1}' with message '{2}'. {3} @@ -9323,7 +9353,7 @@ '{0}' is for evaluation purposes only and is subject to change or removal in future updates. - 'Element „{0}” jest przeznaczony wyłącznie do celów ewaluacyjnych i może zostać zmieniony albo usunięty w przyszłych aktualizacjach. + '{0}' is for evaluation purposes only and is subject to change or removal in future updates. diff --git a/src/Compilers/VisualBasic/Portable/xlf/VBResources.pt-BR.xlf b/src/Compilers/VisualBasic/Portable/xlf/VBResources.pt-BR.xlf index 065eae97dd592..63a169b2c342f 100644 --- a/src/Compilers/VisualBasic/Portable/xlf/VBResources.pt-BR.xlf +++ b/src/Compilers/VisualBasic/Portable/xlf/VBResources.pt-BR.xlf @@ -17,6 +17,16 @@ Erro de sintaxe de linha de comando: '{0}' não é um valor válido para a opção '{1}'. O valor precisa estar no formato '{2}'. + + Cannot use 'OverloadResolutionPriorityAttribute' on this member. + Cannot use 'OverloadResolutionPriorityAttribute' on this member. + + + + Cannot use 'OverloadResolutionPriorityAttribute' on an overriding member. + Cannot use 'OverloadResolutionPriorityAttribute' on an overriding member. + + Cannot inherit from '{0}' because it has required members. Não é possível herdar de '{0}' porque ele tem membros necessários. @@ -97,6 +107,11 @@ A lista de membros requeridos '{0}' está malformada e não pode ser interpretada. + + The type 'Microsoft.CodeAnalysis.EmbeddedAttribute' must be non-generic, Friend, NotInheritable, have a Public parameterless constructor, inherit from System.Attribute, and be able to be applied to any type + The type 'Microsoft.CodeAnalysis.EmbeddedAttribute' must be non-generic, Friend, NotInheritable, have a Public parameterless constructor, inherit from System.Attribute, and be able to be applied to any type + + Target runtime doesn't support default interface implementation. O runtime de destino não é compatível com a implementação de interface padrão. @@ -162,6 +177,11 @@ atribuindo ou passando as propriedades 'ByRef' com setters apenas para inicialização + + overload resolution priority + overload resolution priority + + unconstrained type parameters in binary conditional expressions parâmetros de tipo irrestritos em expressões condicionais binárias @@ -658,6 +678,16 @@ Referência do analisador especificada várias vezes + + '{0}' is for evaluation purposes only and is subject to change or removal in future updates: '{1}'. + '{0}' is for evaluation purposes only and is subject to change or removal in future updates: '{1}'. + + + + Type is for evaluation purposes only and is subject to change or removal in future updates. + Type is for evaluation purposes only and is subject to change or removal in future updates. + + Generator '{0}' failed to generate source. It will not contribute to the output and compilation errors may occur as a result. Exception was of type '{1}' with message '{2}'. {3} @@ -9323,7 +9353,7 @@ '{0}' is for evaluation purposes only and is subject to change or removal in future updates. - '{0}' é para fins de avaliação somente e está sujeito a alterações ou remoções em atualizações futuras. + '{0}' is for evaluation purposes only and is subject to change or removal in future updates. diff --git a/src/Compilers/VisualBasic/Portable/xlf/VBResources.ru.xlf b/src/Compilers/VisualBasic/Portable/xlf/VBResources.ru.xlf index 5ca402b9da612..e7856243d8ebf 100644 --- a/src/Compilers/VisualBasic/Portable/xlf/VBResources.ru.xlf +++ b/src/Compilers/VisualBasic/Portable/xlf/VBResources.ru.xlf @@ -17,6 +17,16 @@ Ошибка в синтаксисе командной строки: "{0}" не является допустимым значением для параметра "{1}". Значение должно иметь форму "{2}". + + Cannot use 'OverloadResolutionPriorityAttribute' on this member. + Cannot use 'OverloadResolutionPriorityAttribute' on this member. + + + + Cannot use 'OverloadResolutionPriorityAttribute' on an overriding member. + Cannot use 'OverloadResolutionPriorityAttribute' on an overriding member. + + Cannot inherit from '{0}' because it has required members. Не удалось наследование от "{0}", так как в нем есть обязательные элементы. @@ -97,6 +107,11 @@ Неправильный формат списка обязательных элементов для "{0}", его не удается интерпретировать. + + The type 'Microsoft.CodeAnalysis.EmbeddedAttribute' must be non-generic, Friend, NotInheritable, have a Public parameterless constructor, inherit from System.Attribute, and be able to be applied to any type + The type 'Microsoft.CodeAnalysis.EmbeddedAttribute' must be non-generic, Friend, NotInheritable, have a Public parameterless constructor, inherit from System.Attribute, and be able to be applied to any type + + Target runtime doesn't support default interface implementation. Целевая среда выполнения не поддерживает реализацию интерфейса по умолчанию. @@ -162,6 +177,11 @@ назначение свойств "ByRef" или их передача с помощью методов задания, предназначенных только для инициализации + + overload resolution priority + overload resolution priority + + unconstrained type parameters in binary conditional expressions параметры неограниченного типа в двоичных условных выражениях @@ -658,6 +678,16 @@ optionstrict[+|-] Принудительное применени Ссылка на анализатор указана несколько раз + + '{0}' is for evaluation purposes only and is subject to change or removal in future updates: '{1}'. + '{0}' is for evaluation purposes only and is subject to change or removal in future updates: '{1}'. + + + + Type is for evaluation purposes only and is subject to change or removal in future updates. + Type is for evaluation purposes only and is subject to change or removal in future updates. + + Generator '{0}' failed to generate source. It will not contribute to the output and compilation errors may occur as a result. Exception was of type '{1}' with message '{2}'. {3} @@ -9323,7 +9353,7 @@ optionstrict[+|-] Принудительное применени '{0}' is for evaluation purposes only and is subject to change or removal in future updates. - "{0}" предназначен только для оценки и может быть изменен или удален в будущих обновлениях. + '{0}' is for evaluation purposes only and is subject to change or removal in future updates. diff --git a/src/Compilers/VisualBasic/Portable/xlf/VBResources.tr.xlf b/src/Compilers/VisualBasic/Portable/xlf/VBResources.tr.xlf index 60eb93ca8b25c..73460a226362c 100644 --- a/src/Compilers/VisualBasic/Portable/xlf/VBResources.tr.xlf +++ b/src/Compilers/VisualBasic/Portable/xlf/VBResources.tr.xlf @@ -17,6 +17,16 @@ Komut satırı söz dizimi hatası: '{0}', '{1}' seçeneği için geçerli bir değer değil. Değer '{2}' biçiminde olmalıdır. + + Cannot use 'OverloadResolutionPriorityAttribute' on this member. + Cannot use 'OverloadResolutionPriorityAttribute' on this member. + + + + Cannot use 'OverloadResolutionPriorityAttribute' on an overriding member. + Cannot use 'OverloadResolutionPriorityAttribute' on an overriding member. + + Cannot inherit from '{0}' because it has required members. Gerekli üyelere sahip olduğu için '{0}' öğesinden devralınamaz. @@ -97,6 +107,11 @@ '{0}' için gerekli üye listesi hatalı biçimlendirilmiş ve yorumlanamıyor. + + The type 'Microsoft.CodeAnalysis.EmbeddedAttribute' must be non-generic, Friend, NotInheritable, have a Public parameterless constructor, inherit from System.Attribute, and be able to be applied to any type + The type 'Microsoft.CodeAnalysis.EmbeddedAttribute' must be non-generic, Friend, NotInheritable, have a Public parameterless constructor, inherit from System.Attribute, and be able to be applied to any type + + Target runtime doesn't support default interface implementation. Hedef çalışma zamanı varsayılan arabirim uygulamasını desteklemiyor. @@ -162,6 +177,11 @@ init-only ayarlayıcıları ile 'ByRef' özelliklerine atama veya geçirme + + overload resolution priority + overload resolution priority + + unconstrained type parameters in binary conditional expressions ikili koşullu ifadelerde kısıtlanmamış tür parametreleri @@ -659,6 +679,16 @@ Çözümleyici referansı birden çok kez belirtildi + + '{0}' is for evaluation purposes only and is subject to change or removal in future updates: '{1}'. + '{0}' is for evaluation purposes only and is subject to change or removal in future updates: '{1}'. + + + + Type is for evaluation purposes only and is subject to change or removal in future updates. + Type is for evaluation purposes only and is subject to change or removal in future updates. + + Generator '{0}' failed to generate source. It will not contribute to the output and compilation errors may occur as a result. Exception was of type '{1}' with message '{2}'. {3} @@ -9324,7 +9354,7 @@ '{0}' is for evaluation purposes only and is subject to change or removal in future updates. - '{0}' yalnızca değerlendirme amaçlıdır ve gelecekteki güncelleştirmelerde değiştirilebilir veya kaldırılabilir. + '{0}' is for evaluation purposes only and is subject to change or removal in future updates. diff --git a/src/Compilers/VisualBasic/Portable/xlf/VBResources.zh-Hans.xlf b/src/Compilers/VisualBasic/Portable/xlf/VBResources.zh-Hans.xlf index 32c667db2d4ef..379363209abe0 100644 --- a/src/Compilers/VisualBasic/Portable/xlf/VBResources.zh-Hans.xlf +++ b/src/Compilers/VisualBasic/Portable/xlf/VBResources.zh-Hans.xlf @@ -17,6 +17,16 @@ 命令行语法错误:“{0}”不是“{1}”选项的有效值。值的格式必须为 "{2}"。 + + Cannot use 'OverloadResolutionPriorityAttribute' on this member. + Cannot use 'OverloadResolutionPriorityAttribute' on this member. + + + + Cannot use 'OverloadResolutionPriorityAttribute' on an overriding member. + Cannot use 'OverloadResolutionPriorityAttribute' on an overriding member. + + Cannot inherit from '{0}' because it has required members. 无法从 "{0}" 继承,因为它具有必需的成员。 @@ -97,6 +107,11 @@ '{0}' 所需的成员列表格式不正确,无法解释。 + + The type 'Microsoft.CodeAnalysis.EmbeddedAttribute' must be non-generic, Friend, NotInheritable, have a Public parameterless constructor, inherit from System.Attribute, and be able to be applied to any type + The type 'Microsoft.CodeAnalysis.EmbeddedAttribute' must be non-generic, Friend, NotInheritable, have a Public parameterless constructor, inherit from System.Attribute, and be able to be applied to any type + + Target runtime doesn't support default interface implementation. 目标运行时不支持默认接口实现。 @@ -162,6 +177,11 @@ 通过 init-only 资源库分配或传递 "ByRef" 属性 + + overload resolution priority + overload resolution priority + + unconstrained type parameters in binary conditional expressions 二进制条件表达式中的无约束类型参数 @@ -658,6 +678,16 @@ 已多次指定分析器引用 + + '{0}' is for evaluation purposes only and is subject to change or removal in future updates: '{1}'. + '{0}' is for evaluation purposes only and is subject to change or removal in future updates: '{1}'. + + + + Type is for evaluation purposes only and is subject to change or removal in future updates. + Type is for evaluation purposes only and is subject to change or removal in future updates. + + Generator '{0}' failed to generate source. It will not contribute to the output and compilation errors may occur as a result. Exception was of type '{1}' with message '{2}'. {3} @@ -9323,7 +9353,7 @@ '{0}' is for evaluation purposes only and is subject to change or removal in future updates. - “{0}”仅用于评估,在将来的更新中可能会被更改或删除。 + '{0}' is for evaluation purposes only and is subject to change or removal in future updates. diff --git a/src/Compilers/VisualBasic/Portable/xlf/VBResources.zh-Hant.xlf b/src/Compilers/VisualBasic/Portable/xlf/VBResources.zh-Hant.xlf index 23796ebb92044..61edb731f0278 100644 --- a/src/Compilers/VisualBasic/Portable/xlf/VBResources.zh-Hant.xlf +++ b/src/Compilers/VisualBasic/Portable/xlf/VBResources.zh-Hant.xlf @@ -17,6 +17,16 @@ 命令列語法錯誤: '{0}' 對 '{1}' 選項而言不是有效的值。此值的格式必須是 '{2}'。 + + Cannot use 'OverloadResolutionPriorityAttribute' on this member. + Cannot use 'OverloadResolutionPriorityAttribute' on this member. + + + + Cannot use 'OverloadResolutionPriorityAttribute' on an overriding member. + Cannot use 'OverloadResolutionPriorityAttribute' on an overriding member. + + Cannot inherit from '{0}' because it has required members. '{0}' 具有必要的成員,因此無法從其繼承。 @@ -97,6 +107,11 @@ '{0}' 的必要成員清單格式錯誤,無法解譯。 + + The type 'Microsoft.CodeAnalysis.EmbeddedAttribute' must be non-generic, Friend, NotInheritable, have a Public parameterless constructor, inherit from System.Attribute, and be able to be applied to any type + The type 'Microsoft.CodeAnalysis.EmbeddedAttribute' must be non-generic, Friend, NotInheritable, have a Public parameterless constructor, inherit from System.Attribute, and be able to be applied to any type + + Target runtime doesn't support default interface implementation. 目標執行階段不支援預設介面實作。 @@ -162,6 +177,11 @@ 使用僅限初始化的 setter,指派或傳遞 'ByRef' 屬性 + + overload resolution priority + overload resolution priority + + unconstrained type parameters in binary conditional expressions 二進位條件運算式中的非限制式型別參數 @@ -659,6 +679,16 @@ 已指定多次分析器參考 + + '{0}' is for evaluation purposes only and is subject to change or removal in future updates: '{1}'. + '{0}' is for evaluation purposes only and is subject to change or removal in future updates: '{1}'. + + + + Type is for evaluation purposes only and is subject to change or removal in future updates. + Type is for evaluation purposes only and is subject to change or removal in future updates. + + Generator '{0}' failed to generate source. It will not contribute to the output and compilation errors may occur as a result. Exception was of type '{1}' with message '{2}'. {3} @@ -9324,7 +9354,7 @@ '{0}' is for evaluation purposes only and is subject to change or removal in future updates. - '{0}' 僅供評估之用。後續更新時可能會有所變更或移除。 + '{0}' is for evaluation purposes only and is subject to change or removal in future updates. diff --git a/src/Compilers/VisualBasic/Test/CommandLine/CommandLineTests.vb b/src/Compilers/VisualBasic/Test/CommandLine/CommandLineTests.vb index bb42d5e53c829..8841ef4e3fa67 100644 --- a/src/Compilers/VisualBasic/Test/CommandLine/CommandLineTests.vb +++ b/src/Compilers/VisualBasic/Test/CommandLine/CommandLineTests.vb @@ -2056,9 +2056,7 @@ End Module").Path Public Sub LanguageVersionAdded_Canary() ' When a new version is added, this test will break. This list must be checked: - ' - update the "UpgradeProject" codefixer (not yet supported in VB) ' - update all the tests that call this canary - ' - update the command-line documentation (CommandLine.md) AssertEx.SetEqual({"default", "9", "10", "11", "12", "14", "15", "15.3", "15.5", "16", "16.9", "17.13", "latest"}, System.Enum.GetValues(GetType(LanguageVersion)).Cast(Of LanguageVersion)().Select(Function(v) v.ToDisplayString())) ' For minor versions, the format should be "x.y", such as "15.3" @@ -2104,6 +2102,7 @@ End Module").Path Assert.Equal(LanguageVersion.VisualBasic16, LanguageVersion.VisualBasic16.MapSpecifiedToEffectiveVersion()) Assert.Equal(LanguageVersion.VisualBasic16_9, LanguageVersion.VisualBasic16_9.MapSpecifiedToEffectiveVersion()) Assert.Equal(LanguageVersion.VisualBasic17_13, LanguageVersion.VisualBasic17_13.MapSpecifiedToEffectiveVersion()) + Assert.Equal(LanguageVersion.VisualBasic17_13, LanguageVersion.Default.MapSpecifiedToEffectiveVersion()) ' The canary check is a reminder that this test needs to be updated when a language version is added LanguageVersionAdded_Canary() @@ -10854,6 +10853,54 @@ dotnet_diagnostic.BC42380.severity = warning") Assert.Contains("warning DiagID: 'C' is for evaluation purposes only and is subject to change or removal in future updates.", outWriter.ToString()) End Sub + + Public Sub ExperimentalWithValidDiagnosticID_WarnForExperimentalWithMessage() + Dim dir = Temp.CreateDirectory() + + Dim src = dir.CreateFile("test.vb").WriteAllText(" +Public Class D + Public Sub M(c As C) + End Sub +End Class + + +Public Class C + Public Shared Sub M() + End Sub +End Class + +Namespace System.Diagnostics.CodeAnalysis + Public NotInheritable Class ExperimentalAttribute + Inherits Attribute + + Public Sub New(ByVal diagnosticId As String) + End Sub + + Property Message As String + End Class +End Namespace +") + + Dim analyzerConfig = dir.CreateFile(".editorconfig").WriteAllText(" +[*.vb] +dotnet_diagnostic.BC42509.severity = warning") + + Assert.Equal(DirectCast(42509, ERRID), ERRID.WRN_ExperimentalWithMessage) + + Dim cmd = New MockVisualBasicCompiler(Nothing, dir.Path, { + "/nologo", + "/t:library", + "/preferreduilang:en", + "/analyzerconfig:" + analyzerConfig.Path, + src.Path}) + + Dim outWriter = New StringWriter(CultureInfo.InvariantCulture) + Dim exitCode = cmd.Run(outWriter) + Assert.Equal(0, exitCode) + ' Note: the behavior differs from C# in that the editorconfig rule is applied + Assert.Contains("warning DiagID: 'C' is for evaluation purposes only and is subject to change or removal in future updates: 'use CCC'.", outWriter.ToString()) + End Sub + Private Function EmitGenerator(ByVal targetFramework As String) As String Dim targetFrameworkAttributeText As String = If(TypeOf targetFramework Is Object, $"", String.Empty) Dim generatorSource As String = $" diff --git a/src/Compilers/VisualBasic/Test/Emit/Attributes/AttributeTests.vb b/src/Compilers/VisualBasic/Test/Emit/Attributes/AttributeTests.vb index 3c64b76dadf01..489f5ef45ae5c 100644 --- a/src/Compilers/VisualBasic/Test/Emit/Attributes/AttributeTests.vb +++ b/src/Compilers/VisualBasic/Test/Emit/Attributes/AttributeTests.vb @@ -4852,12 +4852,12 @@ BC30002: Type 'xyz' is not defined. Public Sub ReferencingEmbeddedAttributesFromADifferentAssemblyFails_Internal() - Dim reference = + Dim referenceCode = Namespace Microsoft.CodeAnalysis - Friend Class EmbeddedAttribute + Friend NotInheritable Class EmbeddedAttribute Inherits System.Attribute End Class End Namespace @@ -4875,7 +4875,9 @@ End Namespace - Dim referenceCompilation = CreateCompilationWithMscorlib40(reference).ToMetadataReference() + Dim referenceCompilation As VisualBasicCompilation = CreateCompilationWithMscorlib40(referenceCode) + referenceCompilation.AssertTheseDiagnostics() + Dim reference = referenceCompilation.ToMetadataReference() Dim code = " Public Class Program @@ -4886,7 +4888,7 @@ Public Class Program End Sub End Class" - Dim compilation = CreateCompilationWithMscorlib40(code, references:={referenceCompilation}, assemblyName:="Source") + Dim compilation = CreateCompilationWithMscorlib40(code, references:={reference}, assemblyName:="Source") AssertTheseDiagnostics(compilation, + + + + Public Sub EmbeddedAttributeFromSourceValidation_Valid(targetsList As String) + Dim targets = If(targetsList <> "", $", System.AttributeUsage({targetsList})", "") + + Dim code = $" +Namespace Microsoft.CodeAnalysis + + Friend NotInheritable Class EmbeddedAttribute + Inherits System.Attribute + + Public Sub New() + End Sub + End Class +End Namespace +" + + Dim comp = CreateCompilationWithMscorlib40(code) + comp.AssertNoDiagnostics() + + Dim comp2 = CreateCSharpCompilation("CSharpTest", " +public class Test +{ + public static void M(in int p) {} +} +", referencedCompilations:={comp}) + + CompileAndVerify(comp2).VerifyDiagnostics() + End Sub + + + Public Sub EmbeddedAttributeFromSourceValidation_Public() + Dim code = " +Namespace Microsoft.CodeAnalysis + + Public NotInheritable Class EmbeddedAttribute + Inherits System.Attribute + + Public Sub New() + End Sub + End Class +End Namespace +" + + CreateCompilation(code, assemblyName:="testModule", targetFramework:=TargetFramework.NetStandard20).AssertTheseDiagnostics( + ~~~~~~~~~~~ +]]>) + End Sub + + + Public Sub EmbeddedAttributeFromSourceValidation_NoSealed() + Dim code = " +Namespace Microsoft.CodeAnalysis + + Friend Class EmbeddedAttribute + Inherits System.Attribute + + Public Sub New() + End Sub + End Class +End Namespace +" + + CreateCompilation(code, assemblyName:="testModule", targetFramework:=TargetFramework.NetStandard20).AssertTheseDiagnostics( + "BC37335: The type 'Microsoft.CodeAnalysis.EmbeddedAttribute' must be non-generic, Friend, NotInheritable, have a Public parameterless constructor, inherit from System.Attribute, and be able to be applied to any type + + ~~~~~~~~~~~") + End Sub + + + + + + + + Public Sub EmbeddedAttributeFromSourceValidation_CtorAccessibility(ctorAccessModifier As String) + Dim code = $" +Namespace Microsoft.CodeAnalysis + Friend NotInheritable Class EmbeddedAttribute + Inherits System.Attribute + + {ctorAccessModifier} Sub New() + End Sub + End Class +End Namespace +" + + CreateCompilation(code, assemblyName:="testModule", targetFramework:=TargetFramework.NetStandard20).AssertTheseDiagnostics() + End Sub + + + Public Sub EmbeddedAttributeFromSourceValidation_MissingEmbeddedAttributeApplicationGeneratesAttributeApplication(hasObsolete As Boolean) + Dim obsolete = If(hasObsolete, "", "") + Dim code = $" +Namespace Microsoft.CodeAnalysis + {obsolete} + Friend NotInheritable Class EmbeddedAttribute + Inherits System.Attribute + + Public Sub New() + End Sub + End Class +End Namespace +" + + Dim comp = CreateCompilation(code, assemblyName:="testModule", targetFramework:=TargetFramework.NetStandard20) + Dim embeddedAttribute = comp.Assembly.GetTypeByMetadataName(AttributeDescription.CodeAnalysisEmbeddedAttribute.FullName) + Assert.True(embeddedAttribute.HasCodeAnalysisEmbeddedAttribute) + + CompileAndVerify(comp, symbolValidator:=Sub([module]) + Dim embeddedAttr = [module].ContainingAssembly.GetTypeByMetadataName(AttributeDescription.CodeAnalysisEmbeddedAttribute.FullName) + Assert.NotNull(embeddedAttr) + Assert.Equal({"Microsoft.CodeAnalysis.EmbeddedAttribute"}, + embeddedAttr.GetAttributes().Where(Function(a) a.AttributeClass.Name <> "ObsoleteAttribute").Select(Function(a) a.AttributeClass.ToTestDisplayString())) + End Sub).VerifyDiagnostics() + End Sub + + + Public Sub EmbeddedAttributeFromSourceValidation_MissingEmbeddedAttributeApplicationGeneratesAttributeApplication_Partial() + Dim code = " +Namespace Microsoft.CodeAnalysis + Friend NotInheritable Partial Class EmbeddedAttribute + Inherits System.Attribute + End Class +End Namespace" + + Dim comp = CreateCompilationWithMscorlib40({code, code}) + comp.AssertNoDiagnostics() + + Dim sourceDeclaration = comp.SourceAssembly.GetTypeByMetadataName("Microsoft.CodeAnalysis.EmbeddedAttribute") + Assert.Equal(2, sourceDeclaration.Locations.Length) + + CompileAndVerify(comp, symbolValidator:=Sub([module]) + Dim embeddedAttr = [module].ContainingAssembly.GetTypeByMetadataName(AttributeDescription.CodeAnalysisEmbeddedAttribute.FullName) + Assert.NotNull(embeddedAttr) + Assert.Equal({"Microsoft.CodeAnalysis.EmbeddedAttribute"}, + embeddedAttr.GetAttributes().Select(Function(a) a.AttributeClass.ToTestDisplayString())) + End Sub) + End Sub + + + Public Sub EmbeddedAttributeFromSourceValidation_Generic() + Dim code = " +Namespace Microsoft.CodeAnalysis + + Friend NotInheritable Class EmbeddedAttribute(Of T) + Inherits System.Attribute + + Public Sub New() + End Sub + End Class +End Namespace +" + + Dim comp = CreateCompilation(code, assemblyName:="testModule", targetFramework:=TargetFramework.NetStandard20) + comp.AssertTheseDiagnostics( + ~~~~~~~~ +BC32066: Type arguments are not valid because attributes cannot be generic. + + ~~~~~~~~ +BC32074: Classes that are generic or contained in a generic type cannot inherit from an attribute class. + Friend NotInheritable Class EmbeddedAttribute(Of T) + ~~~~~~~~~~~~~~~~~ +]]>) + End Sub + + + Public Sub EmbeddedAttributeFromSourceValidation_Static() + Dim code = " +Namespace Microsoft.CodeAnalysis + + Friend Module EmbeddedAttribute + Inherits System.Attribute + End Module +End Namespace +" + + CreateCompilation(code, assemblyName:="testModule", targetFramework:=TargetFramework.NetStandard20).AssertTheseDiagnostics( + ~~~~~~~~~~~ +BC31504: 'EmbeddedAttribute' cannot be used as an attribute because it does not inherit from 'System.Attribute'. + + ~~~~~~~~ +BC35000: Requested operation is not available because the runtime library function 'Microsoft.VisualBasic.CompilerServices.StandardModuleAttribute..ctor' is not defined. + Friend Module EmbeddedAttribute + ~~~~~~~~~~~~~~~~~ +BC30230: 'Inherits' not valid in Modules. + Inherits System.Attribute + ~~~~~~~~~~~~~~~~~~~~~~~~~ + +]]>) + End Sub + + + Public Sub EmbeddedAttributeFromSourceValidation_WrongBaseType() + Dim code = " +Namespace Microsoft.CodeAnalysis + + Friend NotInheritable Class EmbeddedAttribute + + Public Sub New() + End Sub + End Class +End Namespace +" + + CreateCompilation(code, assemblyName:="testModule", targetFramework:=TargetFramework.NetStandard20).AssertTheseDiagnostics( + ~~~~~~~~~~~ +BC31504: 'EmbeddedAttribute' cannot be used as an attribute because it does not inherit from 'System.Attribute'. + + ~~~~~~~~ +]]>) + End Sub + + + + + + + + Public Sub EmbeddedAttributeFromSourceValidation_AttributeUsage(targets As String) + Dim code = $" +Imports System +Namespace Microsoft.CodeAnalysis + + Friend NotInheritable Class EmbeddedAttribute + Inherits System.Attribute + + Public Sub New() + End Sub + End Class +End Namespace +" + + If Not targets.Contains("Class") Then + End If + + Dim comp = CreateCompilation(code, assemblyName:="testModule", targetFramework:=TargetFramework.NetStandard20) + + If targets.Contains("Class") Then + comp.AssertTheseDiagnostics($"BC37335: The type 'Microsoft.CodeAnalysis.EmbeddedAttribute' must be non-generic, Friend, NotInheritable, have a Public parameterless constructor, inherit from System.Attribute, and be able to be applied to any type + + ~~~~~~~~~~~~~~~~~~~~~~~~~~{(New String("~"c, targets.Length))}~~~" +) + Else + + comp.AssertTheseDiagnostics( + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +BC30662: Attribute 'EmbeddedAttribute' cannot be applied to 'EmbeddedAttribute' because the attribute is not valid on this declaration type. + + ~~~~~~~~ +]]>) + End If + End Sub + Public Sub AttributeWithTaskDelegateParameter() Dim code = " @@ -5150,9 +5422,12 @@ namespace System.Diagnostics.CodeAnalysis public ExperimentalAttribute(string diagnosticId) { } public string? UrlFormat { get; set; } + + public string? Message { get; set; } } } " + Private Const DefaultHelpLinkUri As String = "https://msdn.microsoft.com/query/roslyn.query?appId=roslyn&k=k(BC42380)" Public Sub ExperimentalWithDiagnosticsId() @@ -5185,7 +5460,7 @@ DiagID1: 'C' is for evaluation purposes only and is subject to change or removal Dim diag = comp.GetDiagnostics().Single() Assert.Equal("DiagID1", diag.Id) Assert.Equal(ERRID.WRN_Experimental, diag.Code) - Assert.Equal("https://msdn.microsoft.com/query/roslyn.query?appId=roslyn&k=k(BC42380)", diag.Descriptor.HelpLinkUri) + Assert.Equal(DefaultHelpLinkUri, diag.Descriptor.HelpLinkUri) End Sub @@ -5440,6 +5715,40 @@ DiagID1: 'C' is for evaluation purposes only and is subject to change or removal Assert.Equal("https://example.org/DiagID1", diag.Descriptor.HelpLinkUri) End Sub + + Public Sub ExperimentalWithDiagnosticsIdAndMessage() + Dim attrComp = CreateCSharpCompilation(experimentalAttributeCSharpSrc) + + Dim src = + + +Class C +End Class + +Class D + Sub M(c As C) + End Sub +End Class +]]> + + + + Dim comp = CreateCompilation(src, references:={attrComp.EmitToImageReference()}) + + comp.AssertTheseDiagnostics( +) + + Dim diag = comp.GetDiagnostics().Single() + Assert.Equal("DiagID1", diag.Id) + Assert.Equal(ERRID.WRN_ExperimentalWithMessage, diag.Code) + Assert.Equal($"https://msdn.microsoft.com/query/roslyn.query?appId=roslyn&k=k(BC{CInt(ERRID.WRN_ExperimentalWithMessage)})", diag.Descriptor.HelpLinkUri) + End Sub + Public Sub ExperimentalWithDiagnosticsIdAndUrlFormat_InMetadata() Dim attrReference = CreateCSharpCompilation(experimentalAttributeCSharpSrc).EmitToImageReference() @@ -5478,6 +5787,188 @@ DiagID1: 'C' is for evaluation purposes only and is subject to change or removal Assert.Equal("https://example.org/DiagID1", diag.Descriptor.HelpLinkUri) End Sub + + Public Sub ExperimentalWithDiagnosticsIdAndMessage_InMetadata() + Dim attrReference = CreateCSharpCompilation(experimentalAttributeCSharpSrc).EmitToImageReference() + + Dim libSrc = + + +Public Class C +End Class +]]> + + + + Dim libComp = CreateCompilation(libSrc, references:={attrReference}) + + Dim src = " +Class D + Sub M(c As C) + End Sub +End Class +" + + Dim comp = CreateCompilation(src, references:={attrReference, libComp.EmitToImageReference()}) + + comp.AssertTheseDiagnostics( +) + + Dim diag = comp.GetDiagnostics().Single() + Assert.Equal("DiagID1", diag.Id) + Assert.Equal(ERRID.WRN_ExperimentalWithMessage, diag.Code) + Assert.Equal($"https://msdn.microsoft.com/query/roslyn.query?appId=roslyn&k=k(BC{CInt(ERRID.WRN_ExperimentalWithMessage)})", diag.Descriptor.HelpLinkUri) + End Sub + + + Public Sub ExperimentalWithDiagnosticsIdAndEmptyMessage() + Dim attrComp = CreateCSharpCompilation(experimentalAttributeCSharpSrc) + + Dim src = + + +Class C +End Class + +Class D + Sub M(c As C) + End Sub +End Class +]]> + + + + Dim comp = CreateCompilation(src, references:={attrComp.EmitToImageReference()}) + + comp.AssertTheseDiagnostics( +) + + Dim diag = comp.GetDiagnostics().Single() + Assert.Equal("DiagID1", diag.Id) + Assert.Equal(ERRID.WRN_Experimental, diag.Code) + Assert.Equal(DefaultHelpLinkUri, diag.Descriptor.HelpLinkUri) + End Sub + + + Public Sub ExperimentalWithDiagnosticsIdAndEmptyMessage_InMetadata() + Dim attrReference = CreateCSharpCompilation(experimentalAttributeCSharpSrc).EmitToImageReference() + + Dim libSrc = + + +Public Class C +End Class +]]> + + + + Dim libComp = CreateCompilation(libSrc, references:={attrReference}) + + Dim src = " +Class D + Sub M(c As C) + End Sub +End Class +" + + Dim comp = CreateCompilation(src, references:={attrReference, libComp.EmitToImageReference()}) + + comp.AssertTheseDiagnostics( +) + + Dim diag = comp.GetDiagnostics().Single() + Assert.Equal("DiagID1", diag.Id) + Assert.Equal(ERRID.WRN_Experimental, diag.Code) + Assert.Equal(DefaultHelpLinkUri, diag.Descriptor.HelpLinkUri) + End Sub + + + Public Sub ExperimentalWithDiagnosticsIdAndNullMessage() + Dim attrComp = CreateCSharpCompilation(experimentalAttributeCSharpSrc) + + Dim src = + + +Class C +End Class + +Class D + Sub M(c As C) + End Sub +End Class +]]> + + + + Dim comp = CreateCompilation(src, references:={attrComp.EmitToImageReference()}) + + comp.AssertTheseDiagnostics( +) + + Dim diag = comp.GetDiagnostics().Single() + Assert.Equal("DiagID1", diag.Id) + Assert.Equal(ERRID.WRN_Experimental, diag.Code) + Assert.Equal(DefaultHelpLinkUri, diag.Descriptor.HelpLinkUri) + End Sub + + + Public Sub ExperimentalWithDiagnosticsIdAndNullMessage_InMetadata() + Dim attrReference = CreateCSharpCompilation(experimentalAttributeCSharpSrc).EmitToImageReference() + + Dim libSrc = + + +Public Class C +End Class +]]> + + + + Dim libComp = CreateCompilation(libSrc, references:={attrReference}) + + Dim src = " +Class D + Sub M(c As C) + End Sub +End Class +" + + Dim comp = CreateCompilation(src, references:={attrReference, libComp.EmitToImageReference()}) + + comp.AssertTheseDiagnostics( +) + + Dim diag = comp.GetDiagnostics().Single() + Assert.Equal("DiagID1", diag.Id) + Assert.Equal(ERRID.WRN_Experimental, diag.Code) + Assert.Equal(DefaultHelpLinkUri, diag.Descriptor.HelpLinkUri) + End Sub + Public Sub OnAssembly_UsedFromSource() Dim attrComp = CreateCSharpCompilation(experimentalAttributeCSharpSrc) @@ -5549,7 +6040,7 @@ DiagID1: 'C' is for evaluation purposes only and is subject to change or removal Dim diag = comp.GetDiagnostics().Single() Assert.Equal("DiagID1", diag.Id) Assert.Equal(ERRID.WRN_Experimental, diag.Code) - Assert.Equal("https://msdn.microsoft.com/query/roslyn.query?appId=roslyn&k=k(BC42380)", diag.Descriptor.HelpLinkUri) + Assert.Equal(DefaultHelpLinkUri, diag.Descriptor.HelpLinkUri) End Sub @@ -6262,7 +6753,7 @@ DiagID1: 'Public Shared Sub M()' is for evaluation purposes only and is subject For Each diag In comp.GetDiagnostics() Assert.Equal("DiagID1", diag.Id) Assert.Equal(ERRID.WRN_Experimental, diag.Code) - Assert.Equal("https://msdn.microsoft.com/query/roslyn.query?appId=roslyn&k=k(BC42380)", diag.Descriptor.HelpLinkUri) + Assert.Equal(DefaultHelpLinkUri, diag.Descriptor.HelpLinkUri) Next End Sub diff --git a/src/Compilers/VisualBasic/Test/Emit/CodeGen/CodeGenAsyncTests.vb b/src/Compilers/VisualBasic/Test/Emit/CodeGen/CodeGenAsyncTests.vb index 96f40fcfc1e6e..aa80370e68742 100644 --- a/src/Compilers/VisualBasic/Test/Emit/CodeGen/CodeGenAsyncTests.vb +++ b/src/Compilers/VisualBasic/Test/Emit/CodeGen/CodeGenAsyncTests.vb @@ -12327,6 +12327,53 @@ End Class Dim compilation = CreateCompilation(source, options:=TestOptions.ReleaseExe) CompileAndVerify(compilation, expectedOutput:="1") End Sub + + + Public Sub CompilerLoweringPreserveAttribute_01() + Dim source1 = " +Imports System +Imports System.Runtime.CompilerServices + + + +Public Class Preserve1Attribute + Inherits Attribute +End Class + + + +Public Class Preserve2Attribute + Inherits Attribute +End Class + + +Public Class Preserve3Attribute + Inherits Attribute +End Class +" + Dim source2 = " +Imports System.Threading.Tasks + +Class Test1 + Async Function M2( x As Integer) As Task(Of Integer) + Await Task.Yield() + Return x + End Function +End Class +" + + Dim validate = Sub(m As ModuleSymbol) + AssertEx.SequenceEqual( + {"Preserve1Attribute"}, + m.GlobalNamespace.GetMember("Test1.VB$StateMachine_1_M2.$VB$Local_x").GetAttributes().Select(Function(a) a.ToString())) + End Sub + + Dim comp1 = CreateCompilation( + {source1, source2, CompilerLoweringPreserveAttributeDefinition}, + options:=TestOptions.DebugDll.WithMetadataImportOptions(MetadataImportOptions.All)) + CompileAndVerify(comp1, symbolValidator:=validate).VerifyDiagnostics() + End Sub + End Class End Namespace diff --git a/src/Compilers/VisualBasic/Test/Emit/CodeGen/CodeGenIterators.vb b/src/Compilers/VisualBasic/Test/Emit/CodeGen/CodeGenIterators.vb index 30a10a1236414..1d10bf41d4dae 100644 --- a/src/Compilers/VisualBasic/Test/Emit/CodeGen/CodeGenIterators.vb +++ b/src/Compilers/VisualBasic/Test/Emit/CodeGen/CodeGenIterators.vb @@ -1838,5 +1838,959 @@ BC35000: Requested operation is not available because the runtime library functi ) End Sub + + Public Sub StateAfterMoveNext_YieldReturn() + Dim source = + + +Imports System + +Module Program + Sub Main() + Dim enumerator = C.GetEnumerator() + + Console.Write(enumerator.MoveNext()) + Console.Write(enumerator.Current) + + enumerator.Dispose() + Console.Write("disposed ") + + Console.Write(enumerator.MoveNext()) + Console.Write(enumerator.Current) + End Sub +End Module + +Class C + Public Shared Iterator Function GetEnumerator() As System.Collections.Generic.IEnumerator(Of String) + Yield " one " + Yield " two " + End Function +End Class + + + + Dim verifier = CompileAndVerify(source, expectedOutput:="True one disposed False one") + verifier.VerifyIL("C.VB$StateMachine_1_GetEnumerator.Dispose()", " +{ + // Code size 9 (0x9) + .maxstack 2 + IL_0000: ldarg.0 + IL_0001: ldc.i4.s -2 + IL_0003: stfld ""C.VB$StateMachine_1_GetEnumerator.$State As Integer"" + IL_0008: ret +} +") + End Sub + + + Public Sub StateAfterMoveNext_YieldReturn_IEnumerable() + Dim source = + + +Imports System + +Module Program + Sub Main() + Dim enumerator = C.Produce().GetEnumerator() + + Console.Write(enumerator.MoveNext()) + Console.Write(enumerator.Current) + + enumerator.Dispose() + Console.Write("disposed ") + + Console.Write(enumerator.MoveNext()) + Console.Write(enumerator.Current) + End Sub +End Module + +Class C + Public Shared Iterator Function Produce() As System.Collections.Generic.IEnumerable(Of String) + Yield " one " + Yield " two " + End Function +End Class + + + + CompileAndVerify(source, expectedOutput:="True one disposed False one") + + ' Verify GetEnumerator + Dim source2 = + + +Imports System + +Module Program + Sub Main() + Dim enumerable = C.Produce() + Dim enumerator = enumerable.GetEnumerator() + + Console.Write(Object.ReferenceEquals(enumerable, enumerator)) + Console.Write(Not Object.ReferenceEquals(enumerable, enumerable.GetEnumerator())) + + Console.Write(enumerator.MoveNext()) + Console.Write(Not Object.ReferenceEquals(enumerable, enumerable.GetEnumerator())) + + enumerator.Dispose() + + Console.Write(Object.ReferenceEquals(enumerable, enumerable.GetEnumerator())) + + enumerator.Dispose() + enumerator.Dispose() + + Console.Write(Object.ReferenceEquals(enumerable, enumerable.GetEnumerator())) + End Sub +End Module + +Class C + Public Shared Iterator Function Produce() As System.Collections.Generic.IEnumerable(Of Integer) + Yield 42 + Yield 43 + End Function +End Class + + + + CompileAndVerify(source2, expectedOutput:="TrueTrueTrueTrueTrueTrue") + End Sub + + + Public Sub StateAfterMoveNext_DisposeTwice() + Dim source = + + +Imports System + +Module Program + Sub Main() + Dim enumerator = C.GetEnumerator() + + Console.Write(enumerator.MoveNext()) + Console.Write(enumerator.Current) + + enumerator.Dispose() + Console.Write("disposed ") + + enumerator.Dispose() + Console.Write("disposed2 ") + + Console.Write(enumerator.MoveNext()) + Console.Write(enumerator.Current) + End Sub +End Module + +Class C + Public Shared Iterator Function GetEnumerator() As System.Collections.Generic.IEnumerator(Of String) + Dim local As String = "" + Yield " one " + local.ToString() + End Function +End Class + + + + CompileAndVerify(source, expectedOutput:="True one disposed disposed2 False one") + End Sub + + + Public Sub StateAfterMoveNext_YieldBreak() + Dim source = + + +Imports System + +Module Program + Sub Main() + Dim enumerator = C.GetEnumerator(True) + + Console.Write(enumerator.MoveNext()) + Console.Write(enumerator.Current) + + Console.Write(enumerator.MoveNext()) + Console.Write(enumerator.Current) + + Console.Write(enumerator.MoveNext()) + Console.Write(enumerator.Current) + End Sub +End Module + +Class C + Public Shared Iterator Function GetEnumerator(b As Boolean) As System.Collections.Generic.IEnumerator(Of String) + Yield " one " + If b Then + Return + End If + Yield " two " + End Function +End Class + + + + CompileAndVerify(source, expectedOutput:="True one False one False one") + + ' Verify GetEnumerator + Dim source2 = + + +Imports System + +Module Program + Sub Main() + Dim enumerable = C.Produce(True) + Dim enumerator = enumerable.GetEnumerator() + + Console.Write(enumerator.MoveNext()) + Console.Write(Not Object.ReferenceEquals(enumerable, enumerable.GetEnumerator())) + + Console.Write(Not enumerator.MoveNext()) + Console.Write(Object.ReferenceEquals(enumerable, enumerable.GetEnumerator())) + End Sub +End Module + +Class C + Public Shared Iterator Function Produce(b As Boolean) As System.Collections.Generic.IEnumerable(Of Integer) + Yield 42 + If b Then + Return + End If + Yield 43 + End Function +End Class + + + + ' We're not setting the state to "after"/"finished" + ' Tracked by https://github.com/dotnet/roslyn/issues/76089 + CompileAndVerify(source2, expectedOutput:="TrueTrueTrueFalse") + End Sub + + + Public Sub StateAfterMoveNext_EndOfBody() + Dim source = + + +Imports System + +Module Program + Sub Main() + Dim enumerator = C.GetEnumerator(True) + + Console.Write(enumerator.MoveNext()) + Console.Write(enumerator.Current) + + Console.Write(enumerator.MoveNext()) + Console.Write(enumerator.Current) + + Console.Write(enumerator.MoveNext()) + Console.Write(enumerator.Current) + End Sub +End Module + +Class C + Public Shared Iterator Function GetEnumerator(b As Boolean) As System.Collections.Generic.IEnumerator(Of String) + Yield " one " + Console.Write("done ") + End Function +End Class + + + + CompileAndVerify(source, expectedOutput:="True one done False one False one") + + ' Verify GetEnumerator + Dim source2 = + + +Imports System + +Module Program + Sub Main() + Dim enumerable = C.Produce(True) + Dim enumerator = enumerable.GetEnumerator() + + Console.Write(enumerator.MoveNext()) + Console.Write(Not Object.ReferenceEquals(enumerable, enumerable.GetEnumerator())) + + Console.Write(Not enumerator.MoveNext()) + Console.Write(Object.ReferenceEquals(enumerable, enumerable.GetEnumerator())) + End Sub +End Module + +Class C + Public Shared Iterator Function Produce(b As Boolean) As System.Collections.Generic.IEnumerable(Of Integer) + Yield 42 + End Function +End Class + + + + ' We're not setting the state to "after"/"finished" + ' Tracked by https://github.com/dotnet/roslyn/issues/76089 + CompileAndVerify(source2, expectedOutput:="TrueTrueTrueFalse") + End Sub + + + Public Sub StateAfterMoveNext_ThrowException() + Dim source = + + +Imports System + +Module Program + Sub Main() + Dim enumerator = C.GetEnumerator(True) + + Console.Write(enumerator.MoveNext()) + Console.Write(enumerator.Current) + + Try + Console.Write(enumerator.MoveNext()) + Catch e As Exception + Console.Write(e.Message) + End Try + + Console.Write(enumerator.Current) + + Console.Write(enumerator.MoveNext()) + Console.Write(enumerator.Current) + End Sub +End Module + +Class C + Public Shared Iterator Function GetEnumerator(b As Boolean) As System.Collections.Generic.IEnumerator(Of String) + Yield " one " + Throw New Exception("exception") + End Function +End Class + + + + CompileAndVerify(source, expectedOutput:="True one exception one False one") + + ' Verify GetEnumerator + Dim source2 = + + +Imports System + +Module Program + Sub Main() + Dim enumerable = C.Produce() + Dim enumerator = enumerable.GetEnumerator() + + Console.Write(enumerator.MoveNext()) + Console.Write(Not Object.ReferenceEquals(enumerable, enumerable.GetEnumerator())) + + Try + enumerator.MoveNext() + Catch + Console.Write(Object.ReferenceEquals(enumerable, enumerable.GetEnumerator())) + End Try + End Sub +End Module + +Class C + Public Shared Iterator Function Produce() As System.Collections.Generic.IEnumerable(Of Integer) + Yield 42 + Throw New Exception("exception") + End Function +End Class + + + + ' We're not setting the state to "after"/"finished" + ' Tracked by https://github.com/dotnet/roslyn/issues/76089 + CompileAndVerify(source2, expectedOutput:="TrueTrueFalse") + End Sub + + + Public Sub StateAfterMoveNext_YieldReturn_InTryFinally() + Dim source = + + +Imports System + +Module Program + Sub Main() + Dim enumerator = C.GetEnumerator() + + Console.Write(enumerator.MoveNext()) + Console.Write(enumerator.Current) + + Console.Write("disposing ") + Try + enumerator.Dispose() + Catch e As Exception + Console.Write(e.Message) + End Try + Console.Write(" disposed ") + + Console.Write(enumerator.MoveNext()) + Console.Write(enumerator.Current) + End Sub +End Module + +Class C + Public Shared Iterator Function GetEnumerator() As System.Collections.Generic.IEnumerator(Of String) + Try + Yield " one " + Finally + Throw New Exception("exception") + End Try + End Function +End Class + + + + Dim verifier = CompileAndVerify(source, expectedOutput:="True one disposing exception disposed False one") + verifier.VerifyIL("C.VB$StateMachine_1_GetEnumerator.Dispose()", " +{ + // Code size 44 (0x2c) + .maxstack 2 + .locals init (Integer V_0) + IL_0000: ldarg.0 + IL_0001: ldfld ""C.VB$StateMachine_1_GetEnumerator.$State As Integer"" + IL_0006: stloc.0 + IL_0007: ldloc.0 + IL_0008: ldc.i4.1 + IL_0009: bne.un.s IL_0015 + IL_000b: ldarg.0 + IL_000c: ldc.i4.s -3 + IL_000e: stfld ""C.VB$StateMachine_1_GetEnumerator.$State As Integer"" + IL_0013: br.s IL_001c + IL_0015: ldarg.0 + IL_0016: ldc.i4.m1 + IL_0017: stfld ""C.VB$StateMachine_1_GetEnumerator.$State As Integer"" + IL_001c: ldarg.0 + IL_001d: call ""Function C.VB$StateMachine_1_GetEnumerator.MoveNext() As Boolean"" + IL_0022: pop + IL_0023: ldarg.0 + IL_0024: ldc.i4.s -2 + IL_0026: stfld ""C.VB$StateMachine_1_GetEnumerator.$State As Integer"" + IL_002b: ret +} +") + + ' Verify GetEnumerator + Dim source2 = + + +Imports System + +Module Program + Sub Main() + Dim enumerable = C.Produce() + Dim enumerator = enumerable.GetEnumerator() + + Console.Write(enumerator.MoveNext()) + Console.Write(Not Object.ReferenceEquals(enumerable, enumerable.GetEnumerator())) + + Try + enumerator.Dispose() + Catch + Console.Write(Object.ReferenceEquals(enumerable, enumerable.GetEnumerator())) + End Try + End Sub +End Module + +Class C + Public Shared Iterator Function Produce() As System.Collections.Generic.IEnumerable(Of Integer) + Try + Yield 42 + Finally + Throw New Exception("exception") + End Try + End Function +End Class + + + + ' We're not setting the state to "after"/"finished" + ' Tracked by https://github.com/dotnet/roslyn/issues/76089 + CompileAndVerify(source2, expectedOutput:="TrueTrueFalse") + End Sub + + + Public Sub StateAfterMoveNext_YieldBreak_InTryFinally() + Dim source = + + +Imports System + +Module Program + Sub Main() + Dim enumerator = C.GetEnumerator(True) + + Console.Write(enumerator.MoveNext()) + Console.Write(enumerator.Current) + + Console.Write(enumerator.MoveNext()) + Console.Write(enumerator.Current) + + Console.Write(enumerator.MoveNext()) + Console.Write(enumerator.Current) + End Sub +End Module + +Class C + Public Shared Iterator Function GetEnumerator(b As Boolean) As System.Collections.Generic.IEnumerator(Of String) + Yield " one " + Try + If b Then + Return + End If + Finally + Console.Write("finally ") + End Try + Yield " two " + End Function +End Class + + + + CompileAndVerify(source, expectedOutput:="True one finally False one False one") + + ' Verify GetEnumerator + Dim source2 = + + +Imports System +Imports System.Collections.Generic + +Module Program + Sub Main() + Dim enumerable = C.Produce(True) + Dim enumerator = enumerable.GetEnumerator() + + Console.Write(enumerator.MoveNext()) + Console.Write(Not Object.ReferenceEquals(enumerable, enumerable.GetEnumerator())) + + Console.Write(Not enumerator.MoveNext()) + Console.Write(Object.ReferenceEquals(enumerable, enumerable.GetEnumerator())) + End Sub +End Module + +Class C + Public Shared Iterator Function Produce(b As Boolean) As IEnumerable(Of Integer) + Yield 42 + Try + If b Then + Exit Function + End If + Finally + Console.Write(" finally ") + End Try + Yield 43 + End Function +End Class + + + + ' We're not setting the state to "after"/"finished" + ' Tracked by https://github.com/dotnet/roslyn/issues/76089 + CompileAndVerify(source2, expectedOutput:="TrueTrue finally TrueFalse") + End Sub + + + Public Sub StateAfterMoveNext_ThrowException_InTryFinally() + Dim source = + + +Imports System + +Module Program + Sub Main() + Dim enumerator = C.GetEnumerator(True) + + Console.Write(enumerator.MoveNext()) + Console.Write(enumerator.Current) + + Try + Console.Write(enumerator.MoveNext()) + Catch e As Exception + Console.Write(e.Message) + End Try + + Console.Write(enumerator.Current) + + Console.Write(enumerator.MoveNext()) + Console.Write(enumerator.Current) + + enumerator.Dispose() + + Console.Write(enumerator.MoveNext()) + Console.Write(enumerator.Current) + End Sub +End Module + +Class C + Public Shared Iterator Function GetEnumerator(b As Boolean) As System.Collections.Generic.IEnumerator(Of String) + Yield " one " + Try + Throw New Exception("exception") + Finally + Console.Write("finally ") + End Try + End Function +End Class + + + + CompileAndVerify(source, expectedOutput:="True one finally exception one False one False one") + + ' Verify GetEnumerator + Dim source2 = + + +Imports System +Imports System.Collections.Generic + +Module Program + Sub Main() + Dim enumerable = C.Produce() + Dim enumerator = enumerable.GetEnumerator() + + Console.Write(enumerator.MoveNext()) + + Try + enumerator.MoveNext() + Catch ex As Exception + Console.Write(Object.ReferenceEquals(enumerable, enumerable.GetEnumerator())) + End Try + + enumerator.Dispose() + Console.Write(Object.ReferenceEquals(enumerable, enumerable.GetEnumerator())) + End Sub +End Module + +Class C + Public Shared Iterator Function Produce() As IEnumerable(Of Integer) + Yield 42 + Try + Throw New Exception("exception") + Finally + Console.Write(" finally ") + End Try + End Function +End Class + + + + ' We're not setting the state to "after"/"finished" + ' Tracked by https://github.com/dotnet/roslyn/issues/76089 + CompileAndVerify(source2, expectedOutput:="True finally FalseTrue") + End Sub + + + Public Sub StateAfterMoveNext_ThrowException_InTryFinally_WithYieldInTry() + Dim source = + + +Imports System + +Module Program + Sub Main() + Dim enumerator = C.GetEnumerator(True) + + Console.Write(enumerator.MoveNext()) + Console.Write(enumerator.Current) + + Try + Console.Write(enumerator.MoveNext()) + Catch e As Exception + Console.Write(e.Message) + End Try + + Console.Write(enumerator.Current) + + Console.Write(enumerator.MoveNext()) + Console.Write(enumerator.Current) + End Sub +End Module + +Class C + Public Shared Iterator Function GetEnumerator(b As Boolean) As System.Collections.Generic.IEnumerator(Of String) + Try + Yield " one " + If b Then + Throw New Exception("exception") + End If + Finally + Console.Write("finally ") + End Try + End Function +End Class + + + + Dim verifier = CompileAndVerify(source, expectedOutput:="True one finally exception one False one") + verifier.VerifyIL("C.VB$StateMachine_1_GetEnumerator.Dispose()", " +{ + // Code size 44 (0x2c) + .maxstack 2 + .locals init (Integer V_0) + IL_0000: ldarg.0 + IL_0001: ldfld ""C.VB$StateMachine_1_GetEnumerator.$State As Integer"" + IL_0006: stloc.0 + IL_0007: ldloc.0 + IL_0008: ldc.i4.1 + IL_0009: bne.un.s IL_0015 + IL_000b: ldarg.0 + IL_000c: ldc.i4.s -3 + IL_000e: stfld ""C.VB$StateMachine_1_GetEnumerator.$State As Integer"" + IL_0013: br.s IL_001c + IL_0015: ldarg.0 + IL_0016: ldc.i4.m1 + IL_0017: stfld ""C.VB$StateMachine_1_GetEnumerator.$State As Integer"" + IL_001c: ldarg.0 + IL_001d: call ""Function C.VB$StateMachine_1_GetEnumerator.MoveNext() As Boolean"" + IL_0022: pop + IL_0023: ldarg.0 + IL_0024: ldc.i4.s -2 + IL_0026: stfld ""C.VB$StateMachine_1_GetEnumerator.$State As Integer"" + IL_002b: ret +} +") + + ' Verify GetEnumerator + Dim source2 = + + +Imports System +Imports System.Collections.Generic + +Module Program + Sub Main() + Dim enumerable = C.Produce() + Dim enumerator = enumerable.GetEnumerator() + + Console.Write(enumerator.MoveNext()) + + Try + enumerator.MoveNext() + Catch ex As Exception + Console.Write(Object.ReferenceEquals(enumerable, enumerable.GetEnumerator())) + End Try + End Sub +End Module + +Class C + Public Shared Iterator Function Produce() As IEnumerable(Of Integer) + Try + Yield 42 + Throw New Exception("exception") + Finally + Console.Write(" finally ") + End Try + End Function +End Class + + + + ' We're not setting the state to "after"/"finished" + ' Tracked by https://github.com/dotnet/roslyn/issues/76089 + CompileAndVerify(source2, expectedOutput:="True finally False") + End Sub + + + Public Sub StateAfterMoveNext_YieldReturn_AfterTryFinally() + Dim source = + + +Imports System +Imports System.Collections.Generic + +Module Program + Sub Main() + Dim enumerator = C.GetEnumerator(True) + + Console.Write(enumerator.MoveNext()) + Console.Write(enumerator.Current) + + Console.Write(enumerator.MoveNext()) + Console.Write(enumerator.Current) + + enumerator.Dispose() + + Console.Write(enumerator.MoveNext()) + Console.Write(enumerator.Current) + End Sub +End Module + +Class C + Public Shared Iterator Function GetEnumerator(b As Boolean) As IEnumerator(Of String) + Try + Yield " one " + Finally + Console.Write("finally ") + End Try + + Yield " two " + Console.Write("not executed after disposal") + End Function +End Class + + + Dim verifier = CompileAndVerify(source, expectedOutput:="True one finally True two False two") + verifier.VerifyIL("C.VB$StateMachine_1_GetEnumerator.MoveNext()", " +{ + // Code size 171 (0xab) + .maxstack 3 + .locals init (Boolean V_0, + Integer V_1) + IL_0000: ldarg.0 + IL_0001: ldfld ""C.VB$StateMachine_1_GetEnumerator.$State As Integer"" + IL_0006: stloc.1 + IL_0007: ldloc.1 + IL_0008: ldc.i4.s -3 + IL_000a: sub + IL_000b: switch ( + IL_0033, + IL_0028, + IL_0028, + IL_002a, + IL_0033, + IL_0094) + IL_0028: ldc.i4.0 + IL_0029: ret + IL_002a: ldarg.0 + IL_002b: ldc.i4.m1 + IL_002c: dup + IL_002d: stloc.1 + IL_002e: stfld ""C.VB$StateMachine_1_GetEnumerator.$State As Integer"" + IL_0033: nop + .try + { + IL_0034: ldloc.1 + IL_0035: ldc.i4.s -3 + IL_0037: beq.s IL_003f + IL_0039: ldloc.1 + IL_003a: ldc.i4.1 + IL_003b: beq.s IL_0064 + IL_003d: br.s IL_004c + IL_003f: ldarg.0 + IL_0040: ldc.i4.m1 + IL_0041: dup + IL_0042: stloc.1 + IL_0043: stfld ""C.VB$StateMachine_1_GetEnumerator.$State As Integer"" + IL_0048: ldc.i4.1 + IL_0049: stloc.0 + IL_004a: leave.s IL_00a9 + IL_004c: ldarg.0 + IL_004d: ldstr "" one "" + IL_0052: stfld ""C.VB$StateMachine_1_GetEnumerator.$Current As String"" + IL_0057: ldarg.0 + IL_0058: ldc.i4.1 + IL_0059: dup + IL_005a: stloc.1 + IL_005b: stfld ""C.VB$StateMachine_1_GetEnumerator.$State As Integer"" + IL_0060: ldc.i4.1 + IL_0061: stloc.0 + IL_0062: leave.s IL_00a9 + IL_0064: ldarg.0 + IL_0065: ldc.i4.m1 + IL_0066: dup + IL_0067: stloc.1 + IL_0068: stfld ""C.VB$StateMachine_1_GetEnumerator.$State As Integer"" + IL_006d: leave.s IL_007e + } + finally + { + IL_006f: ldloc.1 + IL_0070: ldc.i4.0 + IL_0071: bge.s IL_007d + IL_0073: ldstr ""finally "" + IL_0078: call ""Sub System.Console.Write(String)"" + IL_007d: endfinally + } + IL_007e: ldarg.0 + IL_007f: ldstr "" two "" + IL_0084: stfld ""C.VB$StateMachine_1_GetEnumerator.$Current As String"" + IL_0089: ldarg.0 + IL_008a: ldc.i4.2 + IL_008b: dup + IL_008c: stloc.1 + IL_008d: stfld ""C.VB$StateMachine_1_GetEnumerator.$State As Integer"" + IL_0092: ldc.i4.1 + IL_0093: ret + IL_0094: ldarg.0 + IL_0095: ldc.i4.m1 + IL_0096: dup + IL_0097: stloc.1 + IL_0098: stfld ""C.VB$StateMachine_1_GetEnumerator.$State As Integer"" + IL_009d: ldstr ""not executed after disposal"" + IL_00a2: call ""Sub System.Console.Write(String)"" + IL_00a7: ldc.i4.0 + IL_00a8: ret + IL_00a9: ldloc.0 + IL_00aa: ret +} +") + verifier.VerifyIL("C.VB$StateMachine_1_GetEnumerator.Dispose()", " +{ + // Code size 44 (0x2c) + .maxstack 2 + .locals init (Integer V_0) + IL_0000: ldarg.0 + IL_0001: ldfld ""C.VB$StateMachine_1_GetEnumerator.$State As Integer"" + IL_0006: stloc.0 + IL_0007: ldloc.0 + IL_0008: ldc.i4.1 + IL_0009: bne.un.s IL_0015 + IL_000b: ldarg.0 + IL_000c: ldc.i4.s -3 + IL_000e: stfld ""C.VB$StateMachine_1_GetEnumerator.$State As Integer"" + IL_0013: br.s IL_001c + IL_0015: ldarg.0 + IL_0016: ldc.i4.m1 + IL_0017: stfld ""C.VB$StateMachine_1_GetEnumerator.$State As Integer"" + IL_001c: ldarg.0 + IL_001d: call ""Function C.VB$StateMachine_1_GetEnumerator.MoveNext() As Boolean"" + IL_0022: pop + IL_0023: ldarg.0 + IL_0024: ldc.i4.s -2 + IL_0026: stfld ""C.VB$StateMachine_1_GetEnumerator.$State As Integer"" + IL_002b: ret +} +") + + ' Verify GetEnumerator + Dim source2 = + + +Imports System +Imports System.Collections.Generic + +Module Program + Sub Main() + Dim enumerable = C.Produce() + Dim enumerator = enumerable.GetEnumerator() + + Console.Write(enumerator.MoveNext()) + Console.Write(enumerator.MoveNext()) + + enumerator.Dispose() + Console.Write(Object.ReferenceEquals(enumerable, enumerable.GetEnumerator())) + End Sub +End Module + +Class C + Public Shared Iterator Function Produce() As IEnumerable(Of Integer) + Try + Yield 42 + Finally + Console.Write(" finally ") + End Try + + Yield 43 + Console.Write("not executed after disposal") + End Function +End Class + + + + CompileAndVerify(source2, expectedOutput:="True finally TrueTrue") + End Sub End Class End Namespace diff --git a/src/Compilers/VisualBasic/Test/Emit/Emit/EditAndContinue/EditAndContinueStateMachineTests.vb b/src/Compilers/VisualBasic/Test/Emit/Emit/EditAndContinue/EditAndContinueStateMachineTests.vb index 4f734333f79fe..805965edc6ba0 100644 --- a/src/Compilers/VisualBasic/Test/Emit/Emit/EditAndContinue/EditAndContinueStateMachineTests.vb +++ b/src/Compilers/VisualBasic/Test/Emit/Emit/EditAndContinue/EditAndContinueStateMachineTests.vb @@ -13,6 +13,7 @@ Imports Xunit.Abstractions Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests + Public Class EditAndContinueStateMachineTests Inherits EditAndContinueTestBase @@ -253,9 +254,12 @@ End Class IL_0018: ret } { - // Code size 1 (0x1) + // Code size 9 (0x9) .maxstack 8 - IL_0000: ret + IL_0000: ldarg.0 + IL_0001: ldc.i4.s -2 + IL_0003: stfld 0x04000005 + IL_0008: ret } { // Code size 63 (0x3f) @@ -4993,7 +4997,7 @@ End Try v0.VerifyIL("C.VB$StateMachine_9_F.Dispose", " { - // Code size 38 (0x26) + // Code size 46 (0x2e) .maxstack 2 .locals init (Integer V_0) IL_0000: ldarg.0 @@ -5013,11 +5017,14 @@ End Try IL_001e: ldarg.0 IL_001f: call ""Function C.VB$StateMachine_9_F.MoveNext() As Boolean"" IL_0024: pop - IL_0025: ret + IL_0025: ldarg.0 + IL_0026: ldc.i4.s -2 + IL_0028: stfld ""C.VB$StateMachine_9_F.$State As Integer"" + IL_002d: ret }") diff1.VerifyIL("C.VB$StateMachine_9_F.Dispose", " { - // Code size 78 (0x4e) + // Code size 86 (0x56) .maxstack 2 .locals init (Integer V_0) IL_0000: ldarg.0 @@ -5050,7 +5057,10 @@ End Try IL_0046: ldarg.0 IL_0047: call ""Function C.VB$StateMachine_9_F.MoveNext() As Boolean"" IL_004c: pop - IL_004d: ret + IL_004d: ldarg.0 + IL_004e: ldc.i4.s -2 + IL_0050: stfld ""C.VB$StateMachine_9_F.$State As Integer"" + IL_0055: ret }") v0.VerifyIL("C.VB$StateMachine_9_F.MoveNext", " { @@ -5496,8 +5506,8 @@ End Using "C: {VB$StateMachine_6_F}") v0.VerifyIL("C.VB$StateMachine_6_F.Dispose", " - { - // Code size 38 (0x26) +{ + // Code size 46 (0x2e) .maxstack 2 .locals init (Integer V_0) IL_0000: ldarg.0 @@ -5507,24 +5517,24 @@ End Using IL_0008: ldc.i4.1 IL_0009: beq.s IL_000d IL_000b: br.s IL_0017 - IL_000d: ldarg.0 IL_000e: ldc.i4.s -3 IL_0010: stfld ""C.VB$StateMachine_6_F.$State As Integer"" IL_0015: br.s IL_001e - IL_0017: ldarg.0 IL_0018: ldc.i4.m1 IL_0019: stfld ""C.VB$StateMachine_6_F.$State As Integer"" - IL_001e: ldarg.0 IL_001f: call ""Function C.VB$StateMachine_6_F.MoveNext() As Boolean"" IL_0024: pop - IL_0025: ret + IL_0025: ldarg.0 + IL_0026: ldc.i4.s -2 + IL_0028: stfld ""C.VB$StateMachine_6_F.$State As Integer"" + IL_002d: ret }") diff1.VerifyIL("C.VB$StateMachine_6_F.Dispose", " { - // Code size 40 (0x28) + // Code size 48 (0x30) .maxstack 2 .locals init (Integer V_0) IL_0000: ldarg.0 @@ -5536,20 +5546,20 @@ End Using IL_000a: ldc.i4.1 IL_000b: ble.un.s IL_000f IL_000d: br.s IL_0019 - IL_000f: ldarg.0 IL_0010: ldc.i4.s -3 IL_0012: stfld ""C.VB$StateMachine_6_F.$State As Integer"" IL_0017: br.s IL_0020 - IL_0019: ldarg.0 IL_001a: ldc.i4.m1 IL_001b: stfld ""C.VB$StateMachine_6_F.$State As Integer"" - IL_0020: ldarg.0 IL_0021: call ""Function C.VB$StateMachine_6_F.MoveNext() As Boolean"" IL_0026: pop - IL_0027: ret + IL_0027: ldarg.0 + IL_0028: ldc.i4.s -2 + IL_002a: stfld ""C.VB$StateMachine_6_F.$State As Integer"" + IL_002f: ret }") v0.VerifyIL("C.VB$StateMachine_6_F.MoveNext", " { diff --git a/src/Compilers/VisualBasic/Test/Semantic/FlowAnalysis/RegionAnalysisTests.vb b/src/Compilers/VisualBasic/Test/Semantic/FlowAnalysis/RegionAnalysisTests.vb index 7525a6f8f50b8..00673802748a4 100644 --- a/src/Compilers/VisualBasic/Test/Semantic/FlowAnalysis/RegionAnalysisTests.vb +++ b/src/Compilers/VisualBasic/Test/Semantic/FlowAnalysis/RegionAnalysisTests.vb @@ -9994,6 +9994,38 @@ End Module capturedOutside) End Sub + + + Public Sub NestedBinaryOperator() + Dim compilation = CreateCompilationWithMscorlib40AndVBRuntime( + + +Module Program + Sub M(i As Integer, j As Integer, k As Integer, l As Integer) + Dim x = i + j + k + l + End Sub +End Module + + ) + + Dim tree = compilation.SyntaxTrees.First() + Dim model = compilation.GetSemanticModel(tree) + Dim nodes = tree.GetRoot().DescendantNodes().OfType(Of BinaryExpressionSyntax)().ToArray() + Assert.Equal(3, nodes.Length) + + Assert.Equal("i + j + k + l", nodes(0).ToString()) + Dim dataFlowResults = model.AnalyzeDataFlow(nodes(0)) + Assert.Equal("i, j, k, l", GetSymbolNamesJoined(dataFlowResults.ReadInside)) + + Assert.Equal("i + j + k", nodes(1).ToString()) + dataFlowResults = model.AnalyzeDataFlow(nodes(1)) + Assert.Equal("i, j, k", GetSymbolNamesJoined(dataFlowResults.ReadInside)) + + Assert.Equal("i + j", nodes(2).ToString()) + dataFlowResults = model.AnalyzeDataFlow(nodes(2)) + Assert.Equal("i, j", GetSymbolNamesJoined(dataFlowResults.ReadInside)) + End Sub + #End Region End Class diff --git a/src/Compilers/VisualBasic/Test/Semantic/Semantics/IteratorTests.vb b/src/Compilers/VisualBasic/Test/Semantic/Semantics/IteratorTests.vb index 1a2785c1851ff..9eb87de985e30 100644 --- a/src/Compilers/VisualBasic/Test/Semantic/Semantics/IteratorTests.vb +++ b/src/Compilers/VisualBasic/Test/Semantic/Semantics/IteratorTests.vb @@ -1023,6 +1023,55 @@ End Class CompileAndVerify(compilation, expectedOutput:="123") End Sub + + Public Sub CompilerLoweringPreserveAttribute_01() + Dim source1 = " +Imports System +Imports System.Runtime.CompilerServices + + + +Public Class Preserve1Attribute + Inherits Attribute +End Class + + + +Public Class Preserve2Attribute + Inherits Attribute +End Class + + +Public Class Preserve3Attribute + Inherits Attribute +End Class +" + Dim source2 = " +Imports System.Collections.Generic + +Class Test1 + Iterator Function M2( x As Integer) As IEnumerable(Of Integer) + Yield x + End Function +End Class +" + + Dim validate = Sub(m As ModuleSymbol) + AssertEx.SequenceEqual( + {"Preserve1Attribute"}, + m.GlobalNamespace.GetMember("Test1.VB$StateMachine_1_M2.$VB$Local_x").GetAttributes().Select(Function(a) a.ToString())) + + AssertEx.SequenceEqual( + {"Preserve1Attribute"}, + m.GlobalNamespace.GetMember("Test1.VB$StateMachine_1_M2.$P_x").GetAttributes().Select(Function(a) a.ToString())) + End Sub + + Dim comp1 = CreateCompilation( + {source1, source2, CompilerLoweringPreserveAttributeDefinition}, + options:=TestOptions.DebugDll.WithMetadataImportOptions(MetadataImportOptions.All)) + CompileAndVerify(comp1, symbolValidator:=validate).VerifyDiagnostics() + End Sub + End Class End Namespace diff --git a/src/Compilers/VisualBasic/Test/Semantic/Semantics/LambdaTests.vb b/src/Compilers/VisualBasic/Test/Semantic/Semantics/LambdaTests.vb index 2266638c2b490..be410c2a6445f 100644 --- a/src/Compilers/VisualBasic/Test/Semantic/Semantics/LambdaTests.vb +++ b/src/Compilers/VisualBasic/Test/Semantic/Semantics/LambdaTests.vb @@ -4,6 +4,7 @@ Imports Microsoft.CodeAnalysis Imports Microsoft.CodeAnalysis.VisualBasic +Imports Microsoft.CodeAnalysis.VisualBasic.Symbols Imports Roslyn.Test.Utilities Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests.Semantics @@ -2447,5 +2448,48 @@ BC30661: Field or property 'Name' is not found. ) End Sub + + Public Sub CompilerLoweringPreserveAttribute_01() + Dim source1 = " +Imports System +Imports System.Runtime.CompilerServices + + + +Public Class Preserve1Attribute + Inherits Attribute +End Class + + + +Public Class Preserve2Attribute + Inherits Attribute +End Class + + +Public Class Preserve3Attribute + Inherits Attribute +End Class +" + Dim source2 = " +Class Test1 + Function M2( x As Integer) As System.Func(Of Integer) + Return Function() x + End Function +End Class +" + + Dim validate = Sub(m As ModuleSymbol) + AssertEx.SequenceEqual( + {"Preserve1Attribute"}, + m.GlobalNamespace.GetMember("Test1._Closure$__1-0.$VB$Local_x").GetAttributes().Select(Function(a) a.ToString())) + End Sub + + Dim comp1 = CreateCompilation( + {source1, source2, CompilerLoweringPreserveAttributeDefinition}, + options:=TestOptions.DebugDll.WithMetadataImportOptions(MetadataImportOptions.All)) + CompileAndVerify(comp1, symbolValidator:=validate).VerifyDiagnostics() + End Sub + End Class End Namespace diff --git a/src/Compilers/VisualBasic/Test/Semantic/Semantics/MethodCalls.vb b/src/Compilers/VisualBasic/Test/Semantic/Semantics/MethodCalls.vb index e8fb53f6628ab..e728fb5b8dc0d 100644 --- a/src/Compilers/VisualBasic/Test/Semantic/Semantics/MethodCalls.vb +++ b/src/Compilers/VisualBasic/Test/Semantic/Semantics/MethodCalls.vb @@ -4334,18 +4334,25 @@ Namespace GenMethod4140 Overridable Function fun1(Of T)(ByRef t1 As T) As Object Return Nothing End Function + Overridable Function fun2(ByRef t1 As UShort) As Object + Return Nothing + End Function End Class Class Derived Inherits Base Overrides Function fun1(Of T)(ByRef t2 As T) As Object Return Nothing End Function + Overrides Function fun2(ByRef t2 As UShort) As Object + Return Nothing + End Function End Class Sub GenMethod4140() Dim c3 As New Derived c3.fun1(t1:=3US) + c3.fun2(t1:=3US) End Sub End Module @@ -4374,6 +4381,12 @@ BC30455: Argument not specified for parameter 't2' of 'Public Overrides Function BC30272: 't1' is not a parameter of 'Public Overrides Function fun1(Of T)(ByRef t2 As T) As Object'. c3.fun1(t1:=3US) ~~ +BC30455: Argument not specified for parameter 't2' of 'Public Overrides Function fun2(ByRef t2 As UShort) As Object'. + c3.fun2(t1:=3US) + ~~~~ +BC30272: 't1' is not a parameter of 'Public Overrides Function fun2(ByRef t2 As UShort) As Object'. + c3.fun2(t1:=3US) + ~~ ) End Sub diff --git a/src/Compilers/VisualBasic/Test/Semantic/Semantics/OverloadResolutionPriorityTests.vb b/src/Compilers/VisualBasic/Test/Semantic/Semantics/OverloadResolutionPriorityTests.vb new file mode 100644 index 0000000000000..c254da5b56930 --- /dev/null +++ b/src/Compilers/VisualBasic/Test/Semantic/Semantics/OverloadResolutionPriorityTests.vb @@ -0,0 +1,4627 @@ +' Licensed to the .NET Foundation under one or more agreements. +' The .NET Foundation licenses this file to you under the MIT license. +' See the LICENSE file in the project root for more information. + +Imports Microsoft.CodeAnalysis.CSharp +Imports Microsoft.CodeAnalysis.Test.Utilities +Imports Microsoft.CodeAnalysis.VisualBasic.Symbols +Imports Microsoft.CodeAnalysis.VisualBasic.Symbols.Retargeting +Imports Roslyn.Test.Utilities + +Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests.Semantics + + Public Class OverloadResolutionPriorityTests + Inherits BasicTestBase + + Private Const OverloadResolutionPriorityAttributeDefinitionCS As String = " +namespace System.Runtime.CompilerServices +{ + [AttributeUsage(AttributeTargets.Method | AttributeTargets.Constructor | AttributeTargets.Property, AllowMultiple = false, Inherited = false)] + public sealed class OverloadResolutionPriorityAttribute(int priority) : Attribute + { + public int Priority => priority; + } +} +" + + Private Const OverloadResolutionPriorityAttributeDefinitionVB As String = " +namespace System.Runtime.CompilerServices + + public class OverloadResolutionPriorityAttribute + Inherits Attribute + + Public Sub New(priority As Integer) + Me.Priority = priority + End Sub + + public Readonly Property Priority As Integer + End Class +End Namespace +" + + Private Const OverloadResolutionPriorityAttributeILDefinition As String = " +.class public auto ansi sealed beforefieldinit System.Runtime.CompilerServices.OverloadResolutionPriorityAttribute + extends [mscorlib]System.Attribute +{ + .custom instance void [mscorlib]System.AttributeUsageAttribute::.ctor(valuetype [mscorlib]System.AttributeTargets) = ( + 01 00 e0 00 00 00 02 00 54 02 0d 41 6c 6c 6f 77 + 4d 75 6c 74 69 70 6c 65 00 54 02 09 49 6e 68 65 + 72 69 74 65 64 00 + ) + .field private int32 'P' + .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( + 01 00 00 00 + ) + .method public hidebysig specialname rtspecialname + instance void .ctor ( + int32 priority + ) cil managed + { + ldarg.0 + ldarg.1 + stfld int32 System.Runtime.CompilerServices.OverloadResolutionPriorityAttribute::'P' + ldarg.0 + call instance void [mscorlib]System.Attribute::.ctor() + ret + } + .method public hidebysig specialname + instance int32 get_Priority () cil managed + { + ldarg.0 + ldfld int32 System.Runtime.CompilerServices.OverloadResolutionPriorityAttribute::'P' + ret + } + .property instance int32 Priority() + { + .get instance int32 System.Runtime.CompilerServices.OverloadResolutionPriorityAttribute::get_Priority() + } +} +" + + + Public Sub IncreasedPriorityWins_01_CS(i1First As Boolean) + + Dim i1Source = " +[OverloadResolutionPriority(1)] +public static void M(I1 x) => System.Console.WriteLine(1); +" + + Dim i2Source = " +public static void M(I2 x) => throw null; +" + + Dim reference = CreateCSharpCompilation(" +using System.Runtime.CompilerServices; + +public interface I1 {} +public interface I2 {} +public interface I3 : I1, I2 {} + +public class C +{" + + If(i1First, i1Source, i2Source) + + If(i1First, i2Source, i1Source) + " +} +" + OverloadResolutionPriorityAttributeDefinitionCS, parseOptions:=New CSharpParseOptions(CSharp.LanguageVersion.Latest)).EmitToImageReference() + + Dim source = " +public class Program + Shared Sub Main + Dim i3 As I3 = Nothing + C.M(i3) + End Sub +End Class +" + + Dim compilation = CreateCompilation(source, references:={reference}, options:=TestOptions.DebugExe) + + Dim c = compilation.GetTypeByMetadataName("C") + Dim ms = c.GetMembers("M").Cast(Of MethodSymbol)() + For Each m In ms + Assert.Equal(If(m.Parameters(0).Type.Name = "I1", 1, 0), m.OverloadResolutionPriority) + Next + + CompileAndVerify(compilation, expectedOutput:="1").VerifyDiagnostics() + End Sub + + + Public Sub IncreasedPriorityWins_01(i1First As Boolean) + + Dim i1Source = " + +public Shared Sub M(x As I1) + System.Console.WriteLine(1) +End Sub +" + + Dim i2Source = " +public Shared Sub M(x As I2) + throw DirectCast(Nothing, System.Exception) +End Sub +" + + Dim reference = " +Imports System.Runtime.CompilerServices + +public interface I1 +End Interface +public interface I2 +End Interface +public interface I3 + Inherits I1, I2 +End Interface + +public class C" + + If(i1First, i1Source, i2Source) + + If(i1First, i2Source, i1Source) + " +End Class +" + + Dim source = " +public class Program + Shared Sub Main + Dim i3 As I3 = Nothing + C.M(i3) + End Sub +End Class +" + + Dim comp1 = CreateCompilation({source, reference, OverloadResolutionPriorityAttributeDefinitionVB}, options:=TestOptions.DebugExe) + + Dim validate = Sub([module] As ModuleSymbol) + Dim c = [module].ContainingAssembly.GetTypeByMetadataName("C") + Dim ms = c.GetMembers("M").Cast(Of MethodSymbol)() + For Each m In ms + Assert.Equal(If(m.Parameters(0).Type.Name = "I1", 1, 0), m.OverloadResolutionPriority) + Next + End Sub + + CompileAndVerify(comp1, expectedOutput:="1", sourceSymbolValidator:=validate, symbolValidator:=validate).VerifyDiagnostics() + + Dim compilationReference As CompilationReference = comp1.ToMetadataReference() + Dim comp2 = CreateCompilation(source, references:={compilationReference}, options:=TestOptions.DebugExe) + CompileAndVerify(comp2, expectedOutput:="1").VerifyDiagnostics() + + Dim metadataReference As MetadataReference = comp1.EmitToImageReference() + Dim comp3 = CreateCompilation(source, references:={metadataReference}, options:=TestOptions.DebugExe) + CompileAndVerify(comp3, expectedOutput:="1").VerifyDiagnostics() + + comp1 = CreateCompilation({source, reference, OverloadResolutionPriorityAttributeDefinitionVB}, options:=TestOptions.DebugExe, parseOptions:=TestOptions.Regular17_13) + CompileAndVerify(comp1, expectedOutput:="1", sourceSymbolValidator:=validate, symbolValidator:=validate).VerifyDiagnostics() + + comp1 = CreateCompilation({source, reference, OverloadResolutionPriorityAttributeDefinitionVB}, options:=TestOptions.DebugExe, parseOptions:=TestOptions.Regular16_9) + comp1.AssertTheseDiagnostics(If(i1First, + + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +]]>, + + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +]]>)) + + comp2 = CreateCompilation(source, references:={compilationReference}, options:=TestOptions.DebugExe, parseOptions:=TestOptions.Regular16_9) + Dim expected = If(i1First, + +BC30521: Overload resolution failed because no accessible 'M' is most specific for these arguments: + 'Public Shared Sub M(x As I1)': Not most specific. + 'Public Shared Sub M(x As I2)': Not most specific. + C.M(i3) + ~ +, + +BC30521: Overload resolution failed because no accessible 'M' is most specific for these arguments: + 'Public Shared Sub M(x As I2)': Not most specific. + 'Public Shared Sub M(x As I1)': Not most specific. + C.M(i3) + ~ +) + + comp2.AssertTheseDiagnostics(expected) + + comp3 = CreateCompilation(source, references:={metadataReference}, options:=TestOptions.DebugExe, parseOptions:=TestOptions.Regular16_9) + comp3.AssertTheseDiagnostics(expected) + End Sub + + + Public Sub Accessibility_01(i1First As Boolean) + + Dim i1Source = " + +protected Shared Sub M(x As I1) + System.Console.WriteLine(1) +End Sub +" + + Dim i2Source = " +public Shared Sub M(x As I2) + System.Console.WriteLine(2) +End Sub +" + + Dim reference = " +Imports System.Runtime.CompilerServices + +public interface I1 +End Interface +public interface I2 +End Interface +public interface I3 + Inherits I1, I2 +End Interface + +public class C" + + If(i1First, i1Source, i2Source) + + If(i1First, i2Source, i1Source) + " +End Class +" + + Dim source = " +public class Program + Shared Sub Main + Dim i3 As I3 = Nothing + C.M(i3) + End Sub +End Class +" + + Dim comp1 = CreateCompilation({source, reference, OverloadResolutionPriorityAttributeDefinitionVB}, options:=TestOptions.DebugExe) + + CompileAndVerify(comp1, expectedOutput:="2").VerifyDiagnostics() + + Dim comp2 = CreateCompilation(source, references:={comp1.ToMetadataReference()}, options:=TestOptions.DebugExe) + CompileAndVerify(comp2, expectedOutput:="2").VerifyDiagnostics() + + Dim comp3 = CreateCompilation(source, references:={comp1.EmitToImageReference()}, options:=TestOptions.DebugExe) + CompileAndVerify(comp3, expectedOutput:="2").VerifyDiagnostics() + End Sub + + + Public Sub EarlyFilteringByParamArray() + + Dim source = " +Imports System + +Module Program + Sub Main() + Dim t As new Test1 + t.M1(1) + t.M2(1) + End Sub +End Module + +Class Test1 + Sub M1(s As Integer) + Console.Write(1) + End Sub + + + Sub M1(ParamArray s As Integer()) + Console.Write(2) + End Sub + + Sub M2(s As Integer) + Console.Write(3) + End Sub + + Sub M2(ParamArray s As Integer()) + Console.Write(4) + End Sub +End Class +" + Dim compilation = CompilationUtils.CreateCompilation({source, OverloadResolutionPriorityAttributeDefinitionVB}, options:=TestOptions.DebugExe) + + CompileAndVerify(compilation, expectedOutput:="23") + End Sub + + + Public Sub EarlyFilteringOnExtensionMethodTargetTypeGenericity() + + Dim source = " +Module Program + Sub Main() + Dim t As new Integer?(1) + t.M1() + t.M2() + End Sub +End Module +" + Dim reference = " +Imports System +Imports System.Runtime.CompilerServices + +Public Module Test1 + + Sub M1(s As Integer?) + Console.Write(1) + End Sub + + + + Sub M1(Of T As Structure)(s As T?) + Console.Write(2) + End Sub + + + Sub M2(s As Integer?) + Console.Write(3) + End Sub + + + Sub M2(Of T As Structure)(s As T?) + Console.Write(4) + End Sub +End Module +" + Dim compilation = CompilationUtils.CreateCompilation({source, reference, OverloadResolutionPriorityAttributeDefinitionVB}, options:=TestOptions.DebugExe) + CompileAndVerify(compilation, expectedOutput:="23") + + compilation = CompilationUtils.CreateCompilation({source, reference, OverloadResolutionPriorityAttributeDefinitionVB}, options:=TestOptions.DebugExe, parseOptions:=TestOptions.Regular17_13) + CompileAndVerify(compilation, expectedOutput:="23") + + compilation = CompilationUtils.CreateCompilation({source, reference, OverloadResolutionPriorityAttributeDefinitionVB}, options:=TestOptions.DebugExe, parseOptions:=TestOptions.Regular16_9) + compilation.AssertTheseDiagnostics( + + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +]]>) + + Dim ref = CompilationUtils.CreateCompilation({reference, OverloadResolutionPriorityAttributeDefinitionVB}, options:=TestOptions.DebugDll) + + compilation = CompilationUtils.CreateCompilation(source, references:={ref.ToMetadataReference()}, options:=TestOptions.DebugExe, parseOptions:=TestOptions.Regular16_9) + CompileAndVerify(compilation, expectedOutput:="13") + + compilation = CompilationUtils.CreateCompilation(source, references:={ref.EmitToImageReference()}, options:=TestOptions.DebugExe, parseOptions:=TestOptions.Regular16_9) + CompileAndVerify(compilation, expectedOutput:="13") + End Sub + + + Public Sub EarlyFilteringOnReceiverType_01() + + Dim source = " +Imports System +Imports System.Runtime.CompilerServices + +Module Program + Sub Main() + Dim t = 1.ToString() + t.M1() + t.M2() + End Sub +End Module + +Module Test1 + + Sub M1(s As String) + Console.Write(1) + End Sub + + + + Sub M1(s As Object) + Console.Write(2) + End Sub + + + Sub M2(s As String) + Console.Write(3) + End Sub + + + Sub M2(s As Object) + Console.Write(4) + End Sub +End Module +" + Dim compilation = CompilationUtils.CreateCompilation({source, OverloadResolutionPriorityAttributeDefinitionVB}, options:=TestOptions.DebugExe) + + CompileAndVerify(compilation, expectedOutput:="23") + End Sub + + + Public Sub EarlyFilteringOnReceiverType_02() + + Dim source = " +Imports System + +Module Program + Sub Main() + Dim t As new Test2 + t.M1(1.ToString()) + t.M2(1.ToString()) + End Sub +End Module + +Class Test1 + overridable Sub M1(s As String) + Console.Write(1) + End Sub + + + Sub M1(s As Object) + Console.Write(2) + End Sub + + overridable Sub M2(s As String) + Console.Write(4) + End Sub + + Sub M2(s As Object) + Console.Write(5) + End Sub +End Class + +Class Test2 + Inherits Test1 + + overrides Sub M1(s As String) + Console.Write(3) + End Sub + + overrides Sub M2(s As String) + Console.Write(6) + End Sub +End Class +" + Dim compilation = CompilationUtils.CreateCompilation({source, OverloadResolutionPriorityAttributeDefinitionVB}, options:=TestOptions.DebugExe) + + CompileAndVerify(compilation, expectedOutput:="26") + End Sub + + + Public Sub EarlyFiltering_OnReceiverType_03() + + Dim source = " +Imports System + +Module Program + Sub Main() + Dim t As new Test2 + t.M1(1.ToString()) + t.M2(1.ToString()) + End Sub +End Module + +Class Test1 + overridable Sub M1(s As String) + Console.Write(1) + End Sub + + + Sub M1(s As String, Optional x as Integer = 0) + Console.Write(2) + End Sub + + overridable Sub M2(s As String) + Console.Write(4) + End Sub + + Sub M2(s As String, Optional x as Integer = 0) + Console.Write(5) + End Sub +End Class + +Class Test2 + Inherits Test1 + + overrides Sub M1(s As String) + Console.Write(3) + End Sub + + overrides Sub M2(s As String) + Console.Write(6) + End Sub +End Class +" + Dim compilation = CompilationUtils.CreateCompilation({source, OverloadResolutionPriorityAttributeDefinitionVB}, options:=TestOptions.DebugExe) + + CompileAndVerify(compilation, expectedOutput:="26") + End Sub + + + Public Sub TestResolutionBasedOnInferenceKind2() + Dim compilationDef = " +Option Strict Off + +Module Module1 + + Sub Main() + Dim val As Integer = 0 + + M1(1, Function(x As Integer) As Integer + Return 2 + End Function, 1, val) + End Sub + + + Sub M1(Of T, U)(x As T, y As System.Func(Of Integer, Integer), z As U, ParamArray v() As Long) + System.Console.Write(1) + End Sub + + + Sub M1(Of T)(x As Integer, y As System.Func(Of Integer, T), z As Integer, v As Integer) + System.Console.Write(2) + End Sub + + + Sub M1(Of T, U)(x As T, y As System.Func(Of Integer, T), z As U, v As Long) + System.Console.Write(3) + End Sub + +End Module +" + Dim compilation = CreateCompilation({compilationDef, OverloadResolutionPriorityAttributeDefinitionVB}, options:=TestOptions.ReleaseExe) + + CompileAndVerify(compilation, expectedOutput:="2") + End Sub + + + Public Sub TestResolutionBasedOnInferenceKind4() + Dim compilationDef = " +Option Strict Off + +Module Module1 + + Sub Main() + Dim val As Integer = 0 + + M1(1, Function(x As Integer) As Integer + Return 2 + End Function, 1, v:=val) + M1(1, Function(x As Integer) As Integer + Return 2 + End Function, 1, val) + End Sub + + + Sub M1(Of T, U)(x As T, y As System.Func(Of Integer, Integer), z As U, v As Long, ParamArray vv() As Long) + System.Console.Write(1) + End Sub + + + Sub M1(Of T)(x As Integer, y As System.Func(Of Integer, T), z As Integer, v As Integer) + System.Console.Write(2) + End Sub + + + Sub M1(Of T, U)(x As T, y As System.Func(Of Integer, T), z As U, v As Long) + System.Console.Write(3) + End Sub +End Module +" + Dim compilation = CreateCompilation({compilationDef, OverloadResolutionPriorityAttributeDefinitionVB}, options:=TestOptions.ReleaseExe) + + CompileAndVerify(compilation, expectedOutput:="22") + End Sub + + + Public Sub NarrowingConversions_01() + Dim compilationDef = " +Option Strict Off + +Module Module1 + + Sub Main() + M1(New C1()) + M1(DirectCast(New C2(), C0)) + End Sub + + + Sub M1(x As I1) + System.Console.Write(1) + End Sub + + Sub M1(x As I2) + System.Console.Write(2) + End Sub +End Module + +Interface I1 +End Interface + +Interface I2 +End Interface + +Class C0 +End Class + +Class C1 + Inherits C0 + Implements I1, I2 +End Class + +Class C2 + Inherits C0 + Implements I2 +End Class +" + Dim compilation = CreateCompilation({compilationDef, OverloadResolutionPriorityAttributeDefinitionVB}, options:=TestOptions.ReleaseExe) + + ' If the priority filtering for 'M1(DirectCast(New C2(), C0))' was applied - System.InvalidCastException: Unable to cast object of type 'C2' to type 'I1'. + compilation.AssertTheseDiagnostics( + +BC30519: Overload resolution failed because no accessible 'M1' can be called without a narrowing conversion: + 'Public Sub M1(x As I1)': Argument matching parameter 'x' narrows from 'C0' to 'I1'. + 'Public Sub M1(x As I2)': Argument matching parameter 'x' narrows from 'C0' to 'I2'. + M1(DirectCast(New C2(), C0)) + ~~ +) + End Sub + + + Public Sub NarrowingConversions_02() + Dim compilationDef = " +Option Strict Off + +Module Module1 + + Sub Main() + M1(CObj(New C2())) + End Sub + + + Sub M1(x As I1) + System.Console.Write(1) + End Sub + + Sub M1(x As I2) + System.Console.Write(2) + End Sub +End Module + +Interface I1 +End Interface + +Interface I2 +End Interface + +Class C0 +End Class + +Class C1 + Inherits C0 + Implements I1, I2 +End Class + +Class C2 + Inherits C0 + Implements I2 +End Class +" + Dim compilation = CreateCompilation({compilationDef, OverloadResolutionPriorityAttributeDefinitionVB}, options:=TestOptions.ReleaseExe) + + ' If the priority filtering was applied - System.InvalidCastException: Unable to cast object of type 'C2' to type 'I1'. + CompileAndVerify(compilation, expectedOutput:="2") + End Sub + + + Public Sub NarrowingConversions_03() + Dim compilationDef = " +Module Module1 + + Sub Main() + Try + M1(New C0()) + Catch ex As System.InvalidCastException + System.Console.Write(ex) + End Try + End Sub + + + Sub M1(x As C1) + End Sub + + Sub M1(x As C2) + System.Console.Write(2) + End Sub +End Module + +Class C0 + public shared narrowing operator CType(x As C0) As C1 + throw new System.InvalidCastException() + End Operator + public shared widening operator CType(x As C0) As C2 + return New C2() + End Operator +End Class + +Class C1 +End Class + +Class C2 +End Class +" + Dim compilation = CreateCompilation({compilationDef, OverloadResolutionPriorityAttributeDefinitionVB}, options:=TestOptions.ReleaseExe.WithOptionStrict(OptionStrict.On)) + CompileAndVerify(compilation, expectedOutput:="2") + + compilation = CreateCompilation({compilationDef, OverloadResolutionPriorityAttributeDefinitionVB}, options:=TestOptions.ReleaseExe.WithOptionStrict(OptionStrict.Off)) + ' If the priority filtering was applied - System.InvalidCastException : Specified cast is not valid. + CompileAndVerify(compilation, expectedOutput:="2") + End Sub + + + Public Sub DelegateRelaxationLevelNarrowing_01() + Dim compilationDef = " +Option Strict Off + +Module Module1 + + Sub Main() + M1(Function() New C1()) + M1(Function() DirectCast(New C2(), C0)) + End Sub + + + Sub M1(x As System.Func(Of I1)) + x() + System.Console.Write(1) + End Sub + + Sub M1(x As System.Func(Of I2)) + x() + System.Console.Write(2) + End Sub +End Module + +Interface I1 +End Interface + +Interface I2 +End Interface + +Class C0 +End Class + +Class C1 + Inherits C0 + Implements I1, I2 +End Class + +Class C2 + Inherits C0 + Implements I2 +End Class +" + Dim compilation = CreateCompilation({compilationDef, OverloadResolutionPriorityAttributeDefinitionVB}, options:=TestOptions.ReleaseExe) + + ' If the priority filtering for 'M1(Function() DirectCast(New C2(), C0))' was applied - System.InvalidCastException: Unable to cast object of type 'C2' to type 'I1'. + compilation.AssertTheseDiagnostics( + +BC30521: Overload resolution failed because no accessible 'M1' is most specific for these arguments: + 'Public Sub M1(x As Func(Of I1))': Not most specific. + 'Public Sub M1(x As Func(Of I2))': Not most specific. + M1(Function() DirectCast(New C2(), C0)) + ~~ +) + End Sub + + + Public Sub NarrowingFromNumericConstant_01() + Dim compilationDef = " +Option Strict Off + +Module Module1 + + Sub Main() + M1(CDbl(0)) + End Sub + + Sub M1(x as Decimal) + System.Console.Write(1) + End Sub + + + Sub M1(x As Single) + System.Console.Write(2) + End Sub +End Module +" + Dim compilation = CreateCompilation({compilationDef, OverloadResolutionPriorityAttributeDefinitionVB}, options:=TestOptions.ReleaseExe) + + compilation.AssertTheseDiagnostics( + +BC30519: Overload resolution failed because no accessible 'M1' can be called without a narrowing conversion: + 'Public Sub M1(x As Decimal)': Argument matching parameter 'x' narrows from 'Double' to 'Decimal'. + 'Public Sub M1(x As Single)': Argument matching parameter 'x' narrows from 'Double' to 'Single'. + M1(CDbl(0)) + ~~ +) + End Sub + + + Public Sub NarrowingFromNumericConstant_02() + Dim compilationDef = " +Module Module1 + + Sub Main() + M1(CLng(0)) + M2(CLng(0)) + End Sub + + Sub M1(x as Integer) + System.Console.Write(1) + End Sub + + + Sub M1(x As UInteger) + System.Console.Write(2) + End Sub + + Sub M2(x as Integer) + System.Console.Write(3) + End Sub + + Sub M2(x As UInteger) + System.Console.Write(4) + End Sub +End Module +" + Dim compilation = CreateCompilation({compilationDef, OverloadResolutionPriorityAttributeDefinitionVB}, options:=TestOptions.ReleaseExe) + + CompileAndVerify(compilation, expectedOutput:="13") + End Sub + + + Public Sub NarrowingFromNumericConstant_03() + Dim compilationDef = " +Module Module1 + + Sub Main() + M1(CLng(0)) + End Sub + + Sub M1(x as Integer) + System.Console.Write(1) + End Sub + + + Sub M1(x As UInteger) + System.Console.Write(2) + End Sub + + Sub M1(x As Long) + System.Console.Write(3) + End Sub +End Module +" + Dim compilation = CreateCompilation({compilationDef, OverloadResolutionPriorityAttributeDefinitionVB}, options:=TestOptions.ReleaseExe) + + CompileAndVerify(compilation, expectedOutput:="3") + End Sub + + + Public Sub NarrowingFromNumericConstant_04() + Dim compilationDef = " +Module Module1 + + Sub Main() + M1(Function() CLng(0)) + M2(Function() CLng(0)) + End Sub + + Sub M1(x as System.Func(Of Integer)) + System.Console.Write(1) + End Sub + + + Sub M1(x As System.Func(Of UInteger)) + System.Console.Write(2) + End Sub + + Sub M2(x as System.Func(Of Integer)) + System.Console.Write(3) + End Sub + + Sub M2(x As System.Func(Of UInteger)) + System.Console.Write(4) + End Sub +End Module +" + Dim compilation = CreateCompilation({compilationDef, OverloadResolutionPriorityAttributeDefinitionVB}, options:=TestOptions.ReleaseExe) + + CompileAndVerify(compilation, expectedOutput:="13") + End Sub + + + Public Sub NarrowingFromNumericConstant_05() + Dim compilationDef = " +Module Module1 + + Sub Main() + M1(Long.MaxValue) + M2(Long.MaxValue) + End Sub + + Sub M1(x as Integer) + System.Console.Write(1) + End Sub + + + Sub M1(x As UInteger) + System.Console.Write(2) + End Sub + + Sub M2(x as Integer) + System.Console.Write(3) + End Sub + + Sub M2(x As UInteger) + System.Console.Write(4) + End Sub +End Module +" + Dim compilation = CreateCompilation({compilationDef, OverloadResolutionPriorityAttributeDefinitionVB}, options:=TestOptions.ReleaseExe.WithOverflowChecks(False)) + + CompileAndVerify(compilation, expectedOutput:="13") + + compilation = CreateCompilation({compilationDef, OverloadResolutionPriorityAttributeDefinitionVB}, options:=TestOptions.ReleaseExe.WithOverflowChecks(True)) + + compilation.AssertTheseDiagnostics( + +BC30518: Overload resolution failed because no accessible 'M1' can be called with these arguments: + 'Public Sub M1(x As Integer)': Constant expression not representable in type 'Integer'. + 'Public Sub M1(x As UInteger)': Constant expression not representable in type 'UInteger'. + M1(Long.MaxValue) + ~~ +BC30518: Overload resolution failed because no accessible 'M2' can be called with these arguments: + 'Public Sub M2(x As Integer)': Constant expression not representable in type 'Integer'. + 'Public Sub M2(x As UInteger)': Constant expression not representable in type 'UInteger'. + M2(Long.MaxValue) + ~~ +) + End Sub + + + Public Sub IncreasedPriorityWins_01_CS_Property(i1First As Boolean) + + Dim i1Source = " +[OverloadResolutionPriority(1)] +public int this[I1 x] { set { System.Console.WriteLine(1); } } +" + + Dim i2Source = " +public int this[I2 x] { set { throw null; } } +" + + Dim reference = CreateCSharpCompilation(" +using System.Runtime.CompilerServices; + +public interface I1 {} +public interface I2 {} +public interface I3 : I1, I2 {} + +public class C +{" + + If(i1First, i1Source, i2Source) + + If(i1First, i2Source, i1Source) + " +} +" + OverloadResolutionPriorityAttributeDefinitionCS, parseOptions:=New CSharpParseOptions(CSharp.LanguageVersion.Latest)).EmitToImageReference() + + Dim source = " +public class Program + Shared Sub Main + Dim c As New C() + Dim i3 As I3 = Nothing + c(i3) = 0 + End Sub +End Class +" + + Dim compilation = CreateCompilation(source, references:={reference}, options:=TestOptions.DebugExe) + + Dim c = compilation.GetTypeByMetadataName("C") + Dim ms = c.GetMembers("Item").Cast(Of PropertySymbol)() + For Each m In ms + Assert.Equal(If(m.Parameters(0).Type.Name = "I1", 1, 0), m.OverloadResolutionPriority) + Next + + CompileAndVerify(compilation, expectedOutput:="1").VerifyDiagnostics() + End Sub + + + Public Sub IncreasedPriorityWins_01_Property(i1First As Boolean) + + Dim i1Source = " + +public Shared WriteOnly Property M(x As I1) As Integer + Set + System.Console.WriteLine(1) + End Set +End Property +" + + Dim i2Source = " +public Shared WriteOnly Property M(x As I2) As Integer + Set + throw DirectCast(Nothing, System.Exception) + End Set +End Property +" + + Dim reference = " +Imports System.Runtime.CompilerServices + +public interface I1 +End Interface +public interface I2 +End Interface +public interface I3 + Inherits I1, I2 +End Interface + +public class C" + + If(i1First, i1Source, i2Source) + + If(i1First, i2Source, i1Source) + " +End Class +" + + Dim source = " +public class Program + Shared Sub Main + Dim i3 As I3 = Nothing + C.M(i3) = 0 + End Sub +End Class +" + + Dim comp1 = CreateCompilation({source, reference, OverloadResolutionPriorityAttributeDefinitionVB}, options:=TestOptions.DebugExe) + + Dim validate = Sub([module] As ModuleSymbol) + Dim c = [module].ContainingAssembly.GetTypeByMetadataName("C") + Dim ms = c.GetMembers("M").Cast(Of PropertySymbol)() + For Each m In ms + Assert.Equal(If(m.Parameters(0).Type.Name = "I1", 1, 0), m.OverloadResolutionPriority) + Next + End Sub + + CompileAndVerify(comp1, expectedOutput:="1", sourceSymbolValidator:=validate, symbolValidator:=validate).VerifyDiagnostics() + + Dim compilationReference As CompilationReference = comp1.ToMetadataReference() + Dim comp2 = CreateCompilation(source, references:={compilationReference}, options:=TestOptions.DebugExe) + CompileAndVerify(comp2, expectedOutput:="1").VerifyDiagnostics() + + Dim metadataReference As MetadataReference = comp1.EmitToImageReference() + Dim comp3 = CreateCompilation(source, references:={metadataReference}, options:=TestOptions.DebugExe) + CompileAndVerify(comp3, expectedOutput:="1").VerifyDiagnostics() + + comp1 = CreateCompilation({source, reference, OverloadResolutionPriorityAttributeDefinitionVB}, options:=TestOptions.DebugExe, parseOptions:=TestOptions.Regular17_13) + CompileAndVerify(comp1, expectedOutput:="1", sourceSymbolValidator:=validate, symbolValidator:=validate).VerifyDiagnostics() + + comp1 = CreateCompilation({source, reference, OverloadResolutionPriorityAttributeDefinitionVB}, options:=TestOptions.DebugExe, parseOptions:=TestOptions.Regular16_9) + comp1.AssertTheseDiagnostics(If(i1First, + + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +]]>, + + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +]]>)) + + comp2 = CreateCompilation(source, references:={compilationReference}, options:=TestOptions.DebugExe, parseOptions:=TestOptions.Regular16_9) + Dim expected = If(i1First, + +BC30521: Overload resolution failed because no accessible 'M' is most specific for these arguments: + 'Public Shared WriteOnly Property M(x As I1) As Integer': Not most specific. + 'Public Shared WriteOnly Property M(x As I2) As Integer': Not most specific. + C.M(i3) = 0 + ~ +, + +BC30521: Overload resolution failed because no accessible 'M' is most specific for these arguments: + 'Public Shared WriteOnly Property M(x As I2) As Integer': Not most specific. + 'Public Shared WriteOnly Property M(x As I1) As Integer': Not most specific. + C.M(i3) = 0 + ~ +) + + comp2.AssertTheseDiagnostics(expected) + + comp3 = CreateCompilation(source, references:={metadataReference}, options:=TestOptions.DebugExe, parseOptions:=TestOptions.Regular16_9) + comp3.AssertTheseDiagnostics(expected) + End Sub + + + Public Sub ParameterlessProperty_01() + Dim compilationDef = " +Module Module1 + + Sub Main() + M1 = 0 + End Sub + + + WriteOnly Property M1 As Integer + Set + System.Console.Write(1) + End Set + End Property + + WriteOnly Property M1(Optional x As Integer = 0) As Integer + Set + System.Console.Write(2) + End Set + End Property +End Module +" + Dim compilation = CreateCompilation({compilationDef, OverloadResolutionPriorityAttributeDefinitionVB}, options:=TestOptions.ReleaseExe) + CompileAndVerify(compilation, expectedOutput:="2") + End Sub + + + Public Sub ParameterlessProperty_02() + Dim compilationDef = " +Module Module1 + + Sub Main() + M1 = 0 + End Sub + + WriteOnly Property M1 As Integer + Set + System.Console.Write(1) + End Set + End Property + + + WriteOnly Property M1(Optional x As Integer = 0) As Integer + Set + System.Console.Write(2) + End Set + End Property +End Module +" + Dim compilation = CreateCompilation({compilationDef, OverloadResolutionPriorityAttributeDefinitionVB}, options:=TestOptions.ReleaseExe) + CompileAndVerify(compilation, expectedOutput:="2") + End Sub + + + Public Sub TestObsoleteAttributeCycles() + Dim source = " +Imports System + +Public Class Test + + + Public Const F1 As Integer = 10 + + + + Public Const F2 As Integer = 10 + + + + Public Const F3 As Integer = 10 + + + Public Const F4 As String = ""blah"" + + + Public F5 As String = ""blah"" + + + + Public ReadOnly Property P1 As String + Get + Return ""blah"" + End Get + End Property + + + + + Public ReadOnly Property P2 As String + Get + Return ""blah"" + End Get + End Property + + + Public Sub Method1() + End Sub + + + + Public Sub Method2() + End Sub + + + + + Public Const F6 As String = ""F6 is obsolete"" + + + + + Public Const F7 As String = ""F7 is obsolete"" +End Class + + +Public Class SomeAttr + Inherits Attribute + Public Sub New(x As Integer) + End Sub + Public Sub New(x As String) + End Sub +End Class + +Public Class SomeAttr1 + Inherits Attribute + Public Sub New(x As Action) + End Sub +End Class +" + Dim compilation = CreateCompilation({source, OverloadResolutionPriorityAttributeDefinitionVB}) + compilation.AssertTheseDiagnostics( + + ~~ +BC30369: Cannot refer to an instance member of a class from within a shared method or shared member initializer without an explicit instance of the class. + + ~~ +BC30059: Constant expression is required. + + ~~ +BC30369: Cannot refer to an instance member of a class from within a shared method or shared member initializer without an explicit instance of the class. + + ~~ +BC30516: Overload resolution failed because no accessible 'New' accepts this number of arguments. + + ~~~~~~~~ +BC30059: Constant expression is required. + + ~~ +BC30369: Cannot refer to an instance member of a class from within a shared method or shared member initializer without an explicit instance of the class. + + ~~ +BC30369: Cannot refer to an instance member of a class from within a shared method or shared member initializer without an explicit instance of the class. + + ~~~~~~~ +BC30369: Cannot refer to an instance member of a class from within a shared method or shared member initializer without an explicit instance of the class. + + ~~~~~~~ +]]> + ) + End Sub + + + Public Sub PropertyInAttribute_01() + Dim source = " +Imports System + + +Public Class SomeAttr + Inherits Attribute + + Public Property P1 As Integer + Get + Return 0 + End Get + Set + End Set + End Property + + + Public Property P1(ParamArray x As Integer()) As Integer + Get + Return 0 + End Get + Set + End Set + End Property + +End Class + + +Public Class SomeAttr1 +End Class +" + Dim compilation = CreateCompilation({source, OverloadResolutionPriorityAttributeDefinitionVB}) + compilation.AssertNoDiagnostics() + + Dim attr = compilation.GetTypeByMetadataName("SomeAttr1").GetAttributes().Single() + Assert.Equal("SomeAttr(P1:=1)", attr.ToString()) + End Sub + + + Public Sub PropertyInAttribute_02() + Dim source = " +Imports System + + +Public Class SomeAttr + Inherits Attribute + + Public Property P1(Optional x As Integer = 0) As Integer + Get + Return 0 + End Get + Set + End Set + End Property + + Public Property P2(ParamArray x As Integer()) As Integer + Get + Return 0 + End Get + Set + End Set + End Property + +End Class + + + +Public Class SomeAttr1 +End Class +" + Dim compilation = CreateCompilation(source) + compilation.AssertTheseDiagnostics( + + ~~ +BC30658: Property 'P2' with no parameters cannot be found. + + ~~ +]]> + ) + End Sub + + + Public Sub DefaultProperty_01() + Dim compilationDef = " +Class Module1 + + Shared Sub Main() + End Sub + + + Default WriteOnly Property M1 As Integer + Set + System.Console.Write(1) + End Set + End Property + + Default WriteOnly Property M1(x As Integer) As Integer + Set + System.Console.Write(2) + End Set + End Property +End Class +" + Dim compilation = CreateCompilation({compilationDef, OverloadResolutionPriorityAttributeDefinitionVB}, options:=TestOptions.ReleaseExe) + compilation.AssertTheseDiagnostics( + +BC31048: Properties with no required parameters cannot be declared 'Default'. + Default WriteOnly Property M1 As Integer + ~~ +) + End Sub + + + Public Sub DefaultProperty_02() + Dim compilationDef = " +Class Module1 + + Shared Sub Main() + End Sub + + + WriteOnly Property M1 As Integer + Set + System.Console.Write(1) + End Set + End Property + + Default WriteOnly Property M1(x As Integer) As Integer + Set + System.Console.Write(2) + End Set + End Property +End Class +" + Dim compilation = CreateCompilation({compilationDef, OverloadResolutionPriorityAttributeDefinitionVB}, options:=TestOptions.ReleaseExe) + compilation.AssertTheseDiagnostics( + +BC30361: 'Public WriteOnly Default Property M1(x As Integer) As Integer' and 'Public WriteOnly Property M1 As Integer' cannot overload each other because only one is declared 'Default'. + WriteOnly Property M1 As Integer + ~~ +) + End Sub + + + Public Sub DefaultProperty_03(i1First As Boolean) + + Dim i1Source = " + +public Default WriteOnly Property M(x As I1) As Integer + Set + System.Console.Write(1) + End Set +End Property +" + + Dim i2Source = " +public Default WriteOnly Property M(x As I2) As Integer + Set + throw DirectCast(Nothing, System.Exception) + End Set +End Property +" + + Dim reference = " +Imports System.Runtime.CompilerServices + +public interface I1 +End Interface +public interface I2 +End Interface +public interface I3 + Inherits I1, I2 +End Interface + +public class C" + + If(i1First, i1Source, i2Source) + + If(i1First, i2Source, i1Source) + " +End Class +" + + Dim source = " +public class Program + Shared Sub Main + Dim c as New C() + Dim i3 As I3 = Nothing + c.M(i3) = 0 + c(i3) = 0 + End Sub +End Class +" + + Dim comp1 = CreateCompilation({source, reference, OverloadResolutionPriorityAttributeDefinitionVB}, options:=TestOptions.DebugExe) + + Dim validate = Sub([module] As ModuleSymbol) + Dim c = [module].ContainingAssembly.GetTypeByMetadataName("C") + Dim ms = c.GetMembers("M").Cast(Of PropertySymbol)() + For Each m In ms + Assert.Equal(If(m.Parameters(0).Type.Name = "I1", 1, 0), m.OverloadResolutionPriority) + Next + End Sub + + CompileAndVerify(comp1, expectedOutput:="11", sourceSymbolValidator:=validate, symbolValidator:=validate).VerifyDiagnostics() + + Dim comp2 = CreateCompilation(source, references:={comp1.ToMetadataReference()}, options:=TestOptions.DebugExe) + CompileAndVerify(comp2, expectedOutput:="11").VerifyDiagnostics() + + Dim comp3 = CreateCompilation(source, references:={comp1.EmitToImageReference()}, options:=TestOptions.DebugExe) + CompileAndVerify(comp3, expectedOutput:="11").VerifyDiagnostics() + End Sub + + + Public Sub WriteOnlyVsReadOnlyProperty_01() + + Dim compilationDef = " +Imports System.Runtime.CompilerServices + +public interface I1 +End Interface +public interface I2 +End Interface +public interface I3 + Inherits I1, I2 +End Interface + +public class C + + public Shared WriteOnly Property M(x As I1) As Integer + Set + System.Console.WriteLine(1) + End Set + End Property + public Shared ReadOnly Property M(x As I2) As Integer + Get + throw DirectCast(Nothing, System.Exception) + End Get + End Property +End Class + +public class Program + Shared Sub Main + Dim i3 As I3 = Nothing + Dim x = C.M(i3) + End Sub +End Class +" + Dim compilation = CreateCompilation({compilationDef, OverloadResolutionPriorityAttributeDefinitionVB}, options:=TestOptions.ReleaseExe) + compilation.AssertTheseDiagnostics( + +BC30524: Property 'M' is 'WriteOnly'. + Dim x = C.M(i3) + ~~~~~~~ +) + End Sub + + + Public Sub WriteOnlyVsReadOnlyProperty_02() + + Dim compilationDef = " +Imports System.Runtime.CompilerServices + +public interface I1 +End Interface +public interface I2 +End Interface +public interface I3 + Inherits I1, I2 +End Interface + +public class C + public Shared WriteOnly Property M(x As I1) As Integer + Set + System.Console.WriteLine(1) + End Set + End Property + + public Shared ReadOnly Property M(x As I2) As Integer + Get + throw DirectCast(Nothing, System.Exception) + End Get + End Property +End Class + +public class Program + Shared Sub Main + Dim i3 As I3 = Nothing + C.M(i3) = 0 + End Sub +End Class +" + Dim compilation = CreateCompilation({compilationDef, OverloadResolutionPriorityAttributeDefinitionVB}, options:=TestOptions.ReleaseExe) + compilation.AssertTheseDiagnostics( + +BC30526: Property 'M' is 'ReadOnly'. + C.M(i3) = 0 + ~~~~~~~~~~~ +) + End Sub + + + Public Sub LiftedOperator_01() + Dim reference = " +public Structure S + + + public shared operator-(x As S) As S + System.Console.Write(1) + return Nothing + End Operator + + public shared operator-(x As S?) As S? + System.Console.Write(2) + return Nothing + End Operator +End Structure +" + Dim source = " +Module Module1 + Sub Main() + Dim s As New S?(Nothing) + s = -s + End Sub +End Module +" + Dim compilation = CreateCompilation({source, reference, OverloadResolutionPriorityAttributeDefinitionVB}, options:=TestOptions.ReleaseExe) + CompileAndVerify(compilation, expectedOutput:="1") + + compilation = CreateCompilation({source, reference, OverloadResolutionPriorityAttributeDefinitionVB}, options:=TestOptions.ReleaseExe, parseOptions:=TestOptions.Regular17_13) + CompileAndVerify(compilation, expectedOutput:="1") + + compilation = CreateCompilation({source, reference, OverloadResolutionPriorityAttributeDefinitionVB}, options:=TestOptions.ReleaseExe, parseOptions:=TestOptions.Regular16_9) + compilation.AssertTheseDiagnostics( + + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +]]>) + + Dim ref = CreateCompilation({reference, OverloadResolutionPriorityAttributeDefinitionVB}, options:=TestOptions.ReleaseDll) + + compilation = CreateCompilation(source, references:={ref.ToMetadataReference()}, options:=TestOptions.ReleaseExe, parseOptions:=TestOptions.Regular16_9) + CompileAndVerify(compilation, expectedOutput:="2") + + compilation = CreateCompilation(source, references:={ref.EmitToImageReference()}, options:=TestOptions.ReleaseExe, parseOptions:=TestOptions.Regular16_9) + CompileAndVerify(compilation, expectedOutput:="2") + End Sub + + + Public Sub Plus2() + Dim compilationDef = " +Option Strict Off + +Imports System + +Module Module1 + + Structure S1 + + + Public Shared Operator +(x As S1) As S1 + System.Console.WriteLine(""+(x As S1) As S1"") + Return x + End Operator + + + Public Shared Operator +(x As S1?) As Integer + System.Console.WriteLine(""+(x As S1?) As Integer"") + Return 0 + End Operator + + End Structure + + Sub Main() + Dim y1 = +New S1() + System.Console.WriteLine(""-----"") + Dim y2 = +New S1?() + System.Console.WriteLine(""-----"") + Dim y3 = +New S1?(New S1()) + End Sub +End Module +" + Dim compilation = CreateCompilation({compilationDef, OverloadResolutionPriorityAttributeDefinitionVB}, options:=TestOptions.ReleaseExe) + + CompileAndVerify(compilation, expectedOutput:= + ) + End Sub + + + Public Sub ConversionOperator_01() + Dim compilationDef = " +Structure S + + public shared widening operator CType(x As Integer) As S + System.Console.Write(1) + return Nothing + End Operator + + + public shared widening operator CType(x As Long) As S + System.Console.Write(2) + return Nothing + End Operator +End Structure + +Module Module1 + Sub Main() + Dim val as Integer = 0 + Dim s As S = val + End Sub +End Module +" + Dim compilation = CreateCompilation({compilationDef, OverloadResolutionPriorityAttributeDefinitionVB}, options:=TestOptions.ReleaseExe) + + compilation.AssertTheseDiagnostics( + + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +]]>) + End Sub + + + Public Sub IncreasedPriorityWins_02_CS(i1First As Boolean) + + Dim reference = CreateCSharpCompilation(" +using System.Runtime.CompilerServices; + +public interface I1 {} +public interface I2 {} +public interface I3 : I1, I2 {} + +public class C +{ + [OverloadResolutionPriority(2)] + public static void M(object o) => System.Console.WriteLine(1); + + [OverloadResolutionPriority(1)] + public static void M(I1 x) => throw null; + + public static void M(I2 x) => throw null; +} +" + OverloadResolutionPriorityAttributeDefinitionCS, parseOptions:=New CSharpParseOptions(CSharp.LanguageVersion.Latest)).EmitToImageReference() + + Dim source = " +public class Program + Shared Sub Main + Dim i3 As I3 = Nothing + C.M(i3) + End Sub +End Class +" + + Dim compilation = CreateCompilation(source, references:={reference}, options:=TestOptions.DebugExe) + CompileAndVerify(compilation, expectedOutput:="1").VerifyDiagnostics() + End Sub + + + Public Sub IncreasedPriorityWins_02() + + Dim reference = " +Imports System.Runtime.CompilerServices + +public interface I1 +End Interface +public interface I2 +End Interface +public interface I3 + Inherits I1, I2 +End Interface + +public class C + + public Shared Sub M(x As Object) + System.Console.WriteLine(1) + End Sub + + public Shared Sub M(x As I1) + throw DirectCast(Nothing, System.Exception) + End Sub + public Shared Sub M(x As I2) + throw DirectCast(Nothing, System.Exception) + End Sub +End Class +" + + Dim source = " +public class Program + Shared Sub Main + Dim i3 As I3 = Nothing + C.M(i3) + End Sub +End Class +" + + Dim comp1 = CreateCompilation({source, reference, OverloadResolutionPriorityAttributeDefinitionVB}, options:=TestOptions.DebugExe) + + CompileAndVerify(comp1, expectedOutput:="1").VerifyDiagnostics() + + Dim comp2 = CreateCompilation(source, references:={comp1.ToMetadataReference()}, options:=TestOptions.DebugExe) + CompileAndVerify(comp2, expectedOutput:="1").VerifyDiagnostics() + + Dim comp3 = CreateCompilation(source, references:={comp1.EmitToImageReference()}, options:=TestOptions.DebugExe) + CompileAndVerify(comp3, expectedOutput:="1").VerifyDiagnostics() + End Sub + + + Public Sub DecreasedPriorityLoses(i1First As Boolean) + + Dim i1Source = " +public Shared Sub M(x As I1) + System.Console.WriteLine(1) +End Sub +" + + Dim i2Source = " + +public Shared Sub M(x As I2) + throw DirectCast(Nothing, System.Exception) +End Sub +" + + Dim reference = " +Imports System.Runtime.CompilerServices + +public interface I1 +End Interface +public interface I2 +End Interface +public interface I3 + Inherits I1, I2 +End Interface + +public class C" + + If(i1First, i1Source, i2Source) + + If(i1First, i2Source, i1Source) + " +End Class +" + + Dim source = " +public class Program + Shared Sub Main + Dim i3 As I3 = Nothing + C.M(i3) + End Sub +End Class +" + + Dim comp1 = CreateCompilation({source, reference, OverloadResolutionPriorityAttributeDefinitionVB}, options:=TestOptions.DebugExe) + + CompileAndVerify(comp1, expectedOutput:="1").VerifyDiagnostics() + + Dim comp2 = CreateCompilation(source, references:={comp1.ToMetadataReference()}, options:=TestOptions.DebugExe) + CompileAndVerify(comp2, expectedOutput:="1").VerifyDiagnostics() + + Dim comp3 = CreateCompilation(source, references:={comp1.EmitToImageReference()}, options:=TestOptions.DebugExe) + CompileAndVerify(comp3, expectedOutput:="1").VerifyDiagnostics() + End Sub + + + Public Sub ZeroIsTreatedAsDefault() + + Dim reference = " +Imports System.Runtime.CompilerServices + +public interface I1 +End Interface +public interface I2 +End Interface +public interface I3 + Inherits I1, I2 +End Interface + +public class C + public Shared Sub M(x As I1) + System.Console.WriteLine(1) + End Sub + + public Shared Sub M(x As I2) + throw DirectCast(Nothing, System.Exception) + End Sub +End Class +" + + Dim source = " +public class Program + Shared Sub Main + Dim i3 As I3 = Nothing + C.M(i3) + End Sub +End Class +" + + Dim comp1 = CreateCompilation({source, reference, OverloadResolutionPriorityAttributeDefinitionVB}, options:=TestOptions.DebugExe) + + Dim expected = + +BC30521: Overload resolution failed because no accessible 'M' is most specific for these arguments: + 'Public Shared Sub M(x As I1)': Not most specific. + 'Public Shared Sub M(x As I2)': Not most specific. + C.M(i3) + ~ + + + comp1.AssertTheseDiagnostics(expected) + + comp1 = CreateCompilation({reference, OverloadResolutionPriorityAttributeDefinitionVB}, options:=TestOptions.DebugDll) + Dim validate = Sub([module] As ModuleSymbol) + Dim c = [module].ContainingAssembly.GetTypeByMetadataName("C") + Dim ms = c.GetMembers("M").Cast(Of MethodSymbol)() + For Each m In ms + Assert.Equal(0, m.OverloadResolutionPriority) + Next + End Sub + CompileAndVerify(comp1, sourceSymbolValidator:=validate, symbolValidator:=validate).VerifyDiagnostics() + + Dim comp2 = CreateCompilation(source, references:={comp1.ToMetadataReference()}, options:=TestOptions.DebugExe) + comp2.AssertTheseDiagnostics(expected) + + Dim comp3 = CreateCompilation(source, references:={comp1.EmitToImageReference()}, options:=TestOptions.DebugExe) + comp3.AssertTheseDiagnostics(expected) + End Sub + + + + + + + Public Sub AmbiguityWithinPriority(priority As Integer) + + Dim reference = $" +Imports System.Runtime.CompilerServices + +public interface I1 +End Interface +public interface I2 +End Interface +public interface I3 + Inherits I1, I2 +End Interface + +public class C + + public Shared Sub M(x As I1) + System.Console.WriteLine(1) + End Sub + + public Shared Sub M(x As I2) + throw DirectCast(Nothing, System.Exception) + End Sub +End Class +" + + Dim source = " +public class Program + Shared Sub Main + Dim i3 As I3 = Nothing + C.M(i3) + End Sub +End Class +" + + Dim comp1 = CreateCompilation({source, reference, OverloadResolutionPriorityAttributeDefinitionVB}, options:=TestOptions.DebugExe) + + Dim expected = + +BC30521: Overload resolution failed because no accessible 'M' is most specific for these arguments: + 'Public Shared Sub M(x As I1)': Not most specific. + 'Public Shared Sub M(x As I2)': Not most specific. + C.M(i3) + ~ + + + comp1.AssertTheseDiagnostics(expected) + End Sub + + + Public Sub MethodDiscoveryStopsAtFirstApplicableMethod_CS() + + Dim reference = CreateCSharpCompilation(" +using System.Runtime.CompilerServices; + +public interface I1 {} +public interface I2 {} +public interface I3 : I1, I2 {} + +public class Base +{ + [OverloadResolutionPriority(1)] + public static void M(I2 x) => throw null; +} +public class Derived : Base +{ + public static void M(I1 x) => System.Console.WriteLine(1); +} +" + OverloadResolutionPriorityAttributeDefinitionCS, parseOptions:=New CSharpParseOptions(CSharp.LanguageVersion.Latest)).EmitToImageReference() + + Dim source = " +public class Program + Shared Sub Main + Dim i3 As I3 = Nothing + Derived.M(i3) + End Sub +End Class +" + + Dim compilation = CreateCompilation(source, references:={reference}, options:=TestOptions.DebugExe) + + ' Unlike C#, VB doesn't stop collecting candidates at Derived + compilation.AssertTheseDiagnostics( + +BC30521: Overload resolution failed because no accessible 'M' is most specific for these arguments: + 'Public Shared Overloads Sub Derived.M(x As I1)': Not most specific. + 'Public Shared Overloads Sub Base.M(x As I2)': Not most specific. + Derived.M(i3) + ~ +) + End Sub + + + Public Sub MethodDiscoveryStopsAtFirstApplicableIndexer_CS() + + Dim reference = CreateCSharpCompilation(" +using System.Runtime.CompilerServices; + +public interface I1 {} +public interface I2 {} +public interface I3 : I1, I2 {} + +public class Base +{ + [OverloadResolutionPriority(1)] + public int this[I2 x] + { + get => throw null; + set => throw null; + } +} +public class Derived : Base +{ + public int this[I1 x] + { + get { System.Console.Write(1); return 1; } + set => System.Console.Write(2); + } +} +" + OverloadResolutionPriorityAttributeDefinitionCS, parseOptions:=New CSharpParseOptions(CSharp.LanguageVersion.Latest)).EmitToImageReference() + + Dim source = " +public class Program + Shared Sub Main + Dim i3 As I3 = Nothing + Dim d = new Derived() + Dim x = d(i3) + d(i3) = 0 + End Sub +End Class +" + + Dim compilation = CreateCompilation(source, references:={reference}, options:=TestOptions.DebugExe) + + ' Unlike C#, VB doesn't stop collecting candidates at Derived + compilation.AssertTheseDiagnostics( + +BC30521: Overload resolution failed because no accessible 'Item' is most specific for these arguments: + 'Public Overloads Default Property Derived.Item(x As I1) As Integer': Not most specific. + 'Public Overloads Default Property Base.Item(x As I2) As Integer': Not most specific. + Dim x = d(i3) + ~ +BC30521: Overload resolution failed because no accessible 'Item' is most specific for these arguments: + 'Public Overloads Default Property Derived.Item(x As I1) As Integer': Not most specific. + 'Public Overloads Default Property Base.Item(x As I2) As Integer': Not most specific. + d(i3) = 0 + ~ +) + End Sub + + + Public Sub OrderingWithAnExtensionMethodContainingClass_CS() + + Dim reference = CreateCSharpCompilation(" +using System.Runtime.CompilerServices; + +public interface I1 {} +public interface I2 {} +public interface I3 : I1, I2 {} + +public static class C +{ + [OverloadResolutionPriority(1)] + public static void M(this I1 x) => System.Console.WriteLine(1); + + public static void M(this I2 x) => throw null; +} +" + OverloadResolutionPriorityAttributeDefinitionCS, parseOptions:=New CSharpParseOptions(CSharp.LanguageVersion.Latest)).EmitToImageReference() + + Dim source = " +public class Program + Shared Sub Main + Dim i3 As I3 = Nothing + i3.M() + End Sub +End Class +" + + Dim compilation = CreateCompilation(source, references:={reference}, options:=TestOptions.DebugExe) + CompileAndVerify(compilation, expectedOutput:="1").VerifyDiagnostics() + End Sub + + + Public Sub DoesNotOrderBetweenExtensionMethodContainingClasses_CS() + + Dim reference = CreateCSharpCompilation(" +using System.Runtime.CompilerServices; + +public interface I1 {} +public interface I2 {} +public interface I3 : I1, I2 {} + +public static class C1 +{ + [OverloadResolutionPriority(1)] + public static void M(this I1 x) => System.Console.WriteLine(1); +} + +public static class C2 +{ + public static void M(this I2 x) => throw null; +} +" + OverloadResolutionPriorityAttributeDefinitionCS, parseOptions:=New CSharpParseOptions(CSharp.LanguageVersion.Latest)).EmitToImageReference() + + Dim source = " +public class Program + Shared Sub Main + Dim i3 As I3 = Nothing + i3.M() + End Sub +End Class +" + + Dim compilation = CreateCompilation(source, references:={reference}, options:=TestOptions.DebugExe) + compilation.AssertTheseDiagnostics( + +BC30521: Overload resolution failed because no accessible 'M' is most specific for these arguments: + Extension method 'Public Sub M()' defined in 'C1': Not most specific. + Extension method 'Public Sub M()' defined in 'C2': Not most specific. + i3.M() + ~ +) + End Sub + + + Public Sub Overrides_NoPriorityChangeFromBase_Methods_CS() + + Dim reference = CreateCSharpCompilation(" +using System.Runtime.CompilerServices; + +public class Base +{ + [OverloadResolutionPriority(1)] + public virtual void M(object o) => throw null; + public virtual void M(string s) => throw null; +} + +public class Derived : Base +{ + public override void M(object o) => System.Console.WriteLine(""1""); + public override void M(string s) => throw null; +} +" + OverloadResolutionPriorityAttributeDefinitionCS, parseOptions:=New CSharpParseOptions(CSharp.LanguageVersion.Latest)).EmitToImageReference() + + Dim source = " +public class Program + Shared Sub Main + Dim d = new Derived() + d.M(""test"") + End Sub +End Class +" + + Dim compilation = CreateCompilation(source, references:={reference}, options:=TestOptions.DebugExe) + CompileAndVerify(compilation, expectedOutput:="1").VerifyDiagnostics() + End Sub + + + Public Sub Overrides_ChangePriorityInSource_Methods() + + Dim source = " +Imports System.Runtime.CompilerServices + +public class Base + + public Overridable Sub M(o As Object) + throw DirectCast(Nothing, System.Exception) + End Sub + public Overridable Sub M(s As String) + throw DirectCast(Nothing, System.Exception) + End Sub + + public Overridable Sub M2(o As Object) + throw DirectCast(Nothing, System.Exception) + End Sub +End Class + +public class Derived + Inherits Base + + + public Overrides Sub M(o As Object) + System.Console.WriteLine(""1"") + End Sub + + public Overrides Sub M(s As String) + throw DirectCast(Nothing, System.Exception) + End Sub + ' Priority matches + public Overrides Sub M2(o As Object) + System.Console.WriteLine(""1"") + End Sub +End Class + +public class Program + Shared Sub Main + Dim d = new Derived() + d.M(""test"") + End Sub +End Class +" + + Dim compilation = CreateCompilation({source, OverloadResolutionPriorityAttributeDefinitionVB}, options:=TestOptions.DebugExe) + + compilation.AssertTheseDiagnostics( + + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +BC37333: Cannot use 'OverloadResolutionPriorityAttribute' on an overriding member. + + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +BC37333: Cannot use 'OverloadResolutionPriorityAttribute' on an overriding member. + ' Priority matches + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +]]>) + End Sub + + + Public Sub Overrides_ChangePriorityInMetadata_Methods() + + Dim source1 = " +Imports System.Runtime.CompilerServices + +public class Base + + public Overridable Sub M(o As Object) + throw DirectCast(Nothing, System.Exception) + End Sub + public Overridable Sub M(s As String) + throw DirectCast(Nothing, System.Exception) + End Sub +End Class +" + + Dim comp1 = CreateCompilation({source1, OverloadResolutionPriorityAttributeDefinitionVB}, options:=TestOptions.DebugDll, assemblyName:="assembly1") + Dim assembly1 = comp1.EmitToImageReference() + + ' Equivalent to: + ' + ' public class Derived : Base + ' { + ' [OverloadResolutionPriority(0)] + ' public override void M(object o) => System.Console.WriteLine("1"); + ' [OverloadResolutionPriority(2)] + ' public override void M(string s) => throw null; + ' } + Dim il2 = " +.assembly extern assembly1 {} + +.class public auto ansi beforefieldinit Derived extends [assembly1]Base +{ + .method public hidebysig virtual + instance void M ( + object o + ) cil managed + { + .custom instance void [assembly1]System.Runtime.CompilerServices.OverloadResolutionPriorityAttribute::.ctor(int32) = ( + 01 00 00 00 00 00 00 00 + ) + ldstr ""1"" + call void [mscorlib]System.Console::WriteLine(string) + ret + } // end of method Derived::M + + .method public hidebysig virtual + instance void M ( + string s + ) cil managed + { + .custom instance void [assembly1]System.Runtime.CompilerServices.OverloadResolutionPriorityAttribute::.ctor(int32) = ( + 01 00 02 00 00 00 00 00 + ) + ldnull + throw + } // end of method Derived::M + + .method public hidebysig specialname rtspecialname + instance void .ctor () cil managed + { + ldarg.0 + call instance void [assembly1]Base::.ctor() + ret + } // end of method Derived::.ctor + +} +" + + Dim source = " +public class Program + Shared Sub Main + Dim d = new Derived() + d.M(""test"") + End Sub +End Class +" + Dim assembly2 = CompileIL(il2) + + Dim compilation = CreateCompilation(source, references:={assembly1, assembly2}, options:=TestOptions.DebugExe) + + CompileAndVerify(compilation, expectedOutput:="1").VerifyDiagnostics() + End Sub + + + Public Sub Overrides_ChangePriorityInMetadata_Indexers() + + Dim source1 = " +Imports System.Runtime.CompilerServices + +public class Base + + public Overridable Default Property Item(o As Object) As Integer + Get + throw DirectCast(Nothing, System.Exception) + End Get + Set + throw DirectCast(Nothing, System.Exception) + End Set + End Property + public Overridable Default Property Item(s As String) As Integer + Get + throw DirectCast(Nothing, System.Exception) + End Get + Set + throw DirectCast(Nothing, System.Exception) + End Set + End Property +End Class +" + + Dim comp1 = CreateCompilation({source1, OverloadResolutionPriorityAttributeDefinitionVB}, options:=TestOptions.DebugDll, assemblyName:="assembly1") + Dim assembly1 = comp1.EmitToImageReference() + + ' Equivalent to: + ' + ' public class Derived: Base + ' { + ' public override int this[object o] + ' { + ' get { System.Console.Write(1); return 1; } + ' set => System.Console.Write(2); + ' } + ' [OverloadResolutionPriority(2)] + ' public override int this[string s] + ' { + ' get => throw null; + ' set => throw null; + ' } + ' } + Dim il2 = " +.assembly extern assembly1 {} + +.class public auto ansi beforefieldinit Derived extends [assembly1]Base +{ + .custom instance void [mscorlib]System.Reflection.DefaultMemberAttribute::.ctor(string) = ( + 01 00 04 49 74 65 6d 00 00 + ) + // Methods + .method public hidebysig specialname virtual + instance int32 get_Item ( + object o + ) cil managed + { + ldc.i4.1 + call void [mscorlib]System.Console::Write(int32) + ldc.i4.1 + ret + } // end of method Derived::get_Item + + .method public hidebysig specialname virtual + instance void set_Item ( + object o, + int32 'value' + ) cil managed + { + ldc.i4.2 + call void [mscorlib]System.Console::Write(int32) + ret + } // end of method Derived::set_Item + + .method public hidebysig specialname virtual + instance int32 get_Item ( + string s + ) cil managed + { + ldnull + throw + } // end of method Derived::get_Item + + .method public hidebysig specialname virtual + instance void set_Item ( + string s, + int32 'value' + ) cil managed + { + ldnull + throw + } // end of method Derived::set_Item + + .method public hidebysig specialname rtspecialname + instance void .ctor () cil managed + { + ldarg.0 + call instance void [assembly1]Base::.ctor() + ret + } // end of method Derived::.ctor + + // Properties + .property instance int32 Item( + object o + ) + { + .get instance int32 Derived::get_Item(object) + .set instance void Derived::set_Item(object, int32) + } + .property instance int32 Item( + string s + ) + { + .custom instance void [assembly1]System.Runtime.CompilerServices.OverloadResolutionPriorityAttribute::.ctor(int32) = ( + 01 00 02 00 00 00 00 00 + ) + .get instance int32 Derived::get_Item(string) + .set instance void Derived::set_Item(string, int32) + } +} +" + + Dim source = " +public class Program + Shared Sub Main + Dim d = new Derived() + Dim x = d(""test"") + d(""test"") = 0 + x = d.Item(""test"") + d.Item(""test"") = 0 + End Sub +End Class +" + Dim assembly2 = CompileIL(il2) + + Dim compilation = CreateCompilation(source, references:={assembly1, assembly2}, options:=TestOptions.DebugExe) + + CompileAndVerify(compilation, expectedOutput:="1212").VerifyDiagnostics() + End Sub + + + Public Sub Overrides_ChangePriorityInSource_Indexers() + + Dim source = " +Imports System.Runtime.CompilerServices + +public class Base + + public Overridable Default Property Item(o As Object) As Integer + Get + throw DirectCast(Nothing, System.Exception) + End Get + Set + throw DirectCast(Nothing, System.Exception) + End Set + End Property + public Overridable Default Property Item(s As String) As Integer + Get + throw DirectCast(Nothing, System.Exception) + End Get + Set + throw DirectCast(Nothing, System.Exception) + End Set + End Property + + public Overridable Default Property Item(o As Integer) As Integer + Get + throw DirectCast(Nothing, System.Exception) + End Get + Set + throw DirectCast(Nothing, System.Exception) + End Set + End Property +End Class + +public class Derived + Inherits Base + + public Overrides Default Property Item(o As Object) As Integer + Get + System.Console.Write(1) + return 1 + End Get + Set + System.Console.Write(2) + End Set + End Property + + + public Overrides Default Property Item(s As String) As Integer + Get + throw DirectCast(Nothing, System.Exception) + End Get + Set + throw DirectCast(Nothing, System.Exception) + End Set + End Property + + ' Priority matches + public Overrides Default Property Item(o As Integer) As Integer + Get + throw DirectCast(Nothing, System.Exception) + End Get + Set + throw DirectCast(Nothing, System.Exception) + End Set + End Property +End Class + +public class Program + Shared Sub Main + Dim d = new Derived() + Dim x = d(""test"") + d(""test"") = 0 + x = d.Item(""test"") + d.Item(""test"") = 0 + End Sub +End Class +" + Dim compilation = CreateCompilation({source, OverloadResolutionPriorityAttributeDefinitionVB}, options:=TestOptions.DebugExe) + + compilation.AssertTheseDiagnostics( + + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +BC37333: Cannot use 'OverloadResolutionPriorityAttribute' on an overriding member. + ' Priority matches + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +]]>) + End Sub + + + Public Sub ThroughRetargeting_Methods() + + Dim source1 = " +public class RetValue +End Class +" + + Dim comp1_1 = CreateCompilation(source1, options:=TestOptions.DebugDll, assemblyName:="Ret") + DirectCast(comp1_1.Assembly, SourceAssemblySymbol).m_lazyIdentity = New AssemblyIdentity("Ret", New Version(1, 0, 0, 0), isRetargetable:=True) + Dim comp1_2 = CreateCompilation(source1, options:=TestOptions.DebugDll, assemblyName:="Ret") + DirectCast(comp1_2.Assembly, SourceAssemblySymbol).m_lazyIdentity = New AssemblyIdentity("Ret", New Version(2, 0, 0, 0), isRetargetable:=True) + + Dim source2 = " +Imports System.Runtime.CompilerServices + +public class C + + public Function M(o As Object) As RetValue + System.Console.WriteLine(""1"") + return new RetValue() + End Function + public Function M(s As String) + throw DirectCast(Nothing, System.Exception) + End Function +End Class +" + + Dim comp2 = CreateCompilation({source2, OverloadResolutionPriorityAttributeDefinitionVB}, references:={comp1_1.ToMetadataReference()}, options:=TestOptions.DebugDll) + comp2.VerifyDiagnostics() + + Dim source3 = " +public class Program + Shared Sub Main + Dim c = new C() + c.M(""test"") + End Sub +End Class +" + + Dim comp3 = CreateCompilation(source3, references:={comp2.ToMetadataReference(), comp1_2.ToMetadataReference()}, options:=TestOptions.DebugExe) + Dim c = comp3.GetTypeByMetadataName("C") + Dim ms = c.GetMembers("M").Cast(Of MethodSymbol)().ToArray() + Assert.Equal(2, ms.Length) + Assert.All(ms, Function(m) Assert.IsType(Of RetargetingMethodSymbol)(m)) + AssertEx.Equal("Function C.M(o As System.Object) As RetValue", ms(0).ToTestDisplayString()) + Assert.Equal(1, ms(0).OverloadResolutionPriority) + AssertEx.Equal("Function C.M(s As System.String) As System.Object", ms(1).ToTestDisplayString()) + Assert.Equal(0, ms(1).OverloadResolutionPriority) + + comp3.VerifyDiagnostics() + End Sub + + + Public Sub ThroughRetargeting_Indexers() + + Dim source1 = " +public class RetValue +End Class +" + + Dim comp1_1 = CreateCompilation(source1, options:=TestOptions.DebugDll, assemblyName:="Ret") + DirectCast(comp1_1.Assembly, SourceAssemblySymbol).m_lazyIdentity = New AssemblyIdentity("Ret", New Version(1, 0, 0, 0), isRetargetable:=True) + Dim comp1_2 = CreateCompilation(source1, options:=TestOptions.DebugDll, assemblyName:="Ret") + DirectCast(comp1_2.Assembly, SourceAssemblySymbol).m_lazyIdentity = New AssemblyIdentity("Ret", New Version(2, 0, 0, 0), isRetargetable:=True) + + Dim source2 = " +Imports System.Runtime.CompilerServices + +public class C + + public Default Property M(o As Object) As RetValue + Get + System.Console.WriteLine(""1"") + return new RetValue() + End Get + Set + System.Console.WriteLine(""2"") + End Set + End Property + public Default Property M(s As String) + Get + throw DirectCast(Nothing, System.Exception) + End Get + Set + throw DirectCast(Nothing, System.Exception) + End Set + End Property +End Class +" + + Dim comp2 = CreateCompilation({source2, OverloadResolutionPriorityAttributeDefinitionVB}, references:={comp1_1.ToMetadataReference()}, options:=TestOptions.DebugDll) + comp2.VerifyDiagnostics() + + Dim source3 = " +public class Program + Shared Sub Main + Dim c = new C() + Dim x = c(""test"") + c(""test"") = new RetValue() + End Sub +End Class +" + + Dim comp3 = CreateCompilation(source3, references:={comp2.ToMetadataReference(), comp1_2.ToMetadataReference()}, options:=TestOptions.DebugExe) + Dim c = comp3.GetTypeByMetadataName("C") + Dim ms = c.GetMembers("M").Cast(Of PropertySymbol)().ToArray() + Assert.Equal(2, ms.Length) + Assert.All(ms, Function(m) Assert.IsType(Of RetargetingPropertySymbol)(m)) + AssertEx.Equal("Property C.M(o As System.Object) As RetValue", ms(0).ToTestDisplayString()) + Assert.Equal(1, ms(0).OverloadResolutionPriority) + AssertEx.Equal("Property C.M(s As System.String) As System.Object", ms(1).ToTestDisplayString()) + Assert.Equal(0, ms(1).OverloadResolutionPriority) + + comp3.VerifyDiagnostics() + End Sub + + + Public Sub AppliedToAttributeConstructors() + + Dim source = " +Imports System.Runtime.CompilerServices + + +public class C + Inherits System.Attribute + + + public Sub New(o As object) + End Sub + + public Sub New(s As string) + End Sub +End Class +" + + Dim compilation = CreateCompilation({source, OverloadResolutionPriorityAttributeDefinitionVB}, options:=TestOptions.DebugDll) + CompileAndVerify(compilation).VerifyDiagnostics() + + Dim c = compilation.GetTypeByMetadataName("C") + + Dim attr = c.GetAttributes().Single() + AssertEx.Equal("Sub C..ctor(o As System.Object)", attr.AttributeConstructor.ToTestDisplayString()) + End Sub + + + Public Sub CycleOnOverloadResolutionPriorityConstructor_01() + + Dim source = " +namespace System.Runtime.CompilerServices + + public class OverloadResolutionPriorityAttribute + Inherits Attribute + + + Public Sub New(priority As Integer) + Me.Priority = priority + End Sub + + public Readonly Property Priority As Integer + End Class +End Namespace +" + + Dim compilation = CreateCompilation(source, options:=TestOptions.DebugDll) + CompileAndVerify(compilation).VerifyDiagnostics() + End Sub + + + + + Public Sub CycleOnOverloadResolutionPriorityConstructor_02(ctorToForce As Integer) + + Dim source = " +Imports System.Runtime.CompilerServices + +namespace System.Runtime.CompilerServices + + public class OverloadResolutionPriorityAttribute + Inherits Attribute + + Public Sub New(priority As Integer) + Me.Priority = priority + End Sub + + ' Attribute is intentionally ignored, as this will cause a cycle + + Public Sub New(priority As Object) + Me.Priority = priority + End Sub + + public Readonly Property Priority As Integer + End Class +End Namespace + +public interface I1 +End Interface +public interface I2 +End Interface +public interface I3 + Inherits I1, I2 +End Interface + +public Module Program + + + + Sub M(this As I1) + System.Console.WriteLine(1) + End Sub + + + Sub M(this As I2) + throw DirectCast(Nothing, System.Exception) + End Sub + + Sub Main + Dim i3 As I3 = Nothing + i3.M() + End Sub +End Module +" + + Dim compilation = CreateCompilation(source, options:=TestOptions.DebugExe) + compilation.AssertTheseEmitDiagnostics( + +BC30521: Overload resolution failed because no accessible 'M' is most specific for these arguments: + Extension method 'Public Sub M()' defined in 'Program': Not most specific. + Extension method 'Public Sub M()' defined in 'Program': Not most specific. + i3.M() + ~ + + ) + + compilation = CreateCompilation(source, options:=TestOptions.DebugExe) + Dim ctors = compilation.GetTypeByMetadataName("System.Runtime.CompilerServices.OverloadResolutionPriorityAttribute").Constructors + Dim ctor = ctors(1) + AssertEx.Equal("Sub System.Runtime.CompilerServices.OverloadResolutionPriorityAttribute..ctor(priority As System.Object)", ctor.ToTestDisplayString()) + + ctors(ctorToForce).GetAttributes() + compilation.AssertTheseEmitDiagnostics( + +BC30521: Overload resolution failed because no accessible 'M' is most specific for these arguments: + Extension method 'Public Sub M()' defined in 'Program': Not most specific. + Extension method 'Public Sub M()' defined in 'Program': Not most specific. + i3.M() + ~ + + ) + + Assert.Equal(1, ctor.OverloadResolutionPriority) + AssertEx.Equal("Sub System.Runtime.CompilerServices.OverloadResolutionPriorityAttribute..ctor(priority As System.Int32)", ctor.GetAttributes().Single().AttributeConstructor.ToTestDisplayString()) + + Dim m = compilation.GetTypeByMetadataName("Program").GetMembers("M").OfType(Of MethodSymbol)().First() + Assert.Equal(0, m.OverloadResolutionPriority) + AssertEx.Equal("Sub System.Runtime.CompilerServices.OverloadResolutionPriorityAttribute..ctor(priority As System.Object)", m.GetAttributes().First().AttributeConstructor.ToTestDisplayString()) + End Sub + + + Public Sub CycleOnOverloadResolutionPriorityConstructor_04() + + Dim source = " +Imports System.Runtime.CompilerServices + +namespace System.Runtime.CompilerServices + + public class OverloadResolutionPriorityAttribute + Inherits Attribute + + + Public Sub New(priority As Integer) + Me.Priority = priority + End Sub + + public Readonly Property Priority As Integer + End Class +End Namespace + +public class OtherAttribute + Inherits System.Attribute + + + Public Sub New() + End Sub +End Class +" + + Dim compilation = CreateCompilation(source, options:=TestOptions.DebugDll) + CompileAndVerify(compilation).VerifyDiagnostics() + End Sub + + + Public Sub CycleOnOverloadResolutionPriorityConstructor_05() + + Dim source = " +Imports System.Runtime.CompilerServices + +namespace System.Runtime.CompilerServices + + public class OverloadResolutionPriorityAttribute + Inherits Attribute + + + Public Sub New(priority As Integer) + Me.Priority = priority + End Sub + + public Readonly Property Priority As Integer + End Class +End Namespace + +Namespace System + public class ObsoleteAttribute + Inherits System.Attribute + + + Public Sub New() + End Sub + End Class +End Namespace +" + + Dim compilation = CreateCompilation(source, options:=TestOptions.DebugDll) + CompileAndVerify(compilation).Diagnostics.AssertTheseDiagnostics( + + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +]]> + ) + End Sub + + + + + Public Sub CycleOnOverloadResolutionPriorityConstructor_06(ctorToForce As Integer) + + Dim source = " +Imports System.Runtime.CompilerServices + +namespace System.Runtime.CompilerServices + + public class OverloadResolutionPriorityAttribute + Inherits Attribute + + Public Sub New(priority As Integer) + Me.Priority = priority + End Sub + + ' Attribute is intentionally ignored, as this will cause a cycle + + Public Sub New(priority As SByte) + Me.Priority = priority + End Sub + + public Readonly Property Priority As Integer + End Class +End Namespace + +public interface I1 +End Interface +public interface I2 +End Interface +public interface I3 + Inherits I1, I2 +End Interface + +public Module Program + + + + Sub M(this As I1) + System.Console.WriteLine(1) + End Sub + + + Sub M(this As I2) + throw DirectCast(Nothing, System.Exception) + End Sub + + Sub Main + Dim i3 As I3 = Nothing + i3.M() + End Sub +End Module +" + + Dim compilation = CreateCompilation(source, options:=TestOptions.DebugExe) + CompileAndVerify(compilation, expectedOutput:="1").VerifyDiagnostics() + + compilation = CreateCompilation(source, options:=TestOptions.DebugExe) + Dim ctors = compilation.GetTypeByMetadataName("System.Runtime.CompilerServices.OverloadResolutionPriorityAttribute").Constructors + Dim ctor = ctors(1) + AssertEx.Equal("Sub System.Runtime.CompilerServices.OverloadResolutionPriorityAttribute..ctor(priority As System.SByte)", ctor.ToTestDisplayString()) + + ctors(ctorToForce).GetAttributes() + CompileAndVerify(compilation, expectedOutput:="1").VerifyDiagnostics() + + Assert.Equal(0, ctor.OverloadResolutionPriority) + AssertEx.Equal("Sub System.Runtime.CompilerServices.OverloadResolutionPriorityAttribute..ctor(priority As System.SByte)", ctor.GetAttributes().Single().AttributeConstructor.ToTestDisplayString()) + + Dim m = compilation.GetTypeByMetadataName("Program").GetMembers("M").OfType(Of MethodSymbol)().First() + Assert.Equal(1, m.OverloadResolutionPriority) + AssertEx.Equal("Sub System.Runtime.CompilerServices.OverloadResolutionPriorityAttribute..ctor(priority As System.Int32)", m.GetAttributes().First().AttributeConstructor.ToTestDisplayString()) + End Sub + + + Public Sub CycleOnOverloadResolutionPriorityConstructor_07() + + Dim source = " +Imports System.Runtime.CompilerServices + +Namespace System + public class ObsoleteAttribute + Inherits System.Attribute + + Public Sub New(x As String) + End Sub + + + Public Sub New(x As String, Optional y As Boolean = False) + End Sub + + End Class +End Namespace + + +Class C +End Class + +Class D + Dim x As C +End Class +" + + Dim compilation = CreateCompilation({source, OverloadResolutionPriorityAttributeDefinitionVB}, options:=TestOptions.DebugDll) + Dim verifier = CompileAndVerify( + compilation, + symbolValidator:=Sub(m) + AssertEx.Equal("Sub System.ObsoleteAttribute..ctor(x As System.String, [y As System.Boolean = False])", + m.ContainingAssembly.GetTypeByMetadataName("C").GetAttributes.Single().AttributeConstructor.ToTestDisplayString()) + End Sub) + + verifier.Diagnostics.AssertTheseDiagnostics( + + ) + End Sub + + + Public Sub CycleOnOverloadResolutionPriorityConstructor_08() + + Dim source = " +Imports System.Runtime.CompilerServices + +Namespace System + public class ObsoleteAttribute + Inherits System.Attribute + + Public Sub New(x As String) + End Sub + + + Public Sub New(x As String, Optional y As Boolean = True) + End Sub + + End Class +End Namespace + + +Class C +End Class + +Class D + Dim x As C +End Class +" + + Dim compilation = CreateCompilation({source, OverloadResolutionPriorityAttributeDefinitionVB}, options:=TestOptions.DebugDll) + AssertEx.Equal("Sub System.ObsoleteAttribute..ctor(x As System.String, [y As System.Boolean = True])", + compilation.GetTypeByMetadataName("C").GetAttributes.Single().AttributeConstructor.ToTestDisplayString()) + + compilation.AssertTheseDiagnostics( + + ) + End Sub + + + Public Sub OverloadResolutionAppliedToIndexers(i1First As Boolean) + + Dim i1Source = " + +public Default Property Item(x As I1) As Integer + Get + System.Console.Write(1) + Return 0 + End Get + Set + System.Console.Write(2) + End Set +End Property +" + + Dim i2Source = " +public Default Property Item(x As I2) As Integer + Get + throw DirectCast(Nothing, System.Exception) + End Get + Set + throw DirectCast(Nothing, System.Exception) + End Set +End Property +" + + Dim reference = " +Imports System.Runtime.CompilerServices + +public interface I1 +End Interface +public interface I2 +End Interface +public interface I3 + Inherits I1, I2 +End Interface + +public class C" + + If(i1First, i1Source, i2Source) + + If(i1First, i2Source, i1Source) + " +End Class +" + + Dim source = " +public class Program + Shared Sub Main + Dim c = new C() + Dim i3 As I3 = Nothing + Dim x = c(i3) + c(i3) = 0 + End Sub +End Class +" + + Dim comp1 = CreateCompilation({source, reference, OverloadResolutionPriorityAttributeDefinitionVB}, options:=TestOptions.DebugExe) + + Dim validate = Sub([module] As ModuleSymbol) + Dim c = [module].ContainingAssembly.GetTypeByMetadataName("C") + Dim ms = c.GetMembers("Item").Cast(Of PropertySymbol)() + For Each m In ms + Assert.Equal(If(m.Parameters(0).Type.Name = "I1", 1, 0), m.OverloadResolutionPriority) + Next + End Sub + + CompileAndVerify(comp1, expectedOutput:="12", sourceSymbolValidator:=validate, symbolValidator:=validate).VerifyDiagnostics() + + Dim compilationReference As CompilationReference = comp1.ToMetadataReference() + Dim comp2 = CreateCompilation(source, references:={compilationReference}, options:=TestOptions.DebugExe) + CompileAndVerify(comp2, expectedOutput:="12").VerifyDiagnostics() + + Dim metadataReference As MetadataReference = comp1.EmitToImageReference() + Dim comp3 = CreateCompilation(source, references:={metadataReference}, options:=TestOptions.DebugExe) + CompileAndVerify(comp3, expectedOutput:="12").VerifyDiagnostics() + + comp1 = CreateCompilation({source, reference, OverloadResolutionPriorityAttributeDefinitionVB}, options:=TestOptions.DebugExe, parseOptions:=TestOptions.Regular17_13) + CompileAndVerify(comp1, expectedOutput:="12", sourceSymbolValidator:=validate, symbolValidator:=validate).VerifyDiagnostics() + + comp1 = CreateCompilation({source, reference, OverloadResolutionPriorityAttributeDefinitionVB}, options:=TestOptions.DebugExe, parseOptions:=TestOptions.Regular16_9) + comp1.AssertTheseDiagnostics(If(i1First, + + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +]]>, + + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +]]>)) + + comp2 = CreateCompilation(source, references:={compilationReference}, options:=TestOptions.DebugExe, parseOptions:=TestOptions.Regular16_9) + Dim expected = If(i1First, + +BC30521: Overload resolution failed because no accessible 'Item' is most specific for these arguments: + 'Public Default Property Item(x As I1) As Integer': Not most specific. + 'Public Default Property Item(x As I2) As Integer': Not most specific. + Dim x = c(i3) + ~ +BC30521: Overload resolution failed because no accessible 'Item' is most specific for these arguments: + 'Public Default Property Item(x As I1) As Integer': Not most specific. + 'Public Default Property Item(x As I2) As Integer': Not most specific. + c(i3) = 0 + ~ +, + +BC30521: Overload resolution failed because no accessible 'Item' is most specific for these arguments: + 'Public Default Property Item(x As I2) As Integer': Not most specific. + 'Public Default Property Item(x As I1) As Integer': Not most specific. + Dim x = c(i3) + ~ +BC30521: Overload resolution failed because no accessible 'Item' is most specific for these arguments: + 'Public Default Property Item(x As I2) As Integer': Not most specific. + 'Public Default Property Item(x As I1) As Integer': Not most specific. + c(i3) = 0 + ~ +) + + comp2.AssertTheseDiagnostics(expected) + + comp3 = CreateCompilation(source, references:={metadataReference}, options:=TestOptions.DebugExe, parseOptions:=TestOptions.Regular16_9) + comp3.AssertTheseDiagnostics(expected) + End Sub + + + Public Sub NoImpactToFunctionType() + + Dim source = " +Option Infer On + +Imports System.Runtime.CompilerServices + +Class C + + Shared Sub Main() + Dim x = AddressOf M1 + End Sub + + + Shared Sub M1(x As Integer) + End Sub + + Shared Sub M1(x As String) + End Sub +End Class +" + + Dim compilation = CreateCompilation({source, OverloadResolutionPriorityAttributeDefinitionVB}, options:=TestOptions.DebugDll) + compilation.AssertTheseDiagnostics( + + ) + End Sub + + + Public Sub DelegateConversion() + + Dim source1 = " +Imports System.Runtime.CompilerServices + +Public Class C + + + Shared Sub M(x As Object) + System.Console.Write(1) + End Sub + + Shared Sub M(x As String) + throw DirectCast(Nothing, System.Exception) + End Sub +End Class +" + Dim source2 = " +Module Program + Sub Main() + Dim a As System.Action(Of string) = AddressOf C.M + a(Nothing) + End Sub +End Module +" + + Dim comp1 = CreateCompilation({source1, source2, OverloadResolutionPriorityAttributeDefinitionVB}, options:=TestOptions.DebugExe) + CompileAndVerify(comp1, expectedOutput:="1").VerifyDiagnostics() + + Dim comp2 = CreateCompilation(source2, references:={comp1.ToMetadataReference()}, options:=TestOptions.DebugExe) + CompileAndVerify(comp2, expectedOutput:="1").VerifyDiagnostics() + + Dim comp3 = CreateCompilation(source2, references:={comp1.EmitToImageReference()}, options:=TestOptions.DebugExe) + CompileAndVerify(comp3, expectedOutput:="1").VerifyDiagnostics() + End Sub + + + Public Sub Interface_DifferentPriorities_Methods() + + Dim source1 = " +Imports System.Runtime.CompilerServices + +public interface I1 +End Interface +public interface I2 +End Interface +public interface I3 + Inherits I1, I2 +End Interface + +Public Interface I + + Sub M(x As I1) + Sub M(x As I2) +End Interface + +Public Class C + Implements I + + public Sub M(x As I1) Implements I.M + System.Console.Write(1) + End Sub + + + public Sub M(x As I2) Implements I.M + System.Console.Write(2) + End Sub +End Class +" + Dim source2 = " +Module Program + Sub Main() + Dim c = new C() + Dim i3 As I3 = Nothing + c.M(i3) + DirectCast(c, I).M(i3) + End Sub +End Module +" + + Dim comp1 = CreateCompilation({source1, source2, OverloadResolutionPriorityAttributeDefinitionVB}, options:=TestOptions.DebugExe) + CompileAndVerify(comp1, expectedOutput:="21").VerifyDiagnostics() + + Dim comp2 = CreateCompilation(source2, references:={comp1.ToMetadataReference()}, options:=TestOptions.DebugExe) + CompileAndVerify(comp2, expectedOutput:="21").VerifyDiagnostics() + + Dim comp3 = CreateCompilation(source2, references:={comp1.EmitToImageReference()}, options:=TestOptions.DebugExe) + CompileAndVerify(comp3, expectedOutput:="21").VerifyDiagnostics() + End Sub + + + Public Sub Interface_DifferentPriorities_Indexers() + + Dim source1 = " +Imports System.Runtime.CompilerServices + +public interface I1 +End Interface +public interface I2 +End Interface +public interface I3 + Inherits I1, I2 +End Interface + +Public Interface I + + Default Property Item(x As I1) As Integer + Default Property Item(x As I2) As Integer +End Interface + +Public Class C + Implements I + + Default Property Item(x As I1) As Integer Implements I.Item + Get + System.Console.Write(1) + return 0 + End Get + Set + System.Console.Write(2) + End Set + End Property + + Default Property Item(x As I2) As Integer Implements I.Item + Get + System.Console.Write(3) + return 0 + End Get + Set + System.Console.Write(4) + End Set + End Property +End Class +" + Dim source2 = " +Module Program + Sub Main() + Dim c = new C() + Dim i3 As I3 = Nothing + + c(I3) = 1 + Dim x = c(i3) + c.Item(I3) = 1 + x = c.Item(i3) + + Dim i As I = DirectCast(c, I) + i(I3) = 1 + x = i(i3) + i.Item(I3) = 1 + x = i.Item(i3) + End Sub +End Module +" + + Dim comp1 = CreateCompilation({source1, source2, OverloadResolutionPriorityAttributeDefinitionVB}, options:=TestOptions.DebugExe) + CompileAndVerify(comp1, expectedOutput:="43432121").VerifyDiagnostics() + + Dim comp2 = CreateCompilation(source2, references:={comp1.ToMetadataReference()}, options:=TestOptions.DebugExe) + CompileAndVerify(comp2, expectedOutput:="43432121").VerifyDiagnostics() + + Dim comp3 = CreateCompilation(source2, references:={comp1.EmitToImageReference()}, options:=TestOptions.DebugExe) + CompileAndVerify(comp3, expectedOutput:="43432121").VerifyDiagnostics() + End Sub + + + Public Sub AppliedToIndexerGetterSetter_Source() + + Dim source = " +Imports System.Runtime.CompilerServices + +Public Class C + + Default Property Item(x As Integer) As Integer + + Get + throw DirectCast(Nothing, System.Exception) + End Get + + Set + throw DirectCast(Nothing, System.Exception) + End Set + End Property +End Class +" + + Dim comp = CreateCompilation({source, OverloadResolutionPriorityAttributeDefinitionVB}, options:=TestOptions.DebugDll) + + Dim c = comp.GetTypeByMetadataName("C") + Dim indexer = c.GetMember(Of PropertySymbol)("Item") + + Assert.Equal(0, indexer.OverloadResolutionPriority) + Assert.Equal(0, indexer.GetMethod.OverloadResolutionPriority) + Assert.Equal(0, indexer.SetMethod.OverloadResolutionPriority) + + comp.AssertTheseDiagnostics( + + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +BC37334: Cannot use 'OverloadResolutionPriorityAttribute' on this member. + + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +]]>) + End Sub + + + Public Sub AppliedToIndexerGetterSetter_Metadata() + + ' Equivalent to: + ' public class C + ' { + ' public int this[object x] + ' { + ' [System.Runtime.CompilerServices.OverloadResolutionPriority(1)] + ' get => throw null; + ' [System.Runtime.CompilerServices.OverloadResolutionPriority(1)] + ' set => throw null; + ' } + ' public int this[string x] + ' { + ' get { System.Console.Write(1); return 1; } + ' set => System.Console.Write(2); + ' } + ' } + Dim il = " +.class public auto ansi beforefieldinit C + extends [mscorlib]System.Object +{ + .custom instance void [mscorlib]System.Reflection.DefaultMemberAttribute::.ctor(string) = ( + 01 00 04 49 74 65 6d 00 00 + ) + // Methods + .method public hidebysig specialname + instance int32 get_Item ( + object x + ) cil managed + { + .custom instance void System.Runtime.CompilerServices.OverloadResolutionPriorityAttribute::.ctor(int32) = ( + 01 00 01 00 00 00 00 00 + ) + ldnull + throw + } // end of method C::get_Item + + .method public hidebysig specialname + instance void set_Item ( + object x, + int32 'value' + ) cil managed + { + .custom instance void System.Runtime.CompilerServices.OverloadResolutionPriorityAttribute::.ctor(int32) = ( + 01 00 01 00 00 00 00 00 + ) + ldnull + throw + } // end of method C::set_Item + + .method public hidebysig specialname + instance int32 get_Item ( + string x + ) cil managed + { + ldc.i4.1 + call void [mscorlib]System.Console::Write(int32) + ldc.i4.1 + ret + } // end of method C::get_Item + + .method public hidebysig specialname + instance void set_Item ( + string x, + int32 'value' + ) cil managed + { + ldc.i4.2 + call void [mscorlib]System.Console::Write(int32) + ret + } // end of method C::set_Item + + .method public hidebysig specialname rtspecialname + instance void .ctor () cil managed + { + ldarg.0 + call instance void [mscorlib]System.Object::.ctor() + ret + } // end of method C::.ctor + + // Properties + .property instance int32 Item( + object x + ) + { + .get instance int32 C::get_Item(object) + .set instance void C::set_Item(object, int32) + } + .property instance int32 Item( + string x + ) + { + .get instance int32 C::get_Item(string) + .set instance void C::set_Item(string, int32) + } +} +" + + Dim ilRef = CompileIL(il + OverloadResolutionPriorityAttributeILDefinition) + + Dim source = " +public class Program + Shared Sub Main + Dim c = new C() + Dim x = c(""test"") + c(""test"") = 0 + End Sub +End Class +" + Dim comp = CreateCompilation(source, references:={ilRef}, options:=TestOptions.DebugExe) + + CompileAndVerify(comp, expectedOutput:="12").VerifyDiagnostics() + + Dim c = comp.GetTypeByMetadataName("C") + Dim indexers = c.GetMembers("Item").OfType(Of PropertySymbol)().ToArray() + + Assert.Equal(2, indexers.Length) + + Dim indexer = indexers(0) + AssertEx.Equal("Property C.Item(x As System.Object) As System.Int32", indexer.ToTestDisplayString()) + Assert.Equal(0, indexer.OverloadResolutionPriority) + Assert.Equal(0, indexer.GetMethod.OverloadResolutionPriority) + Assert.Equal(0, indexer.SetMethod.OverloadResolutionPriority) + + indexer = indexers(1) + AssertEx.Equal("Property C.Item(x As System.String) As System.Int32", indexer.ToTestDisplayString()) + Assert.Equal(0, indexer.OverloadResolutionPriority) + Assert.Equal(0, indexer.GetMethod.OverloadResolutionPriority) + Assert.Equal(0, indexer.SetMethod.OverloadResolutionPriority) + End Sub + + + Public Sub AppliedToPropertyGetterSetter() + + Dim source = " +Imports System.Runtime.CompilerServices + +Public Class C + + Property Prop As Integer + + Get + throw DirectCast(Nothing, System.Exception) + End Get + + Set + throw DirectCast(Nothing, System.Exception) + End Set + End Property +End Class +" + + Dim comp = CreateCompilation({source, OverloadResolutionPriorityAttributeDefinitionVB}, options:=TestOptions.DebugDll) + + Dim c = comp.GetTypeByMetadataName("C") + Dim indexer = c.GetMember(Of PropertySymbol)("Prop") + + Assert.Equal(0, indexer.OverloadResolutionPriority) + Assert.Equal(0, indexer.GetMethod.OverloadResolutionPriority) + Assert.Equal(0, indexer.SetMethod.OverloadResolutionPriority) + + comp.AssertTheseDiagnostics( + + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +BC37334: Cannot use 'OverloadResolutionPriorityAttribute' on this member. + + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +]]>) + End Sub + + + Public Sub AppliedToEventGetterSetter() + + Dim source = " +Imports System.Runtime.CompilerServices + +Public Class C + + Custom Event Prop As System.Action + + AddHandler(x as System.Action) + End AddHandler + + RemoveHandler(x as System.Action) + End RemoveHandler + + RaiseEvent() + End RaiseEvent + End Event +End Class +" + + Dim comp = CreateCompilation({source, OverloadResolutionPriorityAttributeDefinitionVB}, options:=TestOptions.DebugDll.WithMetadataImportOptions(MetadataImportOptions.All)) + + Dim c = comp.GetTypeByMetadataName("C") + Dim indexer = c.GetMember(Of EventSymbol)("Prop") + + Assert.Equal(0, indexer.AddMethod.OverloadResolutionPriority) + Assert.Equal(0, indexer.RemoveMethod.OverloadResolutionPriority) + Assert.Equal(0, indexer.RaiseMethod.OverloadResolutionPriority) + + comp.AssertTheseDiagnostics( + + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +BC37334: Cannot use 'OverloadResolutionPriorityAttribute' on this member. + + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +BC37334: Cannot use 'OverloadResolutionPriorityAttribute' on this member. + + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +]]>) + End Sub + + + Public Sub Dynamic() + + Dim source1 = " +Imports System.Runtime.CompilerServices + +Public Class C + + + Sub M(o As Long) + throw DirectCast(Nothing, System.Exception) + End Sub + + Sub M(s As String) + System.Console.Write(2) + End Sub + + + Default Property Item(x As Long) As Integer + Get + throw DirectCast(Nothing, System.Exception) + End Get + Set + throw DirectCast(Nothing, System.Exception) + End Set + End Property + + Default Property Item(x As String) As Integer + Get + System.Console.Write(3) + Return 0 + End Get + Set + System.Console.Write(4) + End Set + End Property +End Class +" + + Dim source2 = " +Option Strict Off + +public class Program + Shared Sub Main + Dim arg As Object = ""test"" + Dim c = new C() + c.M(arg) + Dim x = c(arg) + c(arg) = 0 + End Sub +End Class +" + + Dim comp = CreateCompilation({source2, source1, OverloadResolutionPriorityAttributeDefinitionVB}, options:=TestOptions.DebugExe) + CompileAndVerify(comp, expectedOutput:="234").VerifyDiagnostics() + + Dim comp1 = CreateCompilation({source1, OverloadResolutionPriorityAttributeDefinitionVB}, options:=TestOptions.DebugDll) + + Dim comp2 = CreateCompilation(source2, references:={comp1.ToMetadataReference()}, options:=TestOptions.DebugExe) + CompileAndVerify(comp2, expectedOutput:="234").VerifyDiagnostics() + + Dim comp3 = CreateCompilation(source2, references:={comp1.EmitToImageReference()}, options:=TestOptions.DebugExe) + CompileAndVerify(comp3, expectedOutput:="234").VerifyDiagnostics() + End Sub + + + Public Sub Destructor() + + Dim source = " +Imports System.Runtime.CompilerServices + +Public Class C + + Protected Overrides Sub Finalize() + End Sub +End Class +" + + Dim comp = CreateCompilation({source, OverloadResolutionPriorityAttributeDefinitionVB}, options:=TestOptions.DebugDll) + + comp.AssertTheseDiagnostics( + + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +]]>) + End Sub + + + Public Sub BinaryOperators_SameType() + + Dim source1 = " +Imports System.Runtime.CompilerServices + +public interface I1 +End Interface +public interface I2 +End Interface +public interface I3 + Inherits I1, I2 +End Interface + +Public Class C + + + Shared Operator + (c As C, i As I1) As C + System.Console.Write(1) + return c + End Operator + + Shared Operator + (c As C, i As I2) As C + throw DirectCast(Nothing, System.Exception) + End Operator +End Class +" + + Dim source2 = " +Option Strict Off + +public class Program + Shared Sub Main + Dim c = new C() + Dim i3 As I3 = Nothing + Dim x = c + i3 + End Sub +End Class +" + + Dim comp = CreateCompilation({source2, source1, OverloadResolutionPriorityAttributeDefinitionVB}, options:=TestOptions.DebugExe) + CompileAndVerify(comp, expectedOutput:="1").VerifyDiagnostics() + + Dim comp1 = CreateCompilation({source1, OverloadResolutionPriorityAttributeDefinitionVB}, options:=TestOptions.DebugDll) + + Dim comp2 = CreateCompilation(source2, references:={comp1.ToMetadataReference()}, options:=TestOptions.DebugExe) + CompileAndVerify(comp2, expectedOutput:="1").VerifyDiagnostics() + + Dim comp3 = CreateCompilation(source2, references:={comp1.EmitToImageReference()}, options:=TestOptions.DebugExe) + CompileAndVerify(comp3, expectedOutput:="1").VerifyDiagnostics() + End Sub + + + Public Sub BinaryOperators_DifferentType() + + Dim source1 = " +Imports System.Runtime.CompilerServices + +public interface I1 +End Interface +public interface I2 +End Interface +public interface I3 + Inherits I1, I2 +End Interface + +Public Class C1 + + Shared Operator + (c1 As C1, c2 As C2) As C1 + throw DirectCast(Nothing, System.Exception) + End Operator +End Class + +Public Class C2 + Shared Operator + (c1 As C1, c2 As C2) As C2 + throw DirectCast(Nothing, System.Exception) + End Operator +End Class +" + + Dim source2 = " +Option Strict Off + +public class Program + Shared Sub Main + Dim c1 = new C1() + Dim c2 = new C2() + Dim x = c1 + c2 + End Sub +End Class +" + + Dim comp = CreateCompilation({source2, source1, OverloadResolutionPriorityAttributeDefinitionVB}, options:=TestOptions.DebugExe) + Dim errs As XElement = + +BC30521: Overload resolution failed because no accessible '+' is most specific for these arguments: + 'Public Shared Operator C1.+(c1 As C1, c2 As C2) As C1': Not most specific. + 'Public Shared Operator C2.+(c1 As C1, c2 As C2) As C2': Not most specific. + Dim x = c1 + c2 + ~~~~~~~ + + comp.AssertTheseDiagnostics(errs) + + Dim comp1 = CreateCompilation({source1, OverloadResolutionPriorityAttributeDefinitionVB}, options:=TestOptions.DebugDll) + + Dim comp2 = CreateCompilation(source2, references:={comp1.ToMetadataReference()}, options:=TestOptions.DebugExe) + comp2.AssertTheseDiagnostics(errs) + + Dim comp3 = CreateCompilation(source2, references:={comp1.EmitToImageReference()}, options:=TestOptions.DebugExe) + comp3.AssertTheseDiagnostics(errs) + End Sub + + + Public Sub DisallowedOnStaticCtors() + + Dim source = " +Imports System.Runtime.CompilerServices + +Public Class C + + Shared Sub New() + End Sub +End Class +" + + Dim comp = CreateCompilation({source, OverloadResolutionPriorityAttributeDefinitionVB}, options:=TestOptions.DebugDll) + + comp.AssertTheseDiagnostics( + + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +]]>) + End Sub + + + ", "")> + ")> + Public Sub PartialMethod(definitionPriority As String, implementationPriority As String) + + Dim definition = " +Public Partial Class C + + " + definitionPriority + " + Private Partial Sub M(x As Object) + End Sub +End Class +" + + Dim implementation = " +Public Partial Class C + + " + implementationPriority + " + Private Sub M(x As Object) + System.Console.Write(1) + End Sub + + Sub M(x As String) + throw DirectCast(Nothing, System.Exception) + End Sub +End Class +" + + Dim source2 = " +Partial Class C + Shared Sub Main() + Dim c = new C() + c.M("""") + End Sub +End Class +" + + Dim comp1 = CreateCompilation({source2, definition, implementation, OverloadResolutionPriorityAttributeDefinitionVB}, options:=TestOptions.DebugExe) + CompileAndVerify(comp1, expectedOutput:="1").VerifyDiagnostics() + End Sub + + + Public Sub AttributeAppliedTwiceMethod_Source() + + Dim source = " +Imports System.Runtime.CompilerServices + +Class C + + + Shared Sub M(x As Object) + End Sub + + Shared Sub M(x As String) + End Sub +End Class +" + + Dim compilation = CreateCompilation({source, OverloadResolutionPriorityAttributeDefinitionVB}, options:=TestOptions.DebugDll) + compilation.AssertTheseDiagnostics( + + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +]]> + ) + + Dim m = compilation.GetTypeByMetadataName("C").GetMembers("M").OfType(Of MethodSymbol)().First() + Assert.Equal("Sub C.M(x As System.Object)", m.ToTestDisplayString()) + Assert.Equal(2, m.OverloadResolutionPriority) + End Sub + + + Public Sub AttributeAppliedTwiceMethod_Metadata() + + ' Equivalent to: + ' public class C + ' { + ' [OverloadResolutionPriority(1)] + ' [OverloadResolutionPriority(2)] + ' public void M(object o) => System.Console.Write(1); + ' public void M(string s) => System.Console.Write(2); + ' } + Dim il = " +.class public auto ansi beforefieldinit C extends [mscorlib]System.Object +{ + .method public hidebysig + instance void M ( + object o + ) cil managed + { + .custom instance void System.Runtime.CompilerServices.OverloadResolutionPriorityAttribute::.ctor(int32) = ( + 01 00 01 00 00 00 00 00 + ) + .custom instance void System.Runtime.CompilerServices.OverloadResolutionPriorityAttribute::.ctor(int32) = ( + 01 00 02 00 00 00 00 00 + ) + ldc.i4.1 + call void [mscorlib]System.Console::Write(int32) + ret + } // end of method C::M + + .method public hidebysig + instance void M ( + string s + ) cil managed + { + ldc.i4.2 + call void [mscorlib]System.Console::Write(int32) + ret + } // end of method C::M + + .method public hidebysig specialname rtspecialname + instance void .ctor () cil managed + { + ldarg.0 + call instance void [mscorlib]System.Object::.ctor() + ret + } // end of method C::.ctor +} // end of class C +" + + Dim ilRef = CompileIL(il + OverloadResolutionPriorityAttributeILDefinition) + + Dim source = " +public class Program + Shared Sub Main + Dim c = new C() + c.M(""test"") + End Sub +End Class +" + Dim comp = CreateCompilation(source, references:={ilRef}, options:=TestOptions.DebugExe) + + CompileAndVerify(comp, expectedOutput:="1").VerifyDiagnostics() + + Dim m = comp.GetTypeByMetadataName("C").GetMembers("M").OfType(Of MethodSymbol)().First() + Assert.Equal("Sub C.M(o As System.Object)", m.ToTestDisplayString()) + Assert.Equal(2, m.OverloadResolutionPriority) + End Sub + + + Public Sub AttributeAppliedTwiceConstructor_Source() + + Dim source = " +Imports System.Runtime.CompilerServices + +Class C + + + Sub New(x As Object) + End Sub + + Sub New(x As String) + End Sub +End Class +" + + Dim compilation = CreateCompilation({source, OverloadResolutionPriorityAttributeDefinitionVB}, options:=TestOptions.DebugDll) + compilation.AssertTheseDiagnostics( + + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +]]> + ) + + Dim m = compilation.GetTypeByMetadataName("C").GetMembers(".ctor").OfType(Of MethodSymbol)().First() + Assert.Equal("Sub C..ctor(x As System.Object)", m.ToTestDisplayString()) + Assert.Equal(2, m.OverloadResolutionPriority) + End Sub + + + Public Sub AttributeAppliedTwiceConstructor_Metadata() + + ' Equivalent to: + ' public class C + ' { + ' [OverloadResolutionPriority(1)] + ' [OverloadResolutionPriority(2)] + ' public C(object o) {} + ' public C(string s) {} + ' } + Dim il = " +.class public auto ansi beforefieldinit C extends [mscorlib]System.Object +{ + .method public hidebysig specialname rtspecialname + instance void .ctor ( + object o + ) cil managed + { + .custom instance void System.Runtime.CompilerServices.OverloadResolutionPriorityAttribute::.ctor(int32) = ( + 01 00 01 00 00 00 00 00 + ) + .custom instance void System.Runtime.CompilerServices.OverloadResolutionPriorityAttribute::.ctor(int32) = ( + 01 00 02 00 00 00 00 00 + ) + ldarg.0 + call instance void [mscorlib]System.Object::.ctor() + ldc.i4.1 + call void [mscorlib]System.Console::Write(int32) + ret + } + + .method public hidebysig specialname rtspecialname + instance void .ctor ( + string s + ) cil managed + { + ldarg.0 + call instance void [mscorlib]System.Object::.ctor() + ldc.i4.2 + call void [mscorlib]System.Console::Write(int32) + ret + } // end of method C::.ctor +} // end of class C +" + + Dim ilRef = CompileIL(il + OverloadResolutionPriorityAttributeILDefinition) + + Dim source = " +public class Program + Shared Sub Main + Dim c = new C(""test"") + End Sub +End Class +" + Dim comp = CreateCompilation(source, references:={ilRef}, options:=TestOptions.DebugExe) + + CompileAndVerify(comp, expectedOutput:="1").VerifyDiagnostics() + + Dim m = comp.GetTypeByMetadataName("C").GetMembers(".ctor").OfType(Of MethodSymbol)().First() + Assert.Equal("Sub C..ctor(o As System.Object)", m.ToTestDisplayString()) + Assert.Equal(2, m.OverloadResolutionPriority) + End Sub + + + Public Sub AttributeAppliedTwiceIndexer_Source() + + Dim source = " +Imports System.Runtime.CompilerServices + +Class C + + + Default Property Item(x As Object) As Integer + Get + throw DirectCast(Nothing, System.Exception) + End Get + Set + throw DirectCast(Nothing, System.Exception) + End Set + End Property + + Default Property Item(x As String) As Integer + Get + throw DirectCast(Nothing, System.Exception) + End Get + Set + throw DirectCast(Nothing, System.Exception) + End Set + End Property +End Class +" + + Dim compilation = CreateCompilation({source, OverloadResolutionPriorityAttributeDefinitionVB}, options:=TestOptions.DebugDll) + compilation.AssertTheseDiagnostics( + + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +]]> + ) + + Dim m = compilation.GetTypeByMetadataName("C").GetMembers("Item").OfType(Of PropertySymbol)().First() + AssertEx.Equal("Property C.Item(x As System.Object) As System.Int32", m.ToTestDisplayString()) + Assert.Equal(2, m.OverloadResolutionPriority) + End Sub + + + Public Sub AttributeAppliedTwiceIndexer_Metadata() + + ' Equivalent to: + ' public class C + ' { + ' [OverloadResolutionPriority(1)] + ' [OverloadResolutionPriority(2)] + ' public int this[object o] + ' { + ' get => throw null; + ' set => throw null; + ' } + ' public int this[string o] + ' { + ' get => throw null; + ' set => throw null; + ' } + ' } + Dim il = " +.class public auto ansi beforefieldinit C extends [mscorlib]System.Object +{ + .custom instance void [mscorlib]System.Reflection.DefaultMemberAttribute::.ctor(string) = ( + 01 00 04 49 74 65 6d 00 00 + ) + // Methods + .method public hidebysig specialname + instance int32 get_Item ( + object o + ) cil managed + { + ldc.i4.1 + call void [mscorlib]System.Console::Write(int32) + ldc.i4.1 + ret + } // end of method C::get_Item + + .method public hidebysig specialname + instance void set_Item ( + object o, + int32 'value' + ) cil managed + { + ldc.i4.2 + call void [mscorlib]System.Console::Write(int32) + ret + } // end of method C::set_Item + + .method public hidebysig specialname + instance int32 get_Item ( + string o + ) cil managed + { + ldnull + throw + } // end of method C::get_Item + + .method public hidebysig specialname + instance void set_Item ( + string o, + int32 'value' + ) cil managed + { + ldnull + throw + } // end of method C::set_Item + + .method public hidebysig specialname rtspecialname + instance void .ctor () cil managed + { + ldarg.0 + call instance void [mscorlib]System.Object::.ctor() + ret + } // end of method C::.ctor + + // Properties + .property instance int32 Item( + object o + ) + { + .custom instance void System.Runtime.CompilerServices.OverloadResolutionPriorityAttribute::.ctor(int32) = ( + 01 00 01 00 00 00 00 00 + ) + .custom instance void System.Runtime.CompilerServices.OverloadResolutionPriorityAttribute::.ctor(int32) = ( + 01 00 02 00 00 00 00 00 + ) + .get instance int32 C::get_Item(object) + .set instance void C::set_Item(object, int32) + } + .property instance int32 Item( + string o + ) + { + .get instance int32 C::get_Item(string) + .set instance void C::set_Item(string, int32) + } + +} // end of class C +" + + Dim ilRef = CompileIL(il + OverloadResolutionPriorityAttributeILDefinition) + + Dim source = " +public class Program + Shared Sub Main + Dim c = new C() + Dim x = c(""test"") + c(""test"") = 0 + End Sub +End Class +" + Dim comp = CreateCompilation(source, references:={ilRef}, options:=TestOptions.DebugExe) + + CompileAndVerify(comp, expectedOutput:="12").VerifyDiagnostics() + + Dim m = comp.GetTypeByMetadataName("C").GetMembers("Item").OfType(Of PropertySymbol)().First() + AssertEx.Equal("Property C.Item(o As System.Object) As System.Int32", m.ToTestDisplayString()) + Assert.Equal(2, m.OverloadResolutionPriority) + End Sub + + + Public Sub HonoredInsideExpressionTree() + + Dim source = " +Imports System.Runtime.CompilerServices + +Class C + + Shared Sub M(x As Object) + System.Console.Write(1) + End Sub + + Shared Sub M(x As String) + throw DirectCast(Nothing, System.Exception) + End Sub +End Class + +public class Program + Shared Sub Main + Dim e As System.Linq.Expressions.Expression(Of System.Action) = Sub() C.M(""test"") + e.Compile()() + End Sub +End Class +" + + Dim comp = CreateCompilation({source, OverloadResolutionPriorityAttributeDefinitionVB}, options:=TestOptions.DebugExe) + + CompileAndVerify(comp, expectedOutput:="1").VerifyDiagnostics() + End Sub + + + Public Sub QuerySyntax() + + Dim source = " +Imports System +Imports System.Runtime.CompilerServices + +Class C + + Function [Select](Of T)(selector As Func(Of Integer, T)) As C + System.Console.Write(1) + Return Me + End Function + + Function [Select](selector As Func(Of Integer, Integer)) As C + throw DirectCast(Nothing, System.Exception) + End Function +End Class + +public class Program + Shared Sub Main + Dim c As New C() + Dim y = From x in c Select x + End Sub +End Class +" + + Dim comp = CreateCompilation({source, OverloadResolutionPriorityAttributeDefinitionVB}, options:=TestOptions.DebugExe) + CompileAndVerify(comp, expectedOutput:="1").VerifyDiagnostics() + End Sub + + + Public Sub ObjectInitializers() + + Dim source = " +Imports System +Imports System.Collections +Imports System.Collections.Generic +Imports System.Runtime.CompilerServices + +class C + Implements IEnumerable(Of Integer) + + private _list As New List(Of Integer) + + Sub Add(x As Integer) + throw DirectCast(Nothing, System.Exception) + End Sub + + + Sub Add(x As Integer, Optional y As Integer = 0) + _list.Add(x) + End Sub + + Function GetEnumerator() As IEnumerator(Of Integer) Implements IEnumerable(Of Integer).GetEnumerator + Return _list.GetEnumerator() + End Function + + Function IEnumerable_GetEnumerator() As IEnumerator Implements IEnumerable.GetEnumerator + Return Nothing + End Function +End Class + +class Program + Shared Sub Main() + Dim c As new C() from { 2 } + for each i in c + Console.Write(i) + Next + End Sub +End Class +" + + Dim comp = CreateCompilation({source, OverloadResolutionPriorityAttributeDefinitionVB}, options:=TestOptions.DebugExe) + CompileAndVerify(comp, expectedOutput:="2").VerifyDiagnostics() + End Sub + + + + + + + + + Public Sub ExtensionsOnlyFilteredByApplicability_01(methodOrder As Integer()) + + Dim e2Methods = "" + + For Each method In methodOrder + Select Case method + Case 1 + e2Methods += " + + +Sub R(x As Integer) + Console.WriteLine(""E2.R(int)"") +End Sub +" + Case 2 + e2Methods += " + +Sub R(x As String) + Console.WriteLine(""E2.R(string)"") +End Sub +" + Case 3 + e2Methods += " + +Sub R(x As Boolean) + Console.WriteLine(""E2.R(bool)"") +End Sub +" + Case Else + Throw ExceptionUtilities.Unreachable() + End Select + Next + + Dim source = $" +Imports System +Imports System.Runtime.CompilerServices + +class Program + Shared Sub Main() + Dim x As Integer = 5 + x.R() ' E1.R(int) + End Sub +End Class + +Module E1 + + Sub R(x As Integer) + Console.WriteLine(""E1.R(int)"") + End Sub +End Module + +Module E2 + {e2Methods} +End Module +" + + Dim comp = CreateCompilation({source, OverloadResolutionPriorityAttributeDefinitionVB}, options:=TestOptions.DebugExe) + comp.AssertTheseDiagnostics( + +BC30521: Overload resolution failed because no accessible 'R' is most specific for these arguments: + Extension method 'Public Sub R()' defined in 'E1': Not most specific. + Extension method 'Public Sub R()' defined in 'E2': Not most specific. + x.R() ' E1.R(int) + ~ +) + End Sub + + + + + + + + + Public Sub ExtensionsOnlyFilteredByApplicability_02(methodOrder As Integer()) + + Dim e2Methods = "" + + For Each method In methodOrder + Select Case method + Case 1 + e2Methods += " + + +Sub R(x As Integer) + Console.WriteLine(""E2.R(int)"") +End Sub +" + Case 2 + e2Methods += " + +Sub R(x As String) + Console.WriteLine(""E2.R(string)"") +End Sub +" + Case 3 + e2Methods += " + + +Sub R(x As Boolean) + Console.WriteLine(""E2.R(bool)"") +End Sub +" + Case Else + Throw ExceptionUtilities.Unreachable() + End Select + Next + + Dim source = $" +Imports System +Imports System.Runtime.CompilerServices + +class Program + Shared Sub Main() + Dim x As Integer = 5 + x.R() ' E1.R(int) + End Sub +End Class + +Module E1 + + Sub R(x As Integer) + Console.WriteLine(""E1.R(int)"") + End Sub +End Module + +Module E2 + {e2Methods} +End Module +" + + Dim comp = CreateCompilation({source, OverloadResolutionPriorityAttributeDefinitionVB}, options:=TestOptions.DebugExe) + comp.AssertTheseDiagnostics( + +BC30521: Overload resolution failed because no accessible 'R' is most specific for these arguments: + Extension method 'Public Sub R()' defined in 'E1': Not most specific. + Extension method 'Public Sub R()' defined in 'E2': Not most specific. + x.R() ' E1.R(int) + ~ +) + End Sub + + + + + + + + + Public Sub ExtensionsOnlyFilteredByApplicability_03(methodOrder As Integer()) + + Dim e2Methods = "" + + For Each method In methodOrder + Select Case method + Case 1 + e2Methods += " + + +Sub R(x As Integer) + Console.WriteLine(""E2.R(int)"") +End Sub +" + Case 2 + e2Methods += " + +Sub R(x As String) + Console.WriteLine(""E2.R(string)"") +End Sub +" + Case 3 + e2Methods += " + +Sub R(x As Object) + Console.WriteLine(""E2.R(object)"") +End Sub +" + Case Else + Throw ExceptionUtilities.Unreachable() + End Select + Next + + Dim source = $" +Imports System +Imports System.Runtime.CompilerServices + +class Program + Shared Sub Main() + Dim x As Integer = 5 + x.R() ' E1.R(int) + End Sub +End Class + +Module E1 + + Sub R(x As Integer) + Console.WriteLine(""E1.R(int)"") + End Sub +End Module + +Module E2 + {e2Methods} +End Module +" + + Dim comp = CreateCompilation({source, OverloadResolutionPriorityAttributeDefinitionVB}, options:=TestOptions.DebugExe) + CompileAndVerify(comp, expectedOutput:="E1.R(int)").VerifyDiagnostics() + End Sub + + End Class +End Namespace diff --git a/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/Source/EventTests.vb b/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/Source/EventTests.vb index 842d6e29869bc..8f8c6fb1c6722 100644 --- a/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/Source/EventTests.vb +++ b/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/Source/EventTests.vb @@ -2568,5 +2568,59 @@ BC30401: 'E1' cannot implement 'E1' because there is no matching event on interf Assert.Same(xSym, xSym.ContainingType.DelegateInvokeMethod.Parameters.First()) End Sub + + Public Sub CompilerLoweringPreserveAttribute_01() + Dim source1 = " +Imports System +Imports System.Runtime.CompilerServices + + + +Public Class Preserve1Attribute + Inherits Attribute +End Class + + + +Public Class Preserve2Attribute + Inherits Attribute +End Class + + +Public Class Preserve3Attribute + Inherits Attribute +End Class +" + Dim source2 = " +Class Test1 + + + + Event E1 As System.Action +End Class +" + + Dim validate = Sub(m As ModuleSymbol) + AssertEx.SequenceEqual( + { + "Preserve1Attribute", + "System.Runtime.CompilerServices.CompilerGeneratedAttribute", + "System.Diagnostics.DebuggerBrowsableAttribute(System.Diagnostics.DebuggerBrowsableState.Never)" + }, + m.GlobalNamespace.GetMember("Test1.E1Event").GetAttributes().Select(Function(a) a.ToString())) + End Sub + + Dim comp1 = CreateCompilation( + {source1, source2, CompilerLoweringPreserveAttributeDefinition}, + options:=TestOptions.DebugDll.WithMetadataImportOptions(MetadataImportOptions.All)) + CompileAndVerify(comp1, symbolValidator:=validate).VerifyDiagnostics() + + Dim comp2 = CreateCompilation([source2], references:={comp1.ToMetadataReference()}, options:=TestOptions.DebugDll.WithMetadataImportOptions(MetadataImportOptions.All)) + CompileAndVerify(comp2, symbolValidator:=validate).VerifyDiagnostics() + + Dim comp3 = CreateCompilation(source2, references:={comp1.EmitToImageReference()}, options:=TestOptions.DebugDll.WithMetadataImportOptions(MetadataImportOptions.All)) + CompileAndVerify(comp3, symbolValidator:=validate).VerifyDiagnostics() + End Sub + End Class End Namespace diff --git a/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/Source/PropertyTests.vb b/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/Source/PropertyTests.vb index 35d0e91e6d43d..fe4ef71fdc1f2 100644 --- a/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/Source/PropertyTests.vb +++ b/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/Source/PropertyTests.vb @@ -10,6 +10,7 @@ Imports Microsoft.CodeAnalysis.VisualBasic.Symbols.Metadata.PE Imports Microsoft.CodeAnalysis.VisualBasic.Symbols Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Imports Roslyn.Test.Utilities +Imports Microsoft.CodeAnalysis.VisualBasic.Symbols.Retargeting Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests @@ -8092,6 +8093,192 @@ End Class Diagnostic(ERRID.ERR_SynthMemberClashesWithMember5, "A").WithArguments("property", "A", "put_A", "class", "C")) End Sub + + Public Sub CompilerLoweringPreserveAttribute_01() + Dim source1 = " +Imports System +Imports System.Runtime.CompilerServices + + + +Public Class Preserve1Attribute + Inherits Attribute +End Class + + + +Public Class Preserve2Attribute + Inherits Attribute +End Class + + +Public Class Preserve3Attribute + Inherits Attribute +End Class +" + Dim source2 = " +Class Test1 + + + + Property P1 As Integer +End Class +" + + Dim validate = Sub(m As ModuleSymbol) + AssertEx.SequenceEqual( + { + "Preserve1Attribute", + "System.Runtime.CompilerServices.CompilerGeneratedAttribute", + "System.Diagnostics.DebuggerBrowsableAttribute(System.Diagnostics.DebuggerBrowsableState.Never)" + }, + m.GlobalNamespace.GetMember("Test1._P1").GetAttributes().Select(Function(a) a.ToString())) + End Sub + + Dim comp1 = CreateCompilation( + {source1, source2, CompilerLoweringPreserveAttributeDefinition}, + options:=TestOptions.DebugDll.WithMetadataImportOptions(MetadataImportOptions.All)) + CompileAndVerify(comp1, symbolValidator:=validate).VerifyDiagnostics() + + Dim comp2 = CreateCompilation([source2], references:={comp1.ToMetadataReference()}, options:=TestOptions.DebugDll.WithMetadataImportOptions(MetadataImportOptions.All)) + CompileAndVerify(comp2, symbolValidator:=validate).VerifyDiagnostics() + + Dim comp3 = CreateCompilation(source2, references:={comp1.EmitToImageReference()}, options:=TestOptions.DebugDll.WithMetadataImportOptions(MetadataImportOptions.All)) + CompileAndVerify(comp3, symbolValidator:=validate).VerifyDiagnostics() + End Sub + + + Public Sub CompilerLoweringPreserveAttribute_02_Retargeting() + Dim source0 = " +Public Class Test0 +End Class +" + + Dim comp0 = CreateCompilation(source0) + + Dim source1 = " +Imports System +Imports System.Runtime.CompilerServices + + + +Public Class Preserve1Attribute + Inherits Attribute +End Class + + + +Public Class Preserve2Attribute + Inherits Attribute +End Class + + +Public Class Preserve3Attribute + Inherits Attribute +End Class +" + Dim source2 = " +Class Test1 + + + + Property P1 As Integer +End Class +" + + Dim validate = Sub(m As ModuleSymbol) + AssertEx.SequenceEqual( + { + "Preserve1Attribute", + "System.Runtime.CompilerServices.CompilerGeneratedAttribute", + "System.Diagnostics.DebuggerBrowsableAttribute(System.Diagnostics.DebuggerBrowsableState.Never)" + }, + m.GlobalNamespace.GetMember("Test1._P1").GetAttributes().Select(Function(a) a.ToString())) + End Sub + + Dim comp1 = CreateCompilation( + {source1, CompilerLoweringPreserveAttributeDefinition}, + references:={comp0.ToMetadataReference()}, + options:=TestOptions.DebugDll.WithMetadataImportOptions(MetadataImportOptions.All)) + + Dim comp2 = CreateCompilation( + source2, + references:={comp1.ToMetadataReference()}, + options:=TestOptions.DebugDll.WithMetadataImportOptions(MetadataImportOptions.All)) + + Assert.IsType(Of RetargetingNamedTypeSymbol)(comp2.GetTypeByMetadataName("Preserve1Attribute")) + + CompileAndVerify(comp2, symbolValidator:=validate).VerifyDiagnostics() + End Sub + + + Public Sub CompilerLoweringPreserveAttribute_03_Generic() + Dim source1 = " +using System; +using System.Runtime.CompilerServices; + +namespace System.Runtime.CompilerServices +{ + [AttributeUsage(AttributeTargets.Class, Inherited = false)] + public class CompilerLoweringPreserveAttribute : Attribute + { + public CompilerLoweringPreserveAttribute() { } + } +} + +[CompilerLoweringPreserve] +[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)] +public class Preserve1Attribute : Attribute { } + +[CompilerLoweringPreserve] +[AttributeUsage(AttributeTargets.Property)] +public class Preserve2Attribute : Attribute { } + +[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)] +public class Preserve3Attribute : Attribute { } +" + Dim comp1 = CreateCSharpCompilation(source1) + + Dim source2 = " +Class Test1 + + + + Property P1 As Integer +End Class +" + + Dim comp2 = CreateCompilation( + source2, + references:={comp1.EmitToImageReference()}, + options:=TestOptions.DebugDll.WithMetadataImportOptions(MetadataImportOptions.All)) + + Assert.True(comp2.GetTypeByMetadataName("Preserve1Attribute`1").Construct(comp2.ObjectType).HasCompilerLoweringPreserveAttribute) + Assert.False(comp2.GetTypeByMetadataName("Preserve3Attribute`1").Construct(comp2.ObjectType).HasCompilerLoweringPreserveAttribute) + + comp2.AssertTheseDiagnostics( + + ~~~~~~~~~ +BC32066: Type arguments are not valid because attributes cannot be generic. + + ~~~~~~~~~ +BC30002: Type 'Preserve2' is not defined. + + ~~~~~~~~~ +BC32066: Type arguments are not valid because attributes cannot be generic. + + ~~~~~~~~~ +BC30002: Type 'Preserve3' is not defined. + + ~~~~~~~~~ +BC32066: Type arguments are not valid because attributes cannot be generic. + + ~~~~~~~~~ +]]>) + End Sub + #Region "Helpers" Private Sub VerifyMethodsAndAccessorsSame(type As NamedTypeSymbol, [property] As PropertySymbol) VerifyMethodAndAccessorSame(type, [property], [property].GetMethod) diff --git a/src/Compilers/VisualBasic/Test/Syntax/TestSyntaxNodes.vb b/src/Compilers/VisualBasic/Test/Syntax/TestSyntaxNodes.vb index 374ed12618a89..48cefb811e57b 100644 --- a/src/Compilers/VisualBasic/Test/Syntax/TestSyntaxNodes.vb +++ b/src/Compilers/VisualBasic/Test/Syntax/TestSyntaxNodes.vb @@ -2726,7 +2726,35 @@ End Class Dim result = cu2.ToFullString() Assert.Equal(expected, result) + End Sub + + + Public Sub TestRemove_KeepUnbalancedDirectives_Indented() + Dim text = .Value.Replace(vbLf, vbCrLf) + + Dim expected = .Value.Replace(vbLf, vbCrLf) + + Dim cu = SyntaxFactory.ParseCompilationUnit(text) + Dim n = cu.DescendantTokens().Where(Function(t) t.ToString() = "Goo").Select(Function(t) t.Parent.FirstAncestorOrSelf(Of MethodBlockSyntax)()).FirstOrDefault() + + Dim cu2 = cu.RemoveNode(n, SyntaxRemoveOptions.KeepUnbalancedDirectives) + + Dim result = cu2.ToFullString() + + Assert.Equal(expected, result) End Sub diff --git a/src/Dependencies/Collections/Microsoft.CodeAnalysis.Collections.projitems b/src/Dependencies/Collections/Microsoft.CodeAnalysis.Collections.projitems index e17523e5a7ffd..4ee9b9e4624a6 100644 --- a/src/Dependencies/Collections/Microsoft.CodeAnalysis.Collections.projitems +++ b/src/Dependencies/Collections/Microsoft.CodeAnalysis.Collections.projitems @@ -65,7 +65,7 @@ - + diff --git a/src/Dependencies/Collections/RoslynImmutableInterlocked.cs b/src/Dependencies/Collections/RoslynImmutableInterlocked.cs index a96084a0bab16..6e5e8742d30c7 100644 --- a/src/Dependencies/Collections/RoslynImmutableInterlocked.cs +++ b/src/Dependencies/Collections/RoslynImmutableInterlocked.cs @@ -6,6 +6,7 @@ using System.Collections.Generic; using System.Collections.Immutable; using System.Diagnostics.CodeAnalysis; +using System.Threading; namespace Microsoft.CodeAnalysis.Collections { @@ -605,5 +606,32 @@ public static bool TryRemove(ref ImmutableSegmentedDictionary + /// Reads from an ImmutableArray location, ensuring that a read barrier is inserted to prevent any subsequent reads from being reordered before this read. + /// + /// + /// This method is not intended to be used to provide write barriers. + /// + public static ImmutableArray VolatileRead(ref readonly ImmutableArray location) + { + var value = location; + // When Volatile.ReadBarrier() is available in .NET 10, it can be used here. + Interlocked.MemoryBarrier(); + return value; + } + + /// + /// Writes to an ImmutableArray location, ensuring that a write barrier is inserted to prevent any prior writes from being reordered after this write. + /// + /// + /// This method is not intended to be used to provide read barriers. + /// + public static void VolatileWrite(ref ImmutableArray location, ImmutableArray value) + { + // When Volatile.WriteBarrier() is available in .NET 10, it can be used here. + Interlocked.MemoryBarrier(); + location = value; + } } } diff --git a/src/EditorFeatures/CSharp/CompleteStatement/CompleteStatementCommandHandler.cs b/src/EditorFeatures/CSharp/CompleteStatement/CompleteStatementCommandHandler.cs index b64b470029904..2bc5648d8b235 100644 --- a/src/EditorFeatures/CSharp/CompleteStatement/CompleteStatementCommandHandler.cs +++ b/src/EditorFeatures/CSharp/CompleteStatement/CompleteStatementCommandHandler.cs @@ -92,42 +92,59 @@ public void ExecuteCommand(TypeCharCommandArgs args, Action nextCommandHandler, transaction?.Complete(); } - private SemicolonBehavior BeforeExecuteCommand(bool speculative, TypeCharCommandArgs args, CommandExecutionContext executionContext) + private SemicolonBehavior BeforeExecuteCommand( + bool speculative, + TypeCharCommandArgs args, + CommandExecutionContext executionContext) { if (args.TypedChar != ';' || !args.TextView.Selection.IsEmpty) - { return SemicolonBehavior.None; - } - var caretOpt = args.TextView.GetCaretPoint(args.SubjectBuffer); - if (!caretOpt.HasValue) - { + if (args.TextView.GetCaretPoint(args.SubjectBuffer) is not { } caret) return SemicolonBehavior.None; - } if (!_globalOptions.GetOption(CompleteStatementOptionsStorage.AutomaticallyCompleteStatementOnSemicolon)) - { return SemicolonBehavior.None; - } - var caret = caretOpt.Value; var document = caret.Snapshot.GetOpenDocumentInCurrentContextWithChanges(); if (document == null) - { return SemicolonBehavior.None; - } var cancellationToken = executionContext.OperationContext.UserCancellationToken; var syntaxFacts = document.GetRequiredLanguageService(); var root = document.GetRequiredSyntaxRootSynchronously(cancellationToken); - if (!TryGetStartingNode(root, caret, out var currentNode, cancellationToken)) - { + if (!TryGetStartingNode(root, caret, out var tokenOnLeft, out var currentNode, cancellationToken)) return SemicolonBehavior.None; + + // If the user types `= new;` complete it out to `= new();` + if (tokenOnLeft.Kind() is SyntaxKind.NewKeyword && + currentNode is BaseObjectCreationExpressionSyntax + { + Parent: EqualsValueClauseSyntax + { + Parent: VariableDeclaratorSyntax + { + Parent: VariableDeclarationSyntax + { + Parent: FieldDeclarationSyntax or LocalDeclarationStatementSyntax + } + } + } + }) + { + if (!speculative) + { + var edit = args.SubjectBuffer.CreateEdit(); + edit.Insert(caret, "();"); + edit.Apply(); + } + + return SemicolonBehavior.Overtype; } - return MoveCaretToSemicolonPosition(speculative, args, document, root, originalCaret: caret, caret, syntaxFacts, currentNode, - isInsideDelimiters: false, cancellationToken); + return MoveCaretToSemicolonPosition( + speculative, args, document, root, originalCaret: caret, caret, syntaxFacts, currentNode, isInsideDelimiters: false, cancellationToken); } /// @@ -137,6 +154,7 @@ private SemicolonBehavior BeforeExecuteCommand(bool speculative, TypeCharCommand private static bool TryGetStartingNode( SyntaxNode root, SnapshotPoint caret, + out SyntaxToken tokenOnLeft, [NotNullWhen(true)] out SyntaxNode? startingNode, CancellationToken cancellationToken) { @@ -144,15 +162,15 @@ private static bool TryGetStartingNode( startingNode = null; var caretPosition = caret.Position; - var token = root.FindTokenOnLeftOfPosition(caretPosition); + tokenOnLeft = root.FindTokenOnLeftOfPosition(caretPosition); - if (token.SyntaxTree == null - || token.SyntaxTree.IsInNonUserCode(caretPosition, cancellationToken)) + if (tokenOnLeft.SyntaxTree == null || + tokenOnLeft.SyntaxTree.IsInNonUserCode(caretPosition, cancellationToken)) { return false; } - startingNode = token.GetRequiredParent(); + startingNode = tokenOnLeft.GetRequiredParent(); // If the caret is before an opening delimiter or after a closing delimeter, // start analysis with node outside of delimiters. @@ -224,7 +242,7 @@ SyntaxKind.CollectionExpression or isInsideDelimiters = !HasDelimitersButCaretIsOutside(currentNode, caret.Position); var newCaret = args.SubjectBuffer.CurrentSnapshot.GetPoint(newCaretPosition); - if (!TryGetStartingNode(root, newCaret, out currentNode, cancellationToken)) + if (!TryGetStartingNode(root, newCaret, out _, out currentNode, cancellationToken)) return SemicolonBehavior.None; return MoveCaretToSemicolonPosition( diff --git a/src/EditorFeatures/CSharp/DocumentationComments/DocumentationCommentCommandHandler.cs b/src/EditorFeatures/CSharp/DocumentationComments/DocumentationCommentCommandHandler.cs index b2d60950b3383..a0b5d4a0b5726 100644 --- a/src/EditorFeatures/CSharp/DocumentationComments/DocumentationCommentCommandHandler.cs +++ b/src/EditorFeatures/CSharp/DocumentationComments/DocumentationCommentCommandHandler.cs @@ -26,7 +26,7 @@ internal sealed class DocumentationCommentCommandHandler( ITextUndoHistoryRegistry undoHistoryRegistry, IEditorOperationsFactoryService editorOperationsFactoryService, EditorOptionsService editorOptionsService) - : AbstractDocumentationCommentCommandHandler(uiThreadOperationExecutor, undoHistoryRegistry, editorOperationsFactoryService, editorOptionsService) + : AbstractDocumentationCommentCommandHandler(uiThreadOperationExecutor, undoHistoryRegistry, editorOperationsFactoryService, editorOptionsService) { protected override string ExteriorTriviaText => "///"; } diff --git a/src/EditorFeatures/CSharp/EndConstruct/CSharpEndConstructGenerationService.cs b/src/EditorFeatures/CSharp/EndConstruct/CSharpEndConstructGenerationService.cs index d44bf6e7c6a66..ce65cec44f0f4 100644 --- a/src/EditorFeatures/CSharp/EndConstruct/CSharpEndConstructGenerationService.cs +++ b/src/EditorFeatures/CSharp/EndConstruct/CSharpEndConstructGenerationService.cs @@ -6,29 +6,21 @@ using System.Composition; using System.Diagnostics.CodeAnalysis; using System.Threading; +using System.Threading.Tasks; using Microsoft.CodeAnalysis.Editor.Implementation.EndConstructGeneration; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.VisualStudio.Text; using Microsoft.VisualStudio.Text.Editor; +using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Editor.CSharp.EndConstructGeneration; [ExportLanguageService(typeof(IEndConstructGenerationService), LanguageNames.CSharp), Shared] [ExcludeFromCodeCoverage] -internal class CSharpEndConstructGenerationService : IEndConstructGenerationService +[method: ImportingConstructor] +[method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] +internal sealed class CSharpEndConstructGenerationService() : IEndConstructGenerationService { - [ImportingConstructor] - [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - public CSharpEndConstructGenerationService() - { - } - - public bool TryDo( - ITextView textView, - ITextBuffer subjectBuffer, - char typedChar, - CancellationToken cancellationToken) - { - return false; - } + public Task TryDoAsync(ITextView textView, ITextBuffer subjectBuffer, char typedChar, CancellationToken cancellationToken) + => SpecializedTasks.False; } diff --git a/src/EditorFeatures/CSharp/EventHookup/EventHookupCommandHandler_TabKeyCommand.cs b/src/EditorFeatures/CSharp/EventHookup/EventHookupCommandHandler_TabKeyCommand.cs index a065c13adb9dd..809ef38fa78aa 100644 --- a/src/EditorFeatures/CSharp/EventHookup/EventHookupCommandHandler_TabKeyCommand.cs +++ b/src/EditorFeatures/CSharp/EventHookup/EventHookupCommandHandler_TabKeyCommand.cs @@ -53,12 +53,9 @@ public void ExecuteCommand(TabKeyCommandArgs args, Action nextHandler, CommandEx _threadingContext.ThrowIfNotOnUIThread(); if (!TryExecuteCommand(args, nextHandler)) { + EventHookupSessionManager.DismissExistingSessions(); nextHandler(); } - - // We always dismiss the tracking session once a tab has gone through. Either we didn't handle it (and - // nextHandler was called above). Or we did handle it, in which case the bg async work owns the experience now. - EventHookupSessionManager.DismissExistingSessions(); } private bool TryExecuteCommand(TabKeyCommandArgs args, Action nextHandler) @@ -99,18 +96,16 @@ private bool TryExecuteCommand(TabKeyCommandArgs args, Action nextHandler) // Capture everything we need off of the session manager as we'll be dismissing the core session immediately // before we kick off the work to emit hte event. Detach the bg work that was already kicked off so that we // own its lifetime from now on. - var (eventNameTask, eventNameTokenSource) = EventHookupSessionManager.CurrentSession.DetachEventNameTask(); + var eventNameTask = EventHookupSessionManager.CurrentSession.GetEventNameAsync(); var applicableToSpan = EventHookupSessionManager.CurrentSession.TrackingSpan.GetSpan(currentSnapshot); - var task = ExecuteCommandAsync( + ExecuteCommandAsync( args, nextHandler, applicableToSpan, document, eventNameTask, - eventNameTokenSource, - caretPoint.Value); - task.CompletesAsyncOperation(token); + caretPoint.Value).ReportNonFatalErrorAsync().CompletesAsyncOperation(token); // At this point, we've taken control, so don't send the tab into the buffer. But do dismiss the overall // session. We no longer need it. @@ -123,7 +118,6 @@ private async Task ExecuteCommandAsync( SnapshotSpan applicableToSpan, Document document, Task eventNameTask, - CancellationTokenSource eventNameCancellationTokenSource, SnapshotPoint initialCaretPoint) { _threadingContext.ThrowIfNotOnUIThread(); @@ -131,36 +125,19 @@ private async Task ExecuteCommandAsync( var textView = args.TextView; var subjectBuffer = args.SubjectBuffer; - // Don't want any exceptions bubble up from this point on (they have no where to go since we effectively did a - // fire-and-forget). So we instead handle things ourselves, reporting NFWs if unforseen things happened. - try + if (!await TryExecuteCommandAsync().ConfigureAwait(true)) { - if (!await TryExecuteCommandAsync().ConfigureAwait(true)) + _threadingContext.ThrowIfNotOnUIThread(); + + // We didn't successfully handle the command. If no other changes have gotten through in the mean time, + // then attempt to send the tab through to the editor. If other changes went through, don't send the + // tab through as it's likely to make things worse. + if (applicableToSpan.Snapshot.Version == subjectBuffer.CurrentSnapshot.Version && + textView.GetCaretPoint(subjectBuffer) == initialCaretPoint) { - _threadingContext.ThrowIfNotOnUIThread(); - - // We didn't successfully handle the command. If no other changes have gotten through in the mean time, - // then attempt to send the tab through to the editor. If other changes went through, don't send the - // tab through as it's likely to make things worse. - if (applicableToSpan.Snapshot.Version == subjectBuffer.CurrentSnapshot.Version && - textView.GetCaretPoint(subjectBuffer) == initialCaretPoint) - { - nextHandler(); - } + nextHandler(); } } - catch (OperationCanceledException) - { - } - catch (Exception ex) when (FatalError.ReportAndCatch(ex)) - { - } - finally - { - // Once we finish doing our own work (including potentially cancelling out), ensure that any BG worked - // kicked off to compute the event name is canceled as well so it doesn't keep consuming resources. - eventNameCancellationTokenSource.Cancel(); - } return; diff --git a/src/EditorFeatures/CSharp/EventHookup/EventHookupSessionManager.cs b/src/EditorFeatures/CSharp/EventHookup/EventHookupSessionManager.cs index 4159ee9de1ff6..a82060abedcd2 100644 --- a/src/EditorFeatures/CSharp/EventHookup/EventHookupSessionManager.cs +++ b/src/EditorFeatures/CSharp/EventHookup/EventHookupSessionManager.cs @@ -8,11 +8,11 @@ using System.ComponentModel.Composition; using System.Linq; using System.Threading; +using System.Threading.Tasks; using Microsoft.CodeAnalysis.Classification; using Microsoft.CodeAnalysis.Editor.Shared.Extensions; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.Host.Mef; -using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Shared.TestHooks; using Microsoft.VisualStudio.Text; using Microsoft.VisualStudio.Text.Adornments; @@ -32,14 +32,33 @@ internal sealed partial class EventHookupSessionManager( private IToolTipPresenter _toolTipPresenter; - internal EventHookupSession CurrentSession { get; set; } + private EventHookupSession _currentSessionDoNotAccessDirectly; + + internal EventHookupSession CurrentSession + { + get + { + ThreadingContext.ThrowIfNotOnUIThread(); + return _currentSessionDoNotAccessDirectly; + } + + set + { + ThreadingContext.ThrowIfNotOnUIThread(); + _currentSessionDoNotAccessDirectly?.CancelBackgroundTasks(); + _currentSessionDoNotAccessDirectly = value; + } + } // For test purposes only! internal ClassifiedTextElement[] TEST_MostRecentToolTipContent { get; set; } - internal void EventHookupFoundInSession(EventHookupSession analyzedSession, string eventName) + public async Task EventHookupFoundInSessionAsync( + EventHookupSession analyzedSession, string eventName, CancellationToken cancellationToken) { - ThreadingContext.ThrowIfNotOnUIThread(); + await this.ThreadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(alwaysYield: true, cancellationToken); + if (cancellationToken.IsCancellationRequested) + return; var caretPoint = analyzedSession.TextView.GetCaretPoint(analyzedSession.SubjectBuffer); @@ -118,17 +137,10 @@ public void DismissExistingSessions() { ThreadingContext.ThrowIfNotOnUIThread(); - if (_toolTipPresenter != null) - { - _toolTipPresenter.Dismiss(); - _toolTipPresenter = null; - } + _toolTipPresenter?.Dismiss(); + _toolTipPresenter = null; - if (CurrentSession != null) - { - CurrentSession.CancelBackgroundTasks(); - CurrentSession = null; - } + CurrentSession = null; // For test purposes only! TEST_MostRecentToolTipContent = null; diff --git a/src/EditorFeatures/CSharp/EventHookup/EventHookupSessionManager_EventHookupSession.cs b/src/EditorFeatures/CSharp/EventHookup/EventHookupSessionManager_EventHookupSession.cs index 795850ed1cf19..ab6af90bbb219 100644 --- a/src/EditorFeatures/CSharp/EventHookup/EventHookupSessionManager_EventHookupSession.cs +++ b/src/EditorFeatures/CSharp/EventHookup/EventHookupSessionManager_EventHookupSession.cs @@ -15,13 +15,12 @@ using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.Internal.Log; using Microsoft.CodeAnalysis.LanguageService; -using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.TestHooks; using Microsoft.CodeAnalysis.Shared.Utilities; using Microsoft.VisualStudio.Text; using Microsoft.VisualStudio.Text.Editor; -using Roslyn.Utilities; +using Microsoft.VisualStudio.Threading; using static Microsoft.CodeAnalysis.Diagnostics.Analyzers.NamingStyles.SymbolSpecification; namespace Microsoft.CodeAnalysis.Editor.CSharp.EventHookup; @@ -33,7 +32,7 @@ internal sealed partial class EventHookupSessionManager /// += is being used to add an event handler to an event. If it is, then we also determine /// a candidate name for the event handler. /// - internal class EventHookupSession + internal sealed class EventHookupSession { private readonly IThreadingContext _threadingContext; private readonly ITrackingSpan _trackingSpan; @@ -45,8 +44,8 @@ internal class EventHookupSession // For testing purposes only! Should always be null except in tests. internal Mutex? TESTSessionHookupMutex = null; - private Task? _eventNameTask; - private CancellationTokenSource? _cancellationTokenSource; + private readonly Task _eventNameTask; + private readonly CancellationTokenSource _cancellationTokenSource; public ITrackingSpan TrackingSpan { @@ -78,7 +77,7 @@ public ITextBuffer SubjectBuffer public void CancelBackgroundTasks() { _threadingContext.ThrowIfNotOnUIThread(); - _cancellationTokenSource?.Cancel(); + _cancellationTokenSource.Cancel(); } public EventHookupSession( @@ -96,6 +95,7 @@ public EventHookupSession( _cancellationTokenSource = new(); var cancellationToken = _cancellationTokenSource.Token; + _textView = textView; _subjectBuffer = subjectBuffer; this.TESTSessionHookupMutex = testSessionHookupMutex; @@ -106,48 +106,29 @@ public EventHookupSession( var asyncToken = asyncListener.BeginAsyncOperation(GetType().Name + ".Start"); - _eventNameTask = Task.Factory.SafeStartNewFromAsync( - () => DetermineIfEventHookupAndGetHandlerNameAsync(document, position, cancellationToken), - cancellationToken, - TaskScheduler.Default); - - var continuedTask = _eventNameTask.SafeContinueWithFromAsync( - async t => - { - await _threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(alwaysYield: true, cancellationToken); - - // Once we compute the name, update the tooltip (if we haven't already been dismissed) - if (this._eventNameTask != null && t.Result != null) - { - commandHandler.EventHookupSessionManager.EventHookupFoundInSession(this, t.Result); - } - }, - cancellationToken, - TaskContinuationOptions.OnlyOnRanToCompletion | TaskContinuationOptions.ExecuteSynchronously, - TaskScheduler.Default); - - continuedTask.CompletesAsyncOperation(asyncToken); - } - - public (Task eventNameTask, CancellationTokenSource cancellationTokenSource) DetachEventNameTask() - { - _threadingContext.ThrowIfNotOnUIThread(); - - Contract.ThrowIfNull(_eventNameTask); - Contract.ThrowIfNull(_cancellationTokenSource); + _eventNameTask = DetermineIfEventHookupAndGetHandlerNameAsync(document, position, cancellationToken); - var eventNameTask = _eventNameTask; - var cancellationTokenSource = _cancellationTokenSource; + ContinueOnMainThreadAsync(_eventNameTask).CompletesAsyncOperation(asyncToken); - _eventNameTask = null; - _cancellationTokenSource = null; + return; - return (eventNameTask, cancellationTokenSource); + async Task ContinueOnMainThreadAsync( + Task eventNameTask) + { + // Continue on the BG as the normal case is that we're not doing event hookup. In that case, we don't + // want to come back to the UI thread unnecessarily. + var eventName = await eventNameTask.ConfigureAwait(false); + if (eventName != null) + await commandHandler.EventHookupSessionManager.EventHookupFoundInSessionAsync(this, eventName, cancellationToken).ConfigureAwait(false); + } } + public Task GetEventNameAsync() + => _eventNameTask; + private async Task DetermineIfEventHookupAndGetHandlerNameAsync(Document document, int position, CancellationToken cancellationToken) { - _threadingContext.ThrowIfNotOnBackgroundThread(); + await TaskScheduler.Default; // For test purposes only! if (TESTSessionHookupMutex != null) diff --git a/src/EditorFeatures/CSharp/InlineRename/CSharpEditorInlineRenameService.cs b/src/EditorFeatures/CSharp/InlineRename/CSharpEditorInlineRenameService.cs index 2e7dbe8bd7510..cb4855b91cf0b 100644 --- a/src/EditorFeatures/CSharp/InlineRename/CSharpEditorInlineRenameService.cs +++ b/src/EditorFeatures/CSharp/InlineRename/CSharpEditorInlineRenameService.cs @@ -53,9 +53,9 @@ await TryGetSurroundingNodeSpanAsync(renameDefinition.D if (symbolService is not null) { var textSpan = inlineRenameInfo.TriggerSpan; + var semanticModel = await renameDefinition.Document.GetRequiredNullableDisabledSemanticModelAsync(cancellationToken).ConfigureAwait(false); var (symbol, _, _) = await symbolService.GetSymbolProjectAndBoundSpanAsync( - renameDefinition.Document, textSpan.Start, cancellationToken) - .ConfigureAwait(true); + renameDefinition.Document, semanticModel, textSpan.Start, cancellationToken).ConfigureAwait(true); var docComment = symbol?.GetDocumentationCommentXml(expandIncludes: true, cancellationToken: cancellationToken); if (!string.IsNullOrWhiteSpace(docComment)) { diff --git a/src/EditorFeatures/CSharp/Microsoft.CodeAnalysis.CSharp.EditorFeatures.csproj b/src/EditorFeatures/CSharp/Microsoft.CodeAnalysis.CSharp.EditorFeatures.csproj index b38a4252d8b6b..29acf31963df6 100644 --- a/src/EditorFeatures/CSharp/Microsoft.CodeAnalysis.CSharp.EditorFeatures.csproj +++ b/src/EditorFeatures/CSharp/Microsoft.CodeAnalysis.CSharp.EditorFeatures.csproj @@ -34,6 +34,7 @@ + diff --git a/src/EditorFeatures/CSharp/TextStructureNavigation/CSharpTextStructureNavigatorProvider.cs b/src/EditorFeatures/CSharp/TextStructureNavigation/CSharpTextStructureNavigatorProvider.cs index 0400e3443aab7..26f0775e849f4 100644 --- a/src/EditorFeatures/CSharp/TextStructureNavigation/CSharpTextStructureNavigatorProvider.cs +++ b/src/EditorFeatures/CSharp/TextStructureNavigation/CSharpTextStructureNavigatorProvider.cs @@ -8,10 +8,11 @@ using Microsoft.CodeAnalysis.CSharp.Extensions; using Microsoft.CodeAnalysis.Editor.Implementation.TextStructureNavigation; using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.CodeAnalysis.Text; +using Microsoft.CodeAnalysis.Text.Shared.Extensions; using Microsoft.VisualStudio.Text; using Microsoft.VisualStudio.Text.Operations; using Microsoft.VisualStudio.Utilities; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Editor.CSharp.TextStructureNavigation; @@ -19,7 +20,7 @@ namespace Microsoft.CodeAnalysis.Editor.CSharp.TextStructureNavigation; [ContentType(ContentTypeNames.CSharpContentType)] [method: ImportingConstructor] [method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] -internal class CSharpTextStructureNavigatorProvider( +internal sealed class CSharpTextStructureNavigatorProvider( ITextStructureNavigatorSelectorService selectorService, IContentTypeRegistryService contentTypeService, IUIThreadOperationExecutor uIThreadOperationExecutor) : AbstractTextStructureNavigatorProvider(selectorService, contentTypeService, uIThreadOperationExecutor) @@ -27,91 +28,97 @@ internal class CSharpTextStructureNavigatorProvider( protected override bool ShouldSelectEntireTriviaFromStart(SyntaxTrivia trivia) => trivia.IsRegularOrDocComment(); - protected override bool IsWithinNaturalLanguage(SyntaxToken token, int position) + protected override TextExtent GetExtentOfWordFromToken(ITextStructureNavigator naturalLanguageNavigator, SyntaxToken token, SnapshotPoint position) { - switch (token.Kind()) + var snapshot = position.Snapshot; + + // Legacy behavior. We let the editor handle these. Note: this can be revisited if we think we would do a better + // job handling these. + if (token.Kind() is SyntaxKind.InterpolatedStringTextToken or SyntaxKind.XmlTextLiteralToken) + return naturalLanguageNavigator.GetExtentOfWord(position); + + // Legacy behavior. If we're on the start of a char literal, we select the entire thing. For anything else, we + // defer to the editor. Note: this can be revisited if we think we would do a better + if (token.Kind() is SyntaxKind.CharacterLiteralToken) { - case SyntaxKind.StringLiteralToken: - case SyntaxKind.Utf8StringLiteralToken: - // This, in combination with the override of GetExtentOfWordFromToken() below, treats the closing - // quote as a separate token. This maintains behavior with VS2013. - return !IsAtClosingQuote(token, position); - - case SyntaxKind.SingleLineRawStringLiteralToken: - case SyntaxKind.MultiLineRawStringLiteralToken: - case SyntaxKind.Utf8SingleLineRawStringLiteralToken: - case SyntaxKind.Utf8MultiLineRawStringLiteralToken: - { - // Like with normal string literals, treat the closing quotes as as the end of the string so that - // navigation ends there and doesn't go past them. - var end = GetStartOfRawStringLiteralEndDelimiter(token); - return position < end; - } - - case SyntaxKind.CharacterLiteralToken: - // Before the ' is considered outside the character - return position != token.SpanStart; - - case SyntaxKind.InterpolatedStringTextToken: - case SyntaxKind.XmlTextLiteralToken: - return true; + if (token.SpanStart == position) + return GetTokenExtent(token, snapshot); + + return naturalLanguageNavigator.GetExtentOfWord(position); } - return false; - } + // For string literals, if we're on the starting quote, we want to select the entire string. + // + // If we're on the closing quote, we want to treat it as separate token. This allows the cursor to stop during + // word navigation (Ctrl+LeftArrow, etc.) immediately before AND after the closing quote, just like it did in + // VS2013 and like it currently does for interpolated strings. + // + // If we're in the middle of the string, we want to let the editor take over. but if it selects a span outside + // of the string, we'll clamp the result back to within the string. - private static int GetStartOfRawStringLiteralEndDelimiter(SyntaxToken token) - { - var text = token.ToString(); - var start = 0; - var end = text.Length; + var isNormalStringLiteral = token.Kind() is SyntaxKind.StringLiteralToken or SyntaxKind.Utf8StringLiteralToken; + var isRawStringLiteral = token.Kind() is SyntaxKind.SingleLineRawStringLiteralToken or SyntaxKind.Utf8SingleLineRawStringLiteralToken or SyntaxKind.MultiLineRawStringLiteralToken or SyntaxKind.Utf8MultiLineRawStringLiteralToken; - if (token.Kind() is SyntaxKind.Utf8MultiLineRawStringLiteralToken or SyntaxKind.Utf8SingleLineRawStringLiteralToken) + if (!isNormalStringLiteral && !isRawStringLiteral) { - // Skip past the u8 suffix - end -= "u8".Length; + // Not a string literal. Just select the entire token. + return GetTokenExtent(token, snapshot); } - while (start < end && text[start] == '"') - start++; + // At the start of the string, select the start span. + var (startSpan, contentSpan, endSpan) = GetStringLiteralParts(); + if (startSpan.Contains(position)) + return new TextExtent(startSpan.ToSnapshotSpan(snapshot), isSignificant: true); - while (end > start && text[end - 1] == '"') - end--; + // If at the end, select the end piece only. + if (endSpan.Contains(position)) + return new TextExtent(endSpan.ToSnapshotSpan(snapshot), isSignificant: true); - return token.SpanStart + end; - } + // We're in the middle. Defer to the editor. But make sure we don't go outside of the middle section. + var naturalExtent = naturalLanguageNavigator.GetExtentOfWord(position); - private static bool IsAtClosingQuote(SyntaxToken token, int position) - => token.Kind() switch - { - SyntaxKind.StringLiteralToken => position == token.Span.End - 1 && token.Text[^1] == '"', - SyntaxKind.Utf8StringLiteralToken => position == token.Span.End - 3 && token.Text is [.., '"', 'u' or 'U', '8'], - _ => throw ExceptionUtilities.Unreachable() - }; + var intersection = naturalExtent.Span.Intersection(contentSpan.ToSpan()); + return intersection is null ? naturalExtent : new TextExtent(intersection.Value, isSignificant: naturalExtent.IsSignificant); - protected override TextExtent GetExtentOfWordFromToken(SyntaxToken token, SnapshotPoint position) - { - if (token.Kind() is SyntaxKind.StringLiteralToken or SyntaxKind.Utf8StringLiteralToken && - IsAtClosingQuote(token, position.Position)) - { - // Special case to treat the closing quote of a string literal as a separate token. This allows the - // cursor to stop during word navigation (Ctrl+LeftArrow, etc.) immediately before AND after the - // closing quote, just like it did in VS2013 and like it currently does for interpolated strings. - var span = new Span(position.Position, token.Span.End - position.Position); - return new TextExtent(new SnapshotSpan(position.Snapshot, span), isSignificant: true); - } - else if (token.Kind() is - SyntaxKind.SingleLineRawStringLiteralToken or - SyntaxKind.MultiLineRawStringLiteralToken or - SyntaxKind.Utf8SingleLineRawStringLiteralToken or - SyntaxKind.Utf8MultiLineRawStringLiteralToken) - { - var delimiterStart = GetStartOfRawStringLiteralEndDelimiter(token); - return new TextExtent(new SnapshotSpan(position.Snapshot, Span.FromBounds(delimiterStart, token.Span.End)), isSignificant: true); - } - else + (TextSpan startSpan, TextSpan contentSpan, TextSpan endSpan) GetStringLiteralParts() { - return base.GetExtentOfWordFromToken(token, position); + var start = token.Span.Start; + var contentStart = start; + + if (CharAt(contentStart) == '@') + contentStart++; + + if (CharAt(contentStart) == '"') + contentStart++; + + if (isRawStringLiteral) + { + while (CharAt(contentStart) == '"') + contentStart++; + } + + var end = token.Span.End; + var contentEnd = end; + + if (CharAt(contentEnd - 1) == '8') + contentEnd--; + + if (CharAt(contentEnd - 1) is 'u' or 'U') + contentEnd--; + + if (CharAt(contentEnd - 1) == '"') + contentEnd--; + + if (isRawStringLiteral) + { + while (CharAt(contentEnd - 1) == '"') + contentEnd--; + } + + return (TextSpan.FromBounds(start, contentStart), TextSpan.FromBounds(contentStart, contentEnd), TextSpan.FromBounds(contentEnd, end)); } + + char CharAt(int position) + => position >= 0 && position < snapshot.Length ? snapshot[position] : '\0'; } } diff --git a/src/EditorFeatures/CSharpTest/Classification/SemanticClassifierTests_TestMarkup.cs b/src/EditorFeatures/CSharpTest/Classification/SemanticClassifierTests_TestMarkup.cs index b84547333eeac..ad522e9d63473 100644 --- a/src/EditorFeatures/CSharpTest/Classification/SemanticClassifierTests_TestMarkup.cs +++ b/src/EditorFeatures/CSharpTest/Classification/SemanticClassifierTests_TestMarkup.cs @@ -20,7 +20,7 @@ namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Classification; -public partial class SemanticClassifierTests : AbstractCSharpClassifierTests +public sealed partial class SemanticClassifierTests : AbstractCSharpClassifierTests { private const string s_testMarkup = """ @@ -53,6 +53,27 @@ void M() await TestEmbeddedCSharpWithMultipleSpansAsync(allCode, testHost, spans, expected); } + private async Task TestSingleLineEmbeddedCSharpAsync( + string code, + TestHost testHost, + params FormattedClassification[] expected) + { + var allCode = $$""""" + class C + { + void M() + { + Test.M(""""{{code}}""""); + } + } + """"" + s_testMarkup; + + var start = allCode.IndexOf(code, StringComparison.Ordinal); + var length = code.Length; + var spans = ImmutableArray.Create(new TextSpan(start, length)); + await TestEmbeddedCSharpWithMultipleSpansAsync(allCode, testHost, spans, expected); + } + private async Task TestEmbeddedCSharpWithMultipleSpansAsync( string allCode, TestHost testHost, @@ -457,4 +478,26 @@ class D Punctuation.Semicolon, Punctuation.CloseCurly); } + + [Theory, CombinatorialData] + [WorkItem("https://github.com/dotnet/roslyn/issues/76575")] + public async Task TestOnlyMarkup1(TestHost testHost) + { + await TestEmbeddedCSharpAsync( + "[||]", + testHost, + TestCodeMarkdown("[|"), + TestCodeMarkdown("|]")); + } + + [Theory, CombinatorialData] + [WorkItem("https://github.com/dotnet/roslyn/issues/76575")] + public async Task TestOnlyMarkup2(TestHost testHost) + { + await TestSingleLineEmbeddedCSharpAsync( + "[||]", + testHost, + TestCodeMarkdown("[|"), + TestCodeMarkdown("|]")); + } } diff --git a/src/EditorFeatures/CSharpTest/CodeActions/AddUsing/AddUsingNuGetTests.cs b/src/EditorFeatures/CSharpTest/CodeActions/AddUsing/AddUsingNuGetTests.cs index a38934a9956c8..9bf7f0e5aa0a5 100644 --- a/src/EditorFeatures/CSharpTest/CodeActions/AddUsing/AddUsingNuGetTests.cs +++ b/src/EditorFeatures/CSharpTest/CodeActions/AddUsing/AddUsingNuGetTests.cs @@ -29,7 +29,7 @@ namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.AddUsing; public class AddUsingNuGetTests : AbstractAddUsingTests { private static readonly ImmutableArray NugetPackageSources = - ImmutableArray.Create(new PackageSource(PackageSourceHelper.NugetOrgSourceName, "http://nuget.org/")); + [new PackageSource(PackageSourceHelper.NugetOrgSourceName, "http://nuget.org/")]; protected override void InitializeWorkspace(EditorTestWorkspace workspace, TestParameters parameters) { @@ -55,29 +55,33 @@ public async Task TestSearchPackageCustomFeedName() var installerServiceMock = new Mock(MockBehavior.Strict); installerServiceMock.Setup(i => i.IsEnabled(It.IsAny())).Returns(true); installerServiceMock.Setup(i => i.IsInstalled(It.IsAny(), "NuGetPackage")).Returns(false); - installerServiceMock.Setup(i => i.GetInstalledVersions("NuGetPackage")).Returns(ImmutableArray.Empty); + installerServiceMock.Setup(i => i.GetInstalledVersions("NuGetPackage")).Returns([]); installerServiceMock.Setup(i => i.TryGetPackageSources()).Returns(packageSources); installerServiceMock.Setup(s => s.TryInstallPackageAsync(It.IsAny(), It.IsAny(), It.IsAny(), "NuGetPackage", It.IsAny(), It.IsAny(), It.IsAny>(), It.IsAny())) .Returns(Task.FromResult(true)); var packageServiceMock = new Mock(MockBehavior.Strict); - packageServiceMock.Setup(s => s.FindReferenceAssembliesWithTypeAsync("NuGetType", 0, It.IsAny())) - .Returns(() => ValueTaskFactory.FromResult(ImmutableArray.Empty)); - packageServiceMock.Setup(s => s.FindPackagesWithTypeAsync( - PackageSourceHelper.NugetOrgSourceName, "NuGetType", 0, It.IsAny())) + packageServiceMock.Setup(s => s.FindReferenceAssembliesAsync(new TypeQuery("NuGetType", 0), It.IsAny(), It.IsAny())) + .Returns(() => ValueTaskFactory.FromResult(ImmutableArray.Empty)); + packageServiceMock.Setup(s => s.FindPackagesAsync( + PackageSourceHelper.NugetOrgSourceName, new TypeQuery("NuGetType", 0), It.IsAny(), It.IsAny())) .Returns(() => CreateSearchResult("NuGetPackage", "NuGetType", CreateNameParts("NuGetNamespace"))); await TestInRegularAndScriptAsync( -@"class C -{ - [|NuGetType|] n; -}", -@"using NuGetNamespace; - -class C -{ - NuGetType n; -}", fixProviderData: new FixProviderData(installerServiceMock.Object, packageServiceMock.Object)); + """ + class C + { + [|NuGetType|] n; + } + """, + """ + using NuGetNamespace; + + class C + { + NuGetType n; + } + """, fixProviderData: new FixProviderData(installerServiceMock.Object, packageServiceMock.Object)); } [Fact] @@ -88,29 +92,33 @@ public async Task TestSearchPackageFakeNugetFeed() var installerServiceMock = new Mock(MockBehavior.Strict); installerServiceMock.Setup(i => i.IsEnabled(It.IsAny())).Returns(true); installerServiceMock.Setup(i => i.IsInstalled(It.IsAny(), "NuGetPackage")).Returns(false); - installerServiceMock.Setup(i => i.GetInstalledVersions("NuGetPackage")).Returns(ImmutableArray.Empty); + installerServiceMock.Setup(i => i.GetInstalledVersions("NuGetPackage")).Returns([]); installerServiceMock.Setup(i => i.TryGetPackageSources()).Returns(packageSources); installerServiceMock.Setup(s => s.TryInstallPackageAsync(It.IsAny(), It.IsAny(), It.IsAny(), "NuGetPackage", It.IsAny(), It.IsAny(), It.IsAny>(), It.IsAny())) .Returns(Task.FromResult(true)); var packageServiceMock = new Mock(MockBehavior.Strict); - packageServiceMock.Setup(s => s.FindReferenceAssembliesWithTypeAsync("NuGetType", 0, It.IsAny())) - .Returns(() => ValueTaskFactory.FromResult(ImmutableArray.Empty)); - packageServiceMock.Setup(s => s.FindPackagesWithTypeAsync( - "nuget.org", "NuGetType", 0, It.IsAny())) + packageServiceMock.Setup(s => s.FindReferenceAssembliesAsync(new TypeQuery("NuGetType", 0), It.IsAny(), It.IsAny())) + .Returns(() => ValueTaskFactory.FromResult(ImmutableArray.Empty)); + packageServiceMock.Setup(s => s.FindPackagesAsync( + "nuget.org", new TypeQuery("NuGetType", 0), It.IsAny(), It.IsAny())) .Returns(() => CreateSearchResult("NuGetPackage", "NuGetType", CreateNameParts("NuGetNamespace"))); await TestInRegularAndScriptAsync( -@"class C -{ - [|NuGetType|] n; -}", -@"using NuGetNamespace; - -class C -{ - NuGetType n; -}", fixProviderData: new FixProviderData(installerServiceMock.Object, packageServiceMock.Object)); + """ + class C + { + [|NuGetType|] n; + } + """, + """ + using NuGetNamespace; + + class C + { + NuGetType n; + } + """, fixProviderData: new FixProviderData(installerServiceMock.Object, packageServiceMock.Object)); } [Fact] @@ -119,29 +127,33 @@ public async Task TestSearchPackageSingleName() var installerServiceMock = new Mock(MockBehavior.Strict); installerServiceMock.Setup(i => i.IsEnabled(It.IsAny())).Returns(true); installerServiceMock.Setup(i => i.IsInstalled(It.IsAny(), "NuGetPackage")).Returns(false); - installerServiceMock.Setup(i => i.GetInstalledVersions("NuGetPackage")).Returns(ImmutableArray.Empty); + installerServiceMock.Setup(i => i.GetInstalledVersions("NuGetPackage")).Returns([]); installerServiceMock.Setup(i => i.TryGetPackageSources()).Returns(NugetPackageSources); installerServiceMock.Setup(s => s.TryInstallPackageAsync(It.IsAny(), It.IsAny(), It.IsAny(), "NuGetPackage", It.IsAny(), It.IsAny(), It.IsAny>(), It.IsAny())) .Returns(SpecializedTasks.True); var packageServiceMock = new Mock(MockBehavior.Strict); - packageServiceMock.Setup(s => s.FindReferenceAssembliesWithTypeAsync("NuGetType", 0, It.IsAny())) - .Returns(() => ValueTaskFactory.FromResult(ImmutableArray.Empty)); - packageServiceMock.Setup(s => s.FindPackagesWithTypeAsync( - PackageSourceHelper.NugetOrgSourceName, "NuGetType", 0, It.IsAny())) + packageServiceMock.Setup(s => s.FindReferenceAssembliesAsync(new TypeQuery("NuGetType", 0), It.IsAny(), It.IsAny())) + .Returns(() => ValueTaskFactory.FromResult(ImmutableArray.Empty)); + packageServiceMock.Setup(s => s.FindPackagesAsync( + PackageSourceHelper.NugetOrgSourceName, new TypeQuery("NuGetType", 0), It.IsAny(), It.IsAny())) .Returns(() => CreateSearchResult("NuGetPackage", "NuGetType", CreateNameParts("NuGetNamespace"))); await TestInRegularAndScriptAsync( -@"class C -{ - [|NuGetType|] n; -}", -@"using NuGetNamespace; - -class C -{ - NuGetType n; -}", fixProviderData: new FixProviderData(installerServiceMock.Object, packageServiceMock.Object)); + """ + class C + { + [|NuGetType|] n; + } + """, + """ + using NuGetNamespace; + + class C + { + NuGetType n; + } + """, fixProviderData: new FixProviderData(installerServiceMock.Object, packageServiceMock.Object)); } [Fact] @@ -150,29 +162,33 @@ public async Task TestSearchPackageMultipleNames() var installerServiceMock = new Mock(MockBehavior.Strict); installerServiceMock.Setup(i => i.IsEnabled(It.IsAny())).Returns(true); installerServiceMock.Setup(i => i.IsInstalled(It.IsAny(), "NuGetPackage")).Returns(false); - installerServiceMock.Setup(i => i.GetInstalledVersions("NuGetPackage")).Returns(ImmutableArray.Empty); + installerServiceMock.Setup(i => i.GetInstalledVersions("NuGetPackage")).Returns([]); installerServiceMock.Setup(i => i.TryGetPackageSources()).Returns(NugetPackageSources); installerServiceMock.Setup(s => s.TryInstallPackageAsync(It.IsAny(), It.IsAny(), It.IsAny(), "NuGetPackage", It.IsAny(), It.IsAny(), It.IsAny>(), It.IsAny())) .Returns(SpecializedTasks.True); var packageServiceMock = new Mock(MockBehavior.Strict); - packageServiceMock.Setup(s => s.FindReferenceAssembliesWithTypeAsync("NuGetType", 0, It.IsAny())) - .Returns(() => ValueTaskFactory.FromResult(ImmutableArray.Empty)); - packageServiceMock.Setup(s => s.FindPackagesWithTypeAsync( - PackageSourceHelper.NugetOrgSourceName, "NuGetType", 0, It.IsAny())) + packageServiceMock.Setup(s => s.FindReferenceAssembliesAsync(new TypeQuery("NuGetType", 0), It.IsAny(), It.IsAny())) + .Returns(() => ValueTaskFactory.FromResult(ImmutableArray.Empty)); + packageServiceMock.Setup(s => s.FindPackagesAsync( + PackageSourceHelper.NugetOrgSourceName, new TypeQuery("NuGetType", 0), It.IsAny(), It.IsAny())) .Returns(() => CreateSearchResult("NuGetPackage", "NuGetType", CreateNameParts("NS1", "NS2"))); await TestInRegularAndScriptAsync( -@"class C -{ - [|NuGetType|] n; -}", -@"using NS1.NS2; - -class C -{ - NuGetType n; -}", fixProviderData: new FixProviderData(installerServiceMock.Object, packageServiceMock.Object)); + """ + class C + { + [|NuGetType|] n; + } + """, + """ + using NS1.NS2; + + class C + { + NuGetType n; + } + """, fixProviderData: new FixProviderData(installerServiceMock.Object, packageServiceMock.Object)); } [Fact] @@ -185,17 +201,19 @@ public async Task TestMissingIfPackageAlreadyInstalled() .Returns(true); var packageServiceMock = new Mock(MockBehavior.Strict); - packageServiceMock.Setup(s => s.FindReferenceAssembliesWithTypeAsync("NuGetType", 0, It.IsAny())) - .Returns(() => ValueTaskFactory.FromResult(ImmutableArray.Empty)); - packageServiceMock.Setup(s => s.FindPackagesWithTypeAsync( - PackageSourceHelper.NugetOrgSourceName, "NuGetType", 0, It.IsAny())) + packageServiceMock.Setup(s => s.FindReferenceAssembliesAsync(new TypeQuery("NuGetType", 0), It.IsAny(), It.IsAny())) + .Returns(() => ValueTaskFactory.FromResult(ImmutableArray.Empty)); + packageServiceMock.Setup(s => s.FindPackagesAsync( + PackageSourceHelper.NugetOrgSourceName, new TypeQuery("NuGetType", 0), It.IsAny(), It.IsAny())) .Returns(() => CreateSearchResult("NuGetPackage", "NuGetType", CreateNameParts("NS1", "NS2"))); await TestMissingInRegularAndScriptAsync( -@"class C -{ - [|NuGetType|] n; -}", new TestParameters(fixProviderData: new FixProviderData(installerServiceMock.Object, packageServiceMock.Object))); + """ + class C + { + [|NuGetType|] n; + } + """, new TestParameters(fixProviderData: new FixProviderData(installerServiceMock.Object, packageServiceMock.Object))); } [Fact] @@ -204,43 +222,49 @@ public async Task TestOptionsOffered() var installerServiceMock = new Mock(MockBehavior.Strict); installerServiceMock.Setup(i => i.IsEnabled(It.IsAny())).Returns(true); installerServiceMock.Setup(i => i.IsInstalled(It.IsAny(), "NuGetPackage")).Returns(false); - installerServiceMock.Setup(i => i.GetProjectsWithInstalledPackage(It.IsAny(), "NuGetPackage", "1.0")).Returns(ImmutableArray.Empty); - installerServiceMock.Setup(i => i.GetProjectsWithInstalledPackage(It.IsAny(), "NuGetPackage", "2.0")).Returns(ImmutableArray.Empty); + installerServiceMock.Setup(i => i.GetProjectsWithInstalledPackage(It.IsAny(), "NuGetPackage", "1.0")).Returns([]); + installerServiceMock.Setup(i => i.GetProjectsWithInstalledPackage(It.IsAny(), "NuGetPackage", "2.0")).Returns([]); installerServiceMock.Setup(i => i.TryGetPackageSources()).Returns(NugetPackageSources); installerServiceMock.Setup(s => s.GetInstalledVersions("NuGetPackage")) - .Returns(ImmutableArray.Create("1.0", "2.0")); + .Returns(["1.0", "2.0"]); var packageServiceMock = new Mock(MockBehavior.Strict); - packageServiceMock.Setup(s => s.FindReferenceAssembliesWithTypeAsync("NuGetType", 0, It.IsAny())) - .Returns(() => ValueTaskFactory.FromResult(ImmutableArray.Empty)); - packageServiceMock.Setup(s => s.FindPackagesWithTypeAsync( - PackageSourceHelper.NugetOrgSourceName, "NuGetType", 0, It.IsAny())) + packageServiceMock.Setup(s => s.FindReferenceAssembliesAsync(new TypeQuery("NuGetType", 0), It.IsAny(), It.IsAny())) + .Returns(() => ValueTaskFactory.FromResult(ImmutableArray.Empty)); + packageServiceMock.Setup(s => s.FindPackagesAsync( + PackageSourceHelper.NugetOrgSourceName, new TypeQuery("NuGetType", 0), It.IsAny(), It.IsAny())) .Returns(() => CreateSearchResult("NuGetPackage", "NuGetType", CreateNameParts("NS1", "NS2"))); var data = new FixProviderData(installerServiceMock.Object, packageServiceMock.Object); await TestSmartTagTextAsync( -@"class C -{ - [|NuGetType|] n; -}", -string.Format(FeaturesResources.Use_local_version_0, "1.0"), -parameters: new TestParameters(fixProviderData: data)); + """ + class C + { + [|NuGetType|] n; + } + """, + string.Format(FeaturesResources.Use_local_version_0, "1.0"), + parameters: new TestParameters(fixProviderData: data)); await TestSmartTagTextAsync( -@"class C -{ - [|NuGetType|] n; -}", -string.Format(FeaturesResources.Use_local_version_0, "2.0"), -parameters: new TestParameters(index: 1, fixProviderData: data)); + """ + class C + { + [|NuGetType|] n; + } + """, + string.Format(FeaturesResources.Use_local_version_0, "2.0"), + parameters: new TestParameters(index: 1, fixProviderData: data)); await TestSmartTagTextAsync( -@"class C -{ - [|NuGetType|] n; -}", -FeaturesResources.Find_and_install_latest_version, -parameters: new TestParameters(index: 2, fixProviderData: data)); + """ + class C + { + [|NuGetType|] n; + } + """, + FeaturesResources.Find_and_install_latest_version, + parameters: new TestParameters(index: 2, fixProviderData: data)); } [Fact] @@ -249,29 +273,33 @@ public async Task TestInstallGetsCalledNoVersion() var installerServiceMock = new Mock(MockBehavior.Strict); installerServiceMock.Setup(i => i.IsEnabled(It.IsAny())).Returns(true); installerServiceMock.Setup(i => i.IsInstalled(It.IsAny(), "NuGetPackage")).Returns(false); - installerServiceMock.Setup(i => i.GetInstalledVersions("NuGetPackage")).Returns(ImmutableArray.Empty); + installerServiceMock.Setup(i => i.GetInstalledVersions("NuGetPackage")).Returns([]); installerServiceMock.Setup(i => i.TryGetPackageSources()).Returns(NugetPackageSources); installerServiceMock.Setup(s => s.TryInstallPackageAsync(It.IsAny(), It.IsAny(), It.IsAny(), "NuGetPackage", /*versionOpt*/ null, It.IsAny(), It.IsAny>(), It.IsAny())) .Returns(SpecializedTasks.True); var packageServiceMock = new Mock(MockBehavior.Strict); - packageServiceMock.Setup(s => s.FindReferenceAssembliesWithTypeAsync("NuGetType", 0, It.IsAny())) - .Returns(() => ValueTaskFactory.FromResult(ImmutableArray.Empty)); - packageServiceMock.Setup(s => s.FindPackagesWithTypeAsync( - PackageSourceHelper.NugetOrgSourceName, "NuGetType", 0, It.IsAny())) + packageServiceMock.Setup(s => s.FindReferenceAssembliesAsync(new TypeQuery("NuGetType", 0), It.IsAny(), It.IsAny())) + .Returns(() => ValueTaskFactory.FromResult(ImmutableArray.Empty)); + packageServiceMock.Setup(s => s.FindPackagesAsync( + PackageSourceHelper.NugetOrgSourceName, new TypeQuery("NuGetType", 0), It.IsAny(), It.IsAny())) .Returns(() => CreateSearchResult("NuGetPackage", "NuGetType", CreateNameParts("NuGetNamespace"))); await TestInRegularAndScriptAsync( -@"class C -{ - [|NuGetType|] n; -}", -@"using NuGetNamespace; - -class C -{ - NuGetType n; -}", fixProviderData: new FixProviderData(installerServiceMock.Object, packageServiceMock.Object)); + """ + class C + { + [|NuGetType|] n; + } + """, + """ + using NuGetNamespace; + + class C + { + NuGetType n; + } + """, fixProviderData: new FixProviderData(installerServiceMock.Object, packageServiceMock.Object)); installerServiceMock.Verify(); } @@ -281,30 +309,34 @@ public async Task TestInstallGetsCalledWithVersion() var installerServiceMock = new Mock(MockBehavior.Strict); installerServiceMock.Setup(i => i.IsEnabled(It.IsAny())).Returns(true); installerServiceMock.Setup(i => i.IsInstalled(It.IsAny(), "NuGetPackage")).Returns(false); - installerServiceMock.Setup(i => i.GetProjectsWithInstalledPackage(It.IsAny(), "NuGetPackage", "1.0")).Returns(ImmutableArray.Empty); + installerServiceMock.Setup(i => i.GetProjectsWithInstalledPackage(It.IsAny(), "NuGetPackage", "1.0")).Returns([]); installerServiceMock.Setup(i => i.TryGetPackageSources()).Returns(NugetPackageSources); installerServiceMock.Setup(s => s.GetInstalledVersions("NuGetPackage")) - .Returns(ImmutableArray.Create("1.0")); + .Returns(["1.0"]); installerServiceMock.Setup(s => s.TryInstallPackageAsync(It.IsAny(), It.IsAny(), It.IsAny(), "NuGetPackage", "1.0", It.IsAny(), It.IsAny>(), It.IsAny())) .Returns(SpecializedTasks.True); var packageServiceMock = new Mock(MockBehavior.Strict); - packageServiceMock.Setup(s => s.FindReferenceAssembliesWithTypeAsync("NuGetType", 0, It.IsAny())) - .Returns(() => ValueTaskFactory.FromResult(ImmutableArray.Empty)); - packageServiceMock.Setup(s => s.FindPackagesWithTypeAsync(PackageSourceHelper.NugetOrgSourceName, "NuGetType", 0, It.IsAny())) + packageServiceMock.Setup(s => s.FindReferenceAssembliesAsync(new TypeQuery("NuGetType", 0), It.IsAny(), It.IsAny())) + .Returns(() => ValueTaskFactory.FromResult(ImmutableArray.Empty)); + packageServiceMock.Setup(s => s.FindPackagesAsync(PackageSourceHelper.NugetOrgSourceName, new TypeQuery("NuGetType", 0), It.IsAny(), It.IsAny())) .Returns(() => CreateSearchResult("NuGetPackage", "NuGetType", CreateNameParts("NuGetNamespace"))); await TestInRegularAndScriptAsync( -@"class C -{ - [|NuGetType|] n; -}", -@"using NuGetNamespace; - -class C -{ - NuGetType n; -}", fixProviderData: new FixProviderData(installerServiceMock.Object, packageServiceMock.Object)); + """ + class C + { + [|NuGetType|] n; + } + """, + """ + using NuGetNamespace; + + class C + { + NuGetType n; + } + """, fixProviderData: new FixProviderData(installerServiceMock.Object, packageServiceMock.Object)); installerServiceMock.Verify(); } @@ -314,42 +346,46 @@ public async Task TestFailedInstallRollsBackFile() var installerServiceMock = new Mock(MockBehavior.Strict); installerServiceMock.Setup(i => i.IsEnabled(It.IsAny())).Returns(true); installerServiceMock.Setup(i => i.IsInstalled(It.IsAny(), "NuGetPackage")).Returns(false); - installerServiceMock.Setup(i => i.GetProjectsWithInstalledPackage(It.IsAny(), "NuGetPackage", "1.0")).Returns(ImmutableArray.Empty); + installerServiceMock.Setup(i => i.GetProjectsWithInstalledPackage(It.IsAny(), "NuGetPackage", "1.0")).Returns([]); installerServiceMock.Setup(i => i.TryGetPackageSources()).Returns(NugetPackageSources); installerServiceMock.Setup(s => s.GetInstalledVersions("NuGetPackage")) - .Returns(ImmutableArray.Create("1.0")); + .Returns(["1.0"]); installerServiceMock.Setup(s => s.TryInstallPackageAsync(It.IsAny(), It.IsAny(), It.IsAny(), "NuGetPackage", "1.0", It.IsAny(), It.IsAny>(), It.IsAny())) .Returns(SpecializedTasks.False); var packageServiceMock = new Mock(MockBehavior.Strict); - packageServiceMock.Setup(s => s.FindReferenceAssembliesWithTypeAsync("NuGetType", 0, It.IsAny())) - .Returns(() => ValueTaskFactory.FromResult(ImmutableArray.Empty)); - packageServiceMock.Setup(s => s.FindPackagesWithTypeAsync(PackageSourceHelper.NugetOrgSourceName, "NuGetType", 0, It.IsAny())) + packageServiceMock.Setup(s => s.FindReferenceAssembliesAsync(new TypeQuery("NuGetType", 0), It.IsAny(), It.IsAny())) + .Returns(() => ValueTaskFactory.FromResult(ImmutableArray.Empty)); + packageServiceMock.Setup(s => s.FindPackagesAsync(PackageSourceHelper.NugetOrgSourceName, new TypeQuery("NuGetType", 0), It.IsAny(), It.IsAny())) .Returns(() => CreateSearchResult("NuGetPackage", "NuGetType", CreateNameParts("NuGetNamespace"))); await TestInRegularAndScriptAsync( -@"class C -{ - [|NuGetType|] n; -}", -@"class C -{ - NuGetType n; -}", fixProviderData: new FixProviderData(installerServiceMock.Object, packageServiceMock.Object)); + """ + class C + { + [|NuGetType|] n; + } + """, + """ + class C + { + NuGetType n; + } + """, fixProviderData: new FixProviderData(installerServiceMock.Object, packageServiceMock.Object)); installerServiceMock.Verify(); } - private static ValueTask> CreateSearchResult( + private static ValueTask> CreateSearchResult( string packageName, string typeName, ImmutableArray containingNamespaceNames) { - return CreateSearchResult(new PackageWithTypeResult( + return CreateSearchResult(new PackageResult( packageName: packageName, rank: 0, typeName: typeName, version: null, containingNamespaceNames: containingNamespaceNames)); } - private static ValueTask> CreateSearchResult(params PackageWithTypeResult[] results) + private static ValueTask> CreateSearchResult(params PackageResult[] results) => new(ImmutableArray.Create(results)); private static ImmutableArray CreateNameParts(params string[] parts) - => parts.ToImmutableArray(); + => [.. parts]; } diff --git a/src/EditorFeatures/CSharpTest/CodeActions/AddUsing/AddUsingTests.cs b/src/EditorFeatures/CSharpTest/CodeActions/AddUsing/AddUsingTests.cs index b3260af748791..553f3dc7c3415 100644 --- a/src/EditorFeatures/CSharpTest/CodeActions/AddUsing/AddUsingTests.cs +++ b/src/EditorFeatures/CSharpTest/CodeActions/AddUsing/AddUsingTests.cs @@ -4929,7 +4929,7 @@ void M() [|Other|] b; } } -", ImmutableArray.Empty); +", []); } [Fact] diff --git a/src/EditorFeatures/CSharpTest/CodeActions/GenerateEqualsAndGetHashCodeFromMembers/GenerateEqualsAndGetHashCodeFromMembersTests.cs b/src/EditorFeatures/CSharpTest/CodeActions/GenerateEqualsAndGetHashCodeFromMembers/GenerateEqualsAndGetHashCodeFromMembersTests.cs index 1b977d47ab288..ed9be9de37571 100644 --- a/src/EditorFeatures/CSharpTest/CodeActions/GenerateEqualsAndGetHashCodeFromMembers/GenerateEqualsAndGetHashCodeFromMembersTests.cs +++ b/src/EditorFeatures/CSharpTest/CodeActions/GenerateEqualsAndGetHashCodeFromMembers/GenerateEqualsAndGetHashCodeFromMembersTests.cs @@ -1098,7 +1098,7 @@ public override int GetHashCode() TestCode = code, FixedCode = fixedCode, CodeActionIndex = 1, - MemberNames = ImmutableArray.Empty, + MemberNames = [], LanguageVersion = LanguageVersion.CSharp6, Options = { PreferImplicitTypeWithInfo() }, }.RunAsync(); @@ -2039,7 +2039,7 @@ public override bool Equals(object obj) { TestCode = code, FixedCode = fixedCode, - MemberNames = ImmutableArray.Create("a", "b"), + MemberNames = ["a", "b"], LanguageVersion = LanguageVersion.CSharp6, Options = { PreferImplicitTypeWithInfo() }, }.RunAsync(); @@ -2084,7 +2084,7 @@ public override bool Equals(object obj) { TestCode = code, FixedCode = fixedCode, - MemberNames = ImmutableArray.Create("c", "b"), + MemberNames = ["c", "b"], LanguageVersion = LanguageVersion.CSharp6, Options = { PreferImplicitTypeWithInfo() }, }.RunAsync(); @@ -2127,7 +2127,7 @@ public override bool Equals(object obj) { TestCode = code, FixedCode = fixedCode, - MemberNames = ImmutableArray.Empty, + MemberNames = [], LanguageVersion = LanguageVersion.CSharp6, Options = { PreferImplicitTypeWithInfo() }, }.RunAsync(); @@ -3251,7 +3251,7 @@ public override System.Int32 GetHashCode() DiagnosticResult.CompilerError("CS1069").WithSpan(18, 52, 18, 57).WithArguments("Int32", "System", "mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"), }, }, - ReferenceAssemblies = ReferenceAssemblies.Default.WithAssemblies(ImmutableArray.Empty), + ReferenceAssemblies = ReferenceAssemblies.Default.WithAssemblies([]), }.RunAsync(); } @@ -4152,7 +4152,7 @@ partial class Goo """, }, }, - MemberNames = ImmutableArray.Create("bar"), + MemberNames = ["bar"], CodeActionIndex = 1, }.RunAsync(); } @@ -4210,7 +4210,7 @@ public override int GetHashCode() """, }, }, - MemberNames = ImmutableArray.Create("bar"), + MemberNames = ["bar"], CodeActionIndex = 1, }.RunAsync(); } @@ -4268,7 +4268,7 @@ partial class Goo """, }, }, - MemberNames = ImmutableArray.Create("bar"), + MemberNames = ["bar"], CodeActionIndex = 1, }.RunAsync(); } @@ -4328,7 +4328,7 @@ public override int GetHashCode() """, }, }, - MemberNames = ImmutableArray.Create("bar"), + MemberNames = ["bar"], CodeActionIndex = 1, }.RunAsync(); } diff --git a/src/EditorFeatures/CSharpTest/CodeActions/GenerateType/GenerateTypeTests.cs b/src/EditorFeatures/CSharpTest/CodeActions/GenerateType/GenerateTypeTests.cs index 669ac6f76c832..aea301c35c97c 100644 --- a/src/EditorFeatures/CSharpTest/CodeActions/GenerateType/GenerateTypeTests.cs +++ b/src/EditorFeatures/CSharpTest/CodeActions/GenerateType/GenerateTypeTests.cs @@ -23,13 +23,9 @@ namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Diagnostics.GenerateTypeTests; [Trait(Traits.Feature, Traits.Features.CodeActionsGenerateType)] -public partial class GenerateTypeTests : AbstractCSharpDiagnosticProviderBasedUserDiagnosticTest +public sealed partial class GenerateTypeTests(ITestOutputHelper logger) + : AbstractCSharpDiagnosticProviderBasedUserDiagnosticTest(logger) { - public GenerateTypeTests(ITestOutputHelper logger) - : base(logger) - { - } - internal override (DiagnosticAnalyzer?, CodeFixProvider) CreateDiagnosticProviderAndFixer(Workspace workspace) => (null, new GenerateTypeCodeFixProvider()); @@ -48,299 +44,361 @@ protected override TestComposition GetComposition() public async Task TestGenerateTypeParameterFromArgumentInferT() { await TestInRegularAndScriptAsync( -@"class Program -{ - void Main() - { - [|Goo|] f; - } -}", -@"class Program -{ - void Main() - { - Goo f; - } -} + """ + class Program + { + void Main() + { + [|Goo|] f; + } + } + """, + """ + class Program + { + void Main() + { + Goo f; + } + } -internal class Goo -{ -}", -index: 1); + internal class Goo + { + } + """, + index: 1); } [Fact] public async Task TestGenerateClassFromTypeParameter() { await TestInRegularAndScriptAsync( -@"class Class -{ - System.Action<[|Employee|]> employees; -}", -@"class Class -{ - System.Action employees; + """ + class Class + { + System.Action<[|Employee|]> employees; + } + """, + """ + class Class + { + System.Action employees; - private class Employee - { - } -}", -index: 2); + private class Employee + { + } + } + """, + index: 2); } [Fact] public async Task TestGenerateInternalClassFromASingleConstraintClause() { await TestInRegularAndScriptAsync( -@"class EmployeeList where T : [|Employee|], new() -{ -}", -@"class EmployeeList where T : Employee, new() -{ -} + """ + class EmployeeList where T : [|Employee|], new() + { + } + """, + """ + class EmployeeList where T : Employee, new() + { + } -internal class Employee -{ -}", -index: 1); + internal class Employee + { + } + """, + index: 1); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/18240")] public async Task TestGeneratePublicClassFromASingleConstraintClause() { await TestInRegularAndScriptAsync( -@"public class EmployeeList where T : [|Employee|], new() -{ -}", -@"public class EmployeeList where T : Employee, new() -{ -} + """ + public class EmployeeList where T : [|Employee|], new() + { + } + """, + """ + public class EmployeeList where T : Employee, new() + { + } -public class Employee -{ -}", -index: 1); + public class Employee + { + } + """, + index: 1); } [Fact] public async Task NegativeTestGenerateClassFromConstructorConstraint() { await TestMissingInRegularAndScriptAsync( -@"class EmployeeList where T : Employee, [|new()|] -{ -}"); + """ + class EmployeeList where T : Employee, [|new()|] + { + } + """); } [Fact] public async Task TestGenerateInternalClassFromMultipleTypeConstraintClauses() { await TestInRegularAndScriptAsync( -@"class Derived - where U : struct - where T : [|Base|], new() -{ -}", -@"class Derived - where U : struct - where T : Base, new() -{ -} + """ + class Derived + where U : struct + where T : [|Base|], new() + { + } + """, + """ + class Derived + where U : struct + where T : Base, new() + { + } -internal class Base -{ -}", -index: 1); + internal class Base + { + } + """, + index: 1); } [Fact] public async Task TestGeneratePublicClassFromMultipleTypeConstraintClauses() { await TestInRegularAndScriptAsync( -@"public class Derived - where U : struct - where T : [|Base|], new() -{ -}", -@"public class Derived - where U : struct - where T : Base, new() -{ -} + """ + public class Derived + where U : struct + where T : [|Base|], new() + { + } + """, + """ + public class Derived + where U : struct + where T : Base, new() + { + } -public class Base -{ -}", -index: 1); + public class Base + { + } + """, + index: 1); } [Fact] public async Task NegativeTestGenerateClassFromClassOrStructConstraint() { await TestMissingInRegularAndScriptAsync( -@"class Derived - where U : [|struct|] - where T : Base, new() -{ -}"); + """ + class Derived + where U : [|struct|] + where T : Base, new() + { + } + """); } [Fact] public async Task TestAbsenceOfGenerateIntoInvokingTypeForConstraintList() { await TestActionCountAsync( -@"class EmployeeList where T : [|Employee|] -{ -}", -count: 3, -parameters: new TestParameters(Options.Regular)); + """ + class EmployeeList where T : [|Employee|] + { + } + """, + count: 3, + parameters: new TestParameters(Options.Regular)); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/18240")] public async Task TestGenerateInternalClassFromASingleConstraintClauseInterface() { await TestInRegularAndScriptAsync( -@"interface IEmployeeList where T : [|Employee|], new() -{ -}", -@"interface IEmployeeList where T : Employee, new() -{ -} + """ + interface IEmployeeList where T : [|Employee|], new() + { + } + """, + """ + interface IEmployeeList where T : Employee, new() + { + } -internal class Employee -{ -}", -index: 1); + internal class Employee + { + } + """, + index: 1); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/18240")] public async Task TestGeneratePublicClassFromASingleConstraintClausePublicInterface() { await TestInRegularAndScriptAsync( -@"public interface IEmployeeList where T : [|Employee|], new() -{ -}", -@"public interface IEmployeeList where T : Employee, new() -{ -} + """ + public interface IEmployeeList where T : [|Employee|], new() + { + } + """, + """ + public interface IEmployeeList where T : Employee, new() + { + } -public class Employee -{ -}", -index: 1); + public class Employee + { + } + """, + index: 1); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/18240")] public async Task TestGenerateInternalClassFromASingleConstraintClauseInternalDelegate() { await TestInRegularAndScriptAsync( -@"class Employee -{ - internal delegate void Action() where T : [|Command|]; -}", -@"class Employee -{ - internal delegate void Action() where T : Command; -} + """ + class Employee + { + internal delegate void Action() where T : [|Command|]; + } + """, + """ + class Employee + { + internal delegate void Action() where T : Command; + } -internal class Command -{ -}", -index: 1); + internal class Command + { + } + """, + index: 1); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/18240")] public async Task TestGenerateInternalClassFromASingleConstraintClausePublicDelegate() { await TestInRegularAndScriptAsync( -@"class Employee -{ - public delegate void Action() where T : [|Command|]; -}", -@"class Employee -{ - public delegate void Action() where T : Command; -} + """ + class Employee + { + public delegate void Action() where T : [|Command|]; + } + """, + """ + class Employee + { + public delegate void Action() where T : Command; + } -internal class Command -{ -}", -index: 1); + internal class Command + { + } + """, + index: 1); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/18240")] public async Task TestGenerateInternalClassFromASingleConstraintClauseInternalMethod() { await TestInRegularAndScriptAsync( -@"class Employee -{ - internal void Action() where T : [|Command|] {} -}", -@"class Employee -{ - internal void Action() where T : Command {} -} + """ + class Employee + { + internal void Action() where T : [|Command|] {} + } + """, + """ + class Employee + { + internal void Action() where T : Command {} + } -internal class Command -{ -}", -index: 1); + internal class Command + { + } + """, + index: 1); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/18240")] public async Task TestGenerateInternalClassFromASingleConstraintClausePublicMethod() { await TestInRegularAndScriptAsync( -@"class Employee -{ - public void Action() where T : [|Command|] {} -}", -@"class Employee -{ - public void Action() where T : Command {} -} + """ + class Employee + { + public void Action() where T : [|Command|] {} + } + """, + """ + class Employee + { + public void Action() where T : Command {} + } -internal class Command -{ -}", -index: 1); + internal class Command + { + } + """, + index: 1); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/18240")] public async Task TestGenerateInternalClassFromASingleConstraintClauseMethod() { await TestInRegularAndScriptAsync( -@"class Employee -{ - void Action() where T : [|Command|] {} -}", -@"class Employee -{ - void Action() where T : Command {} -} + """ + class Employee + { + void Action() where T : [|Command|] {} + } + """, + """ + class Employee + { + void Action() where T : Command {} + } -internal class Command -{ -}", -index: 1); + internal class Command + { + } + """, + index: 1); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/18240")] public async Task TestGenerateInternalClassFromASingleConstraintClauseMethodInInterface() { await TestInRegularAndScriptAsync( -@"interface Employee -{ - void Action() where T : [|Command|] {} -}", -@"interface Employee -{ - void Action() where T : Command {} -} + """ + interface Employee + { + void Action() where T : [|Command|] {} + } + """, + """ + interface Employee + { + void Action() where T : Command {} + } -internal class Command -{ -}", -index: 1); + internal class Command + { + } + """, + index: 1); } [Theory, WorkItem("https://github.com/dotnet/roslyn/issues/18240")] @@ -355,31 +413,35 @@ internal class Command public async Task TestGenerateInternalClassFromASingleConstraintClauseNestedClass(string middleAccessibility, string accessibility, string generatedAccessibility) { await TestInRegularAndScriptAsync( -$@"public class A -{{ - {middleAccessibility} class B - {{ - {accessibility} class C where T : [|D|] - {{ + $$""" + public class A + { + {{middleAccessibility}} class B + { + {{accessibility}} class C where T : [|D|] + { - }} - }} -}}", -$@"public class A -{{ - {middleAccessibility} class B - {{ - {accessibility} class C where T : D - {{ + } + } + } + """, + $$""" + public class A + { + {{middleAccessibility}} class B + { + {{accessibility}} class C where T : D + { - }} - }} -}} + } + } + } -{generatedAccessibility} class D -{{ -}}", -index: 1); + {{generatedAccessibility}} class D + { + } + """, + index: 1); } #endregion @@ -390,42 +452,50 @@ await TestInRegularAndScriptAsync( public async Task TestGenerateClassFromParenthesizedLambdaExpressionsParameter() { await TestInRegularAndScriptAsync( -@"class Class -{ - Func l = ([|Employee|] e, int age) => e.Age > age; -}", -@"class Class -{ - Func l = (Employee e, int age) => e.Age > age; + """ + class Class + { + Func l = ([|Employee|] e, int age) => e.Age > age; + } + """, + """ + class Class + { + Func l = (Employee e, int age) => e.Age > age; - private class Employee - { - } -}", -index: 2); + private class Employee + { + } + } + """, + index: 2); } [Fact] public async Task TestGenerateClassFromParenthesizedLambdaExpressionsBody() { await TestInRegularAndScriptAsync( -@"class Class -{ - System.Action l = (Class e, int age) => { - [|Wage|] w; - }; -}", -@"class Class -{ - System.Action l = (Class e, int age) => { - Wage w; - }; + """ + class Class + { + System.Action l = (Class e, int age) => { + [|Wage|] w; + }; + } + """, + """ + class Class + { + System.Action l = (Class e, int age) => { + Wage w; + }; - private class Wage - { - } -}", -index: 2); + private class Wage + { + } + } + """, + index: 2); } #endregion @@ -434,474 +504,388 @@ private class Wage public async Task TestGenerateClassFromFieldDeclarationIntoSameType() { await TestInRegularAndScriptAsync( -@"class Class -{ - [|Goo|] f; -}", -@"class Class -{ - Goo f; + """ + class Class + { + [|Goo|] f; + } + """, + """ + class Class + { + Goo f; - private class Goo - { - } -}", -index: 2); + private class Goo + { + } + } + """, + index: 2); } [Fact] public async Task TestGenerateClassFromNullableFieldDeclarationIntoSameType() { await TestInRegularAndScriptAsync( -@"#nullable enable -class Class -{ - [|Goo?|] f; -}", -@"#nullable enable -class Class -{ - Goo? f; + """ + #nullable enable + class Class + { + [|Goo?|] f; + } + """, + """ + #nullable enable + class Class + { + Goo? f; - private class Goo - { - } -}", -index: 2); + private class Goo + { + } + } + """, + index: 2); } [WpfFact] public async Task TestGenerateClassFromFieldDeclarationIntoGlobalNamespace() { await TestAddDocumentInRegularAndScriptAsync( -@"class Program { void Main ( ) { [|Goo|] f ; } } ", -@"internal class Goo -{ -}", -expectedContainers: ImmutableArray.Empty, -expectedDocumentName: "Goo.cs"); + @"class Program { void Main ( ) { [|Goo|] f ; } } ", + """ + internal class Goo + { + } + """, + expectedContainers: [], + expectedDocumentName: "Goo.cs"); } [WpfFact] public async Task TestGenerateClassFromFieldDeclarationIntoCustomNamespace() { await TestAddDocumentInRegularAndScriptAsync( -@"class Class { [|TestNamespace|].Goo f; }", -@"namespace TestNamespace -{ - internal class Goo - { - } -}", -expectedContainers: ImmutableArray.Create("TestNamespace"), -expectedDocumentName: "Goo.cs"); + @"class Class { [|TestNamespace|].Goo f; }", + """ + namespace TestNamespace + { + internal class Goo + { + } + } + """, + expectedContainers: ["TestNamespace"], + expectedDocumentName: "Goo.cs"); } [Fact] public async Task TestGenerateClassFromFieldDeclarationIntoSameNamespace() { await TestInRegularAndScriptAsync( -@"class Class -{ - [|Goo|] f; -}", -@"class Class -{ - Goo f; -} + """ + class Class + { + [|Goo|] f; + } + """, + """ + class Class + { + Goo f; + } -internal class Goo -{ -}", -index: 1); + internal class Goo + { + } + """, + index: 1); } [Fact] public async Task TestGenerateClassWithCtorFromObjectCreation() { await TestInRegularAndScriptAsync( -@"class Class -{ - Goo f = new [|Goo|](); -}", -@"class Class -{ - Goo f = new Goo(); + """ + class Class + { + Goo f = new [|Goo|](); + } + """, + """ + class Class + { + Goo f = new Goo(); - private class Goo - { - public Goo() - { - } - } -}", -index: 2); - } + private class Goo + { + public Goo() + { + } + } + } + """, + index: 2); + } [Fact] public async Task TestGenerateClassWithCtorFromObjectCreationWithTuple() { await TestInRegularAndScriptAsync( -@"class Class -{ - var f = new [|Generated|]((1, 2)); -}", -@"class Class -{ - var f = new Generated((1, 2)); + """ + class Class + { + var f = new [|Generated|]((1, 2)); + } + """, + """ + class Class + { + var f = new Generated((1, 2)); - private class Generated - { - private (int, int) value; + private class Generated + { + private (int, int) value; - public Generated((int, int) value) - { - this.value = value; - } - } -}", -index: 2); + public Generated((int, int) value) + { + this.value = value; + } + } + } + """, + index: 2); } [Fact] public async Task TestGenerateClassWithCtorFromObjectCreationWithTupleWithNames() { await TestInRegularAndScriptAsync( -@"class Class -{ - var f = new [|Generated|]((a: 1, b: 2, 3)); -}", -@"class Class -{ - var f = new Generated((a: 1, b: 2, 3)); + """ + class Class + { + var f = new [|Generated|]((a: 1, b: 2, 3)); + } + """, + """ + class Class + { + var f = new Generated((a: 1, b: 2, 3)); - private class Generated - { - private (int a, int b, int) value; + private class Generated + { + private (int a, int b, int) value; - public Generated((int a, int b, int) value) - { - this.value = value; - } - } -}", -index: 2); + public Generated((int a, int b, int) value) + { + this.value = value; + } + } + } + """, + index: 2); } [Fact] public async Task TestGenerateClassFromBaseList() { await TestInRegularAndScriptAsync( -@"class Class : [|BaseClass|] -{ -}", -@"class Class : BaseClass -{ -} + """ + class Class : [|BaseClass|] + { + } + """, + """ + class Class : BaseClass + { + } -internal class BaseClass -{ -}", -index: 1); + internal class BaseClass + { + } + """, + index: 1); } [Fact] public async Task TestGenerateClassFromMethodParameters() { await TestInRegularAndScriptAsync( -@"class Class -{ - void Method([|Goo|] f) - { - } -}", -@"class Class -{ - void Method(Goo f) - { - } + """ + class Class + { + void Method([|Goo|] f) + { + } + } + """, + """ + class Class + { + void Method(Goo f) + { + } - private class Goo - { - } -}", -index: 2); + private class Goo + { + } + } + """, + index: 2); } [Fact] public async Task TestGenerateClassFromMethodReturnType() { await TestInRegularAndScriptAsync( -@"class Class -{ - [|Goo|] Method() - { - } -}", -@"class Class -{ - Goo Method() - { - } + """ + class Class + { + [|Goo|] Method() + { + } + } + """, + """ + class Class + { + Goo Method() + { + } - private class Goo - { - } -}", -index: 2); + private class Goo + { + } + } + """, + index: 2); } [Fact] public async Task TestGenerateClassFromAttribute() { await TestInRegularAndScriptAsync( -@"class Class -{ - [[|Obsolete|]] - void Method() - { - } -}", -@"using System; + """ + class Class + { + [[|Obsolete|]] + void Method() + { + } + } + """, + """ + using System; -class Class -{ - [Obsolete] - void Method() - { - } + class Class + { + [Obsolete] + void Method() + { + } - private class ObsoleteAttribute : Attribute - { - } -}", -index: 2); + private class ObsoleteAttribute : Attribute + { + } + } + """, + index: 2); } [Fact] public async Task TestGenerateClassFromExpandedAttribute() { await TestInRegularAndScriptAsync( -@"class Class -{ - [[|ObsoleteAttribute|]] - void Method() - { - } -}", -@"using System; + """ + class Class + { + [[|ObsoleteAttribute|]] + void Method() + { + } + } + """, + """ + using System; -class Class -{ - [ObsoleteAttribute] - void Method() - { - } + class Class + { + [ObsoleteAttribute] + void Method() + { + } - private class ObsoleteAttribute : Attribute - { - } -}", -index: 2); + private class ObsoleteAttribute : Attribute + { + } + } + """, + index: 2); } [Fact] public async Task TestGenerateClassFromCatchClause() { await TestInRegularAndScriptAsync( -@"class Class -{ - void Method() - { - try - { - } - catch ([|ExType|]) - { - } - } -}", -@"using System; -using System.Runtime.Serialization; + """ + class Class + { + void Method() + { + try + { + } + catch ([|ExType|]) + { + } + } + } + """, + """ + using System; + using System.Runtime.Serialization; -class Class -{ - void Method() - { - try - { - } - catch (ExType) - { - } - } + class Class + { + void Method() + { + try + { + } + catch (ExType) + { + } + } - [Serializable] - private class ExType : Exception - { - public ExType() - { - } + [Serializable] + private class ExType : Exception + { + public ExType() + { + } - public ExType(string message) : base(message) - { - } + public ExType(string message) : base(message) + { + } - public ExType(string message, Exception innerException) : base(message, innerException) - { - } + public ExType(string message, Exception innerException) : base(message, innerException) + { + } - protected ExType(SerializationInfo info, StreamingContext context) : base(info, context) - { - } - } -}", -index: 2); + protected ExType(SerializationInfo info, StreamingContext context) : base(info, context) + { + } + } + } + """, + index: 2); } [Fact] public async Task TestGenerateClassFromThrowStatement() { await TestInRegularAndScriptAsync( -@"class Class -{ - void Method() - { - throw new [|ExType|](); - } -}", -@"using System; -using System.Runtime.Serialization; - -class Class -{ - void Method() - { - throw new ExType(); - } - - [Serializable] - private class ExType : Exception - { - public ExType() - { - } - - public ExType(string message) : base(message) - { - } - - public ExType(string message, Exception innerException) : base(message, innerException) - { - } - - protected ExType(SerializationInfo info, StreamingContext context) : base(info, context) - { - } - } -}", -index: 2); - } - - [Fact] - public async Task TestGenerateClassFromThrowStatementWithDifferentArg() - { - await TestInRegularAndScriptAsync( -@"class Class -{ - void Method() - { - throw new [|ExType|](1); - } -}", -@"using System; -using System.Runtime.Serialization; - -class Class -{ - void Method() - { - throw new ExType(1); - } - - [Serializable] - private class ExType : Exception - { - private int v; - - public ExType() - { - } - - public ExType(int v) - { - this.v = v; - } - - public ExType(string message) : base(message) - { - } - - public ExType(string message, Exception innerException) : base(message, innerException) - { - } - - protected ExType(SerializationInfo info, StreamingContext context) : base(info, context) - { - } - } -}", -index: 2); - } - - [Fact] - public async Task TestGenerateClassFromThrowStatementWithMatchingArg() - { - await TestInRegularAndScriptAsync( -@"class Class -{ - void Method() - { - throw new [|ExType|](""message""); - } -}", -@"using System; -using System.Runtime.Serialization; - -class Class -{ - void Method() - { - throw new ExType(""message""); - } - - [Serializable] - private class ExType : Exception - { - public ExType() - { - } - - public ExType(string message) : base(message) - { - } - - public ExType(string message, Exception innerException) : base(message, innerException) - { - } - - protected ExType(SerializationInfo info, StreamingContext context) : base(info, context) - { - } - } -}", -index: 2); - } - - [Fact] - public async Task TestGenerateClassFromThrowStatementOnModernDotNet_NoObsoleteConstructor() - { - var source = """ + """ class Class { void Method() @@ -909,16 +893,10 @@ void Method() throw new [|ExType|](); } } - """; - - await TestInRegularAndScriptAsync($""" - - - {source} - - - """, """ + """, + """ using System; + using System.Runtime.Serialization; class Class { @@ -941,1968 +919,2354 @@ public ExType(string message) : base(message) public ExType(string message, Exception innerException) : base(message, innerException) { } + + protected ExType(SerializationInfo info, StreamingContext context) : base(info, context) + { + } } } - """, index: 2); - } - - [Fact] - public async Task TestAbsenceOfGenerateIntoInvokingTypeForBaseList() - { - await TestActionCountAsync( -@"class Class : [|BaseClass|] -{ -}", -count: 3, -parameters: new TestParameters(Options.Regular)); + """, + index: 2); } [Fact] - public async Task TestGenerateClassFromUsingStatement() + public async Task TestGenerateClassFromThrowStatementWithDifferentArg() { await TestInRegularAndScriptAsync( -@"class Class -{ - void Method() - { - using ([|Goo|] f = new Goo()) - { - } + """ + class Class + { + void Method() + { + throw new [|ExType|](1); + } + } + """, + """ + using System; + using System.Runtime.Serialization; + + class Class + { + void Method() + { + throw new ExType(1); + } + + [Serializable] + private class ExType : Exception + { + private int v; + + public ExType() + { + } + + public ExType(int v) + { + this.v = v; + } + + public ExType(string message) : base(message) + { + } + + public ExType(string message, Exception innerException) : base(message, innerException) + { + } + + protected ExType(SerializationInfo info, StreamingContext context) : base(info, context) + { + } + } + } + """, + index: 2); } -}", -@"class Class -{ - void Method() + + [Fact] + public async Task TestGenerateClassFromThrowStatementWithMatchingArg() { - using (Goo f = new Goo()) - { - } + await TestInRegularAndScriptAsync( + """ + class Class + { + void Method() + { + throw new [|ExType|]("message"); + } + } + """, + """ + using System; + using System.Runtime.Serialization; + + class Class + { + void Method() + { + throw new ExType("message"); + } + + [Serializable] + private class ExType : Exception + { + public ExType() + { + } + + public ExType(string message) : base(message) + { + } + + public ExType(string message, Exception innerException) : base(message, innerException) + { + } + + protected ExType(SerializationInfo info, StreamingContext context) : base(info, context) + { + } + } + } + """, + index: 2); } - private class Goo + [Fact] + public async Task TestGenerateClassFromThrowStatementOnModernDotNet_NoObsoleteConstructor() { - } -}", -index: 2); + var source = """ + class Class + { + void Method() + { + throw new [|ExType|](); + } + } + """; + + await TestInRegularAndScriptAsync($""" + + + {source} + + + """, """ + using System; + + class Class + { + void Method() + { + throw new ExType(); + } + + [Serializable] + private class ExType : Exception + { + public ExType() + { + } + + public ExType(string message) : base(message) + { + } + + public ExType(string message, Exception innerException) : base(message, innerException) + { + } + } + } + """, index: 2); } [Fact] - public async Task TestGenerateClassFromForeachStatement() - { - await TestInRegularAndScriptAsync( -@"class Class -{ - void Method() + public async Task TestAbsenceOfGenerateIntoInvokingTypeForBaseList() { - foreach ([|Employee|] e in empList) - { - } + await TestActionCountAsync( + """ + class Class : [|BaseClass|] + { + } + """, + count: 3, + parameters: new TestParameters(Options.Regular)); } -}", -@"class Class -{ - void Method() + + [Fact] + public async Task TestGenerateClassFromUsingStatement() { - foreach (Employee e in empList) - { - } + await TestInRegularAndScriptAsync( + """ + class Class + { + void Method() + { + using ([|Goo|] f = new Goo()) + { + } + } + } + """, + """ + class Class + { + void Method() + { + using (Goo f = new Goo()) + { + } + } + + private class Goo + { + } + } + """, + index: 2); } - private class Employee + [Fact] + public async Task TestGenerateClassFromForeachStatement() { - } -}", -index: 2); + await TestInRegularAndScriptAsync( + """ + class Class + { + void Method() + { + foreach ([|Employee|] e in empList) + { + } + } + } + """, + """ + class Class + { + void Method() + { + foreach (Employee e in empList) + { + } + } + + private class Employee + { + } + } + """, + index: 2); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/538346")] public async Task TestGenerateClassWhereKeywordBecomesTypeName() { await TestInRegularAndScriptAsync( -@"class Class -{ - [|@class|] c; -}", -@"class Class -{ - @class c; + """ + class Class + { + [|@class|] c; + } + """, + """ + class Class + { + @class c; - private class @class - { - } -}", -index: 2); + private class @class + { + } + } + """, + index: 2); } [Fact] public async Task NegativeTestGenerateClassOnContextualKeyword() { await TestInRegularAndScriptAsync( -@"class Class -{ - [|@Goo|] c; -}", -@"class Class -{ - @Goo c; + """ + class Class + { + [|@Goo|] c; + } + """, + """ + class Class + { + @Goo c; - private class Goo - { - } -}", -index: 2); + private class Goo + { + } + } + """, + index: 2); } [Fact] public async Task NegativeTestGenerateClassOnFrameworkTypes() { await TestMissingInRegularAndScriptAsync( -@"class Class -{ - void Method() - { - [|System|].Console.Write(5); - } -}"); + """ + class Class + { + void Method() + { + [|System|].Console.Write(5); + } + } + """); await TestMissingInRegularAndScriptAsync( -@"class Class -{ - void Method() - { - System.[|Console|].Write(5); - } -}"); + """ + class Class + { + void Method() + { + System.[|Console|].Write(5); + } + } + """); await TestMissingInRegularAndScriptAsync( -@"class Class -{ - void Method() - { - System.Console.[|Write|](5); - } -}"); + """ + class Class + { + void Method() + { + System.Console.[|Write|](5); + } + } + """); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/538409")] public async Task GenerateIntoRightPart() { await TestInRegularAndScriptAsync( -@"partial class Class -{ -} + """ + partial class Class + { + } -partial class Class -{ - [|C|] c; -}", -@"partial class Class -{ -} + partial class Class + { + [|C|] c; + } + """, + """ + partial class Class + { + } -partial class Class -{ - C c; + partial class Class + { + C c; - private class C - { - } -}", -index: 2); + private class C + { + } + } + """, + index: 2); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/538408")] public async Task GenerateTypeIntoCompilationUnit() { await TestInRegularAndScriptAsync( -@"class Class -{ - [|C|] c; + """ + class Class + { + [|C|] c; - void Main() - { - } -}", -@"class Class -{ - C c; + void Main() + { + } + } + """, + """ + class Class + { + C c; - void Main() - { - } -} + void Main() + { + } + } -internal class C -{ -}", -index: 1); + internal class C + { + } + """, + index: 1); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/538408")] public async Task GenerateTypeIntoNamespace() { await TestInRegularAndScriptAsync( -@"namespace N -{ - class Class - { - [|C|] c; + """ + namespace N + { + class Class + { + [|C|] c; - void Main() - { - } - } -}", -@"namespace N -{ - class Class - { - C c; + void Main() + { + } + } + } + """, + """ + namespace N + { + class Class + { + C c; - void Main() - { - } - } + void Main() + { + } + } - internal class C - { - } -}", -index: 1); + internal class C + { + } + } + """, + index: 1); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/538115")] public async Task GenerateTypeWithPreprocessor() { await TestInRegularAndScriptAsync( -@"class C -{ -#if true - void Goo([|A|] x) { } -#else -#endif -}", -@"class C -{ -#if true - void Goo(A x) { } + """ + class C + { + #if true + void Goo([|A|] x) { } + #else + #endif + } + """, + """ + class C + { + #if true + void Goo(A x) { } - private class A - { - } -#else -#endif -}", -index: 2); + private class A + { + } + #else + #endif + } + """, + index: 2); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/538495")] public async Task GenerateTypeIntoContainingNamespace() { await TestInRegularAndScriptAsync( -@"namespace N -{ - class Class - { - N.[|C|] c; - } -}", -@"namespace N -{ - class Class - { - N.C c; - } + """ + namespace N + { + class Class + { + N.[|C|] c; + } + } + """, + """ + namespace N + { + class Class + { + N.C c; + } - internal class C - { - } -}", -index: 1); + internal class C + { + } + } + """, + index: 1); } [WpfFact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/538516")] public async Task TestGenerateClassFromIntoNewNamespace() { await TestAddDocumentInRegularAndScriptAsync( -@"class Class { static void Main(string[] args) { [|N|].C c; } }", -@"namespace N -{ - internal class C - { - } -}", -expectedContainers: ImmutableArray.Create("N"), -expectedDocumentName: "C.cs"); + @"class Class { static void Main(string[] args) { [|N|].C c; } }", + """ + namespace N + { + internal class C + { + } + } + """, + expectedContainers: ["N"], + expectedDocumentName: "C.cs"); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/538558")] public async Task NegativeTestGlobalAlias() { await TestMissingInRegularAndScriptAsync( -@"class Class -{ - void Method() - { - [|global|]::System.String s; - } -}"); + """ + class Class + { + void Method() + { + [|global|]::System.String s; + } + } + """); await TestMissingInRegularAndScriptAsync( -@"class Class -{ - void Method() - { - global::[|System|].String s; - } -}"); + """ + class Class + { + void Method() + { + global::[|System|].String s; + } + } + """); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/538069")] public async Task GenerateTypeFromArrayCreation1() { await TestAsync( -@"class A -{ - void Goo() - { - A[] x = new [|C|][] { }; - } -}", -@"class A -{ - void Goo() - { - A[] x = new C[] { }; - } -} + """ + class A + { + void Goo() + { + A[] x = new [|C|][] { }; + } + } + """, + """ + class A + { + void Goo() + { + A[] x = new C[] { }; + } + } -internal class C : A -{ -}", -index: 1, -parseOptions: null); + internal class C : A + { + } + """, + index: 1, + parseOptions: null); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/538069")] public async Task GenerateTypeFromArrayCreation2() { await TestAsync( -@"class A -{ - void Goo() - { - A[][] x = new [|C|][][] { }; - } -}", -@"class A -{ - void Goo() - { - A[][] x = new C[][] { }; - } -} + """ + class A + { + void Goo() + { + A[][] x = new [|C|][][] { }; + } + } + """, + """ + class A + { + void Goo() + { + A[][] x = new C[][] { }; + } + } -internal class C : A -{ -}", -index: 1, -parseOptions: null); + internal class C : A + { + } + """, + index: 1, + parseOptions: null); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/538069")] public async Task GenerateTypeFromArrayCreation3() { await TestAsync( -@"class A -{ - void Goo() - { - A[] x = new [|C|][][] { }; - } -}", -@"class A -{ - void Goo() - { - A[] x = new C[][] { }; - } -} + """ + class A + { + void Goo() + { + A[] x = new [|C|][][] { }; + } + } + """, + """ + class A + { + void Goo() + { + A[] x = new C[][] { }; + } + } -internal class C -{ -}", -index: 1, -parseOptions: null); + internal class C + { + } + """, + index: 1, + parseOptions: null); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/539329")] public async Task NegativeTestNotInUsingDirective() { await TestMissingInRegularAndScriptAsync( -@"using [|A|];"); + @"using [|A|];"); await TestMissingInRegularAndScriptAsync( -@"using [|A.B|];"); + @"using [|A.B|];"); await TestMissingInRegularAndScriptAsync( -@"using [|A|].B;"); + @"using [|A|].B;"); await TestMissingInRegularAndScriptAsync( -@"using A.[|B|];"); + @"using A.[|B|];"); await TestMissingInRegularAndScriptAsync( -@"using X = [|A|];"); + @"using X = [|A|];"); } [Fact] public async Task GenerateSimpleConstructor() { await TestInRegularAndScriptAsync( -@"class Class -{ - void M() - { - new [|T|](); - } -}", -@"class Class -{ - void M() - { - new T(); - } -} + """ + class Class + { + void M() + { + new [|T|](); + } + } + """, + """ + class Class + { + void M() + { + new T(); + } + } -internal class T -{ - public T() - { - } -}", -index: 1); + internal class T + { + public T() + { + } + } + """, + index: 1); } [Fact] public async Task GenerateWithValueParameter() { await TestInRegularAndScriptAsync( -@"class Class -{ - void M() - { - new [|T|](1); - } -}", -@"class Class -{ - void M() - { - new T(1); - } -} + """ + class Class + { + void M() + { + new [|T|](1); + } + } + """, + """ + class Class + { + void M() + { + new T(1); + } + } -internal class T -{ - private int v; + internal class T + { + private int v; - public T(int v) - { - this.v = v; - } -}", -index: 1); + public T(int v) + { + this.v = v; + } + } + """, + index: 1); } [Fact] public async Task GenerateWithTwoValueParameters() { await TestInRegularAndScriptAsync( -@"class Class -{ - void M() - { - new [|T|](1, """"); - } -}", -@"class Class -{ - void M() - { - new T(1, """"); - } -} + """ + class Class + { + void M() + { + new [|T|](1, ""); + } + } + """, + """ + class Class + { + void M() + { + new T(1, ""); + } + } -internal class T -{ - private int v1; - private string v2; + internal class T + { + private int v1; + private string v2; - public T(int v1, string v2) - { - this.v1 = v1; - this.v2 = v2; - } -}", -index: 1); + public T(int v1, string v2) + { + this.v1 = v1; + this.v2 = v2; + } + } + """, + index: 1); } [Fact] public async Task GenerateWithNullableParameter() { await TestInRegularAndScriptAsync( -@"#nullable enable -class Class -{ - void M() - { - string? s = null; - new [|T|](s); - } -}", -@"#nullable enable -class Class -{ - void M() - { - string? s = null; - new [|T|](s); - } -} + """ + #nullable enable + class Class + { + void M() + { + string? s = null; + new [|T|](s); + } + } + """, + """ + #nullable enable + class Class + { + void M() + { + string? s = null; + new [|T|](s); + } + } -internal class T -{ - private string? s; + internal class T + { + private string? s; - public T(string? s) - { - this.s = s; - } -}", -index: 1); + public T(string? s) + { + this.s = s; + } + } + """, + index: 1); } [Fact] public async Task GenerateWithNullableParameterThatIsNotNull() { await TestInRegularAndScriptAsync( -@"#nullable enable -class Class -{ - void M() - { - string? s = ""asdf""; - new [|T|](s); - } -}", -@"#nullable enable -class Class -{ - void M() - { - string? s = ""asdf""; - new [|T|](s); - } -} + """ + #nullable enable + class Class + { + void M() + { + string? s = "asdf"; + new [|T|](s); + } + } + """, + """ + #nullable enable + class Class + { + void M() + { + string? s = "asdf"; + new [|T|](s); + } + } -internal class T -{ - private string s; + internal class T + { + private string s; - public T(string s) - { - this.s = s; - } -}", -index: 1); + public T(string s) + { + this.s = s; + } + } + """, + index: 1); } [Fact] public async Task GenerateWithNamedParameter() { await TestInRegularAndScriptAsync( -@"class Class -{ - void M() - { - new [|T|](arg: 1); - } -}", -@"class Class -{ - void M() - { - new T(arg: 1); - } -} + """ + class Class + { + void M() + { + new [|T|](arg: 1); + } + } + """, + """ + class Class + { + void M() + { + new T(arg: 1); + } + } -internal class T -{ - private int arg; + internal class T + { + private int arg; - public T(int arg) - { - this.arg = arg; - } -}", -index: 1); + public T(int arg) + { + this.arg = arg; + } + } + """, + index: 1); } [Fact] public async Task GenerateWithRefParameter() { await TestInRegularAndScriptAsync( -@"class Class -{ - void M(int i) - { - new [|T|](ref i); - } -}", -@"class Class -{ - void M(int i) - { - new T(ref i); - } -} + """ + class Class + { + void M(int i) + { + new [|T|](ref i); + } + } + """, + """ + class Class + { + void M(int i) + { + new T(ref i); + } + } -internal class T -{ - private int i; + internal class T + { + private int i; - public T(ref int i) - { - this.i = i; - } -}", -index: 1); + public T(ref int i) + { + this.i = i; + } + } + """, + index: 1); } [Fact] public async Task GenerateWithOutParameter() { - await TestInRegularAndScriptAsync( -@"class Class -{ - void M(int i, bool b) - { - new [|T|](out i, ref b, null); - } -}", -@"class Class -{ - void M(int i, bool b) - { - new T(out i, ref b, null); - } -} + await TestInRegularAndScriptAsync( + """ + class Class + { + void M(int i, bool b) + { + new [|T|](out i, ref b, null); + } + } + """, + """ + class Class + { + void M(int i, bool b) + { + new T(out i, ref b, null); + } + } -internal class T -{ - private bool b; - private object value; + internal class T + { + private bool b; + private object value; - public T(out int i, ref bool b, object value) - { - i = 0; - this.b = b; - this.value = value; - } -}", -index: 1); + public T(out int i, ref bool b, object value) + { + i = 0; + this.b = b; + this.value = value; + } + } + """, + index: 1); } [Fact] public async Task GenerateWithOutParameters1() { await TestInRegularAndScriptAsync( -@"class Class -{ - void M(string s) - { - new [|T|](out s); - } -}", -@"class Class -{ - void M(string s) - { - new T(out s); - } -} + """ + class Class + { + void M(string s) + { + new [|T|](out s); + } + } + """, + """ + class Class + { + void M(string s) + { + new T(out s); + } + } -internal class T -{ - public T(out string s) - { - s = null; - } -}", -index: 1); + internal class T + { + public T(out string s) + { + s = null; + } + } + """, + index: 1); } [Fact] public async Task GenerateWithOutParameters2_CSharp7() { await TestInRegularAndScriptAsync( -@"using System; + """ + using System; -class Class -{ - void M(DateTime d) - { - new [|T|](out d); - } -}", -@"using System; + class Class + { + void M(DateTime d) + { + new [|T|](out d); + } + } + """, + """ + using System; -class Class -{ - void M(DateTime d) - { - new T(out d); - } -} + class Class + { + void M(DateTime d) + { + new T(out d); + } + } -internal class T -{ - public T(out DateTime d) - { - d = default(DateTime); - } -}", -index: 1, -parseOptions: TestOptions.Regular7); + internal class T + { + public T(out DateTime d) + { + d = default(DateTime); + } + } + """, + index: 1, + parseOptions: TestOptions.Regular7); } [Fact] public async Task GenerateWithOutParameters2() { await TestInRegularAndScriptAsync( -@"using System; + """ + using System; -class Class -{ - void M(DateTime d) - { - new [|T|](out d); - } -}", -@"using System; + class Class + { + void M(DateTime d) + { + new [|T|](out d); + } + } + """, + """ + using System; -class Class -{ - void M(DateTime d) - { - new T(out d); - } -} + class Class + { + void M(DateTime d) + { + new T(out d); + } + } -internal class T -{ - public T(out DateTime d) - { - d = default; - } -}", -index: 1); + internal class T + { + public T(out DateTime d) + { + d = default; + } + } + """, + index: 1); } [Fact] public async Task GenerateWithOutParameters3() { await TestInRegularAndScriptAsync( -@"using System.Collections.Generic; + """ + using System.Collections.Generic; -class Class -{ - void M(IList d) - { - new [|T|](out d); - } -}", -@"using System.Collections.Generic; + class Class + { + void M(IList d) + { + new [|T|](out d); + } + } + """, + """ + using System.Collections.Generic; -class Class -{ - void M(IList d) - { - new T(out d); - } -} + class Class + { + void M(IList d) + { + new T(out d); + } + } -internal class T -{ - public T(out IList d) - { - d = null; - } -}", -index: 1); + internal class T + { + public T(out IList d) + { + d = null; + } + } + """, + index: 1); } [Fact] public async Task GenerateWithOutParameters4() { await TestInRegularAndScriptAsync( -@"class Class -{ - void M(int? d) - { - new [|T|](out d); - } -}", -@"class Class -{ - void M(int? d) - { - new T(out d); - } -} + """ + class Class + { + void M(int? d) + { + new [|T|](out d); + } + } + """, + """ + class Class + { + void M(int? d) + { + new T(out d); + } + } -internal class T -{ - public T(out int? d) - { - d = null; - } -}", -index: 1); + internal class T + { + public T(out int? d) + { + d = null; + } + } + """, + index: 1); } [Fact] public async Task GenerateWithOutParameters5() { await TestInRegularAndScriptAsync( -@"class Class -{ - void M(X d) - { - new [|T|](out d); - } -}", -@"class Class -{ - void M(X d) - { - new T(out d); - } -} + """ + class Class + { + void M(X d) + { + new [|T|](out d); + } + } + """, + """ + class Class + { + void M(X d) + { + new T(out d); + } + } -internal class T -{ - public T(out object d) - { - d = null; - } -}", -index: 1); + internal class T + { + public T(out object d) + { + d = null; + } + } + """, + index: 1); } [Fact] public async Task GenerateWithOutParameters6_CSharp7() { await TestInRegularAndScriptAsync( -@"class Class -{ - void M(X d) - { - new [|T|](out d); - } -}", -@"class Class -{ - void M(X d) - { - new T(out d); - } + """ + class Class + { + void M(X d) + { + new [|T|](out d); + } + } + """, + """ + class Class + { + void M(X d) + { + new T(out d); + } - private class T - { - public T(out X d) - { - d = default(X); - } - } -}", -index: 2, -parseOptions: TestOptions.Regular7); + private class T + { + public T(out X d) + { + d = default(X); + } + } + } + """, + index: 2, + parseOptions: TestOptions.Regular7); } [Fact] public async Task GenerateWithOutParameters6() { await TestInRegularAndScriptAsync( -@"class Class -{ - void M(X d) - { - new [|T|](out d); - } -}", -@"class Class -{ - void M(X d) - { - new T(out d); - } + """ + class Class + { + void M(X d) + { + new [|T|](out d); + } + } + """, + """ + class Class + { + void M(X d) + { + new T(out d); + } - private class T - { - public T(out X d) - { - d = default; - } - } -}", -index: 2); + private class T + { + public T(out X d) + { + d = default; + } + } + } + """, + index: 2); } [Fact] public async Task GenerateWithOutParameters7() { await TestInRegularAndScriptAsync( -@"class Class where X : class -{ - void M(X d) - { - new [|T|](out d); - } -}", -@"class Class where X : class -{ - void M(X d) - { - new T(out d); - } -} + """ + class Class where X : class + { + void M(X d) + { + new [|T|](out d); + } + } + """, + """ + class Class where X : class + { + void M(X d) + { + new T(out d); + } + } -internal class T -{ - public T(out object d) - { - d = null; - } -}", -index: 1); + internal class T + { + public T(out object d) + { + d = null; + } + } + """, + index: 1); } [Fact] public async Task GenerateWithOutParameters8() { await TestInRegularAndScriptAsync( -@"class Class where X : class -{ - void M(X d) - { - new [|T|](out d); - } -}", -@"class Class where X : class -{ - void M(X d) - { - new T(out d); - } + """ + class Class where X : class + { + void M(X d) + { + new [|T|](out d); + } + } + """, + """ + class Class where X : class + { + void M(X d) + { + new T(out d); + } - private class T - { - public T(out X d) - { - d = null; - } - } -}", -index: 2); + private class T + { + public T(out X d) + { + d = null; + } + } + } + """, + index: 2); } [Fact] public async Task GenerateWithMethod() { await TestInRegularAndScriptAsync( -@"class Class -{ - string M(int i) - { - new [|T|](M); - } -}", -@"using System; + """ + class Class + { + string M(int i) + { + new [|T|](M); + } + } + """, + """ + using System; -class Class -{ - string M(int i) - { - new T(M); - } -} + class Class + { + string M(int i) + { + new T(M); + } + } -internal class T -{ - private Func m; + internal class T + { + private Func m; - public T(Func m) - { - this.m = m; - } -}", -index: 1); + public T(Func m) + { + this.m = m; + } + } + """, + index: 1); } [Fact] public async Task GenerateWithLambda() { await TestInRegularAndScriptAsync( -@"class Class -{ - string M(int i) - { - new [|T|](a => a.ToString()); - } -}", -@"using System; + """ + class Class + { + string M(int i) + { + new [|T|](a => a.ToString()); + } + } + """, + """ + using System; -class Class -{ - string M(int i) - { - new T(a => a.ToString()); - } -} + class Class + { + string M(int i) + { + new T(a => a.ToString()); + } + } -internal class T -{ - private Func value; + internal class T + { + private Func value; - public T(Func value) - { - this.value = value; - } -}", -index: 1); + public T(Func value) + { + this.value = value; + } + } + """, + index: 1); } [Fact] public async Task GenerateWithDelegatingConstructor1() { await TestInRegularAndScriptAsync( -@"class Class -{ - void M(int i) - { - Base b = new [|T|](1); - } -} + """ + class Class + { + void M(int i) + { + Base b = new [|T|](1); + } + } -class Base -{ - protected Base(int i) - { - } -}", -@"class Class -{ - void M(int i) - { - Base b = new T(1); - } -} + class Base + { + protected Base(int i) + { + } + } + """, + """ + class Class + { + void M(int i) + { + Base b = new T(1); + } + } -internal class T : Base -{ - public T(int i) : base(i) - { - } -} + internal class T : Base + { + public T(int i) : base(i) + { + } + } -class Base -{ - protected Base(int i) - { - } -}", -index: 1); + class Base + { + protected Base(int i) + { + } + } + """, + index: 1); } [Fact] public async Task GenerateWithDelegatingConstructor2() { await TestInRegularAndScriptAsync( -@"class Class -{ - void M(int i) - { - Base b = new [|T|](1); - } -} + """ + class Class + { + void M(int i) + { + Base b = new [|T|](1); + } + } -class Base -{ - protected Base(object i) - { - } -}", -@"class Class -{ - void M(int i) - { - Base b = new T(1); - } -} + class Base + { + protected Base(object i) + { + } + } + """, + """ + class Class + { + void M(int i) + { + Base b = new T(1); + } + } -internal class T : Base -{ - public T(object i) : base(i) - { - } -} + internal class T : Base + { + public T(object i) : base(i) + { + } + } -class Base -{ - protected Base(object i) - { - } -}", -index: 1); + class Base + { + protected Base(object i) + { + } + } + """, + index: 1); } [Fact] public async Task GenerateWithDelegatingConstructor3() { await TestInRegularAndScriptAsync( -@"using System.Collections.Generic; + """ + using System.Collections.Generic; -class Class -{ - void M() - { - Base b = new [|T|](new List()); - } -} + class Class + { + void M() + { + Base b = new [|T|](new List()); + } + } -class Base -{ - protected Base(IEnumerable values) - { - } -}", -@"using System.Collections.Generic; + class Base + { + protected Base(IEnumerable values) + { + } + } + """, + """ + using System.Collections.Generic; -class Class -{ - void M() - { - Base b = new T(new List()); - } -} + class Class + { + void M() + { + Base b = new T(new List()); + } + } -internal class T : Base -{ - public T(IEnumerable values) : base(values) - { - } -} + internal class T : Base + { + public T(IEnumerable values) : base(values) + { + } + } -class Base -{ - protected Base(IEnumerable values) - { - } -}", -index: 1); + class Base + { + protected Base(IEnumerable values) + { + } + } + """, + index: 1); } [Fact] public async Task GenerateWithDelegatingConstructor4() { await TestInRegularAndScriptAsync( -@"class Class -{ - void M(int i) - { - Base b = new [|T|](ref i); - } -} + """ + class Class + { + void M(int i) + { + Base b = new [|T|](ref i); + } + } -class Base -{ - protected Base(ref int o) - { - } -}", -@"class Class -{ - void M(int i) - { - Base b = new T(ref i); - } -} + class Base + { + protected Base(ref int o) + { + } + } + """, + """ + class Class + { + void M(int i) + { + Base b = new T(ref i); + } + } -internal class T : Base -{ - public T(ref int o) : base(ref o) - { - } -} + internal class T : Base + { + public T(ref int o) : base(ref o) + { + } + } -class Base -{ - protected Base(ref int o) - { - } -}", -index: 1); + class Base + { + protected Base(ref int o) + { + } + } + """, + index: 1); } [Fact] public async Task GenerateWithDelegatingConstructor5() { await TestInRegularAndScriptAsync( -@"class Class -{ - void M(int i) - { - Base b = new [|T|](a => a.ToString()); - } -} + """ + class Class + { + void M(int i) + { + Base b = new [|T|](a => a.ToString()); + } + } -class Base -{ - protected Base(System.Func f) - { - } -}", -@"using System; + class Base + { + protected Base(System.Func f) + { + } + } + """, + """ + using System; -class Class -{ - void M(int i) - { - Base b = new T(a => a.ToString()); - } -} + class Class + { + void M(int i) + { + Base b = new T(a => a.ToString()); + } + } -internal class T : Base -{ - public T(Func f) : base(f) - { - } -} + internal class T : Base + { + public T(Func f) : base(f) + { + } + } -class Base -{ - protected Base(System.Func f) - { - } -}", -index: 1); + class Base + { + protected Base(System.Func f) + { + } + } + """, + index: 1); } [Fact] public async Task GenerateWithDelegatingConstructor6() { await TestInRegularAndScriptAsync( -@"class Class -{ - void M(int i) - { - Base b = new [|T|](out i); - } -} - -class Base -{ - protected Base(out int o) - { - } -}", -@"class Class -{ - void M(int i) - { - Base b = new T(out i); - } -} + """ + class Class + { + void M(int i) + { + Base b = new [|T|](out i); + } + } -internal class T : Base -{ - public T(out int o) : base(out o) - { - } -} + class Base + { + protected Base(out int o) + { + } + } + """, + """ + class Class + { + void M(int i) + { + Base b = new T(out i); + } + } -class Base -{ - protected Base(out int o) - { - } -}", -index: 1); + internal class T : Base + { + public T(out int o) : base(out o) + { + } + } + + class Base + { + protected Base(out int o) + { + } + } + """, + index: 1); } [Fact] public async Task GenerateWithDelegatingConstructorAssigningToNullableField() { await TestInRegularAndScriptAsync( -@"#nullable enable -class Class -{ - void M() - { - Base? b = new [|T|](); - } -} + """ + #nullable enable + class Class + { + void M() + { + Base? b = new [|T|](); + } + } -class Base -{ -}", -@"#nullable enable -class Class -{ - void M() - { - Base? b = new [|T|](); - } -} + class Base + { + } + """, + """ + #nullable enable + class Class + { + void M() + { + Base? b = new [|T|](); + } + } -internal class T : Base -{ -} + internal class T : Base + { + } -class Base -{ -}", -index: 1); + class Base + { + } + """, + index: 1); } [Fact] public async Task GenerateWithNonDelegatingConstructor1() { await TestInRegularAndScriptAsync( -@"class Class -{ - void M(int i) - { - Base b = new [|T|](1); - } -} + """ + class Class + { + void M(int i) + { + Base b = new [|T|](1); + } + } -class Base -{ - protected Base(string i) - { - } -}", -@"class Class -{ - void M(int i) - { - Base b = new T(1); - } -} + class Base + { + protected Base(string i) + { + } + } + """, + """ + class Class + { + void M(int i) + { + Base b = new T(1); + } + } -internal class T : Base -{ - private int v; + internal class T : Base + { + private int v; - public T(int v) - { - this.v = v; - } -} + public T(int v) + { + this.v = v; + } + } -class Base -{ - protected Base(string i) - { - } -}", -index: 1); + class Base + { + protected Base(string i) + { + } + } + """, + index: 1); } [Fact] public async Task GenerateWithNonDelegatingConstructor2() { await TestInRegularAndScriptAsync( -@"class Class -{ - void M(int i) - { - Base b = new [|T|](ref i); - } -} + """ + class Class + { + void M(int i) + { + Base b = new [|T|](ref i); + } + } -class Base -{ - protected Base(out int o) - { - } -}", -@"class Class -{ - void M(int i) - { - Base b = new T(ref i); - } -} + class Base + { + protected Base(out int o) + { + } + } + """, + """ + class Class + { + void M(int i) + { + Base b = new T(ref i); + } + } -internal class T : Base -{ - private int i; + internal class T : Base + { + private int i; - public T(ref int i) - { - this.i = i; - } -} + public T(ref int i) + { + this.i = i; + } + } -class Base -{ - protected Base(out int o) - { - } -}", -index: 1); + class Base + { + protected Base(out int o) + { + } + } + """, + index: 1); } [Fact] public async Task GenerateWithNonDelegatingConstructor3() { await TestInRegularAndScriptAsync( -@"class Class -{ - void M(int i, bool f) - { - Base b = new [|T|](out i, out f); - } -} + """ + class Class + { + void M(int i, bool f) + { + Base b = new [|T|](out i, out f); + } + } -class Base -{ - protected Base(ref int o, out bool b) - { - } -}", -@"class Class -{ - void M(int i, bool f) - { - Base b = new T(out i, out f); - } -} + class Base + { + protected Base(ref int o, out bool b) + { + } + } + """, + """ + class Class + { + void M(int i, bool f) + { + Base b = new T(out i, out f); + } + } -internal class T : Base -{ - public T(out int i, out bool f) - { - i = 0; - f = false; - } -} + internal class T : Base + { + public T(out int i, out bool f) + { + i = 0; + f = false; + } + } -class Base -{ - protected Base(ref int o, out bool b) - { - } -}", -index: 1); + class Base + { + protected Base(ref int o, out bool b) + { + } + } + """, + index: 1); } [Fact] public async Task GenerateWithNonDelegatingConstructor4() { await TestInRegularAndScriptAsync( -@"class Class -{ - void M() - { - Base b = new [|T|](1); - } -} + """ + class Class + { + void M() + { + Base b = new [|T|](1); + } + } -class Base -{ - private Base(int i) - { - } -}", -@"class Class -{ - void M() - { - Base b = new T(1); - } -} + class Base + { + private Base(int i) + { + } + } + """, + """ + class Class + { + void M() + { + Base b = new T(1); + } + } -internal class T : Base -{ - private int v; + internal class T : Base + { + private int v; - public T(int v) - { - this.v = v; - } -} + public T(int v) + { + this.v = v; + } + } -class Base -{ - private Base(int i) - { - } -}", -index: 1); + class Base + { + private Base(int i) + { + } + } + """, + index: 1); } [Fact] public async Task GenerateWithCallToField1() { await TestInRegularAndScriptAsync( -@"class Class -{ - void M(int i) - { - Base b = new [|T|](i); - } -} + """ + class Class + { + void M(int i) + { + Base b = new [|T|](i); + } + } -class Base -{ - protected int i; -}", -@"class Class -{ - void M(int i) - { - Base b = new T(i); - } -} + class Base + { + protected int i; + } + """, + """ + class Class + { + void M(int i) + { + Base b = new T(i); + } + } -internal class T : Base -{ - public T(int i) - { - this.i = i; - } -} + internal class T : Base + { + public T(int i) + { + this.i = i; + } + } -class Base -{ - protected int i; -}", -index: 1); + class Base + { + protected int i; + } + """, + index: 1); } [Fact] public async Task GenerateWithCallToField2() { await TestInRegularAndScriptAsync( -@"class Class -{ - void M(string i) - { - Base b = new [|T|](i); - } -} + """ + class Class + { + void M(string i) + { + Base b = new [|T|](i); + } + } -class Base -{ - protected object i; -}", -@"class Class -{ - void M(string i) - { - Base b = new T(i); - } -} + class Base + { + protected object i; + } + """, + """ + class Class + { + void M(string i) + { + Base b = new T(i); + } + } -internal class T : Base -{ - public T(string i) - { - this.i = i; - } -} + internal class T : Base + { + public T(string i) + { + this.i = i; + } + } -class Base -{ - protected object i; -}", -index: 1); + class Base + { + protected object i; + } + """, + index: 1); } [Fact] public async Task GenerateWithCallToField3() { await TestInRegularAndScriptAsync( -@"class Class -{ - void M(string i) - { - Base b = new [|T|](i); - } -} + """ + class Class + { + void M(string i) + { + Base b = new [|T|](i); + } + } -class Base -{ - protected bool i; -}", -@"class Class -{ - void M(string i) - { - Base b = new T(i); - } -} + class Base + { + protected bool i; + } + """, + """ + class Class + { + void M(string i) + { + Base b = new T(i); + } + } -internal class T : Base -{ - private string i; + internal class T : Base + { + private string i; - public T(string i) - { - this.i = i; - } -} + public T(string i) + { + this.i = i; + } + } -class Base -{ - protected bool i; -}", -index: 1); + class Base + { + protected bool i; + } + """, + index: 1); } [Fact] public async Task GenerateWithCallToField4() { await TestInRegularAndScriptAsync( -@"class Class -{ - void M(bool i) - { - Base b = new [|T|](i); - } -} + """ + class Class + { + void M(bool i) + { + Base b = new [|T|](i); + } + } -class Base -{ - protected bool ii; -}", -@"class Class -{ - void M(bool i) - { - Base b = new T(i); - } -} + class Base + { + protected bool ii; + } + """, + """ + class Class + { + void M(bool i) + { + Base b = new T(i); + } + } -internal class T : Base -{ - private bool i; + internal class T : Base + { + private bool i; - public T(bool i) - { - this.i = i; - } -} + public T(bool i) + { + this.i = i; + } + } -class Base -{ - protected bool ii; -}", -index: 1); + class Base + { + protected bool ii; + } + """, + index: 1); } [Fact] public async Task GenerateWithCallToField5() { await TestInRegularAndScriptAsync( -@"class Class -{ - void M(bool i) - { - Base b = new [|T|](i); - } -} + """ + class Class + { + void M(bool i) + { + Base b = new [|T|](i); + } + } -class Base -{ - private bool i; -}", -@"class Class -{ - void M(bool i) - { - Base b = new T(i); - } -} + class Base + { + private bool i; + } + """, + """ + class Class + { + void M(bool i) + { + Base b = new T(i); + } + } -internal class T : Base -{ - private bool i; + internal class T : Base + { + private bool i; - public T(bool i) - { - this.i = i; - } -} + public T(bool i) + { + this.i = i; + } + } -class Base -{ - private bool i; -}", -index: 1); + class Base + { + private bool i; + } + """, + index: 1); } [Fact] public async Task GenerateWithCallToField6() { await TestInRegularAndScriptAsync( -@"class Class -{ - void M(bool i) - { - Base b = new [|T|](i); - } -} + """ + class Class + { + void M(bool i) + { + Base b = new [|T|](i); + } + } -class Base -{ - protected readonly bool i; -}", -@"class Class -{ - void M(bool i) - { - Base b = new T(i); - } -} + class Base + { + protected readonly bool i; + } + """, + """ + class Class + { + void M(bool i) + { + Base b = new T(i); + } + } -internal class T : Base -{ - private bool i; + internal class T : Base + { + private bool i; - public T(bool i) - { - this.i = i; - } -} + public T(bool i) + { + this.i = i; + } + } -class Base -{ - protected readonly bool i; -}", -index: 1); + class Base + { + protected readonly bool i; + } + """, + index: 1); } [Fact] public async Task GenerateWithCallToField7() { await TestInRegularAndScriptAsync( -@"class Class -{ - void M(int i) - { - Base b = new [|T|](i); - } -} + """ + class Class + { + void M(int i) + { + Base b = new [|T|](i); + } + } -class Base -{ - protected int I; -}", -@"class Class -{ - void M(int i) - { - Base b = new T(i); - } -} + class Base + { + protected int I; + } + """, + """ + class Class + { + void M(int i) + { + Base b = new T(i); + } + } -internal class T : Base -{ - public T(int i) - { - I = i; - } -} + internal class T : Base + { + public T(int i) + { + I = i; + } + } -class Base -{ - protected int I; -}", -index: 1); + class Base + { + protected int I; + } + """, + index: 1); } [Fact] public async Task GenerateWithCallToField7WithQualification() { await TestInRegularAndScriptAsync( -@"class Class -{ - void M(int i) - { - Base b = new [|T|](i); - } -} + """ + class Class + { + void M(int i) + { + Base b = new [|T|](i); + } + } -class Base -{ - protected int I; -}", -@"class Class -{ - void M(int i) - { - Base b = new T(i); - } -} + class Base + { + protected int I; + } + """, + """ + class Class + { + void M(int i) + { + Base b = new T(i); + } + } -internal class T : Base -{ - public T(int i) - { - this.I = i; - } -} + internal class T : Base + { + public T(int i) + { + this.I = i; + } + } -class Base -{ - protected int I; -}", -index: 1, -options: Option(CodeStyleOptions2.QualifyFieldAccess, true, NotificationOption2.Error)); + class Base + { + protected int I; + } + """, + index: 1, + options: Option(CodeStyleOptions2.QualifyFieldAccess, true, NotificationOption2.Error)); } [Fact] public async Task GenerateWithCallToField8() { await TestInRegularAndScriptAsync( -@"class Class -{ - void M(int i) - { - Base b = new [|T|](i); - } -} + """ + class Class + { + void M(int i) + { + Base b = new [|T|](i); + } + } -class Base -{ - private int I; -}", -@"class Class -{ - void M(int i) - { - Base b = new T(i); - } -} + class Base + { + private int I; + } + """, + """ + class Class + { + void M(int i) + { + Base b = new T(i); + } + } -internal class T : Base -{ - private int i; + internal class T : Base + { + private int i; - public T(int i) - { - this.i = i; - } -} + public T(int i) + { + this.i = i; + } + } -class Base -{ - private int I; -}", -index: 1); + class Base + { + private int I; + } + """, + index: 1); } [Fact] public async Task GenerateWithCallToField9() { await TestInRegularAndScriptAsync( -@"class Class -{ - void M(int i) - { - Base b = new [|T|](i); - } -} + """ + class Class + { + void M(int i) + { + Base b = new [|T|](i); + } + } -class Base -{ - public static int i; -}", -@"class Class -{ - void M(int i) - { - Base b = new T(i); - } -} + class Base + { + public static int i; + } + """, + """ + class Class + { + void M(int i) + { + Base b = new T(i); + } + } -internal class T : Base -{ - private int i; + internal class T : Base + { + private int i; - public T(int i) - { - this.i = i; - } -} + public T(int i) + { + this.i = i; + } + } -class Base -{ - public static int i; -}", -index: 1); + class Base + { + public static int i; + } + """, + index: 1); } [Fact] public async Task GenerateWithCallToField10() { await TestInRegularAndScriptAsync( -@"class Class -{ - void M(int i) - { - D d = new [|T|](i); - } -} + """ + class Class + { + void M(int i) + { + D d = new [|T|](i); + } + } -class D : B -{ - protected int I; -} + class D : B + { + protected int I; + } -class B -{ - protected int i }", -@"class Class -{ - void M(int i) - { - D d = new T(i); - } -} + class B + { + protected int i } + """, + """ + class Class + { + void M(int i) + { + D d = new T(i); + } + } -internal class T : D -{ - public T(int i) - { - this.i = i; - } -} + internal class T : D + { + public T(int i) + { + this.i = i; + } + } -class D : B -{ - protected int I; -} + class D : B + { + protected int I; + } -class B -{ - protected int i }", -index: 1); + class B + { + protected int i } + """, + index: 1); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/49924")] @@ -2911,260 +3275,288 @@ public async Task GenerateCorrectFieldNaming() var options = new NamingStylesTestOptionSets(LanguageNames.CSharp); await TestInRegularAndScriptAsync( -@"class Class -{ - void M(int i) - { - D d = new [|D|](i); - } -}", -@"class Class -{ - void M(int i) - { - D d = new D(i); - } -} + """ + class Class + { + void M(int i) + { + D d = new [|D|](i); + } + } + """, + """ + class Class + { + void M(int i) + { + D d = new D(i); + } + } -internal class D -{ - private int _i; + internal class D + { + private int _i; - public D(int i) - { - _i = i; - } -}", -index: 1, options: options.FieldNamesAreCamelCaseWithUnderscorePrefix); + public D(int i) + { + _i = i; + } + } + """, + index: 1, options: options.FieldNamesAreCamelCaseWithUnderscorePrefix); } [Fact] public async Task GenerateWithCallToProperty1() { await TestInRegularAndScriptAsync( -@"class Class -{ - void M(int i) - { - Base b = new [|T|](i); - } -} + """ + class Class + { + void M(int i) + { + Base b = new [|T|](i); + } + } -class Base -{ - public int I { get; private set; } -}", -@"class Class -{ - void M(int i) - { - Base b = new T(i); - } -} + class Base + { + public int I { get; private set; } + } + """, + """ + class Class + { + void M(int i) + { + Base b = new T(i); + } + } -internal class T : Base -{ - private int i; + internal class T : Base + { + private int i; - public T(int i) - { - this.i = i; - } -} + public T(int i) + { + this.i = i; + } + } -class Base -{ - public int I { get; private set; } -}", -index: 1); + class Base + { + public int I { get; private set; } + } + """, + index: 1); } [Fact] public async Task GenerateWithCallToProperty2() { await TestInRegularAndScriptAsync( -@"class Class -{ - void M(int i) - { - Base b = new [|T|](i); - } -} + """ + class Class + { + void M(int i) + { + Base b = new [|T|](i); + } + } -class Base -{ - public int I { get; protected set; } -}", -@"class Class -{ - void M(int i) - { - Base b = new T(i); - } -} + class Base + { + public int I { get; protected set; } + } + """, + """ + class Class + { + void M(int i) + { + Base b = new T(i); + } + } -internal class T : Base -{ - public T(int i) - { - I = i; - } -} + internal class T : Base + { + public T(int i) + { + I = i; + } + } -class Base -{ - public int I { get; protected set; } -}", -index: 1); + class Base + { + public int I { get; protected set; } + } + """, + index: 1); } [Fact] public async Task GenerateWithCallToProperty2WithQualification() { await TestInRegularAndScriptAsync( -@"class Class -{ - void M(int i) - { - Base b = new [|T|](i); - } -} + """ + class Class + { + void M(int i) + { + Base b = new [|T|](i); + } + } -class Base -{ - public int I { get; protected set; } -}", -@"class Class -{ - void M(int i) - { - Base b = new T(i); - } -} + class Base + { + public int I { get; protected set; } + } + """, + """ + class Class + { + void M(int i) + { + Base b = new T(i); + } + } -internal class T : Base -{ - public T(int i) - { - this.I = i; - } -} + internal class T : Base + { + public T(int i) + { + this.I = i; + } + } -class Base -{ - public int I { get; protected set; } -}", -index: 1, -options: Option(CodeStyleOptions2.QualifyPropertyAccess, true, NotificationOption2.Error)); + class Base + { + public int I { get; protected set; } + } + """, + index: 1, + options: Option(CodeStyleOptions2.QualifyPropertyAccess, true, NotificationOption2.Error)); } [Fact] public async Task GenerateWithCallToProperty3() { await TestInRegularAndScriptAsync( -@"class Class -{ - void M(int i) - { - Base b = new [|T|](i); - } -} + """ + class Class + { + void M(int i) + { + Base b = new [|T|](i); + } + } -class Base -{ - protected int I { get; set; } -}", -@"class Class -{ - void M(int i) - { - Base b = new T(i); - } -} + class Base + { + protected int I { get; set; } + } + """, + """ + class Class + { + void M(int i) + { + Base b = new T(i); + } + } -internal class T : Base -{ - public T(int i) - { - I = i; - } -} + internal class T : Base + { + public T(int i) + { + I = i; + } + } -class Base -{ - protected int I { get; set; } -}", -index: 1); + class Base + { + protected int I { get; set; } + } + """, + index: 1); } [Fact] public async Task GenerateWithCallToProperty3WithQualification() { await TestInRegularAndScriptAsync( -@"class Class -{ - void M(int i) - { - Base b = new [|T|](i); - } -} + """ + class Class + { + void M(int i) + { + Base b = new [|T|](i); + } + } -class Base -{ - protected int I { get; set; } -}", -@"class Class -{ - void M(int i) - { - Base b = new T(i); - } -} + class Base + { + protected int I { get; set; } + } + """, + """ + class Class + { + void M(int i) + { + Base b = new T(i); + } + } -internal class T : Base -{ - public T(int i) - { - this.I = i; - } -} + internal class T : Base + { + public T(int i) + { + this.I = i; + } + } -class Base -{ - protected int I { get; set; } -}", -index: 1, -options: Option(CodeStyleOptions2.QualifyPropertyAccess, true, NotificationOption2.Error)); + class Base + { + protected int I { get; set; } + } + """, + index: 1, + options: Option(CodeStyleOptions2.QualifyPropertyAccess, true, NotificationOption2.Error)); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/942568")] public async Task GenerateTypeWithPreferIntrinsicPredefinedKeywordFalse() { await TestInRegularAndScriptAsync( -@"class Class { - void M(int i) - { - var b = new [|T|](i); - } -}", -@"class Class { - void M(int i) - { - var b = new T(i); - } -} + """ + class Class { + void M(int i) + { + var b = new [|T|](i); + } + } + """, + """ + class Class { + void M(int i) + { + var b = new T(i); + } + } -internal class T -{ - private System.Int32 i; + internal class T + { + private System.Int32 i; - public T(System.Int32 i) - { - this.i = i; - } -}", -index: 1, -options: Option(CodeStyleOptions2.PreferIntrinsicPredefinedTypeKeywordInDeclaration, false, NotificationOption2.Error)); + public T(System.Int32 i) + { + this.i = i; + } + } + """, + index: 1, + options: Option(CodeStyleOptions2.PreferIntrinsicPredefinedTypeKeywordInDeclaration, false, NotificationOption2.Error)); } #endregion @@ -3175,113 +3567,139 @@ public T(System.Int32 i) public async Task TestGenerateInterfaceFromTypeConstraint() { await TestInRegularAndScriptAsync( -@"class EmployeeList where T : Employee, [|IEmployee|], new() -{ -}", -@"class EmployeeList where T : Employee, IEmployee, new() -{ -} + """ + class EmployeeList where T : Employee, [|IEmployee|], new() + { + } + """, + """ + class EmployeeList where T : Employee, IEmployee, new() + { + } -internal interface IEmployee -{ -}", -index: 1); + internal interface IEmployee + { + } + """, + index: 1); } [Fact] public async Task TestGenerateInterfaceFromTypeConstraints() { await TestInRegularAndScriptAsync( -@"class EmployeeList where T : Employee, IEmployee, [|IComparable|], new() -{ -}", -@"class EmployeeList where T : Employee, IEmployee, IComparable, new() -{ -} + """ + class EmployeeList where T : Employee, IEmployee, [|IComparable|], new() + { + } + """, + """ + class EmployeeList where T : Employee, IEmployee, IComparable, new() + { + } -internal interface IComparable where T : Employee, IEmployee, IComparable, new() -{ -}", -index: 1); + internal interface IComparable where T : Employee, IEmployee, IComparable, new() + { + } + """, + index: 1); } [Fact] public async Task NegativeTestGenerateInterfaceFromTypeConstraint() { await TestMissingInRegularAndScriptAsync( -@"using System; + """ + using System; -class EmployeeList where T : Employee, IEmployee, [|IComparable|], new() -{ -}"); + class EmployeeList where T : Employee, IEmployee, [|IComparable|], new() + { + } + """); } [Fact] public async Task TestGenerateInterfaceFromBaseList1() { await TestInRegularAndScriptAsync( -@"interface A : [|B|] -{ -}", -@"interface A : B -{ -} + """ + interface A : [|B|] + { + } + """, + """ + interface A : B + { + } -internal interface B -{ -}", -index: 1); + internal interface B + { + } + """, + index: 1); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/538519")] public async Task TestGenerateInterfaceFromBaseList2() { await TestInRegularAndScriptAsync( -@"class Test : [|ITest|] -{ -}", -@"class Test : ITest -{ -} + """ + class Test : [|ITest|] + { + } + """, + """ + class Test : ITest + { + } -internal interface ITest -{ -}", -index: 1); + internal interface ITest + { + } + """, + index: 1); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/538519")] public async Task TestGenerateInterfaceFromTypeConstraints2() { await TestInRegularAndScriptAsync( -@"class Test where T : [|ITest|] -{ -}", -@"class Test where T : ITest -{ -} + """ + class Test where T : [|ITest|] + { + } + """, + """ + class Test where T : ITest + { + } -internal interface ITest -{ -}", -index: 1); + internal interface ITest + { + } + """, + index: 1); } [Fact] public async Task TestGenerateInterfaceFromBaseList3() { await TestInRegularAndScriptAsync( -@"class A : object, [|B|] -{ -}", -@"class A : object, B -{ -} + """ + class A : object, [|B|] + { + } + """, + """ + class A : object, B + { + } -internal interface B -{ -}", -index: 1); + internal interface B + { + } + """, + index: 1); } #endregion @@ -3290,510 +3708,572 @@ internal interface B public async Task NotInLeftSideOfAssignment() { await TestMissingInRegularAndScriptAsync( -@"class Class -{ - void M(int i) - { - [|Goo|] = 2; - } -}"); + """ + class Class + { + void M(int i) + { + [|Goo|] = 2; + } + } + """); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/539339")] public async Task InLeftSideOfAssignment() { await TestInRegularAndScriptAsync( -@"class Class -{ - void M(int i) - { - [|Goo|].Bar = 2; - } -}", -@"class Class -{ - void M(int i) - { - Goo.Bar = 2; - } -} + """ + class Class + { + void M(int i) + { + [|Goo|].Bar = 2; + } + } + """, + """ + class Class + { + void M(int i) + { + Goo.Bar = 2; + } + } -internal class Goo -{ -}", -index: 1); + internal class Goo + { + } + """, + index: 1); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/539339")] public async Task NotInRightSideOfAssignment() { await TestMissingInRegularAndScriptAsync( -@"class Class -{ - void M(int i) - { - x = [|Goo|]; - } -}"); + """ + class Class + { + void M(int i) + { + x = [|Goo|]; + } + } + """); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/539339")] public async Task InRightSideOfAssignment() { await TestInRegularAndScriptAsync( -@"class Class -{ - void M(int i) - { - x = [|Goo|].Bar; - } -}", -@"class Class -{ - void M(int i) - { - x = Goo.Bar; - } -} + """ + class Class + { + void M(int i) + { + x = [|Goo|].Bar; + } + } + """, + """ + class Class + { + void M(int i) + { + x = Goo.Bar; + } + } -internal class Goo -{ -}", -index: 1); + internal class Goo + { + } + """, + index: 1); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/539489")] public async Task TestEscapedName() { await TestInRegularAndScriptAsync( -@"class Class -{ - [|@Goo|] f; -}", -@"class Class -{ - @Goo f; -} + """ + class Class + { + [|@Goo|] f; + } + """, + """ + class Class + { + @Goo f; + } -internal class Goo -{ -}", -index: 1); + internal class Goo + { + } + """, + index: 1); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/539489")] public async Task TestEscapedKeyword() { await TestInRegularAndScriptAsync( -@"class Class -{ - [|@int|] f; -}", -@"class Class -{ - @int f; -} + """ + class Class + { + [|@int|] f; + } + """, + """ + class Class + { + @int f; + } -internal class @int -{ -}", -index: 1); + internal class @int + { + } + """, + index: 1); } [WpfFact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/539535")] public async Task TestGenerateIntoNewFile() { await TestAddDocumentInRegularAndScriptAsync( -@"class Class { void F() { new [|Goo|].Bar(); } }", -@"namespace Goo -{ - internal class Bar - { - public Bar() - { - } - } -}", -expectedContainers: ImmutableArray.Create("Goo"), -expectedDocumentName: "Bar.cs"); + @"class Class { void F() { new [|Goo|].Bar(); } }", + """ + namespace Goo + { + internal class Bar + { + public Bar() + { + } + } + } + """, + expectedContainers: ["Goo"], + expectedDocumentName: "Bar.cs"); } [WpfFact] public async Task TestGenerateIntoNewFileWithUsings1() { await TestAddDocumentInRegularAndScriptAsync( -@"class Class { void F() { new [|Goo|].Bar(new System.Collections.Generic.List()); } }", -@"using System.Collections.Generic; + @"class Class { void F() { new [|Goo|].Bar(new System.Collections.Generic.List()); } }", + """ + using System.Collections.Generic; -namespace Goo -{ - internal class Bar - { - private List list; + namespace Goo + { + internal class Bar + { + private List list; - public Bar(List list) - { - this.list = list; - } - } -}", -expectedContainers: ImmutableArray.Create("Goo"), -expectedDocumentName: "Bar.cs"); + public Bar(List list) + { + this.list = list; + } + } + } + """, + expectedContainers: ["Goo"], + expectedDocumentName: "Bar.cs"); } [WpfFact] public async Task TestGenerateIntoNewFileWithUsings2() { await TestAddDocumentInRegularAndScriptAsync( -@"class Class { void F() { new [|Goo|].Bar(new System.Collections.Generic.List()); } }", -@"namespace Goo -{ - using System.Collections.Generic; + @"class Class { void F() { new [|Goo|].Bar(new System.Collections.Generic.List()); } }", + """ + namespace Goo + { + using System.Collections.Generic; - internal class Bar - { - private List list; + internal class Bar + { + private List list; - public Bar(List list) - { - this.list = list; - } - } -}", -expectedContainers: ImmutableArray.Create("Goo"), -expectedDocumentName: "Bar.cs", -parameters: new TestParameters(options: Option(CSharpCodeStyleOptions.PreferredUsingDirectivePlacement, AddImportPlacement.InsideNamespace, NotificationOption2.Error))); + public Bar(List list) + { + this.list = list; + } + } + } + """, + expectedContainers: ["Goo"], + expectedDocumentName: "Bar.cs", + parameters: new TestParameters(options: Option(CSharpCodeStyleOptions.PreferredUsingDirectivePlacement, AddImportPlacement.InsideNamespace, NotificationOption2.Error))); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/539620")] public async Task TestDeclarationSpan() { await TestSpansAsync( -@"class Class -{ - void Goo() - { - [|Bar|] b; - } -}"); + """ + class Class + { + void Goo() + { + [|Bar|] b; + } + } + """); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/539674")] public async Task TestNotInEnumBaseList() { await TestMissingInRegularAndScriptAsync( -@"enum E : [|A|] -{ -}"); + """ + enum E : [|A|] + { + } + """); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/539681")] public async Task TestNotInConditional() { await TestMissingInRegularAndScriptAsync( -@"class Program -{ - static void Main(string[] args) - { - if ([|IsTrue|]) - { - } - } -}"); + """ + class Program + { + static void Main(string[] args) + { + if ([|IsTrue|]) + { + } + } + } + """); } [Fact] public async Task TestInUsing() { await TestInRegularAndScriptAsync( -@"using System; -using System.Collections.Generic; -using System.Linq; + """ + using System; + using System.Collections.Generic; + using System.Linq; -class Program -{ - static void Main(string[] args) - { - using ([|Goo|] f = bar()) - { - } - } -}", -@"using System; -using System.Collections.Generic; -using System.Linq; + class Program + { + static void Main(string[] args) + { + using ([|Goo|] f = bar()) + { + } + } + } + """, + """ + using System; + using System.Collections.Generic; + using System.Linq; -class Program -{ - static void Main(string[] args) - { - using (Goo f = bar()) - { - } - } -} + class Program + { + static void Main(string[] args) + { + using (Goo f = bar()) + { + } + } + } -internal class Goo -{ -}", -index: 1); + internal class Goo + { + } + """, + index: 1); } [Fact, WorkItem("https://github.com/dotnet/roslyn/pull/54493")] public async Task TestInLocalFunction() { await TestInRegularAndScriptAsync( -@"using System; + """ + using System; -class Program -{ - static void Main(string[] args) - { - static [|Goo|] - } -}", -@"using System; + class Program + { + static void Main(string[] args) + { + static [|Goo|] + } + } + """, + """ + using System; -class Program -{ - static void Main(string[] args) - { - static Goo - } -} + class Program + { + static void Main(string[] args) + { + static Goo + } + } -internal class Goo -{ -}", -index: 1); + internal class Goo + { + } + """, + index: 1); } [Fact] public async Task TestNotInDelegateConstructor() { await TestMissingInRegularAndScriptAsync( -@"delegate void D(int x); + """ + delegate void D(int x); -class C -{ - void M() - { - D d = new D([|Test|]); - } -}"); + class C + { + void M() + { + D d = new D([|Test|]); + } + } + """); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/539754")] public async Task TestMissingOnVar() { await TestMissingInRegularAndScriptAsync( -@"using System; -using System.Collections.Generic; -using System.Linq; - -class Program -{ - static void Main(string[] args) - { - [|var|] x = new Program(); - } -}"); + """ + using System; + using System.Collections.Generic; + using System.Linq; + + class Program + { + static void Main(string[] args) + { + [|var|] x = new Program(); + } + } + """); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/539765")] public async Task TestElideDefaultConstructor() { await TestInRegularAndScriptAsync( -@"class A -{ - void M() - { - C test = new [|B|](); - } -} + """ + class A + { + void M() + { + C test = new [|B|](); + } + } -internal class C -{ -}", -@"class A -{ - void M() - { - C test = new B(); - } -} + internal class C + { + } + """, + """ + class A + { + void M() + { + C test = new B(); + } + } -internal class B : C -{ -} + internal class B : C + { + } -internal class C -{ -}", -index: 1); + internal class C + { + } + """, + index: 1); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/539783")] public async Task RegressionFor5867ErrorToleranceTopLevel() { await TestMissingAsync( -@"[|this|] . f = f ; ", -new TestParameters(GetScriptOptions())); + @"[|this|] . f = f ; ", + new TestParameters(GetScriptOptions())); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/539799")] public async Task TestOnInaccessibleType() { await TestMissingInRegularAndScriptAsync( -@"class C -{ - private class D - { - } -} + """ + class C + { + private class D + { + } + } -class A -{ - void M() - { - C.[|D|] d = new C.D(); - } -}"); + class A + { + void M() + { + C.[|D|] d = new C.D(); + } + } + """); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/539794")] public async Task TestDefaultConstructorInTypeDerivingFromInterface() { await TestInRegularAndScriptAsync( -@"class Program -{ - static void Main(string[] args) - { - I obj = new [|A|](); - } -} + """ + class Program + { + static void Main(string[] args) + { + I obj = new [|A|](); + } + } -interface I -{ -}", -@"class Program -{ - static void Main(string[] args) - { - I obj = new A(); - } -} + interface I + { + } + """, + """ + class Program + { + static void Main(string[] args) + { + I obj = new A(); + } + } -internal class A : I -{ -} + internal class A : I + { + } -interface I -{ -}", -index: 1); + interface I + { + } + """, + index: 1); } [Fact] public async Task TestGenerateWithThrow() { await TestInRegularAndScriptAsync( -@"using System; + """ + using System; -class C -{ - void M() - { - throw new [|NotFoundException|](); - } -}", -@"using System; -using System.Runtime.Serialization; + class C + { + void M() + { + throw new [|NotFoundException|](); + } + } + """, + """ + using System; + using System.Runtime.Serialization; -class C -{ - void M() - { - throw new NotFoundException(); - } -} + class C + { + void M() + { + throw new NotFoundException(); + } + } -[Serializable] -internal class NotFoundException : Exception -{ - public NotFoundException() - { - } + [Serializable] + internal class NotFoundException : Exception + { + public NotFoundException() + { + } - public NotFoundException(string message) : base(message) - { - } + public NotFoundException(string message) : base(message) + { + } - public NotFoundException(string message, Exception innerException) : base(message, innerException) - { - } + public NotFoundException(string message, Exception innerException) : base(message, innerException) + { + } - protected NotFoundException(SerializationInfo info, StreamingContext context) : base(info, context) - { - } -}", -index: 1); + protected NotFoundException(SerializationInfo info, StreamingContext context) : base(info, context) + { + } + } + """, + index: 1); } [Fact] public async Task TestGenerateInTryCatch() { await TestInRegularAndScriptAsync( -@"using System; + """ + using System; -class C -{ - void M() - { - try - { - } - catch ([|NotFoundException|] ex) - { - } - } -}", -@"using System; -using System.Runtime.Serialization; + class C + { + void M() + { + try + { + } + catch ([|NotFoundException|] ex) + { + } + } + } + """, + """ + using System; + using System.Runtime.Serialization; -class C -{ - void M() - { - try - { - } - catch (NotFoundException ex) - { - } - } -} + class C + { + void M() + { + try + { + } + catch (NotFoundException ex) + { + } + } + } -[Serializable] -internal class NotFoundException : Exception -{ - public NotFoundException() - { - } + [Serializable] + internal class NotFoundException : Exception + { + public NotFoundException() + { + } - public NotFoundException(string message) : base(message) - { - } + public NotFoundException(string message) : base(message) + { + } - public NotFoundException(string message, Exception innerException) : base(message, innerException) - { - } + public NotFoundException(string message, Exception innerException) : base(message, innerException) + { + } - protected NotFoundException(SerializationInfo info, StreamingContext context) : base(info, context) - { - } -}", -index: 1); + protected NotFoundException(SerializationInfo info, StreamingContext context) : base(info, context) + { + } + } + """, + index: 1); } [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsGenerateMethod)] @@ -3801,1027 +4281,1177 @@ protected NotFoundException(SerializationInfo info, StreamingContext context) : public async Task TestNotGenerateInDelegateConstructor() { await TestMissingInRegularAndScriptAsync( -@"using System; + """ + using System; -delegate void D(int x); + delegate void D(int x); -class C -{ - void M() - { - D d = new D([|Test|]); - } -}"); + class C + { + void M() + { + D d = new D([|Test|]); + } + } + """); } [Fact] public async Task TestInStructBaseList() { await TestInRegularAndScriptAsync( -@"struct S : [|A|] -{ -}", -@"struct S : A -{ -} + """ + struct S : [|A|] + { + } + """, + """ + struct S : A + { + } -internal interface A -{ -}", -index: 1); + internal interface A + { + } + """, + index: 1); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/539870")] public async Task TestGenericWhenNonGenericExists() { await TestInRegularAndScriptAsync( -@"class C -{ - void Goo() - { - [|A|] a; - } -} + """ + class C + { + void Goo() + { + [|A|] a; + } + } -class A -{ -}", -@"class C -{ - void Goo() - { - A a; - } -} + class A + { + } + """, + """ + class C + { + void Goo() + { + A a; + } + } -internal class A -{ -} + internal class A + { + } -class A -{ -}", -index: 1); + class A + { + } + """, + index: 1); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/539930")] public async Task TestInheritedTypeParameters() { await TestInRegularAndScriptAsync( -@"class C -{ - void M() - { - I i = new [|D|](); - } -} + """ + class C + { + void M() + { + I i = new [|D|](); + } + } -interface I -{ -}", -@"class C -{ - void M() - { - I i = new D(); - } -} + interface I + { + } + """, + """ + class C + { + void M() + { + I i = new D(); + } + } -internal class D : I -{ -} + internal class D : I + { + } -interface I -{ -}", -index: 1); + interface I + { + } + """, + index: 1); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/539971")] public async Task TestDoNotUseOuterTypeParameters() { await TestInRegularAndScriptAsync( -@"class C -{ - public void Goo() - { - [|D|] d; - } -}", -@"class C -{ - public void Goo() - { - D d; - } + """ + class C + { + public void Goo() + { + [|D|] d; + } + } + """, + """ + class C + { + public void Goo() + { + D d; + } - private class D - { - } -}", -index: 2); + private class D + { + } + } + """, + index: 2); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/539970")] public async Task TestReferencingTypeParameters1() { await TestInRegularAndScriptAsync( -@"class M -{ - public void Goo() - { - I i = new [|C|](); - } -} + """ + class M + { + public void Goo() + { + I i = new [|C|](); + } + } -interface I -{ -}", -@"class M -{ - public void Goo() - { - I i = new C(); - } -} + interface I + { + } + """, + """ + class M + { + public void Goo() + { + I i = new C(); + } + } -internal class C : I -{ -} + internal class C : I + { + } -interface I -{ -}", -index: 1); + interface I + { + } + """, + index: 1); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/539970")] public async Task TestReferencingTypeParameters2() { await TestInRegularAndScriptAsync( -@"class M -{ - public void Goo() - { - I i = new [|C|](); - } -} + """ + class M + { + public void Goo() + { + I i = new [|C|](); + } + } -interface I -{ -}", -@"class M -{ - public void Goo() - { - I i = new C(); - } + interface I + { + } + """, + """ + class M + { + public void Goo() + { + I i = new C(); + } - private class C : I - { - } -} + private class C : I + { + } + } -interface I -{ -}", -index: 2); + interface I + { + } + """, + index: 2); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/539972")] public async Task TestReferencingTypeParameters3() { await TestInRegularAndScriptAsync( -@"class C -{ - public void Goo(T1 t1, T2 t2) - { - A a = new [|A|](t1, t2); - } -}", -@"class C -{ - public void Goo(T1 t1, T2 t2) - { - A a = new A(t1, t2); - } -} + """ + class C + { + public void Goo(T1 t1, T2 t2) + { + A a = new [|A|](t1, t2); + } + } + """, + """ + class C + { + public void Goo(T1 t1, T2 t2) + { + A a = new A(t1, t2); + } + } -internal class A -{ - private object t1; - private object t2; + internal class A + { + private object t1; + private object t2; - public A(object t1, object t2) - { - this.t1 = t1; - this.t2 = t2; - } -}", -index: 1); + public A(object t1, object t2) + { + this.t1 = t1; + this.t2 = t2; + } + } + """, + index: 1); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/539972")] public async Task TestReferencingTypeParameters4() { await TestInRegularAndScriptAsync( -@"class C -{ - public void Goo(T1 t1, T2 t2) - { - A a = new [|A|](t1, t2); - } -}", -@"class C -{ - public void Goo(T1 t1, T2 t2) - { - A a = new A(t1, t2); - } + """ + class C + { + public void Goo(T1 t1, T2 t2) + { + A a = new [|A|](t1, t2); + } + } + """, + """ + class C + { + public void Goo(T1 t1, T2 t2) + { + A a = new A(t1, t2); + } - private class A - { - private T1 t1; - private T2 t2; + private class A + { + private T1 t1; + private T2 t2; - public A(T1 t1, T2 t2) - { - this.t1 = t1; - this.t2 = t2; - } - } -}", -index: 2); + public A(T1 t1, T2 t2) + { + this.t1 = t1; + this.t2 = t2; + } + } + } + """, + index: 2); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/539992")] public async Task TestNotPassingEmptyIssueListToCtor() { await TestMissingInRegularAndScriptAsync( -@"using System.Linq; + """ + using System.Linq; -class Program -{ - void Main() - { - Enumerable.[|T|] Enumerable . Select(Enumerable.Range(0, 9), i => char.Parse(i.ToString())) } -}"); + class Program + { + void Main() + { + Enumerable.[|T|] Enumerable . Select(Enumerable.Range(0, 9), i => char.Parse(i.ToString())) } + } + """); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/540644")] public async Task TestGenerateWithVoidArg() { await TestInRegularAndScriptAsync( -@"class Program -{ - void M() - { - C c = new [|C|](M()); - } -}", -@"class Program -{ - void M() - { - C c = new C(M()); - } -} + """ + class Program + { + void M() + { + C c = new [|C|](M()); + } + } + """, + """ + class Program + { + void M() + { + C c = new C(M()); + } + } -internal class C -{ - private object v; + internal class C + { + private object v; - public C(object v) - { - this.v = v; - } -}", -index: 1); + public C(object v) + { + this.v = v; + } + } + """, + index: 1); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/540989")] public async Task TestMissingOnInaccessibleType() { await TestMissingInRegularAndScriptAsync( -@"class Outer -{ - class Inner - { - } -} + """ + class Outer + { + class Inner + { + } + } -class A -{ - Outer.[|Inner|] inner; -}"); + class A + { + Outer.[|Inner|] inner; + } + """); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/540766")] public async Task TestOnInvalidGlobalCode() { await TestInRegularAndScriptAsync( -@"[|a|] test ", -@"[|a|] test internal class a -{ -}", -index: 1); + @"[|a|] test ", + """ + [|a|] test internal class a + { + } + """, + index: 1); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/539985")] public async Task TestDoNotInferTypeWithWrongArity() { await TestInRegularAndScriptAsync( -@"class C -{ - public void Test() - { - C c = new [|C|](); - } -}", -@"class C -{ - public void Test() - { - C c = new C(); - } -} + """ + class C + { + public void Test() + { + C c = new [|C|](); + } + } + """, + """ + class C + { + public void Test() + { + C c = new C(); + } + } -internal class C -{ - public C() - { - } -}", -index: 1); + internal class C + { + public C() + { + } + } + """, + index: 1); } [Fact] public async Task TestMissingOnInvalidConstructorToExistingType() { await TestMissingInRegularAndScriptAsync( -@"class Program -{ - static void Main() - { - new [|Program|](1); - } -}"); + """ + class Program + { + static void Main() + { + new [|Program|](1); + } + } + """); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/541263")] public async Task TestAccessibilityConstraint() { await TestInRegularAndScriptAsync( -@"public static class MyExtension -{ - public static int ExtensionMethod(this String s, [|D|] d) - { - return 10; - } -}", -@"public static class MyExtension -{ - public static int ExtensionMethod(this String s, D d) - { - return 10; - } -} + """ + public static class MyExtension + { + public static int ExtensionMethod(this String s, [|D|] d) + { + return 10; + } + } + """, + """ + public static class MyExtension + { + public static int ExtensionMethod(this String s, D d) + { + return 10; + } + } -public class D -{ -}", -index: 1); + public class D + { + } + """, + index: 1); } [Fact] public async Task TestBaseTypeAccessibilityConstraint() { await TestInRegularAndScriptAsync( -@"public class C : [|D|] -{ -}", -@"public class C : D -{ -} + """ + public class C : [|D|] + { + } + """, + """ + public class C : D + { + } -public class D -{ -}", -index: 1); + public class D + { + } + """, + index: 1); } [Fact] public async Task TestBaseInterfaceAccessibilityConstraint1() { await TestInRegularAndScriptAsync( -@"public class C : X, [|IGoo|] -{ -}", -@"public class C : X, IGoo -{ -} + """ + public class C : X, [|IGoo|] + { + } + """, + """ + public class C : X, IGoo + { + } -internal interface IGoo -{ -}", -index: 1); + internal interface IGoo + { + } + """, + index: 1); } [Fact] public async Task TestAccessibilityConstraint2() { await TestInRegularAndScriptAsync( -@"public interface C : [|IBar|], IGoo -{ -}", -@"public interface C : IBar, IGoo -{ -} + """ + public interface C : [|IBar|], IGoo + { + } + """, + """ + public interface C : IBar, IGoo + { + } -public interface IBar -{ -}", -index: 1); + public interface IBar + { + } + """, + index: 1); } [Fact] public async Task TestAccessibilityConstraint3() { await TestInRegularAndScriptAsync( -@"public interface C : IBar, [|IGoo|] -{ -}", -@"public interface C : IBar, IGoo -{ -} + """ + public interface C : IBar, [|IGoo|] + { + } + """, + """ + public interface C : IBar, IGoo + { + } -public interface IGoo -{ -}", -index: 1); + public interface IGoo + { + } + """, + index: 1); } [Fact] public async Task TestDelegateReturnTypeAccessibilityConstraint() { await TestInRegularAndScriptAsync( -@"public delegate [|D|] Goo();", -@"public delegate D Goo(); + @"public delegate [|D|] Goo();", + """ + public delegate D Goo(); -public class D -{ -}", -index: 1); + public class D + { + } + """, + index: 1); } [Fact] public async Task TestDelegateParameterAccessibilityConstraint() { await TestInRegularAndScriptAsync( -@"public delegate D Goo([|S|] d);", -@"public delegate D Goo(S d); + @"public delegate D Goo([|S|] d);", + """ + public delegate D Goo(S d); -public class S -{ -}", -index: 1); + public class S + { + } + """, + index: 1); } [Fact] public async Task TestMethodParameterAccessibilityConstraint() { await TestInRegularAndScriptAsync( -@"public class C -{ - public void Goo([|F|] f); -}", -@"public class C -{ - public void Goo(F f); -} + """ + public class C + { + public void Goo([|F|] f); + } + """, + """ + public class C + { + public void Goo(F f); + } -public class F -{ -}", -index: 1); + public class F + { + } + """, + index: 1); } [Fact] public async Task TestMethodReturnTypeAccessibilityConstraint() { await TestInRegularAndScriptAsync( -@"public class C -{ - public [|F|] Goo(Bar f); -}", -@"public class C -{ - public F Goo(Bar f); + """ + public class C + { + public [|F|] Goo(Bar f); + } + """, + """ + public class C + { + public F Goo(Bar f); - public class F - { - } -}", -index: 2); + public class F + { + } + } + """, + index: 2); } [Fact] public async Task TestPropertyTypeAccessibilityConstraint() { await TestInRegularAndScriptAsync( -@"public class C -{ - public [|F|] Goo { get; } -}", -@"public class C -{ - public F Goo { get; } + """ + public class C + { + public [|F|] Goo { get; } + } + """, + """ + public class C + { + public F Goo { get; } - public class F - { - } -}", -index: 2); + public class F + { + } + } + """, + index: 2); } [Fact] public async Task TestFieldEventTypeAccessibilityConstraint() { await TestInRegularAndScriptAsync( -@"public class C -{ - public event [|F|] E; -}", -@"public class C -{ - public event F E; + """ + public class C + { + public event [|F|] E; + } + """, + """ + public class C + { + public event F E; - public class F - { - } -}", -index: 2); + public class F + { + } + } + """, + index: 2); } [Fact] public async Task TestEventTypeAccessibilityConstraint() { await TestInRegularAndScriptAsync( -@"public class C -{ - public event [|F|] E - { - add - { - } + """ + public class C + { + public event [|F|] E + { + add + { + } - remove - { - } - } -}", -@"public class C -{ - public event F E - { - add - { - } + remove + { + } + } + } + """, + """ + public class C + { + public event F E + { + add + { + } - remove - { - } - } -} + remove + { + } + } + } -public class F -{ -}", -index: 1); + public class F + { + } + """, + index: 1); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/541654")] public async Task TestGenerateVarType() { await TestInRegularAndScriptAsync( -@"class C -{ - public static void Main() - { - [|@var|] v; - } -}", -@"class C -{ - public static void Main() - { - @var v; - } -} + """ + class C + { + public static void Main() + { + [|@var|] v; + } + } + """, + """ + class C + { + public static void Main() + { + @var v; + } + } -internal class var -{ -}", -index: 1); + internal class var + { + } + """, + index: 1); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/541641")] public async Task TestOnBadAttribute() { await TestInRegularAndScriptAsync( -@"[[|AttClass|]()] -class C -{ -} + """ + [[|AttClass|]()] + class C + { + } -internal class AttClassAttribute -{ -}", -@"using System; + internal class AttClassAttribute + { + } + """, + """ + using System; -[AttClass()] -class C -{ -} + [AttClass()] + class C + { + } -internal class AttClassAttribute : Attribute -{ -} + internal class AttClassAttribute : Attribute + { + } -internal class AttClassAttribute -{ -}", -index: 1); + internal class AttClassAttribute + { + } + """, + index: 1); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/542528")] public async Task TestGenerateStruct1() { await TestInRegularAndScriptAsync( -@"using System; + """ + using System; -class A where T : struct -{ -} + class A where T : struct + { + } -class Program -{ - static void Main() - { - new A<[|S|]>(); - } -}", -@"using System; + class Program + { + static void Main() + { + new A<[|S|]>(); + } + } + """, + """ + using System; -class A where T : struct -{ -} + class A where T : struct + { + } -class Program -{ - static void Main() - { - new A(); - } -} + class Program + { + static void Main() + { + new A(); + } + } -internal struct S -{ -}", -index: 1); + internal struct S + { + } + """, + index: 1); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/542480")] public async Task TestCopyConstraints1() { await TestInRegularAndScriptAsync( -@"class A where T : class -{ -} + """ + class A where T : class + { + } -class Program -{ - static void Goo() where T : class - { - A a = new [|B|](); - } -}", -@"class A where T : class -{ -} + class Program + { + static void Goo() where T : class + { + A a = new [|B|](); + } + } + """, + """ + class A where T : class + { + } -class Program -{ - static void Goo() where T : class - { - A a = new B(); - } -} + class Program + { + static void Goo() where T : class + { + A a = new B(); + } + } -internal class B : A where T : class -{ -}", -index: 1); + internal class B : A where T : class + { + } + """, + index: 1); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/542528")] public async Task TestGenerateStruct2() { await TestInRegularAndScriptAsync( -@"using System; + """ + using System; -class A where T : struct -{ -} + class A where T : struct + { + } -class Program -{ - static void Main() - { - new A(); - } -}", -@"using System; + class Program + { + static void Main() + { + new A(); + } + } + """, + """ + using System; -class A where T : struct -{ -} + class A where T : struct + { + } -class Program -{ - static void Main() - { - new A(); - } + class Program + { + static void Main() + { + new A(); + } - private struct S - { - } -}"); + private struct S + { + } + } + """); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/542528")] public async Task TestGenerateStruct3() { await TestInRegularAndScriptAsync( -@"using System; + """ + using System; -class Program -{ - static void Main() - { - Goo(); - } + class Program + { + static void Main() + { + Goo(); + } - static void Goo() where T : struct - { - } -}", -@"using System; + static void Goo() where T : struct + { + } + } + """, + """ + using System; -class Program -{ - static void Main() - { - Goo(); - } + class Program + { + static void Main() + { + Goo(); + } - static void Goo() where T : struct - { - } + static void Goo() where T : struct + { + } - private struct S - { - } -}"); + private struct S + { + } + } + """); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/542761")] public async Task TestGenerateOpenType1() { await TestInRegularAndScriptAsync( -@"class Program -{ - static void Main() - { - var x = typeof([|C<,>|]); - } -}", -@"class Program -{ - static void Main() - { - var x = typeof(C<,>); - } -} + """ + class Program + { + static void Main() + { + var x = typeof([|C<,>|]); + } + } + """, + """ + class Program + { + static void Main() + { + var x = typeof(C<,>); + } + } -internal class C -{ -}", -index: 1); + internal class C + { + } + """, + index: 1); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/542766")] public async Task TestGenerateAttributeInGenericType() { await TestActionCountAsync( -@"using System; + """ + using System; -class A -{ - [[|C|]] - void Goo() - { - } -}", -count: 6); + class A + { + [[|C|]] + void Goo() + { + } + } + """, + count: 6); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/543061")] public async Task TestNestedGenericAccessibility() { await TestInRegularAndScriptAsync( -@"using System.Collections.Generic; + """ + using System.Collections.Generic; -public class C -{ - public void Goo(List<[|NewClass|]> x) - { - } -}", -@"using System.Collections.Generic; + public class C + { + public void Goo(List<[|NewClass|]> x) + { + } + } + """, + """ + using System.Collections.Generic; -public class C -{ - public void Goo(List x) - { - } -} + public class C + { + public void Goo(List x) + { + } + } -public class NewClass -{ -}", -index: 1); + public class NewClass + { + } + """, + index: 1); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/543493")] public async Task MissingIfNotInTypeStatementOrExpressionContext() { await TestMissingInRegularAndScriptAsync( -@"class C -{ - void M() - { - a [|b|] c d } -}"); + """ + class C + { + void M() + { + a [|b|] c d } + } + """); await TestMissingInRegularAndScriptAsync( -@"class C -{ - void M() - { - a b [|c|] d } -}"); + """ + class C + { + void M() + { + a b [|c|] d } + } + """); await TestMissingInRegularAndScriptAsync( -@"class C -{ - void M() - { - a b c [|d|] } -}"); + """ + class C + { + void M() + { + a b c [|d|] } + } + """); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/542641")] public async Task TestAttributeSuffixOnAttributeSubclasses() { await TestInRegularAndScriptAsync( -@"using System.Runtime.CompilerServices; + """ + using System.Runtime.CompilerServices; -class Program -{ - static void Main(string[] args) - { - CustomConstantAttribute a = new [|GooAttribute|](); - } -}", -@"using System.Runtime.CompilerServices; + class Program + { + static void Main(string[] args) + { + CustomConstantAttribute a = new [|GooAttribute|](); + } + } + """, + """ + using System.Runtime.CompilerServices; -class Program -{ - static void Main(string[] args) - { - CustomConstantAttribute a = new GooAttribute(); - } -} + class Program + { + static void Main(string[] args) + { + CustomConstantAttribute a = new GooAttribute(); + } + } -internal class GooAttribute : CustomConstantAttribute -{ -}", -index: 1); + internal class GooAttribute : CustomConstantAttribute + { + } + """, + index: 1); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/543853")] public async Task TestDisplayStringForGlobalNamespace() { await TestSmartTagTextAsync( -@"class C : [|Goo|]", -string.Format(FeaturesResources.Generate_0_1_in_new_file, "class", "Goo")); + @"class C : [|Goo|]", + string.Format(FeaturesResources.Generate_0_1_in_new_file, "class", "Goo")); } [WpfFact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/543853")] public async Task TestAddDocumentForGlobalNamespace() { await TestAddDocumentInRegularAndScriptAsync( -@"class C : [|Goo|]", -@"internal class Goo -{ -}", -ImmutableArray.Empty, -"Goo.cs"); + @"class C : [|Goo|]", + """ + internal class Goo + { + } + """, + [], + "Goo.cs"); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/543886")] public async Task TestVerbatimAttribute() { await TestInRegularAndScriptAsync( -@"[[|@X|]] -class Class3 -{ -}", -@"using System; - -[@X] -class Class3 -{ -} + """ + [[|@X|]] + class Class3 + { + } + """, + """ + using System; -internal class X : Attribute -{ -}", -index: 1); + [@X] + class Class3 + { + } + + internal class X : Attribute + { + } + """, + index: 1); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/531220")] public async Task CompareIncompleteMembersToEqual() { await TestInRegularAndScriptAsync( -@"class C -{ - X.X,X class X - { - X - } + """ + class C + { + X.X,X class X + { + X + } - X void X + """; - var expected = @" -namespace A -{ - public class B - { - public class C - { - } - } -} -"; + var expected = """ + namespace A + { + public class B + { + public class C + { + } + } + } + """; await TestInRegularAndScriptAsync(code, expected); } @@ -4901,56 +5529,64 @@ public class C [WpfFact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/932602")] public async Task TestGenerateTypeInFolderNotDefaultNamespace_0() { - var code = @" - - -namespace Namespace1.Namespace2 -{ - public class ClassA : [|$$ClassB|] - { - } -} - - - "; + var code = """ + + + + namespace Namespace1.Namespace2 + { + public class ClassA : [|$$ClassB|] + { + } + } + + + + """; - var expected = @"namespace Namespace1.Namespace2 -{ - public class ClassB - { - } -}"; + var expected = """ + namespace Namespace1.Namespace2 + { + public class ClassB + { + } + } + """; await TestAddDocumentInRegularAndScriptAsync(code, expected, - expectedContainers: ImmutableArray.Empty, + expectedContainers: [], expectedDocumentName: "ClassB.cs"); } [WpfFact] public async Task TestGenerateTypeInFolderNotDefaultNamespace_0_FileScopedNamespace() { - var code = @" - - -namespace Namespace1.Namespace2; + var code = """ + + + + namespace Namespace1.Namespace2; -public class ClassA : [|$$ClassB|] -{ -} - - - "; + public class ClassA : [|$$ClassB|] + { + } + + + + """; - var expected = @"namespace Namespace1.Namespace2; + var expected = """ + namespace Namespace1.Namespace2; -public class ClassB -{ -}"; + public class ClassB + { + } + """; await TestAddDocumentInRegularAndScriptAsync(code, expected, - expectedContainers: ImmutableArray.Empty, + expectedContainers: [], expectedDocumentName: "ClassB.cs", new TestParameters( parseOptions: CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.CSharp10), @@ -4960,29 +5596,33 @@ await TestAddDocumentInRegularAndScriptAsync(code, [WpfFact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/932602")] public async Task TestGenerateTypeInFolderNotDefaultNamespace_1() { - var code = @" - - -namespace Namespace1.Namespace2.Namespace3 -{ - public class ClassA : [|$$ClassB|] - { - } -} - - - "; + var code = """ + + + + namespace Namespace1.Namespace2.Namespace3 + { + public class ClassA : [|$$ClassB|] + { + } + } + + + + """; - var expected = @"namespace Namespace1.Namespace2.Namespace3 -{ - public class ClassB - { - } -}"; + var expected = """ + namespace Namespace1.Namespace2.Namespace3 + { + public class ClassB + { + } + } + """; await TestAddDocumentInRegularAndScriptAsync(code, expected, - expectedContainers: ImmutableArray.Create("Namespace1", "Namespace2"), + expectedContainers: ["Namespace1", "Namespace2"], expectedDocumentName: "ClassB.cs"); } @@ -4991,10 +5631,12 @@ public async Task TestGenerateTypeWithNoBraces() { var code = @"class Test : [|Base|]"; - var expected = @"class Test : Base -internal class Base -{ -}"; + var expected = """ + class Test : Base + internal class Base + { + } + """; await TestInRegularAndScriptAsync(code, expected, index: 1); } @@ -5002,40 +5644,44 @@ internal class Base [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/940003")] public async Task TestWithProperties1() { - var code = @"using System; + var code = """ + using System; -class Program -{ - static void Main(string[] args) - { - var c = new [|Customer|](x: 1, y: ""Hello"") {Name = ""John"", Age = DateTime.Today}; - } -}"; + class Program + { + static void Main(string[] args) + { + var c = new [|Customer|](x: 1, y: "Hello") {Name = "John", Age = DateTime.Today}; + } + } + """; - var expected = @"using System; + var expected = """ + using System; -class Program -{ - static void Main(string[] args) - { - var c = new Customer(x: 1, y: ""Hello"") {Name = ""John"", Age = DateTime.Today}; - } -} + class Program + { + static void Main(string[] args) + { + var c = new Customer(x: 1, y: "Hello") {Name = "John", Age = DateTime.Today}; + } + } -internal class Customer -{ - private int x; - private string y; + internal class Customer + { + private int x; + private string y; - public Customer(int x, string y) - { - this.x = x; - this.y = y; - } + public Customer(int x, string y) + { + this.x = x; + this.y = y; + } - public string Name { get; set; } - public DateTime Age { get; set; } -}"; + public string Name { get; set; } + public DateTime Age { get; set; } + } + """; await TestInRegularAndScriptAsync(code, expected, index: 1); } @@ -5043,40 +5689,44 @@ public Customer(int x, string y) [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/940003")] public async Task TestWithProperties2() { - var code = @"using System; + var code = """ + using System; -class Program -{ - static void Main(string[] args) - { - var c = new [|Customer|](x: 1, y: ""Hello"") {Name = null, Age = DateTime.Today}; - } -}"; + class Program + { + static void Main(string[] args) + { + var c = new [|Customer|](x: 1, y: "Hello") {Name = null, Age = DateTime.Today}; + } + } + """; - var expected = @"using System; + var expected = """ + using System; -class Program -{ - static void Main(string[] args) - { - var c = new Customer(x: 1, y: ""Hello"") {Name = null, Age = DateTime.Today}; - } -} + class Program + { + static void Main(string[] args) + { + var c = new Customer(x: 1, y: "Hello") {Name = null, Age = DateTime.Today}; + } + } -internal class Customer -{ - private int x; - private string y; + internal class Customer + { + private int x; + private string y; - public Customer(int x, string y) - { - this.x = x; - this.y = y; - } + public Customer(int x, string y) + { + this.x = x; + this.y = y; + } - public object Name { get; set; } - public DateTime Age { get; set; } -}"; + public object Name { get; set; } + public DateTime Age { get; set; } + } + """; await TestInRegularAndScriptAsync(code, expected, index: 1); } @@ -5084,40 +5734,44 @@ public Customer(int x, string y) [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/940003")] public async Task TestWithProperties3() { - var code = @"using System; + var code = """ + using System; -class Program -{ - static void Main(string[] args) - { - var c = new [|Customer|](x: 1, y: ""Hello"") {Name = Goo, Age = DateTime.Today}; - } -}"; + class Program + { + static void Main(string[] args) + { + var c = new [|Customer|](x: 1, y: "Hello") {Name = Goo, Age = DateTime.Today}; + } + } + """; - var expected = @"using System; + var expected = """ + using System; -class Program -{ - static void Main(string[] args) - { - var c = new Customer(x: 1, y: ""Hello"") {Name = Goo, Age = DateTime.Today}; - } -} + class Program + { + static void Main(string[] args) + { + var c = new Customer(x: 1, y: "Hello") {Name = Goo, Age = DateTime.Today}; + } + } -internal class Customer -{ - private int x; - private string y; + internal class Customer + { + private int x; + private string y; - public Customer(int x, string y) - { - this.x = x; - this.y = y; - } + public Customer(int x, string y) + { + this.x = x; + this.y = y; + } - public object Name { get; set; } - public DateTime Age { get; set; } -}"; + public object Name { get; set; } + public DateTime Age { get; set; } + } + """; await TestInRegularAndScriptAsync(code, expected, index: 1); } @@ -5125,31 +5779,35 @@ public Customer(int x, string y) [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1082031")] public async Task TestWithProperties4() { - var code = @"using System; + var code = """ + using System; -class Program -{ - static void Main(string[] args) - { - var c = new [|Customer|] {Name = ""John"", Age = DateTime.Today}; - } -}"; + class Program + { + static void Main(string[] args) + { + var c = new [|Customer|] {Name = "John", Age = DateTime.Today}; + } + } + """; - var expected = @"using System; + var expected = """ + using System; -class Program -{ - static void Main(string[] args) - { - var c = new Customer {Name = ""John"", Age = DateTime.Today}; - } -} + class Program + { + static void Main(string[] args) + { + var c = new Customer {Name = "John", Age = DateTime.Today}; + } + } -internal class Customer -{ - public string Name { get; set; } - public DateTime Age { get; set; } -}"; + internal class Customer + { + public string Name { get; set; } + public DateTime Age { get; set; } + } + """; await TestInRegularAndScriptAsync(code, expected, index: 1); } @@ -5157,26 +5815,29 @@ internal class Customer [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1032176"), WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1073099")] public async Task TestWithNameOf() { - var code = @"class C -{ - void M() - { - var x = nameof([|Z|]); - } -} -"; + var code = """ + class C + { + void M() + { + var x = nameof([|Z|]); + } + } + """; - var expected = @"class C -{ - void M() - { - var x = nameof(Z); - } -} + var expected = """ + class C + { + void M() + { + var x = nameof(Z); + } + } -internal class Z -{ -}"; + internal class Z + { + } + """; await TestInRegularAndScriptAsync(code, expected, index: 1); } @@ -5184,25 +5845,29 @@ internal class Z [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1032176"), WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1073099")] public async Task TestWithNameOf2() { - var code = @"class C -{ - void M() - { - var x = nameof([|C.Test|]); - } -}"; + var code = """ + class C + { + void M() + { + var x = nameof([|C.Test|]); + } + } + """; - var expected = @"class C -{ - void M() - { - var x = nameof(C.Test); - } + var expected = """ + class C + { + void M() + { + var x = nameof(C.Test); + } - private class Test - { - } -}"; + private class Test + { + } + } + """; await TestInRegularAndScriptAsync(code, expected); } @@ -5211,232 +5876,274 @@ private class Test public async Task TestWithUsingStatic() { await TestInRegularAndScriptAsync( -@"using static [|Sample|];", -@"using static Sample; + @"using static [|Sample|];", + """ + using static Sample; -internal class Sample -{ -}", -index: 1); + internal class Sample + { + } + """, + index: 1); } [Fact] public async Task TestWithUsingStatic2() { await TestMissingInRegularAndScriptAsync( -@"using [|Sample|];"); + @"using [|Sample|];"); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1107929")] public async Task TestAccessibilityForPublicFields() { await TestInRegularAndScriptAsync( -@"class A -{ - public B b = new [|B|](); -}", -@"public class B -{ - public B() - { - } -}"); + """ + class A + { + public B b = new [|B|](); + } + """, + """ + public class B + { + public B() + { + } + } + """); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1107929")] public async Task TestAccessibilityForPublicFields2() { await TestInRegularAndScriptAsync( -@"class A -{ - public B b = new [|B|](); -}", -@"class A -{ - public B b = new B(); -} + """ + class A + { + public B b = new [|B|](); + } + """, + """ + class A + { + public B b = new B(); + } -public class B -{ - public B() - { - } -}", -index: 1); + public class B + { + public B() + { + } + } + """, + index: 1); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1107929")] public async Task TestAccessibilityForPublicFields3() { await TestInRegularAndScriptAsync( -@"class A -{ - public B b = new [|B|](); -}", -@"class A -{ - public B b = new B(); + """ + class A + { + public B b = new [|B|](); + } + """, + """ + class A + { + public B b = new B(); - public class B - { - public B() - { - } - } -}", -index: 2); + public class B + { + public B() + { + } + } + } + """, + index: 2); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1107929")] public async Task TestAccessibilityForPublicFields4() { await TestInRegularAndScriptAsync( -@"class A -{ - public B b = new [|B|](); -}", -@"public class B -{ - public B() - { - } -}"); + """ + class A + { + public B b = new [|B|](); + } + """, + """ + public class B + { + public B() + { + } + } + """); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1107929")] public async Task TestAccessibilityForPublicFields5() { await TestInRegularAndScriptAsync( -@"class A -{ - public B b = new [|B|](); -}", -@"class A -{ - public B b = new B(); -} + """ + class A + { + public B b = new [|B|](); + } + """, + """ + class A + { + public B b = new B(); + } -public class B -{ - public B() - { - } -}", -index: 1); + public class B + { + public B() + { + } + } + """, + index: 1); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1107929")] public async Task TestAccessibilityForPublicFields6() { await TestInRegularAndScriptAsync( -@"class A -{ - public B b = new [|B|](); -}", -@"class A -{ - public B b = new B(); + """ + class A + { + public B b = new [|B|](); + } + """, + """ + class A + { + public B b = new B(); - public class B - { - public B() - { - } - } -}", -index: 2); + public class B + { + public B() + { + } + } + } + """, + index: 2); } [WpfFact, WorkItem("https://github.com/dotnet/roslyn/issues/17361")] public async Task TestPreserveFileBanner1() { await TestAddDocumentInRegularAndScriptAsync( -@"// I am a banner + """ + // I am a banner -class Program -{ - void Main ( ) - { - [|Goo|] f ; - } -} ", -@"// I am a banner + class Program + { + void Main ( ) + { + [|Goo|] f ; + } + } + """, + """ + // I am a banner -internal class Goo -{ -}", -expectedContainers: ImmutableArray.Empty, -expectedDocumentName: "Goo.cs"); + internal class Goo + { + } + """, + expectedContainers: [], + expectedDocumentName: "Goo.cs"); } [WpfFact, WorkItem("https://github.com/dotnet/roslyn/issues/17361")] public async Task TestPreserveFileBanner2() { await TestAddDocumentInRegularAndScriptAsync( -@"/// I am a doc comment -class Program -{ - void Main ( ) - { - [|Goo|] f ; - } -} ", -@"internal class Goo -{ -}", -expectedContainers: ImmutableArray.Empty, -expectedDocumentName: "Goo.cs"); + """ + /// I am a doc comment + class Program + { + void Main ( ) + { + [|Goo|] f ; + } + } + """, + """ + internal class Goo + { + } + """, + expectedContainers: [], + expectedDocumentName: "Goo.cs"); } [WpfFact, WorkItem("https://github.com/dotnet/roslyn/issues/17361")] public async Task TestPreserveFileBanner3() { await TestAddDocumentInRegularAndScriptAsync( -@"// I am a banner -using System; + """ + // I am a banner + using System; -class Program -{ - void Main (StackOverflowException e) - { - var f = new [|Goo|](e); - } -}", -@"// I am a banner -using System; + class Program + { + void Main (StackOverflowException e) + { + var f = new [|Goo|](e); + } + } + """, + """ + // I am a banner + using System; -internal class Goo -{ - private StackOverflowException e; + internal class Goo + { + private StackOverflowException e; - public Goo(StackOverflowException e) - { - this.e = e; - } -}", -expectedContainers: ImmutableArray.Empty, -expectedDocumentName: "Goo.cs"); + public Goo(StackOverflowException e) + { + this.e = e; + } + } + """, + expectedContainers: [], + expectedDocumentName: "Goo.cs"); } [WpfFact, WorkItem("https://github.com/dotnet/roslyn/issues/17361")] public async Task TestPreserveFileBanner4() { await TestAddDocumentInRegularAndScriptAsync( -@"class Program -{ - void Main ( ) - { - [|Goo|] f ; - } -} ", -@"// I am a banner + """ + class Program + { + void Main ( ) + { + [|Goo|] f ; + } + } + """, + """ + // I am a banner -internal class Goo -{ -}", -expectedContainers: ImmutableArray.Empty, -expectedDocumentName: "Goo.cs", -new TestParameters(options: Option(CodeStyleOptions2.FileHeaderTemplate, "I am a banner"))); + internal class Goo + { + } + """, + expectedContainers: [], + expectedDocumentName: "Goo.cs", + new TestParameters(options: Option(CodeStyleOptions2.FileHeaderTemplate, "I am a banner"))); } [Theory, WorkItem("https://github.com/dotnet/roslyn/issues/22293")] @@ -5445,152 +6152,193 @@ internal class Goo public async Task TestMethodGroupWithMissingSystemActionAndFunc(string returnType) { await TestInRegularAndScriptAsync( -$@" - - - - - -", -$@" -class C -{{ - void M() - {{ - new Class(Method); - }} - - {returnType} Method() - {{ - }} -}} - -internal class Class -{{ - private object method; - - public Class(object method) - {{ - this.method = method; - }} -}}", -index: 1); + $$""" + + + + + + """, + $$""" + class C + { + void M() + { + new Class(Method); + } + + {{returnType}} Method() + { + } + } + + internal class Class + { + private object method; + + public Class(object method) + { + this.method = method; + } + } + """, + index: 1); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/270")] public async Task TestGenerateInIsExpression() { await TestInRegularAndScriptAsync( -@"using System; - -class Program -{ - static void Main(Exception p) - { - bool result = p is [|SampleType|]; - } -}", -@"using System; -using System.Runtime.Serialization; + """ + using System; -class Program -{ - static void Main(Exception p) - { - bool result = p is SampleType; - } -} + class Program + { + static void Main(Exception p) + { + bool result = p is [|SampleType|]; + } + } + """, + """ + using System; + using System.Runtime.Serialization; -[Serializable] -internal class SampleType : Exception -{ - public SampleType() - { - } + class Program + { + static void Main(Exception p) + { + bool result = p is SampleType; + } + } - public SampleType(string message) : base(message) - { - } + [Serializable] + internal class SampleType : Exception + { + public SampleType() + { + } - public SampleType(string message, Exception innerException) : base(message, innerException) - { - } + public SampleType(string message) : base(message) + { + } - protected SampleType(SerializationInfo info, StreamingContext context) : base(info, context) - { - } -}", -index: 1); + public SampleType(string message, Exception innerException) : base(message, innerException) + { + } + + protected SampleType(SerializationInfo info, StreamingContext context) : base(info, context) + { + } + } + """, + index: 1); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/45808")] public async Task TestGenerateUnsafe() { await TestInRegularAndScriptAsync( -@"class C -{ - unsafe void M(int* x) - { - new [|D|](x); - } -}", -@"class C -{ - unsafe void M(int* x) - { - new D(x); - } -} + """ + class C + { + unsafe void M(int* x) + { + new [|D|](x); + } + } + """, + """ + class C + { + unsafe void M(int* x) + { + new D(x); + } + } -internal class D -{ - private unsafe int* x; + internal class D + { + private unsafe int* x; - public unsafe D(int* x) - { - this.x = x; - } -}", index: 1); + public unsafe D(int* x) + { + this.x = x; + } + } + """, index: 1); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/40605")] public async Task DoNoInferArrayBaseType1() { await TestInRegularAndScriptAsync( -@"using System; + """ + using System; -class C -{ - void M() - { - Array.Sort(new[] { ""a"", ""b"", ""c"" }, new [|MyComparer|]()); + class C + { + void M() + { + Array.Sort(new[] { "a", "b", "c" }, new [|MyComparer|]()); + } + } + """, + """ + using System; + using System.Collections; + + class C + { + void M() + { + Array.Sort(new[] { "a", "b", "c" }, new MyComparer()); + } + } + + internal class MyComparer : IComparer + { + } + """, index: 1); } -}", -@"using System; -using System.Collections; -class C -{ - void M() + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/58495")] + public async Task UseImplicitObjectInitializerToPopulateProperties() { - Array.Sort(new[] { ""a"", ""b"", ""c"" }, new MyComparer()); - } -} + await TestInRegularAndScriptAsync( + """ + class Program + { + void Main() + { + [|Test|] x = new() { A = 1, B = 1 }; + } + } + """, + """ + class Program + { + void Main() + { + Test x = new() { A = 1, B = 1 }; + } + } -internal class MyComparer : IComparer -{ -}", index: 1); + internal class Test + { + public int A { get; set; } + public int B { get; set; } + } + """, index: 1); } } diff --git a/src/EditorFeatures/CSharpTest/CodeActions/GenerateType/GenerateTypeTests_Dialog.cs b/src/EditorFeatures/CSharpTest/CodeActions/GenerateType/GenerateTypeTests_Dialog.cs index 8a6acfa346e29..cacb71edb2822 100644 --- a/src/EditorFeatures/CSharpTest/CodeActions/GenerateType/GenerateTypeTests_Dialog.cs +++ b/src/EditorFeatures/CSharpTest/CodeActions/GenerateType/GenerateTypeTests_Dialog.cs @@ -758,7 +758,7 @@ public interface Goo accessibility: Accessibility.Public, typeKind: TypeKind.Interface, isNewFile: true, -newFileFolderContainers: ImmutableArray.Empty, +newFileFolderContainers: [], newFileName: "Test2.cs"); } @@ -797,7 +797,7 @@ public interface Goo accessibility: Accessibility.Public, typeKind: TypeKind.Interface, isNewFile: true, -newFileFolderContainers: ImmutableArray.Create("outer", "inner"), +newFileFolderContainers: ["outer", "inner"], newFileName: "Test2.cs"); } @@ -839,7 +839,7 @@ void Main() accessibility: Accessibility.Public, typeKind: TypeKind.Interface, isNewFile: true, -newFileFolderContainers: ImmutableArray.Create("outer", "inner"), +newFileFolderContainers: ["outer", "inner"], newFileName: "Test2.cs"); } @@ -875,7 +875,7 @@ public interface Goo accessibility: Accessibility.Public, typeKind: TypeKind.Interface, isNewFile: true, -newFileFolderContainers: ImmutableArray.Create("outer", "inner"), +newFileFolderContainers: ["outer", "inner"], newFileName: "Test2.cs"); } @@ -918,7 +918,7 @@ void Main() accessibility: Accessibility.Public, typeKind: TypeKind.Interface, isNewFile: true, -newFileFolderContainers: ImmutableArray.Create("outer", "inner"), +newFileFolderContainers: ["outer", "inner"], newFileName: "Test2.cs"); } @@ -965,7 +965,7 @@ void Main() accessibility: Accessibility.Public, typeKind: TypeKind.Interface, isNewFile: true, -newFileFolderContainers: ImmutableArray.Create("outer"), +newFileFolderContainers: ["outer"], newFileName: "Test2.cs"); } @@ -1014,7 +1014,7 @@ namespace A.B accessibility: Accessibility.Public, typeKind: TypeKind.Interface, isNewFile: true, -newFileFolderContainers: ImmutableArray.Create("outer"), +newFileFolderContainers: ["outer"], newFileName: "Test2.cs"); } @@ -1070,7 +1070,7 @@ void Main() typeKind: TypeKind.Interface, isNewFile: true, areFoldersValidIdentifiers: false, -newFileFolderContainers: ImmutableArray.Create("123", "456"), +newFileFolderContainers: ["123", "456"], newFileName: "Test2.cs"); } @@ -1262,7 +1262,7 @@ public interface Goo typeKind: TypeKind.Interface, isNewFile: true, newFileName: "Test2.cs", -newFileFolderContainers: ImmutableArray.Empty, +newFileFolderContainers: [], projectName: "Assembly2"); } @@ -1307,7 +1307,7 @@ void Main() typeKind: TypeKind.Interface, isNewFile: true, newFileName: "Test2.cs", -newFileFolderContainers: ImmutableArray.Create("outer", "inner"), +newFileFolderContainers: ["outer", "inner"], projectName: "Assembly2"); } @@ -1346,7 +1346,7 @@ public interface Goo typeKind: TypeKind.Interface, isNewFile: true, newFileName: "Test2.cs", -newFileFolderContainers: ImmutableArray.Create("outer", "inner"), +newFileFolderContainers: ["outer", "inner"], projectName: "Assembly2"); } @@ -1392,7 +1392,7 @@ void Main() typeKind: TypeKind.Interface, isNewFile: true, newFileName: "Test2.cs", -newFileFolderContainers: ImmutableArray.Create("outer", "inner"), +newFileFolderContainers: ["outer", "inner"], projectName: "Assembly2"); } @@ -1432,7 +1432,7 @@ public interface Goo typeKind: TypeKind.Interface, isNewFile: true, newFileName: "Test2.cs", -newFileFolderContainers: ImmutableArray.Create("outer", "inner"), +newFileFolderContainers: ["outer", "inner"], projectName: "Assembly2"); } #endregion @@ -1471,7 +1471,7 @@ End Namespace typeKind: TypeKind.Class, isNewFile: true, newFileName: "Test2.vb", -newFileFolderContainers: ImmutableArray.Empty, +newFileFolderContainers: [], projectName: "Assembly2"); } @@ -1515,7 +1515,7 @@ void Main() typeKind: TypeKind.Class, isNewFile: true, newFileName: "Test2.vb", -newFileFolderContainers: ImmutableArray.Create("outer", "inner"), +newFileFolderContainers: ["outer", "inner"], projectName: "Assembly2"); } @@ -1553,7 +1553,7 @@ End Namespace typeKind: TypeKind.Class, isNewFile: true, newFileName: "Test2.vb", -newFileFolderContainers: ImmutableArray.Create("outer", "inner"), +newFileFolderContainers: ["outer", "inner"], projectName: "Assembly2"); } @@ -1598,7 +1598,7 @@ void Main() typeKind: TypeKind.Class, isNewFile: true, newFileName: "Test2.vb", -newFileFolderContainers: ImmutableArray.Create("outer", "inner"), +newFileFolderContainers: ["outer", "inner"], projectName: "Assembly2"); } @@ -1637,7 +1637,7 @@ End Namespace typeKind: TypeKind.Class, isNewFile: true, newFileName: "Test2.vb", -newFileFolderContainers: ImmutableArray.Create("outer", "inner"), +newFileFolderContainers: ["outer", "inner"], projectName: "Assembly2"); } @@ -1682,7 +1682,7 @@ End Namespace typeKind: TypeKind.Class, isNewFile: true, newFileName: "Test3.vb", -newFileFolderContainers: ImmutableArray.Create("outer", "inner"), +newFileFolderContainers: ["outer", "inner"], projectName: "Assembly2"); } @@ -1719,7 +1719,7 @@ End Namespace typeKind: TypeKind.Class, isNewFile: true, newFileName: "Test2.vb", -newFileFolderContainers: ImmutableArray.Empty, +newFileFolderContainers: [], projectName: "Assembly2"); } @@ -1936,7 +1936,7 @@ End Namespace typeKind: TypeKind.Module, isNewFile: true, newFileName: "Test2.vb", -newFileFolderContainers: ImmutableArray.Empty, +newFileFolderContainers: [], projectName: "Assembly2", assertGenerateTypeDialogOptions: new GenerateTypeDialogOptions(false, TypeKindOptions.Class | TypeKindOptions.Structure | TypeKindOptions.Module)); } @@ -3050,7 +3050,7 @@ End Namespace typeKind: TypeKind.Delegate, isNewFile: true, newFileName: "Test2.vb", -newFileFolderContainers: ImmutableArray.Empty, +newFileFolderContainers: [], projectName: "Assembly2"); } diff --git a/src/EditorFeatures/CSharpTest/CodeActions/ImplementInterface/ImplementImplicitlyTests.cs b/src/EditorFeatures/CSharpTest/CodeActions/ImplementInterface/ImplementImplicitlyTests.cs index e921db7c01783..6712c079be7c3 100644 --- a/src/EditorFeatures/CSharpTest/CodeActions/ImplementInterface/ImplementImplicitlyTests.cs +++ b/src/EditorFeatures/CSharpTest/CodeActions/ImplementInterface/ImplementImplicitlyTests.cs @@ -266,8 +266,7 @@ public readonly void Goo1() { } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/70232")] public async Task TestMissingWhenAlreadyContainingImpl() { - await TestMissingAsync( - """ + await TestInRegularAndScriptAsync(""" interface I { event System.EventHandler Click; @@ -278,7 +277,18 @@ class C : I event System.EventHandler I.Click { add { } remove { } } event System.EventHandler [||]I.Click - + } + """, """ + interface I + { + event System.EventHandler Click; + } + + class C : I + { + event System.EventHandler I.Click { add { } remove { } } + + public event System.EventHandler Click } """); } diff --git a/src/EditorFeatures/CSharpTest/CodeActions/InitializeParameter/InitializeMemberFromParameterTests.cs b/src/EditorFeatures/CSharpTest/CodeActions/InitializeParameter/InitializeMemberFromParameterTests.cs index d240eaab08d17..6eeb571f41b3d 100644 --- a/src/EditorFeatures/CSharpTest/CodeActions/InitializeParameter/InitializeMemberFromParameterTests.cs +++ b/src/EditorFeatures/CSharpTest/CodeActions/InitializeParameter/InitializeMemberFromParameterTests.cs @@ -21,7 +21,7 @@ public partial class InitializeMemberFromParameterTests : AbstractCSharpCodeActi protected override CodeRefactoringProvider CreateCodeRefactoringProvider(EditorTestWorkspace workspace, TestParameters parameters) => new CSharpInitializeMemberFromParameterCodeRefactoringProvider(); - private readonly NamingStylesTestOptionSets options = new NamingStylesTestOptionSets(LanguageNames.CSharp); + private readonly NamingStylesTestOptionSets options = new(LanguageNames.CSharp); [Fact] public async Task TestInitializeFieldWithSameName() @@ -1026,358 +1026,358 @@ public Test(int test) public async Task TestNoParameterNamingStyle_CreateAndInitField() { await TestInRegularAndScript1Async( -""" -class C -{ - public C([||]string s) - { - } -} -""", -""" -class C -{ - private readonly string _s; + """ + class C + { + public C([||]string s) + { + } + } + """, + """ + class C + { + private readonly string _s; - public C(string s) - { - _s = s; - } -} -""", index: 1, parameters: new TestParameters(options: options.FieldNamesAreCamelCaseWithUnderscorePrefix)); + public C(string s) + { + _s = s; + } + } + """, index: 1, parameters: new TestParameters(options: options.FieldNamesAreCamelCaseWithUnderscorePrefix)); } [Fact] public async Task TestCommonParameterNamingStyle_CreateAndInitField() { await TestInRegularAndScript1Async( -""" -class C -{ - public C([||]string t_s) - { - } -} -""", -""" -class C -{ - private readonly string _s; + """ + class C + { + public C([||]string t_s) + { + } + } + """, + """ + class C + { + private readonly string _s; - public C(string t_s) - { - _s = t_s; - } -} -""", index: 1, parameters: new TestParameters(options: options.FieldNamesAreCamelCaseWithUnderscorePrefix)); + public C(string t_s) + { + _s = t_s; + } + } + """, index: 1, parameters: new TestParameters(options: options.FieldNamesAreCamelCaseWithUnderscorePrefix)); } [Fact] public async Task TestSpecifiedParameterNamingStyle_CreateAndInitField() { await TestInRegularAndScript1Async( -""" -class C -{ - public C([||]string p_s_End) - { - } -} -""", -""" -class C -{ - private readonly string _s; + """ + class C + { + public C([||]string p_s_End) + { + } + } + """, + """ + class C + { + private readonly string _s; - public C(string p_s_End) - { - _s = p_s_End; - } -} -""", index: 1, parameters: new TestParameters(options: options.MergeStyles(options.FieldNamesAreCamelCaseWithUnderscorePrefix, options.ParameterNamesAreCamelCaseWithPUnderscorePrefixAndUnderscoreEndSuffix))); + public C(string p_s_End) + { + _s = p_s_End; + } + } + """, index: 1, parameters: new TestParameters(options: options.MergeStyles(options.FieldNamesAreCamelCaseWithUnderscorePrefix, options.ParameterNamesAreCamelCaseWithPUnderscorePrefixAndUnderscoreEndSuffix))); } [Fact] public async Task TestCommonAndSpecifiedParameterNamingStyle_CreateAndInitField() { await TestInRegularAndScript1Async( -""" -class C -{ - public C([||]string t_p_s_End) - { - } -} -""", -""" -class C -{ - private readonly string _s; + """ + class C + { + public C([||]string t_p_s_End) + { + } + } + """, + """ + class C + { + private readonly string _s; - public C(string t_p_s_End) - { - _s = t_p_s_End; - } -} -""", index: 1, parameters: new TestParameters(options: options.MergeStyles(options.FieldNamesAreCamelCaseWithUnderscorePrefix, options.ParameterNamesAreCamelCaseWithPUnderscorePrefixAndUnderscoreEndSuffix))); + public C(string t_p_s_End) + { + _s = t_p_s_End; + } + } + """, index: 1, parameters: new TestParameters(options: options.MergeStyles(options.FieldNamesAreCamelCaseWithUnderscorePrefix, options.ParameterNamesAreCamelCaseWithPUnderscorePrefixAndUnderscoreEndSuffix))); } [Fact] public async Task TestCommonAndSpecifiedParameterNamingStyle2_CreateAndInitField() { await TestInRegularAndScript1Async( -""" -class C -{ - public C([||]string p_t_s) - { - } -} -""", - """ - class C - { - private readonly string _s; + """ + class C + { + public C([||]string p_t_s) + { + } + } + """, + """ + class C + { + private readonly string _s; - public C([||]string p_t_s) - { - _s = p_t_s; - } - } - """, index: 1, parameters: new TestParameters(options: options.MergeStyles(options.FieldNamesAreCamelCaseWithUnderscorePrefix, options.ParameterNamesAreCamelCaseWithPUnderscorePrefix))); + public C([||]string p_t_s) + { + _s = p_t_s; + } + } + """, index: 1, parameters: new TestParameters(options: options.MergeStyles(options.FieldNamesAreCamelCaseWithUnderscorePrefix, options.ParameterNamesAreCamelCaseWithPUnderscorePrefix))); } [Fact] public async Task TestNoParameterNamingStyle_CreateAndInitProperty() { await TestInRegularAndScript1Async( -""" -class C -{ - public C([||]string s) - { - } -} -""", -""" -class C -{ - public C(string s) - { - S = s; - } + """ + class C + { + public C([||]string s) + { + } + } + """, + """ + class C + { + public C(string s) + { + S = s; + } - public string S { get; } -} -""", parameters: new TestParameters(options: options.PropertyNamesArePascalCase)); + public string S { get; } + } + """, parameters: new TestParameters(options: options.PropertyNamesArePascalCase)); } [Fact] public async Task TestCommonParameterNamingStyle_CreateAndInitProperty() { await TestInRegularAndScript1Async( -""" -class C -{ - public C([||]string t_s) - { - } -} -""", -""" -class C -{ - public C(string t_s) - { - S = t_s; - } + """ + class C + { + public C([||]string t_s) + { + } + } + """, + """ + class C + { + public C(string t_s) + { + S = t_s; + } - public string S { get; } -} -""", parameters: new TestParameters(options: options.PropertyNamesArePascalCase)); + public string S { get; } + } + """, parameters: new TestParameters(options: options.PropertyNamesArePascalCase)); } [Fact] public async Task TestSpecifiedParameterNamingStyle_CreateAndInitProperty() { await TestInRegularAndScript1Async( -""" -class C -{ - public C([||]string p_s_End) - { - } -} -""", -""" -class C -{ - public C(string p_s_End) - { - S = p_s_End; - } + """ + class C + { + public C([||]string p_s_End) + { + } + } + """, + """ + class C + { + public C(string p_s_End) + { + S = p_s_End; + } - public string S { get; } -} -""", parameters: new TestParameters(options: options.MergeStyles(options.PropertyNamesArePascalCase, options.ParameterNamesAreCamelCaseWithPUnderscorePrefixAndUnderscoreEndSuffix))); + public string S { get; } + } + """, parameters: new TestParameters(options: options.MergeStyles(options.PropertyNamesArePascalCase, options.ParameterNamesAreCamelCaseWithPUnderscorePrefixAndUnderscoreEndSuffix))); } [Fact] public async Task TestCommonAndSpecifiedParameterNamingStyle_CreateAndInitProperty() { await TestInRegularAndScript1Async( -""" -class C -{ - public C([||]string t_p_s_End) - { - } -} -""", -""" -class C -{ - public C(string t_p_s_End) - { - S = t_p_s_End; - } + """ + class C + { + public C([||]string t_p_s_End) + { + } + } + """, + """ + class C + { + public C(string t_p_s_End) + { + S = t_p_s_End; + } - public string S { get; } -} -""", parameters: new TestParameters(options: options.MergeStyles(options.PropertyNamesArePascalCase, options.ParameterNamesAreCamelCaseWithPUnderscorePrefixAndUnderscoreEndSuffix))); + public string S { get; } + } + """, parameters: new TestParameters(options: options.MergeStyles(options.PropertyNamesArePascalCase, options.ParameterNamesAreCamelCaseWithPUnderscorePrefixAndUnderscoreEndSuffix))); } [Fact] public async Task TestCommonAndSpecifiedParameterNamingStyle2_CreateAndInitProperty() { await TestInRegularAndScript1Async( -""" -class C -{ - public C([||]string p_t_s_End) - { - } -} -""", - """ - class C - { - public C([||]string p_t_s_End) - { - S = p_t_s_End; - } + """ + class C + { + public C([||]string p_t_s_End) + { + } + } + """, + """ + class C + { + public C([||]string p_t_s_End) + { + S = p_t_s_End; + } - public string S { get; } - } - """, parameters: new TestParameters(options: options.MergeStyles(options.PropertyNamesArePascalCase, options.ParameterNamesAreCamelCaseWithPUnderscorePrefixAndUnderscoreEndSuffix))); + public string S { get; } + } + """, parameters: new TestParameters(options: options.MergeStyles(options.PropertyNamesArePascalCase, options.ParameterNamesAreCamelCaseWithPUnderscorePrefixAndUnderscoreEndSuffix))); } [Fact] public async Task TestNoParameterNamingStyle_InitializeField() { await TestInRegularAndScript1Async( -""" -class C -{ - private readonly string _s; + """ + class C + { + private readonly string _s; - public C([||]string s) - { - } -} -""", -""" -class C -{ - private readonly string _s; + public C([||]string s) + { + } + } + """, + """ + class C + { + private readonly string _s; - public C(string s) - { - _s = s; - } -} -""", index: 0, parameters: new TestParameters(options: options.FieldNamesAreCamelCaseWithUnderscorePrefix)); + public C(string s) + { + _s = s; + } + } + """, index: 0, parameters: new TestParameters(options: options.FieldNamesAreCamelCaseWithUnderscorePrefix)); } [Fact] public async Task TestCommonParameterNamingStyle_InitializeField() { await TestInRegularAndScript1Async( -""" -class C -{ - private readonly string _s; + """ + class C + { + private readonly string _s; - public C([||]string t_s) - { - } -} -""", -""" -class C -{ - private readonly string _s; + public C([||]string t_s) + { + } + } + """, + """ + class C + { + private readonly string _s; - public C(string t_s) - { - _s = t_s; - } -} -""", index: 0, parameters: new TestParameters(options: options.FieldNamesAreCamelCaseWithUnderscorePrefix)); + public C(string t_s) + { + _s = t_s; + } + } + """, index: 0, parameters: new TestParameters(options: options.FieldNamesAreCamelCaseWithUnderscorePrefix)); } [Fact] public async Task TestSpecifiedParameterNamingStyle_InitializeField() { await TestInRegularAndScript1Async( -""" -class C -{ - private readonly string _s; + """ + class C + { + private readonly string _s; - public C([||]string p_s_End) - { - } -} -""", -""" -class C -{ - private readonly string _s; + public C([||]string p_s_End) + { + } + } + """, + """ + class C + { + private readonly string _s; - public C(string p_s_End) - { - _s = p_s_End; - } -} -""", index: 0, parameters: new TestParameters(options: options.MergeStyles(options.FieldNamesAreCamelCaseWithUnderscorePrefix, options.ParameterNamesAreCamelCaseWithPUnderscorePrefixAndUnderscoreEndSuffix))); + public C(string p_s_End) + { + _s = p_s_End; + } + } + """, index: 0, parameters: new TestParameters(options: options.MergeStyles(options.FieldNamesAreCamelCaseWithUnderscorePrefix, options.ParameterNamesAreCamelCaseWithPUnderscorePrefixAndUnderscoreEndSuffix))); } [Fact] public async Task TestCommonAndSpecifiedParameterNamingStyle_InitializeField() { await TestInRegularAndScript1Async( -""" -class C -{ - private readonly string _s; + """ + class C + { + private readonly string _s; - public C([||]string t_p_s_End) - { - } -} -""", -""" -class C -{ - private readonly string _s; + public C([||]string t_p_s_End) + { + } + } + """, + """ + class C + { + private readonly string _s; - public C(string t_p_s_End) - { - _s = t_p_s_End; - } -} -""", index: 0, parameters: new TestParameters(options: options.MergeStyles(options.FieldNamesAreCamelCaseWithUnderscorePrefix, options.ParameterNamesAreCamelCaseWithPUnderscorePrefixAndUnderscoreEndSuffix))); + public C(string t_p_s_End) + { + _s = t_p_s_End; + } + } + """, index: 0, parameters: new TestParameters(options: options.MergeStyles(options.FieldNamesAreCamelCaseWithUnderscorePrefix, options.ParameterNamesAreCamelCaseWithPUnderscorePrefixAndUnderscoreEndSuffix))); } [Fact] diff --git a/src/EditorFeatures/CSharpTest/CodeActions/MoveStaticMembers/CSharpMoveStaticMembersTests.cs b/src/EditorFeatures/CSharpTest/CodeActions/MoveStaticMembers/CSharpMoveStaticMembersTests.cs index 356a59d1b690b..9ddf9146a0c34 100644 --- a/src/EditorFeatures/CSharpTest/CodeActions/MoveStaticMembers/CSharpMoveStaticMembersTests.cs +++ b/src/EditorFeatures/CSharpTest/CodeActions/MoveStaticMembers/CSharpMoveStaticMembersTests.cs @@ -3221,7 +3221,7 @@ public class Class1 } } }"; - await new Test("", ImmutableArray.Empty, "") + await new Test("", [], "") { TestCode = initialMarkup, }.RunAsync().ConfigureAwait(false); @@ -3238,7 +3238,7 @@ public class Class1 public st[||] {|CS1519:int|} TestField = 0; } }"; - await new Test("", ImmutableArray.Empty, "") + await new Test("", [], "") { TestCode = initialMarkup, }.RunAsync().ConfigureAwait(false); @@ -3255,7 +3255,7 @@ public class Class1 public st [|{|CS1519:int|} Test|]Field = 0; } }"; - await new Test("", ImmutableArray.Empty, "") + await new Test("", [], "") { TestCode = initialMarkup, }.RunAsync().ConfigureAwait(false); @@ -3272,7 +3272,7 @@ public class Class1 [|public st {|CS1519:int|} TestField = 0;|] } }"; - await new Test("", ImmutableArray.Empty, "") + await new Test("", [], "") { TestCode = initialMarkup, }.RunAsync().ConfigureAwait(false); @@ -3289,7 +3289,7 @@ public class Class1 [|publicc {|CS1585:static|} int TestField = 0;|] } }"; - await new Test("", ImmutableArray.Empty, "") + await new Test("", [], "") { TestCode = initialMarkup, }.RunAsync().ConfigureAwait(false); @@ -3381,7 +3381,7 @@ public async Task TestSelectTopLevelStatement_NoAction1() [||]Console.WriteLine(5); "; - await new Test("", ImmutableArray.Empty, "") + await new Test("", [], "") { TestCode = initialMarkup, LanguageVersion = CodeAnalysis.CSharp.LanguageVersion.CSharp10, @@ -3401,7 +3401,7 @@ public async Task TestSelectTopLevelStatement_NoAction2() [|Console.WriteLine(5);|] "; - await new Test("", ImmutableArray.Empty, "") + await new Test("", [], "") { TestCode = initialMarkup, LanguageVersion = CodeAnalysis.CSharp.LanguageVersion.CSharp10, @@ -3424,7 +3424,7 @@ public async Task TestSelectTopLevelLocalFunction_NoAction() } "; - await new Test("", ImmutableArray.Empty, "") + await new Test("", [], "") { TestCode = initialMarkup, LanguageVersion = CodeAnalysis.CSharp.LanguageVersion.CSharp10, @@ -3472,7 +3472,7 @@ protected override Task CreateWorkspaceImplAsync() testOptionsService.SelectedMembers = _selection; testOptionsService.Filename = _destinationName; testOptionsService.CreateNew = _createNew; - testOptionsService.ExpectedPrecheckedMembers = _testPreselection ? _selection : ImmutableArray.Empty; + testOptionsService.ExpectedPrecheckedMembers = _testPreselection ? _selection : []; return Task.FromResult(workspace); } @@ -3546,7 +3546,7 @@ private static async Task TestMovementExistingFileAsync( private static async Task TestNoRefactoringAsync(string initialMarkup) { - await new Test("", ImmutableArray.Empty, "") + await new Test("", [], "") { TestCode = initialMarkup, }.RunAsync().ConfigureAwait(false); diff --git a/src/EditorFeatures/CSharpTest/CodeActions/MoveType/MoveTypeTests.MoveToNewFile.cs b/src/EditorFeatures/CSharpTest/CodeActions/MoveType/MoveTypeTests.MoveToNewFile.cs index 12cfecdc623d2..a698667972f75 100644 --- a/src/EditorFeatures/CSharpTest/CodeActions/MoveType/MoveTypeTests.MoveToNewFile.cs +++ b/src/EditorFeatures/CSharpTest/CodeActions/MoveType/MoveTypeTests.MoveToNewFile.cs @@ -105,7 +105,7 @@ class Class1 { } await TestMoveTypeToNewFileAsync( code, codeAfterMove, expectedDocumentName, - destinationDocumentText, destinationDocumentContainers: ImmutableArray.Create("A", "B")); + destinationDocumentText, destinationDocumentContainers: ["A", "B"]); } [WpfFact] @@ -1179,22 +1179,22 @@ public class [||]Inner #endif """; var codeAfterMove = - """ - using System; + """ + using System; - namespace N - { - class Program + namespace N { - static void Main() + class Program { + static void Main() + { + } } } - } - #if true - #endif - """; + #if true + #endif + """; var expectedDocumentName = "Inner.cs"; var destinationDocumentText = @@ -1237,22 +1237,22 @@ public class [||]Inner } """; var codeAfterMove = - """ - using System; + """ + using System; - namespace N - { - partial class Program + namespace N { - static void Main() + partial class Program { - } + static void Main() + { + } - #if true - #endif + #if true + #endif + } } - } - """; + """; var expectedDocumentName = "Inner.cs"; var destinationDocumentText = @@ -1275,6 +1275,99 @@ await TestMoveTypeToNewFileAsync( code, codeAfterMove, expectedDocumentName, destinationDocumentText); } + [WpfFact, WorkItem("https://github.com/dotnet/roslyn/issues/19613")] + public async Task MoveTypeWithDirectives3() + { + var code = + """ + public class Goo + { + #region Region + public class [||]Bar + { + } + #endregion + } + """; + var codeAfterMove = + """ + public partial class Goo + { + + #region Region + #endregion + } + """; + + var expectedDocumentName = "Bar.cs"; + var destinationDocumentText = + """ + public partial class Goo + { + #region Region + public class Bar + { + } + #endregion + } + """; + + await TestMoveTypeToNewFileAsync( + code, codeAfterMove, expectedDocumentName, destinationDocumentText); + } + + [WpfFact, WorkItem("https://github.com/dotnet/roslyn/issues/19613")] + public async Task MoveTypeWithDirectives4() + { + var code = + """ + public class Goo + { + #region Region1 + public class NotBar + { + } + #endregion + + #region Region2 + public class [||]Bar + { + } + #endregion + } + """; + var codeAfterMove = + """ + public partial class Goo + { + #region Region1 + public class NotBar + { + } + + #endregion + #region Region2 + #endregion + } + """; + + var expectedDocumentName = "Bar.cs"; + var destinationDocumentText = + """ + public partial class Goo + { + #region Region2 + public class Bar + { + } + #endregion + } + """; + + await TestMoveTypeToNewFileAsync( + code, codeAfterMove, expectedDocumentName, destinationDocumentText); + } + [WpfFact, WorkItem("https://github.com/dotnet/roslyn/issues/21456")] public async Task TestLeadingBlankLines1() { @@ -2012,4 +2105,37 @@ partial interface I """; await TestMoveTypeToNewFileAsync(code, codeAfterMove, expectedDocumentName, destinationDocumentText); } + + [WpfFact, WorkItem("https://github.com/dotnet/roslyn/issues/74703")] + public async Task TestUpdateFileName() + { + var code = + """ + + + + // This is a banner referencing Goo.cs + [||]class Class1 { } + class Class2 { } + + + + """; + var codeAfterMove = """ + // This is a banner referencing Goo.cs + class Class2 { } + + """; + + var expectedDocumentName = "Class1.cs"; + var destinationDocumentText = """ + // This is a banner referencing Class1.cs + class Class1 { } + + """; + + await TestMoveTypeToNewFileAsync( + code, codeAfterMove, expectedDocumentName, + destinationDocumentText, destinationDocumentContainers: ["A", "B"]); + } } diff --git a/src/EditorFeatures/CSharpTest/CodeActions/SyncNamespace/CSharpSyncNamespaceTestsBase.cs b/src/EditorFeatures/CSharpTest/CodeActions/SyncNamespace/CSharpSyncNamespaceTestsBase.cs index aa490c885a1a1..b6377fe8b2dbd 100644 --- a/src/EditorFeatures/CSharpTest/CodeActions/SyncNamespace/CSharpSyncNamespaceTestsBase.cs +++ b/src/EditorFeatures/CSharpTest/CodeActions/SyncNamespace/CSharpSyncNamespaceTestsBase.cs @@ -121,10 +121,10 @@ async Task>> TestOperationAsync( await TestOperationsAsync(workspace, expectedText: expectedCode, operations: operations, - conflictSpans: ImmutableArray.Empty, - renameSpans: ImmutableArray.Empty, - warningSpans: ImmutableArray.Empty, - navigationSpans: ImmutableArray.Empty, + conflictSpans: [], + renameSpans: [], + warningSpans: [], + navigationSpans: [], expectedChangedDocumentId: null)); } @@ -170,7 +170,7 @@ protected async Task TestChangeNamespaceAsync( var modifiedOringinalRoot = await modifiedOriginalDocument.GetSyntaxRootAsync(); // One node/token will contain the warning we attached for change namespace action. - Assert.Single(modifiedOringinalRoot.DescendantNodesAndTokensAndSelf().Where(n => + Assert.Single(modifiedOringinalRoot.DescendantNodesAndTokensAndSelf(), n => { IEnumerable annotations; if (n.IsNode) @@ -184,7 +184,7 @@ protected async Task TestChangeNamespaceAsync( return annotations.Any(annotation => WarningAnnotation.GetDescription(annotation) == FeaturesResources.Warning_colon_changing_namespace_may_produce_invalid_code_and_change_code_meaning); - })); + }); var actualText = (await modifiedOriginalDocument.GetTextAsync()).ToString(); AssertEx.EqualOrDiff(expectedSourceOriginal, actualText); diff --git a/src/EditorFeatures/CSharpTest/CodeActions/SyncNamespace/SyncNamespaceTests_ChangeNamespace.cs b/src/EditorFeatures/CSharpTest/CodeActions/SyncNamespace/SyncNamespaceTests_ChangeNamespace.cs index d74102910a0dd..f0929087b76a1 100644 --- a/src/EditorFeatures/CSharpTest/CodeActions/SyncNamespace/SyncNamespaceTests_ChangeNamespace.cs +++ b/src/EditorFeatures/CSharpTest/CodeActions/SyncNamespace/SyncNamespaceTests_ChangeNamespace.cs @@ -152,9 +152,9 @@ interface Class1 class Class2 : {{declaredNamespace}}.Class1 { - {{declaredNamespace}}.D1 d; + {{declaredNamespace}}.D1 d; - void {{declaredNamespace}}.Class1.M1(){} + void {{declaredNamespace}}.Class1.M1() { } } } @@ -341,8 +341,8 @@ public async Task ChangeNamespace_ReferencingTypesDeclaredInOtherDocument() namespace [||]{{declaredNamespace}} { - class Class1 - { + class Class1 + { private Class2 c2; private Class3 c3; private Class4 c4; @@ -351,7 +351,7 @@ class Class1 namespace Foo { - class Class2 {} + class Class2{} namespace Bar { @@ -401,8 +401,8 @@ public async Task ChangeNamespace_ReferencingQualifiedTypesDeclaredInOtherDocume namespace [||]{{declaredNamespace}} { - class Class1 - { + class Class1 + { private Foo.Class2 c2; private Foo.Bar.Class3 c3; private Foo.Bar.Baz.Class4 c4; @@ -411,7 +411,7 @@ class Class1 namespace Foo { - class Class2 {} + class Class2{} namespace Bar { @@ -460,12 +460,12 @@ public async Task ChangeNamespace_WithReferencesInOtherDocument() namespace [||]{{declaredNamespace}} { - class Class1 - { + class Class1 + { } - class Class2 - { + class Class2 + { } } using Foo.Bar.Baz; @@ -533,9 +533,9 @@ public async Task ChangeNamespace_WithQualifiedReferencesInOtherDocument() namespace [||]{{declaredNamespace}} { - interface Interface1 + interface Interface1 { - void M1(Interface1 c1); + void M1(Interface1 c1); } } namespace Foo @@ -663,12 +663,12 @@ public async Task ChangeNamespace_WithAliasReferencesInOtherDocument() namespace [||]{{declaredNamespace}} { - class Class1 - { + class Class1 + { } - class Class2 - { + class Class2 + { } } using System; @@ -789,7 +789,7 @@ interface Class1 class Class2 : {{declaredNamespace}}.Class1 { - global::{{declaredNamespace}}.D1 d; + global::{{declaredNamespace}}.D1 d; void {{declaredNamespace}}.Class1.M1() { } } @@ -832,12 +832,12 @@ public async Task ChangeToGlobalNamespace_WithReferencesInOtherDocument() namespace [||]{{declaredNamespace}} { - class Class1 - { + class Class1 + { } - class Class2 - { + class Class2 + { } } using Foo.Bar.Baz; @@ -903,7 +903,7 @@ public async Task ChangeToGlobalNamespace_WithQualifiedReferencesInOtherDocument { interface Interface1 { - void M1(Interface1 c1); + void M1(Interface1 c1); } } namespace Foo @@ -1013,8 +1013,8 @@ public async Task ChangeToGlobalNamespace_ReferencingTypesDeclaredInOtherDocumen namespace [||]{{declaredNamespace}} { - class Class1 - { + class Class1 + { private Class2 c2; private Class3 c3; private Class4 c4; @@ -1022,7 +1022,7 @@ class Class1 } namespace Foo { - class Class2 {} + class Class2{} namespace Bar { @@ -1138,12 +1138,12 @@ public async Task ChangeToGlobalNamespace_WithAliasReferencesInOtherDocument() namespace [||]{{declaredNamespace}} { - class Class1 - { + class Class1 + { } - class Class2 - { + class Class2 + { } } using System; @@ -1249,7 +1249,7 @@ interface Class1 class Class2 : Class1 { - D1 d; + D1 d; void Class1.M1() { } } @@ -1417,7 +1417,7 @@ class [||]Class1 namespace A { - class Class2 {} + class Class2{} namespace B { @@ -1608,7 +1608,7 @@ public async Task ChangeNamespace_WithReferencesInVBDocument() namespace [||]{{declaredNamespace}} { public class Class1 - { + { } } @@ -1657,7 +1657,7 @@ public async Task ChangeNamespace_WithQualifiedReferencesInVBDocument() namespace [||]{{declaredNamespace}} { public class Class1 - { + { } } @@ -1804,7 +1804,7 @@ public async Task ChangeToGlobalNamespace_WithReferencesInVBDocument() namespace [||]{{declaredNamespace}} { public class Class1 - { + { } } @@ -1848,7 +1848,7 @@ public async Task ChangeToGlobalNamespace_WithReferenceAndConflictDeclarationInV namespace [||]{{declaredNamespace}} { public class MyClass - { + { } } @@ -1965,7 +1965,7 @@ public async Task ChangeNamespace_ExtensionMethodInReducedForm() namespace [||]{{defaultNamespace}} { public static class Extensions - { + { public static bool Foo(this Class1 c1) => true; } } @@ -2022,7 +2022,7 @@ public async Task ChangeNamespace_ExternsionMethodInRegularForm() namespace [||]A { public static class Extensions - { + { public static bool Foo(this Class1 c1) => true; } } @@ -2079,7 +2079,7 @@ public async Task ChangeNamespace_ContainsBothTypeAndExternsionMethod() namespace [||]A { public static class Extensions - { + { public static bool Foo(this Class1 c1) => true; } @@ -2200,7 +2200,7 @@ public async Task ChangeNamespace_WithMemberAccessReferencesInOtherDocument() namespace [||]{{declaredNamespace}} { - enum Enum1 + enum Enum1 { A, B, @@ -2265,7 +2265,7 @@ public async Task ChangeToGlobalNamespace_WithMemberAccessReferencesInOtherDocum namespace [||]{{declaredNamespace}} { - enum Enum1 + enum Enum1 { A, B, diff --git a/src/EditorFeatures/CSharpTest/CompleteStatement/CSharpCompleteStatementCommandHandlerTests.cs b/src/EditorFeatures/CSharpTest/CompleteStatement/CSharpCompleteStatementCommandHandlerTests.cs index 22beee439112f..490b7f558e51f 100644 --- a/src/EditorFeatures/CSharpTest/CompleteStatement/CSharpCompleteStatementCommandHandlerTests.cs +++ b/src/EditorFeatures/CSharpTest/CompleteStatement/CSharpCompleteStatementCommandHandlerTests.cs @@ -14,30 +14,31 @@ namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.CompleteStatement; [Trait(Traits.Feature, Traits.Features.CompleteStatement)] -public class CSharpCompleteStatementCommandHandlerTests : AbstractCompleteStatementTests +public sealed class CSharpCompleteStatementCommandHandlerTests : AbstractCompleteStatementTests { private static string CreateTestWithMethodCall(string code) { return -@"class C - { - static void Main(string[] args) - { - int x = 1; - int y = 2; - int[] a = { 1,2 }; - " + code + @" - - int z = 4; - } - } + """ + class C + { + static void Main(string[] args) + { + int x = 1; + int y = 2; + int[] a = { 1,2 }; + """ + code + """ + int z = 4; + } + } - static class ClassC - { - internal static int MethodM(int a, int b) - => a * b; - } -}"; + static class ClassC + { + internal static int MethodM(int a, int b) + => a * b; + } + } + """; } #region ParameterList @@ -66,17 +67,19 @@ internal static int MethodM(int a, int b) [InlineData("public interface C(int X, int Y$$)", "public interface C(int X, int Y)")] public void ParameterList_CouldBeHandled(string signature, string expectedSignature) { - var code = $@" -public class Class1 -{{ - {signature} -}}"; + var code = $$""" + public class Class1 + { + {{signature}} + } + """; - var expected = $@" -public class Class1 -{{ - {expectedSignature};$$ -}}"; + var expected = $$""" + public class Class1 + { + {{expectedSignature}};$$ + } + """; VerifyTypingSemicolon(code, expected); } @@ -84,17 +87,19 @@ public class Class1 [WpfFact] public void ParameterList_InterfaceMethod() { - var code = @" -public interface I -{ - public void M(object o$$) -}"; + var code = """ + public interface I + { + public void M(object o$$) + } + """; - var expected = @" -public interface I -{ - public void M(object o);$$ -}"; + var expected = """ + public interface I + { + public void M(object o);$$ + } + """; VerifyTypingSemicolon(code, expected); } @@ -107,11 +112,12 @@ public interface I [InlineData("partial void Method($$object o) { }")] public void ParameterList_NotHandled(string signature) { - var code = $@" -public class Class1 -{{ - {signature} -}}"; + var code = $$""" + public class Class1 + { + {{signature}} + } + """; VerifyNoSpecialSemicolonHandling(code); } @@ -217,28 +223,52 @@ public void ArgumentListOfMethodInvocation_SemicolonAlreadyExists() [WorkItem(34176, "https://github.com/dotnet/roslyn/pull/34177")] [WpfTheory] - [InlineData("$$ \"Test\"")] - [InlineData(" $$\"Test\"")] - [InlineData("\"Test\"$$ ")] - [InlineData("\"Test\" $$")] + [InlineData(""" + $$ "Test" + """)] + [InlineData(""" + $$"Test" + """)] + [InlineData(""" + "Test"$$ + """)] + [InlineData(""" + "Test" $$ + """)] // Verbatim strings - [InlineData("$$ @\"Test\"")] - [InlineData(" $$@\"Test\"")] + [InlineData(""" + $$ @"Test" + """)] + [InlineData(""" + $$@"Test" + """)] [InlineData("@\"Test\"$$ ")] [InlineData("@\"Test\" $$")] // Raw strings - [InlineData("$$ \"\"\"Test\"\"\"")] - [InlineData(" $$\"\"\"Test\"\"\"")] - [InlineData("\"\"\"Test\"\"\"$$ ")] - [InlineData("\"\"\"Test\"\"\" $$")] + [InlineData("""" + $$ """Test""" + """")] + [InlineData("""" + $$"""Test""" + """")] + [InlineData("""" + """Test"""$$ + """")] + [InlineData("""" + """Test""" $$ + """")] // UTF-8 strings [InlineData("$$ \"Test\"u8")] [InlineData(" $$\"Test\"u8")] - [InlineData("\"Test\"u8$$ ")] - [InlineData("\"Test\"u8 $$")] + [InlineData(""" + "Test"u8$$ + """)] + [InlineData(""" + "Test"u8 $$ + """)] public void ArgumentListOfMethodInvocation_OutsideStringAsMethodArgument(string argument) { var code = CreateTestWithMethodCall($@"var test = Console.WriteLine({argument})"); @@ -250,14 +280,30 @@ public void ArgumentListOfMethodInvocation_OutsideStringAsMethodArgument(string [WorkItem(34176, "https://github.com/dotnet/roslyn/pull/34177")] [WpfTheory] - [InlineData("\"Test$$\"")] - [InlineData("@\"Test$$\"")] - [InlineData(" @$$\"Test\"")] - [InlineData("\"\"\"Test$$\"\"\"")] - [InlineData("\"\"\"Test\"$$\"\"")] - [InlineData("\"\"\"Test\"\"$$\"")] - [InlineData("\"Test$$\"u8")] - [InlineData("\"Test\"$$u8 ")] + [InlineData(""" + "Test$$" + """)] + [InlineData(""" + @"Test$$" + """)] + [InlineData(""" + @$$"Test" + """)] + [InlineData("""" + """Test$$""" + """")] + [InlineData("""" + """Test"$$"" + """")] + [InlineData("""" + """Test""$$" + """")] + [InlineData(""" + "Test$$"u8 + """)] + [InlineData(""" + "Test"$$u8 + """)] public void ArgumentListOfMethodInvocation_InsideStringAsMethodArgument(string argument) { var code = CreateTestWithMethodCall($@"var test = Console.WriteLine({argument})"); @@ -268,15 +314,17 @@ public void ArgumentListOfMethodInvocation_InsideStringAsMethodArgument(string a [WpfFact] public void ArgumentListOfMethodInvocation_MultiLine() { - var code = CreateTestWithMethodCall(@" -var test = ClassC.MethodM( - x$$, - y)"); + var code = CreateTestWithMethodCall(""" + var test = ClassC.MethodM( + x$$, + y) + """); - var expected = CreateTestWithMethodCall(@" -var test = ClassC.MethodM( - x, - y);$$"); + var expected = CreateTestWithMethodCall(""" + var test = ClassC.MethodM( + x, + y);$$ + """); VerifyTypingSemicolon(code, expected); } @@ -284,17 +332,19 @@ public void ArgumentListOfMethodInvocation_MultiLine() [WpfFact] public void ArgumentListOfMethodInvocation_MultiLine3() { - var code = CreateTestWithMethodCall(@" -var test = ClassC.MethodM( - x$$, - y - )"); + var code = CreateTestWithMethodCall(""" + var test = ClassC.MethodM( + x$$, + y + ) + """); - var expected = CreateTestWithMethodCall(@" -var test = ClassC.MethodM( - x, - y - );$$"); + var expected = CreateTestWithMethodCall(""" + var test = ClassC.MethodM( + x, + y + );$$ + """); VerifyTypingSemicolon(code, expected); } @@ -466,15 +516,17 @@ public void ArgumentListOfNestedMethodInvocation_DualPosition_SemicolonAlreadyEx [WpfFact] public void ArgumentListOfNestedMethodInvocation_MultiLine() { - var code = CreateTestWithMethodCall(@" -var test = ClassC.MethodM( - x.ToString(), - y$$)"); + var code = CreateTestWithMethodCall(""" + var test = ClassC.MethodM( + x.ToString(), + y$$) + """); - var expected = CreateTestWithMethodCall(@" -var test = ClassC.MethodM( - x.ToString(), - y);$$"); + var expected = CreateTestWithMethodCall(""" + var test = ClassC.MethodM( + x.ToString(), + y);$$ + """); VerifyTypingSemicolon(code, expected); } @@ -482,17 +534,19 @@ public void ArgumentListOfNestedMethodInvocation_MultiLine() [WpfFact] public void ArgumentListOfNestedMethodInvocation_MultiLine2() { - var code = CreateTestWithMethodCall(@" -var test = ClassC.MethodM( - x.ToString(), - y$$ - )"); + var code = CreateTestWithMethodCall(""" + var test = ClassC.MethodM( + x.ToString(), + y$$ + ) + """); - var expected = CreateTestWithMethodCall(@" -var test = ClassC.MethodM( - x.ToString(), - y - );$$"); + var expected = CreateTestWithMethodCall(""" + var test = ClassC.MethodM( + x.ToString(), + y + );$$ + """); VerifyTypingSemicolon(code, expected); } @@ -500,17 +554,19 @@ public void ArgumentListOfNestedMethodInvocation_MultiLine2() [WpfFact] public void ArgumentListOfNestedMethodInvocation_MultiLine3() { - var code = CreateTestWithMethodCall(@" -var test = ClassC.MethodM( - x.ToString(), - ""y""$$ - )"); + var code = CreateTestWithMethodCall(""" + var test = ClassC.MethodM( + x.ToString(), + "y"$$ + ) + """); - var expected = CreateTestWithMethodCall(@" -var test = ClassC.MethodM( - x.ToString(), - ""y"" - );$$"); + var expected = CreateTestWithMethodCall(""" + var test = ClassC.MethodM( + x.ToString(), + "y" + );$$ + """); VerifyTypingSemicolon(code, expected); } @@ -687,12 +743,12 @@ public void ArgumentList_Array_MissingInner() public void FieldInitializer_NoParens() { var code = -@" -class C -{ - int i = 4$$ - int j = 5; -"; + """ + class C + { + int i = 4$$ + int j = 5; + """; VerifyNoSpecialSemicolonHandling(code); } @@ -701,20 +757,20 @@ class C public void FieldInitializer2() { var code = -@" -class C -{ - int i = Min(2$$,3) - int j = 5; -"; + """ + class C + { + int i = Min(2$$,3) + int j = 5; + """; var expected = -@" -class C -{ - int i = Min(2,3);$$ - int j = 5; -"; + """ + class C + { + int i = Min(2,3);$$ + int j = 5; + """; VerifyTypingSemicolon(code, expected); } @@ -723,12 +779,12 @@ class C public void FieldInitializer2b_MissingParen() { var code = -@" -class C -{ - int i = Min(2$$,3 - int j = 5; -"; + """ + class C + { + int i = Min(2$$,3 + int j = 5; + """; VerifyNoSpecialSemicolonHandling(code); } @@ -737,20 +793,20 @@ class C public void FieldInitializer3() { var code = -@" -class C -{ - int i = Min(Max(4,5$$),3) - int j = 5; -"; + """ + class C + { + int i = Min(Max(4,5$$),3) + int j = 5; + """; var expected = -@" -class C -{ - int i = Min(Max(4,5),3);$$ - int j = 5; -"; + """ + class C + { + int i = Min(Max(4,5),3);$$ + int j = 5; + """; VerifyTypingSemicolon(code, expected); } @@ -759,12 +815,12 @@ class C public void FieldInitializer3b_MissingInner() { var code = -@" -class C -{ - int i = Min(Max(4,5$$,3) - int j = 5; -"; + """ + class C + { + int i = Min(Max(4,5$$,3) + int j = 5; + """; VerifyNoSpecialSemicolonHandling(code); } @@ -777,14 +833,14 @@ class C public void ForLoopSingleInitializer1() { var code = -@" -class C -{ - static void Main() - { - for (int i = 0$$ ) - int j; -"; + """ + class C + { + static void Main() + { + for (int i = 0$$ ) + int j; + """; VerifyNoSpecialSemicolonHandling(code); } @@ -793,14 +849,14 @@ static void Main() public void ForLoopSingleInitializer2() { var code = -@" -class C -{ - static void Main() - { - for (int i = 0$$ i < 5; i++) - int j; -"; + """ + class C + { + static void Main() + { + for (int i = 0$$ i < 5; i++) + int j; + """; VerifyNoSpecialSemicolonHandling(code); } @@ -809,19 +865,19 @@ static void Main() public void ForLoopSingleInitializer3() { var code = -@" -class C -{ - static void Main() - { - for (int i = 0$$; i < 3; i = i + 1) - { - x = x * 3; - } - System.Console.Write(""{0}"", x); - } -} -"; + """ + class C + { + static void Main() + { + for (int i = 0$$; i < 3; i = i + 1) + { + x = x * 3; + } + System.Console.Write("{0}", x); + } + } + """; VerifyNoSpecialSemicolonHandling(code); } @@ -830,14 +886,14 @@ static void Main() public void ForLoopSingleInitializer_MissingParen() { var code = -@" -class C -{ - static void Main() - { - for (int i = 0$$ - int j; -"; + """ + class C + { + static void Main() + { + for (int i = 0$$ + int j; + """; VerifyNoSpecialSemicolonHandling(code); } @@ -846,14 +902,14 @@ static void Main() public void ForLoopNoStatements() { var code = -@" -class C -{ - static void Main() - { - for ($$ - int j; -"; + """ + class C + { + static void Main() + { + for ($$ + int j; + """; VerifyNoSpecialSemicolonHandling(code); } @@ -862,14 +918,14 @@ static void Main() public void ForLoopNoStatements2() { var code = -@" -class C -{ - static void Main() - { - for ( $$ - int j; -"; + """ + class C + { + static void Main() + { + for ( $$ + int j; + """; VerifyNoSpecialSemicolonHandling(code); } @@ -878,14 +934,14 @@ static void Main() public void ForLoopNoStatements3() { var code = -@" -class C -{ - static void Main() - { - for ( ; $$ - int j; -"; + """ + class C + { + static void Main() + { + for ( ; $$ + int j; + """; VerifyNoSpecialSemicolonHandling(code); } @@ -894,14 +950,14 @@ static void Main() public void ForLoopNoStatements4() { var code = -@" -class C -{ - static void Main() - { - for ( ; ;$$ - int j; -"; + """ + class C + { + static void Main() + { + for ( ; ;$$ + int j; + """; VerifyNoSpecialSemicolonHandling(code); } @@ -910,14 +966,14 @@ static void Main() public void ForLoopNoStatements5() { var code = -@" -class C -{ - static void Main() - { - for ( $$ ;) - int j; -"; + """ + class C + { + static void Main() + { + for ( $$ ;) + int j; + """; VerifyNoSpecialSemicolonHandling(code); } @@ -926,14 +982,14 @@ static void Main() public void ForLoopMultistatementInitializer1() { var code = -@" -class C -{ - static void Main() - { - for ( $$int i = 0, int j = 0) - int j; -"; + """ + class C + { + static void Main() + { + for ( $$int i = 0, int j = 0) + int j; + """; VerifyNoSpecialSemicolonHandling(code); } @@ -942,14 +998,14 @@ static void Main() public void ForLoopMultistatementInitializer2() { var code = -@" -class C -{ - static void Main() - { - for ( int$$ i = 0, int j = 0) - int j; -"; + """ + class C + { + static void Main() + { + for ( int$$ i = 0, int j = 0) + int j; + """; VerifyNoSpecialSemicolonHandling(code); } @@ -958,14 +1014,14 @@ static void Main() public void ForLoopMultistatementInitializer3() { var code = -@" -class C -{ - static void Main() - { - for ( int i$$ = 0, int j = 0) - int j; -"; + """ + class C + { + static void Main() + { + for ( int i$$ = 0, int j = 0) + int j; + """; VerifyNoSpecialSemicolonHandling(code); } @@ -974,14 +1030,14 @@ static void Main() public void ForLoopMultistatementInitializer4() { var code = -@" -class C -{ - static void Main() - { - for ( int i = 0, $$int j = 0) - int j; -"; + """ + class C + { + static void Main() + { + for ( int i = 0, $$int j = 0) + int j; + """; VerifyNoSpecialSemicolonHandling(code); } @@ -990,14 +1046,14 @@ static void Main() public void ForLoopMultistatementInitializer5() { var code = -@" -class C -{ - static void Main() - { - for ( int i = 0, int j =$$ 0) - int j; -"; + """ + class C + { + static void Main() + { + for ( int i = 0, int j =$$ 0) + int j; + """; VerifyNoSpecialSemicolonHandling(code); } @@ -1006,14 +1062,14 @@ static void Main() public void ForLoopMultistatementInitializer6() { var code = -@" -class C -{ - static void Main() - { - for ( int i = 0, int j = 0$$) - int j; -"; + """ + class C + { + static void Main() + { + for ( int i = 0, int j = 0$$) + int j; + """; VerifyNoSpecialSemicolonHandling(code); } @@ -1022,14 +1078,14 @@ static void Main() public void ForLoopMultistatementInitializer7() { var code = -@" -class C -{ - static void Main() - { - for ( int i = 0, int j = 0$$) - int j; -"; + """ + class C + { + static void Main() + { + for ( int i = 0, int j = 0$$) + int j; + """; VerifyNoSpecialSemicolonHandling(code); } @@ -1038,42 +1094,42 @@ static void Main() public void ForLoopNewInInitializer1() { var code = -@" -class C -{ - static void Main(string[] args) - { - for (C1 i = new C1($$)) - int j; - } -} -public class C1 -{ - public static C1 operator ++(C1 obj) - { - return obj; - } -} -"; + """ + class C + { + static void Main(string[] args) + { + for (C1 i = new C1($$)) + int j; + } + } + public class C1 + { + public static C1 operator ++(C1 obj) + { + return obj; + } + } + """; var expected = -@" -class C -{ - static void Main(string[] args) - { - for (C1 i = new C1();$$) - int j; - } -} -public class C1 -{ - public static C1 operator ++(C1 obj) - { - return obj; - } -} -"; + """ + class C + { + static void Main(string[] args) + { + for (C1 i = new C1();$$) + int j; + } + } + public class C1 + { + public static C1 operator ++(C1 obj) + { + return obj; + } + } + """; VerifyTypingSemicolon(code, expected); } @@ -1082,25 +1138,25 @@ public class C1 public void ForLoopNewInInitializer_MissingOneParen() { var code = -@" -class C -{ - static void Main(string[] args) - { - for (C1 i = new C1()$$ - int j; - } -} -public class C1 -{ - public static C1 operator ++(C1 obj) - { - return obj; - } -} -"; - - VerifyNoSpecialSemicolonHandling(code); + """ + class C + { + static void Main(string[] args) + { + for (C1 i = new C1()$$ + int j; + } + } + public class C1 + { + public static C1 operator ++(C1 obj) + { + return obj; + } + } + """; + + VerifyNoSpecialSemicolonHandling(code); } [WpfFact] @@ -1108,23 +1164,23 @@ public void ForLoopNewInInitializer2_MissingBothParens() { // only adding one closing paren var code = -@" -class C -{ - static void Main(string[] args) - { - for (C1 i = new C1($$ - int j; - } -} -public class C1 -{ - public static C1 operator ++(C1 obj) - { - return obj; - } -} -"; + """ + class C + { + static void Main(string[] args) + { + for (C1 i = new C1($$ + int j; + } + } + public class C1 + { + public static C1 operator ++(C1 obj) + { + return obj; + } + } + """; VerifyNoSpecialSemicolonHandling(code); } @@ -1133,24 +1189,24 @@ public class C1 public void ForLoopDeclaration() { var code = -@" -class C -{ - static void Main(string[] args) - { - string s = ""abcdefghij""; - for (int i = s.IndexOf(""bcd""$$) i < 10; i++) -"; + """ + class C + { + static void Main(string[] args) + { + string s = "abcdefghij"; + for (int i = s.IndexOf("bcd"$$) i < 10; i++) + """; var expected = -@" -class C -{ - static void Main(string[] args) - { - string s = ""abcdefghij""; - for (int i = s.IndexOf(""bcd"");$$ i < 10; i++) -"; + """ + class C + { + static void Main(string[] args) + { + string s = "abcdefghij"; + for (int i = s.IndexOf("bcd");$$ i < 10; i++) + """; VerifyTypingSemicolon(code, expected); } @@ -1159,24 +1215,24 @@ static void Main(string[] args) public void ForLoopDeclaration2() { var code = -@" -class C -{ - static void Main(string[] args) - { - string s = ""abcdefghij""; - for (int i = s.IndexOf(""bcd""$$), j=1 i < 10; i++) -"; + """ + class C + { + static void Main(string[] args) + { + string s = "abcdefghij"; + for (int i = s.IndexOf("bcd"$$), j=1 i < 10; i++) + """; var expected = -@" -class C -{ - static void Main(string[] args) - { - string s = ""abcdefghij""; - for (int i = s.IndexOf(""bcd""), j=1;$$ i < 10; i++) -"; + """ + class C + { + static void Main(string[] args) + { + string s = "abcdefghij"; + for (int i = s.IndexOf("bcd"), j=1;$$ i < 10; i++) + """; VerifyTypingSemicolon(code, expected); } @@ -1185,24 +1241,24 @@ static void Main(string[] args) public void ForLoopDeclaration3() { var code = -@" -class C -{ - static void Main(string[] args) - { - string s = ""abcdefghij""; - for (int i = s.IndexOf(""bcd""$$); i < 10; i++) -"; + """ + class C + { + static void Main(string[] args) + { + string s = "abcdefghij"; + for (int i = s.IndexOf("bcd"$$); i < 10; i++) + """; var expected = -@" -class C -{ - static void Main(string[] args) - { - string s = ""abcdefghij""; - for (int i = s.IndexOf(""bcd"");$$ i < 10; i++) -"; + """ + class C + { + static void Main(string[] args) + { + string s = "abcdefghij"; + for (int i = s.IndexOf("bcd");$$ i < 10; i++) + """; VerifyTypingSemicolon(code, expected); } @@ -1211,24 +1267,24 @@ static void Main(string[] args) public void ForLoopDeclaration4() { var code = -@" -class C -{ - static void Main(string[] args) - { - string s = ""abcdefghij""; - for (int i = s.IndexOf(""bcd""$$), j=1; i < 10; i++) -"; + """ + class C + { + static void Main(string[] args) + { + string s = "abcdefghij"; + for (int i = s.IndexOf("bcd"$$), j=1; i < 10; i++) + """; var expected = -@" -class C -{ - static void Main(string[] args) - { - string s = ""abcdefghij""; - for (int i = s.IndexOf(""bcd""), j=1;$$ i < 10; i++) -"; + """ + class C + { + static void Main(string[] args) + { + string s = "abcdefghij"; + for (int i = s.IndexOf("bcd"), j=1;$$ i < 10; i++) + """; VerifyTypingSemicolon(code, expected); } @@ -1237,24 +1293,24 @@ static void Main(string[] args) public void ForLoopDeclaration_MissingParen() { var code = -@" -class C -{ - static void Main(string[] args) - { - string s = ""abcdefghij""; - for (int i = s.IndexOf(""bcd""$$ i < 10; i++) -"; + """ + class C + { + static void Main(string[] args) + { + string s = "abcdefghij"; + for (int i = s.IndexOf("bcd"$$ i < 10; i++) + """; var expected = -@" -class C -{ - static void Main(string[] args) - { - string s = ""abcdefghij""; - for (int i = s.IndexOf(""bcd"";$$ i < 10; i++) -"; + """ + class C + { + static void Main(string[] args) + { + string s = "abcdefghij"; + for (int i = s.IndexOf("bcd";$$ i < 10; i++) + """; VerifyTypingSemicolon(code, expected); } @@ -1263,26 +1319,26 @@ static void Main(string[] args) public void ForLoopInitializers() { var code = -@" -class C -{ - static void Main(string[] args) - { - string s = ""abcdefghij""; - int i; - for (i = s.IndexOf(""bcd""$$) i < 10; i++) -"; + """ + class C + { + static void Main(string[] args) + { + string s = "abcdefghij"; + int i; + for (i = s.IndexOf("bcd"$$) i < 10; i++) + """; var expected = -@" -class C -{ - static void Main(string[] args) - { - string s = ""abcdefghij""; - int i; - for (i = s.IndexOf(""bcd"");$$ i < 10; i++) -"; + """ + class C + { + static void Main(string[] args) + { + string s = "abcdefghij"; + int i; + for (i = s.IndexOf("bcd");$$ i < 10; i++) + """; VerifyTypingSemicolon(code, expected); } @@ -1291,28 +1347,28 @@ static void Main(string[] args) public void ForLoopInitializers2() { var code = -@" -class C -{ - static void Main(string[] args) - { - string s = ""abcdefghij""; - int i; - int j; - for (i = s.IndexOf(""bcd""$$), j=1 i < 10; i++) -"; + """ + class C + { + static void Main(string[] args) + { + string s = "abcdefghij"; + int i; + int j; + for (i = s.IndexOf("bcd"$$), j=1 i < 10; i++) + """; var expected = -@" -class C -{ - static void Main(string[] args) - { - string s = ""abcdefghij""; - int i; - int j; - for (i = s.IndexOf(""bcd""), j=1;$$ i < 10; i++) -"; + """ + class C + { + static void Main(string[] args) + { + string s = "abcdefghij"; + int i; + int j; + for (i = s.IndexOf("bcd"), j=1;$$ i < 10; i++) + """; VerifyTypingSemicolon(code, expected); } @@ -1321,26 +1377,26 @@ static void Main(string[] args) public void ForLoopInitializers3() { var code = -@" -class C -{ - static void Main(string[] args) - { - string s = ""abcdefghij""; - int i; - for (i = s.IndexOf(""bcd""$$); i < 10; i++) -"; + """ + class C + { + static void Main(string[] args) + { + string s = "abcdefghij"; + int i; + for (i = s.IndexOf("bcd"$$); i < 10; i++) + """; var expected = -@" -class C -{ - static void Main(string[] args) - { - string s = ""abcdefghij""; - int i; - for (i = s.IndexOf(""bcd"");$$ i < 10; i++) -"; + """ + class C + { + static void Main(string[] args) + { + string s = "abcdefghij"; + int i; + for (i = s.IndexOf("bcd");$$ i < 10; i++) + """; VerifyTypingSemicolon(code, expected); } @@ -1349,28 +1405,28 @@ static void Main(string[] args) public void ForLoopInitializers4() { var code = -@" -class C -{ - static void Main(string[] args) - { - string s = ""abcdefghij""; - int i; - int j; - for (i = s.IndexOf(""bcd""$$), j=1; i < 10; i++) -"; + """ + class C + { + static void Main(string[] args) + { + string s = "abcdefghij"; + int i; + int j; + for (i = s.IndexOf("bcd"$$), j=1; i < 10; i++) + """; var expected = -@" -class C -{ - static void Main(string[] args) - { - string s = ""abcdefghij""; - int i; - int j; - for (i = s.IndexOf(""bcd""), j=1;$$ i < 10; i++) -"; + """ + class C + { + static void Main(string[] args) + { + string s = "abcdefghij"; + int i; + int j; + for (i = s.IndexOf("bcd"), j=1;$$ i < 10; i++) + """; VerifyTypingSemicolon(code, expected); } @@ -1378,26 +1434,26 @@ static void Main(string[] args) public void ForLoopInitializers_MissingParen() { var code = -@" -class C -{ - static void Main(string[] args) - { - string s = ""abcdefghij""; - int i; - for (i = s.IndexOf(""bcd""$$ i < 10; i++) -"; + """ + class C + { + static void Main(string[] args) + { + string s = "abcdefghij"; + int i; + for (i = s.IndexOf("bcd"$$ i < 10; i++) + """; var expected = -@" -class C -{ - static void Main(string[] args) - { - string s = ""abcdefghij""; - int i; - for (i = s.IndexOf(""bcd"";$$ i < 10; i++) -"; + """ + class C + { + static void Main(string[] args) + { + string s = "abcdefghij"; + int i; + for (i = s.IndexOf("bcd";$$ i < 10; i++) + """; VerifyTypingSemicolon(code, expected); } @@ -1406,24 +1462,24 @@ static void Main(string[] args) public void ForLoopCondition() { var code = -@" -class C -{ - static void Main(string[] args) - { - string s = ""abcdefghij""; - for (int i = s.IndexOf(""bcd""); i < s.IndexOf(""x""$$) i++) -"; + """ + class C + { + static void Main(string[] args) + { + string s = "abcdefghij"; + for (int i = s.IndexOf("bcd"); i < s.IndexOf("x"$$) i++) + """; var expected = -@" -class C -{ - static void Main(string[] args) - { - string s = ""abcdefghij""; - for (int i = s.IndexOf(""bcd""); i < s.IndexOf(""x"");$$ i++) -"; + """ + class C + { + static void Main(string[] args) + { + string s = "abcdefghij"; + for (int i = s.IndexOf("bcd"); i < s.IndexOf("x");$$ i++) + """; VerifyTypingSemicolon(code, expected); } @@ -1432,16 +1488,16 @@ static void Main(string[] args) public void ForLoopConditionIsNull() { var code = -@" -class C -{ - static void Main(string[] args) - { - for (int i = 0; $$ ; i++) - { - Console.WriteLine(""test""); - } -"; + """ + class C + { + static void Main(string[] args) + { + for (int i = 0; $$ ; i++) + { + Console.WriteLine("test"); + } + """; VerifyNoSpecialSemicolonHandling(code); } @@ -1450,27 +1506,27 @@ static void Main(string[] args) public void ForLoopConditionIsNull2() { var code = -@" -class C -{ - static void Main(string[] args) - { - for (int i = Math.Min(3,4$$); ; i++) - { - Console.WriteLine(""test""); - } -"; + """ + class C + { + static void Main(string[] args) + { + for (int i = Math.Min(3,4$$); ; i++) + { + Console.WriteLine("test"); + } + """; var expected = -@" -class C -{ - static void Main(string[] args) - { - for (int i = Math.Min(3,4);$$ ; i++) - { - Console.WriteLine(""test""); - } -"; + """ + class C + { + static void Main(string[] args) + { + for (int i = Math.Min(3,4);$$ ; i++) + { + Console.WriteLine("test"); + } + """; VerifyTypingSemicolon(code, expected); } @@ -1478,24 +1534,24 @@ static void Main(string[] args) public void ForLoopIncrement() { var code = -@" -class C -{ - static void Main(string[] args) - { - string s = ""abcdefghij""; - for (int i = s.IndexOf(""bcd""); i < s.IndexOf(""x""); i = i.IndexOf(""x""$$)) -"; + """ + class C + { + static void Main(string[] args) + { + string s = "abcdefghij"; + for (int i = s.IndexOf("bcd"); i < s.IndexOf("x"); i = i.IndexOf("x"$$)) + """; var expected = -@" -class C -{ - static void Main(string[] args) - { - string s = ""abcdefghij""; - for (int i = s.IndexOf(""bcd""); i < s.IndexOf(""x""); i = i.IndexOf(""x"";$$)) -"; + """ + class C + { + static void Main(string[] args) + { + string s = "abcdefghij"; + for (int i = s.IndexOf("bcd"); i < s.IndexOf("x"); i = i.IndexOf("x";$$)) + """; VerifyTypingSemicolon(code, expected); } @@ -1504,52 +1560,52 @@ static void Main(string[] args) public void ForLoopBody() { var code = -@" -class C -{ - static void Main(string[] args) - { - string s = ""abcdefghij""; - for (int i = s.IndexOf(""bcd""); i < 10; i++) - { - i.ToString($$) - } -"; + """ + class C + { + static void Main(string[] args) + { + string s = "abcdefghij"; + for (int i = s.IndexOf("bcd"); i < 10; i++) + { + i.ToString($$) + } + """; var expected = -@" -class C -{ - static void Main(string[] args) - { - string s = ""abcdefghij""; - for (int i = s.IndexOf(""bcd""); i < 10; i++) - { - i.ToString();$$ - } -"; - - VerifyTypingSemicolon(code, expected); - } + """ + class C + { + static void Main(string[] args) + { + string s = "abcdefghij"; + for (int i = s.IndexOf("bcd"); i < 10; i++) + { + i.ToString();$$ + } + """; + + VerifyTypingSemicolon(code, expected); + } [WpfFact] public void ForLoopObjectInitializer_MissingParen() { var code = -@" -class C -{ - static void Main(string[] args) - { - for (Goo f = new Goo { i = 0, s = ""abc""$$ } - } -} -public class Goo -{ - public int i; - public string s; -} -"; + """ + class C + { + static void Main(string[] args) + { + for (Goo f = new Goo { i = 0, s = "abc"$$ } + } + } + public class Goo + { + public int i; + public string s; + } + """; VerifyNoSpecialSemicolonHandling(code); } @@ -1558,35 +1614,35 @@ public class Goo public void ForLoopObjectInitializer() { var code = -@" -class C -{ - static void Main(string[] args) - { - for (Goo f = new Goo { i = 0, s = ""abc""$$ } ) - } -} -public class Goo -{ - public int i; - public string s; -} -"; + """ + class C + { + static void Main(string[] args) + { + for (Goo f = new Goo { i = 0, s = "abc"$$ } ) + } + } + public class Goo + { + public int i; + public string s; + } + """; var expected = -@" -class C -{ - static void Main(string[] args) - { - for (Goo f = new Goo { i = 0, s = ""abc"" };$$ ) - } -} -public class Goo -{ - public int i; - public string s; -} -"; + """ + class C + { + static void Main(string[] args) + { + for (Goo f = new Goo { i = 0, s = "abc" };$$ ) + } + } + public class Goo + { + public int i; + public string s; + } + """; VerifyTypingSemicolon(code, expected); } @@ -1595,20 +1651,20 @@ public class Goo public void ForLoopObjectInitializer_MissingBrace() { var code = -@" -class C -{ - static void Main(string[] args) - { - for (Goo f = new Goo { i = 0, s = ""abc""$$ - } -} -public class Goo -{ - public int i; - public string s; -} -"; + """ + class C + { + static void Main(string[] args) + { + for (Goo f = new Goo { i = 0, s = "abc"$$ + } + } + public class Goo + { + public int i; + public string s; + } + """; VerifyNoSpecialSemicolonHandling(code); } @@ -1621,29 +1677,31 @@ public class Goo public void Indexer() { var code = -@" -class SampleCollection -{ - private T[] arr = new T[100]; - private int i; - public int Property - { - get { return arr[i$$] } - set { arr[i] = value; } - } -}"; + """ + class SampleCollection + { + private T[] arr = new T[100]; + private int i; + public int Property + { + get { return arr[i$$] } + set { arr[i] = value; } + } + } + """; var expected = -@" -class SampleCollection -{ - private T[] arr = new T[100]; - private int i; - public int Property - { - get { return arr[i];$$ } - set { arr[i] = value; } - } -}"; + """ + class SampleCollection + { + private T[] arr = new T[100]; + private int i; + public int Property + { + get { return arr[i];$$ } + set { arr[i] = value; } + } + } + """; VerifyTypingSemicolon(code, expected); } @@ -1652,29 +1710,29 @@ public int Property public void Indexer2() { var code = -@" -class test -{ - int[] array = { 1, 2, 3 }; + """ + class test + { + int[] array = { 1, 2, 3 }; - void M() - { - var i = array[1$$] - } -} -"; + void M() + { + var i = array[1$$] + } + } + """; var expected = -@" -class test -{ - int[] array = { 1, 2, 3 }; + """ + class test + { + int[] array = { 1, 2, 3 }; - void M() - { - var i = array[1];$$ - } -} -"; + void M() + { + var i = array[1];$$ + } + } + """; VerifyTypingSemicolon(code, expected); } @@ -1683,29 +1741,29 @@ void M() public void Indexer3() { var code = -@" -class C -{ - int[] array = { 1, 2, 3 }; + """ + class C + { + int[] array = { 1, 2, 3 }; - void M() - { - var i = array[Math.Min(2,3$$)] - } -} -"; + void M() + { + var i = array[Math.Min(2,3$$)] + } + } + """; var expected = -@" -class C -{ - int[] array = { 1, 2, 3 }; + """ + class C + { + int[] array = { 1, 2, 3 }; - void M() - { - var i = array[Math.Min(2,3)];$$ - } -} -"; + void M() + { + var i = array[Math.Min(2,3)];$$ + } + } + """; VerifyTypingSemicolon(code, expected); } @@ -1714,29 +1772,29 @@ void M() public void Indexer4() { var code = -@" -class C -{ - int[] array = { 1, 2, 3 }; + """ + class C + { + int[] array = { 1, 2, 3 }; - void M() - { - var i = array[Math.Min(2,3$$) - } -} -"; + void M() + { + var i = array[Math.Min(2,3$$) + } + } + """; var expected = -@" -class C -{ - int[] array = { 1, 2, 3 }; + """ + class C + { + int[] array = { 1, 2, 3 }; - void M() - { - var i = array[Math.Min(2,3;$$) - } -} -"; + void M() + { + var i = array[Math.Min(2,3;$$) + } + } + """; VerifyTypingSemicolon(code, expected); } @@ -2265,21 +2323,21 @@ static void Main(string[] args) public void ObjectInitializer() { var code = -@" -class C -{ - static void Main(string[] args) - { - Goo f = new Goo { i = 0, s = ""abc"" }$$ - } -} + """ + class C + { + static void Main(string[] args) + { + Goo f = new Goo { i = 0, s = "abc" }$$ + } + } -public class Goo -{ - public int i; - public string s; -} -"; + public class Goo + { + public int i; + public string s; + } + """; VerifyNoSpecialSemicolonHandling(code); } @@ -2288,37 +2346,37 @@ public class Goo public void ObjectInitializer2() { var code = -@" -class C -{ - static void Main(string[] args) - { - Goo f = new Goo { i = 0, s = ""abc""$$ } - } -} + """ + class C + { + static void Main(string[] args) + { + Goo f = new Goo { i = 0, s = "abc"$$ } + } + } -public class Goo -{ - public int i; - public string s; -} -"; + public class Goo + { + public int i; + public string s; + } + """; var expected = -@" -class C -{ - static void Main(string[] args) - { - Goo f = new Goo { i = 0, s = ""abc"" };$$ - } -} + """ + class C + { + static void Main(string[] args) + { + Goo f = new Goo { i = 0, s = "abc" };$$ + } + } -public class Goo -{ - public int i; - public string s; -} -"; + public class Goo + { + public int i; + public string s; + } + """; VerifyTypingSemicolon(code, expected); } @@ -2327,37 +2385,37 @@ public class Goo public void ObjectInitializer3() { var code = -@" -class C -{ - static void Main(string[] args) - { - Goo f = new Goo { i = 0$$, s = ""abc"" } - } -} + """ + class C + { + static void Main(string[] args) + { + Goo f = new Goo { i = 0$$, s = "abc" } + } + } -public class Goo -{ - public int i; - public string s; -} -"; + public class Goo + { + public int i; + public string s; + } + """; var expected = -@" -class C -{ - static void Main(string[] args) - { - Goo f = new Goo { i = 0, s = ""abc"" };$$ - } -} + """ + class C + { + static void Main(string[] args) + { + Goo f = new Goo { i = 0, s = "abc" };$$ + } + } -public class Goo -{ - public int i; - public string s; -} -"; + public class Goo + { + public int i; + public string s; + } + """; VerifyTypingSemicolon(code, expected); } @@ -2366,37 +2424,37 @@ public class Goo public void ObjectInitializer4() { var code = -@" -class C -{ - static void Main(string[] args) - { - Goo f = new Goo { i =$$ 0, s = ""abc"" } - } -} + """ + class C + { + static void Main(string[] args) + { + Goo f = new Goo { i =$$ 0, s = "abc" } + } + } -public class Goo -{ - public int i; - public string s; -} -"; + public class Goo + { + public int i; + public string s; + } + """; var expected = -@" -class C -{ - static void Main(string[] args) - { - Goo f = new Goo { i = 0, s = ""abc"" };$$ - } -} - -public class Goo -{ - public int i; - public string s; -} -"; + """ + class C + { + static void Main(string[] args) + { + Goo f = new Goo { i = 0, s = "abc" };$$ + } + } + + public class Goo + { + public int i; + public string s; + } + """; VerifyTypingSemicolon(code, expected); } @@ -2405,37 +2463,37 @@ public class Goo public void ObjectInitializer_MissingBrace() { var code = -@" -class C -{ - static void Main(string[] args) - { - Goo f = new Goo { i = 0, s = ""abc""$$ - } -} + """ + class C + { + static void Main(string[] args) + { + Goo f = new Goo { i = 0, s = "abc"$$ + } + } -public class Goo -{ - public int i; - public string s; -} -"; + public class Goo + { + public int i; + public string s; + } + """; var expected = -@" -class C -{ - static void Main(string[] args) - { - Goo f = new Goo { i = 0, s = ""abc"";$$ - } -} + """ + class C + { + static void Main(string[] args) + { + Goo f = new Goo { i = 0, s = "abc";$$ + } + } -public class Goo -{ - public int i; - public string s; -} -"; + public class Goo + { + public int i; + public string s; + } + """; VerifyTypingSemicolon(code, expected); } @@ -2447,31 +2505,33 @@ public class Goo [WpfFact] public void PropertyAccessors1() { - var code = @" -public class ClassC -{ - private int xValue = 7; - public int XValue - { - get - { - return Math.Min(xValue$$, 1) - } - } -}"; + var code = """ + public class ClassC + { + private int xValue = 7; + public int XValue + { + get + { + return Math.Min(xValue$$, 1) + } + } + } + """; - var expected = @" -public class ClassC -{ - private int xValue = 7; - public int XValue - { - get - { - return Math.Min(xValue, 1);$$ - } - } -}"; + var expected = """ + public class ClassC + { + private int xValue = 7; + public int XValue + { + get + { + return Math.Min(xValue, 1);$$ + } + } + } + """; VerifyTypingSemicolon(code, expected); } @@ -2479,31 +2539,33 @@ public int XValue [WpfFact] public void PropertyAccessors2() { - var code = @" -public class ClassC -{ - private int xValue = 7; - public int XValue - { - get - { - return Math.Min(Math.Max(xValue,0$$), 1) - } - } -}"; + var code = """ + public class ClassC + { + private int xValue = 7; + public int XValue + { + get + { + return Math.Min(Math.Max(xValue,0$$), 1) + } + } + } + """; - var expected = @" -public class ClassC -{ - private int xValue = 7; - public int XValue - { - get - { - return Math.Min(Math.Max(xValue,0), 1);$$ - } - } -}"; + var expected = """ + public class ClassC + { + private int xValue = 7; + public int XValue + { + get + { + return Math.Min(Math.Max(xValue,0), 1);$$ + } + } + } + """; VerifyTypingSemicolon(code, expected); } @@ -2511,20 +2573,21 @@ public int XValue [WpfFact] public void PropertyAccessors3() { - var code = @" -public class Person -{ - private string firstName; - private string lastName; - - public Person(string first, string last) - { - firstName = first; - lastName = last; - } - - public string Name => $""{firstName} {lastName}""$$ -}"; + var code = """ + public class Person + { + private string firstName; + private string lastName; + + public Person(string first, string last) + { + firstName = first; + lastName = last; + } + + public string Name => $"{firstName} {lastName}"$$ + } + """; VerifyNoSpecialSemicolonHandling(code); } @@ -2532,16 +2595,17 @@ public Person(string first, string last) [WpfFact] public void PropertyAccessors4() { - var code = @" -public class SaleItem -{ - string name; - public string Name - { - get => name; - set => name = value$$ - } -}"; + var code = """ + public class SaleItem + { + string name; + public string Name + { + get => name; + set => name = value$$ + } + } + """; VerifyNoSpecialSemicolonHandling(code); } @@ -2549,16 +2613,17 @@ public string Name [WpfFact] public void PropertyAccessors5() { - var code = @" -public class SaleItem -{ - string name; - public string Name - { - get => name$$ - set => name = value; - } -}"; + var code = """ + public class SaleItem + { + string name; + public string Name + { + get => name$$ + set => name = value; + } + } + """; VerifyNoSpecialSemicolonHandling(code); } @@ -2566,26 +2631,28 @@ public string Name [WpfFact] public void PropertyAccessors6() { - var code = @" -public class SaleItem -{ - string name; - public string Name - { - get => name.ToUpper($$) - set => name = value; - } -}"; - var expected = @" -public class SaleItem -{ - string name; - public string Name - { - get => name.ToUpper();$$ - set => name = value; - } -}"; + var code = """ + public class SaleItem + { + string name; + public string Name + { + get => name.ToUpper($$) + set => name = value; + } + } + """; + var expected = """ + public class SaleItem + { + string name; + public string Name + { + get => name.ToUpper();$$ + set => name = value; + } + } + """; VerifyTypingSemicolon(code, expected); } @@ -2593,12 +2660,13 @@ public string Name [WpfFact] public void PropertyAccessors7() { - var code = @" -public class SaleItem -{ - public string Name - { get$$ set; } -}"; + var code = """ + public class SaleItem + { + public string Name + { get$$ set; } + } + """; VerifyNoSpecialSemicolonHandling(code); } @@ -2606,17 +2674,19 @@ public string Name [WpfFact] public void PropertyInitializer1() { - var code = @" -public class C -{ - public static C MyProp { get; } = new C($$) -}"; + var code = """ + public class C + { + public static C MyProp { get; } = new C($$) + } + """; - var expected = @" -public class C -{ - public static C MyProp { get; } = new C();$$ -}"; + var expected = """ + public class C + { + public static C MyProp { get; } = new C();$$ + } + """; VerifyTypingSemicolon(code, expected); } @@ -2624,18 +2694,19 @@ public class C [WpfFact] public void PropertyAttribute1() { - var code = @" -public class C -{ - public int P - { - [My(typeof(C$$))] - get - { - return 0; - } - } -}"; + var code = """ + public class C + { + public int P + { + [My(typeof(C$$))] + get + { + return 0; + } + } + } + """; VerifyNoSpecialSemicolonHandling(code); } @@ -2647,23 +2718,25 @@ public int P [WpfFact] public void ParenthesizedExpression_Assignment1() { - var code = @" -public class Class1 -{ - void M() - { - int i = (6*5$$) - } -}"; + var code = """ + public class Class1 + { + void M() + { + int i = (6*5$$) + } + } + """; - var expected = @" -public class Class1 -{ - void M() - { - int i = (6*5);$$ - } -}"; + var expected = """ + public class Class1 + { + void M() + { + int i = (6*5);$$ + } + } + """; VerifyTypingSemicolon(code, expected); } @@ -2671,23 +2744,25 @@ void M() [WpfFact] public void ParenthesizedExpression_Assignment2() { - var code = @" -public class Class1 -{ - void M() - { - int i = (6*Math.Min(4,5$$)) - } -}"; + var code = """ + public class Class1 + { + void M() + { + int i = (6*Math.Min(4,5$$)) + } + } + """; - var expected = @" -public class Class1 -{ - void M() - { - int i = (6*Math.Min(4,5));$$ - } -}"; + var expected = """ + public class Class1 + { + void M() + { + int i = (6*Math.Min(4,5));$$ + } + } + """; VerifyTypingSemicolon(code, expected); } @@ -2695,25 +2770,27 @@ void M() [WpfFact] public void ParenthesizedExpression_Assignment3() { - var code = @" -public class Class1 -{ - void M() - { - int[] array = { 2, 3, 4 }; - int i = (6*array[2$$]) - } -}"; + var code = """ + public class Class1 + { + void M() + { + int[] array = { 2, 3, 4 }; + int i = (6*array[2$$]) + } + } + """; - var expected = @" -public class Class1 -{ - void M() - { - int[] array = { 2, 3, 4 }; - int i = (6*array[2]);$$ - } -}"; + var expected = """ + public class Class1 + { + void M() + { + int[] array = { 2, 3, 4 }; + int i = (6*array[2]);$$ + } + } + """; VerifyTypingSemicolon(code, expected); } @@ -2721,29 +2798,31 @@ void M() [WpfFact] public void ParenthesizedExpression_ForLoop() { - var code = @" -public class Class1 -{ - void M() - { - for (int i = 0; i < 10; i++) - { - int j = (i+i$$) - } - } -}"; + var code = """ + public class Class1 + { + void M() + { + for (int i = 0; i < 10; i++) + { + int j = (i+i$$) + } + } + } + """; - var expected = @" -public class Class1 -{ - void M() - { - for (int i = 0; i < 10; i++) - { - int j = (i+i);$$ - } - } -}"; + var expected = """ + public class Class1 + { + void M() + { + for (int i = 0; i < 10; i++) + { + int j = (i+i);$$ + } + } + } + """; VerifyTypingSemicolon(code, expected); } @@ -2751,29 +2830,31 @@ void M() [WpfFact] public void ParenthesizedExpression_ForLoop2() { - var code = @" -public class Class1 -{ - void M() - { - for (int i = ((3+2)*4$$); i < 10; i++) - { - int j = (i+i); - } - } -}"; + var code = """ + public class Class1 + { + void M() + { + for (int i = ((3+2)*4$$); i < 10; i++) + { + int j = (i+i); + } + } + } + """; - var expected = @" -public class Class1 -{ - void M() - { - for (int i = ((3+2)*4);$$ i < 10; i++) - { - int j = (i+i); - } - } -}"; + var expected = """ + public class Class1 + { + void M() + { + for (int i = ((3+2)*4);$$ i < 10; i++) + { + int j = (i+i); + } + } + } + """; VerifyTypingSemicolon(code, expected); } @@ -2781,29 +2862,31 @@ void M() [WpfFact] public void ParenthesizedExpression_ForLoop3() { - var code = @" -public class Class1 -{ - void M() - { - for (int i = 0; i < ((3+2)*4$$); i++) - { - int j = (i+i); - } - } -}"; + var code = """ + public class Class1 + { + void M() + { + for (int i = 0; i < ((3+2)*4$$); i++) + { + int j = (i+i); + } + } + } + """; - var expected = @" -public class Class1 -{ - void M() - { - for (int i = 0; i < ((3+2)*4);$$ i++) - { - int j = (i+i); - } - } -}"; + var expected = """ + public class Class1 + { + void M() + { + for (int i = 0; i < ((3+2)*4);$$ i++) + { + int j = (i+i); + } + } + } + """; VerifyTypingSemicolon(code, expected); } @@ -2811,24 +2894,24 @@ void M() [WpfFact] public void ParenthesizedExpression_ForEach() { - var code = @" - public class Class1 - { - static void Main(string[] args) - { - foreach (int i in M((2*3)+4$$)) + var code = """ + public class Class1 { + static void Main(string[] args) + { + foreach (int i in M((2*3)+4$$)) + { - } - } + } + } - private static int[] M(int i) - { - int[] value = { 2, 3, 4 }; - return value; - } - } -"; + private static int[] M(int i) + { + int[] value = { 2, 3, 4 }; + return value; + } + } + """; VerifyNoSpecialSemicolonHandling(code); } @@ -2836,38 +2919,38 @@ private static int[] M(int i) public void ParenthesizedExpression_GoTo2() { var code = -@" -static void Main() -{ - int n = 1; - switch (n) - { - case 1: - goto case (2+1$$) - case 3: - break - default: - break; - } -} -"; + """ + static void Main() + { + int n = 1; + switch (n) + { + case 1: + goto case (2+1$$) + case 3: + break + default: + break; + } + } + """; var expected = -@" -static void Main() -{ - int n = 1; - switch (n) - { - case 1: - goto case (2+1);$$ - case 3: - break - default: - break; - } -} -"; + """ + static void Main() + { + int n = 1; + switch (n) + { + case 1: + goto case (2+1);$$ + case 3: + break + default: + break; + } + } + """; VerifyTypingSemicolon(code, expected); } @@ -2875,22 +2958,22 @@ static void Main() public void ParenthesizedExpression_Switch() { var code = -@" -class Program -{ - static void Main() - { - int i = 3; - switch (i$$) - { - case 1: - case 2: - case 3: - break; - } - } -} -"; + """ + class Program + { + static void Main() + { + int i = 3; + switch (i$$) + { + case 1: + case 2: + case 3: + break; + } + } + } + """; VerifyNoSpecialSemicolonHandling(code); } @@ -2899,22 +2982,22 @@ static void Main() public void ParenthesizedExpression_Switch2() { var code = -@" -class Program -{ - static void Main() - { - int i = 3; - switch (4*(i+2$$)) - { - case 1: - case 2: - case 3: - break; - } - } -} -"; + """ + class Program + { + static void Main() + { + int i = 3; + switch (4*(i+2$$)) + { + case 1: + case 2: + case 3: + break; + } + } + } + """; VerifyNoSpecialSemicolonHandling(code); } @@ -2923,41 +3006,41 @@ static void Main() public void ParenthesizedExpression_Switch3() { var code = -@" -class Program -{ - static void Main() - { - int i = 3; - switch (i) - { - case 1: - Console.WriteLine(4*(i+2$$)) - case 2: - case 3: - break; - } - } -} -"; + """ + class Program + { + static void Main() + { + int i = 3; + switch (i) + { + case 1: + Console.WriteLine(4*(i+2$$)) + case 2: + case 3: + break; + } + } + } + """; var expected = -@" -class Program -{ - static void Main() - { - int i = 3; - switch (i) - { - case 1: - Console.WriteLine(4*(i+2));$$ - case 2: - case 3: - break; - } - } -} -"; + """ + class Program + { + static void Main() + { + int i = 3; + switch (i) + { + case 1: + Console.WriteLine(4*(i+2));$$ + case 2: + case 3: + break; + } + } + } + """; VerifyTypingSemicolon(code, expected); } @@ -2966,20 +3049,20 @@ static void Main() public void ParenthesizedExpression_While() { var code = -@" -using System; -class Program -{ - static void Main() - { - int i = 3; - while (i<4$$) - { - Console.WriteLine(i); - } - } -} -"; + """ + using System; + class Program + { + static void Main() + { + int i = 3; + while (i<4$$) + { + Console.WriteLine(i); + } + } + } + """; VerifyNoSpecialSemicolonHandling(code); } @@ -2988,20 +3071,20 @@ static void Main() public void ParenthesizedExpression_While2() { var code = -@" -using System; -class Program -{ - static void Main() - { - int i = 3; - while (i(); - Console.Write($""B.Length={attr.B.Length}, B[0]={attr.B[0]}, B[1]={attr.B[1]}""); - } -}"; + [Mark(a: true, b: new object[$$] { "Hello", "World" })] + static class Program + { + public static void Main() + { + var attr = typeof(Program).GetCustomAttribute(); + Console.Write($"B.Length={attr.B.Length}, B[0]={attr.B[0]}, B[1]={attr.B[1]}"); + } + } + """; VerifyNoSpecialSemicolonHandling(code); } [WpfFact] public void DoNotComplete_Attribute5() { - var code = @" -using System; -using System.Reflection; + var code = """ + using System; + using System.Reflection; -sealed class MarkAttribute : Attribute -{ - public MarkAttribute(bool a, params object[] b) - { - B = b; - } - public object[] B { get; } -} + sealed class MarkAttribute : Attribute + { + public MarkAttribute(bool a, params object[] b) + { + B = b; + } + public object[] B { get; } + } -[Mark(a: true, b: new object[] { ""Hello"", ""World""$$ })] -static class Program -{ - public static void Main() - { - var attr = typeof(Program).GetCustomAttribute(); - Console.Write($""B.Length={attr.B.Length}, B[0]={attr.B[0]}, B[1]={attr.B[1]}""); - } -}"; + [Mark(a: true, b: new object[] { "Hello", "World"$$ })] + static class Program + { + public static void Main() + { + var attr = typeof(Program).GetCustomAttribute(); + Console.Write($"B.Length={attr.B.Length}, B[0]={attr.B[0]}, B[1]={attr.B[1]}"); + } + } + """; VerifyNoSpecialSemicolonHandling(code); } [WpfFact] public void DoNotComplete_Attribute6() { - var code = @" -using System; + var code = """ + using System; -class Program -{ - static void Main() - { - // Warning: 'Program.Test()' is obsolete - Test(); - } + class Program + { + static void Main() + { + // Warning: 'Program.Test()' is obsolete + Test(); + } - [Obsolete$$ - static void Test() - { - } -}"; + [Obsolete$$ + static void Test() + { + } + } + """; VerifyNoSpecialSemicolonHandling(code); } [WpfFact] public void DoNotComplete_Using() { - var code = @" -using System.Linq$$ -"; + var code = """ + using System.Linq$$ + + """; VerifyNoSpecialSemicolonHandling(code); } [WpfFact] public void DoNotComplete_Using2() { - var code = @" -using System.Linq$$; -"; + var code = """ + using System.Linq$$; + """; VerifyNoSpecialSemicolonHandling(code); } [WpfFact] public void DoNotComplete_Using3() { - var code = @" -using System.$$Linq -"; + var code = """ + using System.$$Linq + """; VerifyNoSpecialSemicolonHandling(code); } [WpfFact, WorkItem("https://github.com/dotnet/roslyn/issues/33851")] public void AtEndOfLineOutsideParens() { - var code = @" -public class Class1 -{ - void M() - { - string s = ""Test""; - string t = s.Replace(""T"", ""t"")$$ - .Trim(); + var code = """ + public class Class1 + { + void M() + { + string s = "Test"; + string t = s.Replace("T", "t")$$ + .Trim(); - } -} -"; + } + } + """; VerifyNoSpecialSemicolonHandling(code); } [WpfFact, WorkItem("https://github.com/dotnet/roslyn/issues/33851")] public void OutsideParensBeforeSpaceDot() { - var code = @" -public class Class1 -{ - void M() - { - string s = ""Test""; - string t = s.Replace(""T"", ""t"")$$ .Trim(); + var code = """ + public class Class1 + { + void M() + { + string s = "Test"; + string t = s.Replace("T", "t")$$ .Trim(); - } -} -"; + } + } + """; VerifyNoSpecialSemicolonHandling(code); } [WpfFact, WorkItem("https://github.com/dotnet/roslyn/issues/34666")] public void BeforeAttribute() { - var code = @" -public class C -{ -private const string s = - @""test""$$ - - [Fact] - public void M() + var code = """ + public class C { - } - }"; + private const string s = + @"test"$$ + + [Fact] + public void M() + { + } + } + """; VerifyNoSpecialSemicolonHandling(code); } [WpfFact, WorkItem("https://github.com/dotnet/roslyn/issues/34666")] public void ElementBindingExpression() { - var code = @" -class C -{ - void M() - { - var data = new int[3]; - var value = data?[0$$] - } -}"; - var expected = @" -class C -{ - void M() - { - var data = new int[3]; - var value = data?[0];$$ - } -}"; + var code = """ + class C + { + void M() + { + var data = new int[3]; + var value = data?[0$$] + } + } + """; + var expected = """ + class C + { + void M() + { + var data = new int[3]; + var value = data?[0];$$ + } + } + """; VerifyTypingSemicolon(code, expected); } [WpfFact, WorkItem("https://github.com/dotnet/roslyn/issues/34666")] public void BeforeElementBindingExpression() { - var code = @" -class C -{ - void M() - { - var data = new int[3]; - var value = data?$$[0] - } -}"; + var code = """ + class C + { + void M() + { + var data = new int[3]; + var value = data?$$[0] + } + } + """; VerifyNoSpecialSemicolonHandling(code); } [WpfFact, WorkItem("https://github.com/dotnet/roslyn/issues/34666")] public void AfterElementBindingExpression() { - var code = @" -class C -{ - void M() - { - var data = new int[3]; - var value = data?[0]$$ - } -}"; + var code = """ + class C + { + void M() + { + var data = new int[3]; + var value = data?[0]$$ + } + } + """; VerifyNoSpecialSemicolonHandling(code); } @@ -4285,398 +4448,418 @@ void M() [WpfFact, WorkItem("https://github.com/dotnet/roslyn/issues/34983")] public void ImplicitElementAccessSyntax() { - var code = @" -class C -{ - void M() - { - var d = new Dictionary - { - [1$$] = 4, - } - } -}"; - var expected = @" -class C -{ - void M() - { - var d = new Dictionary - { - [1] = 4, - };$$ - } -}"; + var code = """ + class C + { + void M() + { + var d = new Dictionary + { + [1$$] = 4, + } + } + } + """; + var expected = """ + class C + { + void M() + { + var d = new Dictionary + { + [1] = 4, + };$$ + } + } + """; VerifyTypingSemicolon(code, expected); } [WpfFact, WorkItem("https://github.com/dotnet/roslyn/issues/34666")] public void BeforeImplicitElementAccessSyntax() { - var code = @" -class C -{ - void M() - { - var d = new Dictionary - { - $$[1] = 4, - } - } -}"; - var expected = @" -class C -{ - void M() - { - var d = new Dictionary - { - [1] = 4, - };$$ - } -}"; + var code = """ + class C + { + void M() + { + var d = new Dictionary + { + $$[1] = 4, + } + } + } + """; + var expected = """ + class C + { + void M() + { + var d = new Dictionary + { + [1] = 4, + };$$ + } + } + """; VerifyTypingSemicolon(code, expected); } [WpfFact, WorkItem("https://github.com/dotnet/roslyn/issues/34666")] public void AfterImplicitElementAccessSyntax() { - var code = @" -class C -{ - void M() - { - var d = new Dictionary - { - [1]$$ = 4, - } - } -}"; - var expected = @" -class C -{ - void M() - { - var d = new Dictionary - { - [1] = 4, - };$$ - } -}"; + var code = """ + class C + { + void M() + { + var d = new Dictionary + { + [1]$$ = 4, + } + } + } + """; + var expected = """ + class C + { + void M() + { + var d = new Dictionary + { + [1] = 4, + };$$ + } + } + """; VerifyTypingSemicolon(code, expected); } [WpfFact, WorkItem("https://github.com/dotnet/roslyn/issues/34983")] public void AttributeParsedAsElementAccessExpression() { - var code = @" -using System; -internal class TestMethodAttribute : Attribute -{ - readonly int i = Foo(3,4$$) + var code = """ + using System; + internal class TestMethodAttribute : Attribute + { + readonly int i = Foo(3,4$$) - [Test] -}"; - var expected = @" -using System; -internal class TestMethodAttribute : Attribute -{ - readonly int i = Foo(3,4);$$ + [Test] + } + """; + var expected = """ + using System; + internal class TestMethodAttribute : Attribute + { + readonly int i = Foo(3,4);$$ - [Test] -}"; + [Test] + } + """; VerifyTypingSemicolon(code, expected); } [WpfFact, WorkItem("https://github.com/dotnet/roslyn/issues/34983")] public void MemberAccessOffOfMethod() { - var code = @" -class Program -{ - static void Main(string[] args) - { - var s = ""Hello""; - var t = s.ToLower($$).Substring(1); - } -}"; - var expected = @" -class Program -{ - static void Main(string[] args) - { - var s = ""Hello""; - var t = s.ToLower();$$.Substring(1); - } -}"; + var code = """ + class Program + { + static void Main(string[] args) + { + var s = "Hello"; + var t = s.ToLower($$).Substring(1); + } + } + """; + var expected = """ + class Program + { + static void Main(string[] args) + { + var s = "Hello"; + var t = s.ToLower();$$.Substring(1); + } + } + """; VerifyTypingSemicolon(code, expected); } [WpfFact, WorkItem("https://github.com/dotnet/roslyn/issues/34983")] public void LinqQuery() { - var code = @" -using System.Collections.Generic; -using System.Linq; -class Query -{ - void Main(string[] args) - { - List c1 = new List { 1, 2, 3, 4, 5, 7 }; - List c2 = new List { 10, 30, 40, 50, 60, 70 }; - var c3 = c1.SelectMany(x1 => c2 - .Where(x2 => object.Equals(x1, x2 / 10$$)) - .Select(x2 => x1 + x2)); - } -}"; - var expected = @" -using System.Collections.Generic; -using System.Linq; -class Query -{ - void Main(string[] args) - { - List c1 = new List { 1, 2, 3, 4, 5, 7 }; - List c2 = new List { 10, 30, 40, 50, 60, 70 }; - var c3 = c1.SelectMany(x1 => c2 - .Where(x2 => object.Equals(x1, x2 / 10)) - .Select(x2 => x1 + x2));$$ - } -}"; + var code = """ + using System.Collections.Generic; + using System.Linq; + class Query + { + void Main(string[] args) + { + List c1 = new List { 1, 2, 3, 4, 5, 7 }; + List c2 = new List { 10, 30, 40, 50, 60, 70 }; + var c3 = c1.SelectMany(x1 => c2 + .Where(x2 => object.Equals(x1, x2 / 10$$)) + .Select(x2 => x1 + x2)); + } + } + """; + var expected = """ + using System.Collections.Generic; + using System.Linq; + class Query + { + void Main(string[] args) + { + List c1 = new List { 1, 2, 3, 4, 5, 7 }; + List c2 = new List { 10, 30, 40, 50, 60, 70 }; + var c3 = c1.SelectMany(x1 => c2 + .Where(x2 => object.Equals(x1, x2 / 10)) + .Select(x2 => x1 + x2));$$ + } + } + """; VerifyTypingSemicolon(code, expected); } [WpfFact, WorkItem("https://github.com/dotnet/roslyn/issues/34983")] public void LinqQuery2() { - var code = @" -using System.Collections.Generic; -using System.Linq; -class Query -{ - void Main(string[] args) - { - List c = new List { 1, 2, 3, 4, 5, 7 }; - var d = c - .Where(x => x == 4$$) - .Select(x => x + x); - } -}"; - var expected = @" -using System.Collections.Generic; -using System.Linq; -class Query -{ - void Main(string[] args) - { - List c = new List { 1, 2, 3, 4, 5, 7 }; - var d = c - .Where(x => x == 4);$$ - .Select(x => x + x); - } -}"; + var code = """ + using System.Collections.Generic; + using System.Linq; + class Query + { + void Main(string[] args) + { + List c = new List { 1, 2, 3, 4, 5, 7 }; + var d = c + .Where(x => x == 4$$) + .Select(x => x + x); + } + } + """; + var expected = """ + using System.Collections.Generic; + using System.Linq; + class Query + { + void Main(string[] args) + { + List c = new List { 1, 2, 3, 4, 5, 7 }; + var d = c + .Where(x => x == 4);$$ + .Select(x => x + x); + } + } + """; VerifyTypingSemicolon(code, expected); } [WpfFact, WorkItem("https://github.com/dotnet/roslyn/issues/34983")] public void BinaryExpression() { - var code = @" -class D -{ - void M() - { - int i = Foo(4$$) + 1 - } + var code = """ + class D + { + void M() + { + int i = Foo(4$$) + 1 + } - private int Foo(int v) - { - return v; - } -}"; - var expected = @" -class D -{ - void M() - { - int i = Foo(4);$$ + 1 - } + private int Foo(int v) + { + return v; + } + } + """; + var expected = """ + class D + { + void M() + { + int i = Foo(4);$$ + 1 + } - private int Foo(int v) - { - return v; - } -}"; + private int Foo(int v) + { + return v; + } + } + """; VerifyTypingSemicolon(code, expected); } [WpfFact, WorkItem("https://github.com/dotnet/roslyn/issues/34983")] public void BinaryExpression2() { - var code = @" -class D -{ - void M() - { - int i = Foo(Foo(4$$) + 1) + 2 - } + var code = """ + class D + { + void M() + { + int i = Foo(Foo(4$$) + 1) + 2 + } - private int Foo(int v) - { - return v; - } -}"; - var expected = @" -class D -{ - void M() - { - int i = Foo(Foo(4) + 1);$$ + 2 - } + private int Foo(int v) + { + return v; + } + } + """; + var expected = """ + class D + { + void M() + { + int i = Foo(Foo(4) + 1);$$ + 2 + } - private int Foo(int v) - { - return v; - } -}"; + private int Foo(int v) + { + return v; + } + } + """; VerifyTypingSemicolon(code, expected); } [WpfFact, WorkItem("https://github.com/dotnet/roslyn/issues/34983")] public void AsOperator() { - var code = @" -class D -{ - void M() - { - string i = Foo(4$$) as string - } - - object Foo(int v) - { - return v.ToString(); - } -}"; - var expected = @" -class D -{ - void M() - { - string i = Foo(4);$$ as string - } + var code = """ + class D + { + void M() + { + string i = Foo(4$$) as string + } - object Foo(int v) - { - return v.ToString(); - } -}"; + object Foo(int v) + { + return v.ToString(); + } + } + """; + var expected = """ + class D + { + void M() + { + string i = Foo(4);$$ as string + } + + object Foo(int v) + { + return v.ToString(); + } + } + """; VerifyTypingSemicolon(code, expected); } [WpfFact, WorkItem("https://github.com/dotnet/roslyn/issues/34983")] public void TernaryOperator() { - var code = @" -class Query -{ - void Main(string[] args) - { - int j = 0; - int k = 0; - int i = j < k ? Foo(j$$) : Foo(3) - } + var code = """ + class Query + { + void Main(string[] args) + { + int j = 0; + int k = 0; + int i = j < k ? Foo(j$$) : Foo(3) + } - private int Foo(int j) - { - return j; - } -"; - var expected = @" -class Query -{ - void Main(string[] args) - { - int j = 0; - int k = 0; - int i = j < k ? Foo(j);$$ : Foo(3) - } + private int Foo(int j) + { + return j; + } + """; + var expected = """ + class Query + { + void Main(string[] args) + { + int j = 0; + int k = 0; + int i = j < k ? Foo(j);$$ : Foo(3) + } - private int Foo(int j) - { - return j; - } -"; + private int Foo(int j) + { + return j; + } + """; VerifyTypingSemicolon(code, expected); } [WpfFact, WorkItem("https://github.com/dotnet/roslyn/issues/34983")] public void SemicolonInCharacterLiteral() { - var code = @" -class D -{ - void Main(string[]args) - { - M('$$') - } + var code = """ + class D + { + void Main(string[]args) + { + M('$$') + } - void M(char c) - { - } -} -"; - var expected = @" -class D -{ - void Main(string[]args) - { - M(';$$') - } + void M(char c) + { + } + } + """; + var expected = """ + class D + { + void Main(string[]args) + { + M(';$$') + } - void M(char c) - { - } -} -"; + void M(char c) + { + } + } + """; VerifyTypingSemicolon(code, expected); } [WpfFact, WorkItem("https://github.com/dotnet/roslyn/issues/35260")] public void IncompleteLambda() { - var code = @" -using System; + var code = """ + using System; -class C -{ - public void Test() - { - C c = new C(); - c.M(z => - { - return 0$$) - } + class C + { + public void Test() + { + C c = new C(); + c.M(z => + { + return 0$$) + } - private void M(Func p) { } -} -"; - var expected = @" -using System; + private void M(Func p) { } + } + """; + var expected = """ + using System; -class C -{ - public void Test() - { - C c = new C(); - c.M(z => - { - return 0;$$) - } + class C + { + public void Test() + { + C c = new C(); + c.M(z => + { + return 0;$$) + } - private void M(Func p) { } -} -"; + private void M(Func p) { } + } + """; VerifyTypingSemicolon(code, expected); } @@ -4694,128 +4877,140 @@ public void ArgumentList_MultipleCharsSelected() [WpfFact, WorkItem("https://github.com/dotnet/roslyn/issues/34051")] public void ParameterList_DelegateDeclaration() { - var code = @" -class C -{ - delegate void Del(string str$$) -}"; - var expected = @" -class C -{ - delegate void Del(string str);$$ -}"; + var code = """ + class C + { + delegate void Del(string str$$) + } + """; + var expected = """ + class C + { + delegate void Del(string str);$$ + } + """; VerifyTypingSemicolon(code, expected); } [WpfFact, WorkItem("https://github.com/dotnet/roslyn/issues/34051")] public void ParameterList_DelegateDeclaration2() { - var code = @" -class C -{ - public delegate TResult Blah(T arg) -}"; + var code = """ + class C + { + public delegate TResult Blah(T arg) + } + """; VerifyNoSpecialSemicolonHandling(code); } [WpfFact, WorkItem("https://github.com/dotnet/roslyn/issues/34051")] public void ParameterList_DelegateDeclaration3() { - var code = @" -class C -{ - public delegate TResult Blah(T arg$$) -}"; - var expected = @" -class C -{ - public delegate TResult Blah(T arg);$$ -}"; + var code = """ + class C + { + public delegate TResult Blah(T arg$$) + } + """; + var expected = """ + class C + { + public delegate TResult Blah(T arg);$$ + } + """; VerifyTypingSemicolon(code, expected); } [WpfFact, WorkItem("https://github.com/dotnet/roslyn/issues/34051")] public void ParameterList_MultilineDelegateDeclaration() { - var code = @" -class C -{ - delegate void Del(string str$$, - int i, - string str2) -}"; - var expected = @" -class C -{ - delegate void Del(string str, - int i, - string str2);$$ -}"; + var code = """ + class C + { + delegate void Del(string str$$, + int i, + string str2) + } + """; + var expected = """ + class C + { + delegate void Del(string str, + int i, + string str2);$$ + } + """; VerifyTypingSemicolon(code, expected); } [WpfFact, WorkItem("https://github.com/dotnet/roslyn/issues/34051")] public void ParameterList_Constructor() { - var code = @" -class D -{ - public D($$) - { - } -}"; + var code = """ + class D + { + public D($$) + { + } + } + """; VerifyNoSpecialSemicolonHandling(code); } [WpfFact, WorkItem("https://github.com/dotnet/roslyn/issues/34051")] public void ParameterList_Destructor() { - var code = @" -class D -{ - public D() - { - } + var code = """ + class D + { + public D() + { + } - ~D($$) - { - } -}"; + ~D($$) + { + } + } + """; VerifyNoSpecialSemicolonHandling(code); } [WpfFact, WorkItem("https://github.com/dotnet/roslyn/issues/34051")] public void ParameterList_MethodDeclaration() { - var code = @" -class D -{ - void M($$) - { - } -}"; + var code = """ + class D + { + void M($$) + { + } + } + """; VerifyNoSpecialSemicolonHandling(code); } [WpfFact, WorkItem("https://github.com/dotnet/roslyn/issues/54709")] public void YieldReturn() { - var code = @" -class D -{ - private static IEnumerable M() - { - yield return GetNumber($$) - } -}"; - var expected = @" -class D -{ - private static IEnumerable M() - { - yield return GetNumber();$$ - } -}"; + var code = """ + class D + { + private static IEnumerable M() + { + yield return GetNumber($$) + } + } + """; + var expected = """ + class D + { + private static IEnumerable M() + { + yield return GetNumber();$$ + } + } + """; VerifyTypingSemicolon(code, expected); } @@ -4860,7 +5055,10 @@ public void InsideComments(string argument) [InlineData("/* comments */$$")] [InlineData("3$$, /* comments */")] [InlineData("3, $$/* comments */")] - [InlineData("// comments \r\n$$")] + [InlineData(""" + // comments + $$ + """)] public void NearComments(string argument) { var code = CreateTestWithMethodCall(@"var test = ClassC.MethodM(" + argument + ")"); @@ -4874,29 +5072,31 @@ public void NearComments(string argument) [WpfFact, WorkItem("https://devdiv.visualstudio.com/DevDiv/_workitems/edit/923157")] public void BrokenCode_ReturnIfCaretDoesNotMove() { - var code = @" -class D -{ - public Delegate Task Handles(int num)$$ -}"; + var code = """ + class D + { + public Delegate Task Handles(int num)$$ + } + """; VerifyNoSpecialSemicolonHandling(code); } [WpfFact, WorkItem("https://github.com/dotnet/roslyn/pull/37874")] public void TestWithSettingTurnedOff() { - var code = @" -public class ClassC -{ - private int xValue = 7; - public int XValue - { - get - { - return Math.Min(xValue$$, 1) - } - } -}"; + var code = """ + public class ClassC + { + private int xValue = 7; + public int XValue + { + get + { + return Math.Min(xValue$$, 1) + } + } + } + """; var expected = code.Replace("$$", ";$$"); Verify(code, expected, ExecuteTest, @@ -4910,52 +5110,55 @@ public int XValue [WpfFact] public void TestSwitchExpression() { - var code = @" -public class Bar -{ - public void Test(string myString) - { - var a = myString switch - { - ""Hello"" => 1, - ""World"" => 2, - _ => 3$$ - } - } -}"; + var code = """ + public class Bar + { + public void Test(string myString) + { + var a = myString switch + { + "Hello" => 1, + "World" => 2, + _ => 3$$ + } + } + } + """; - var expected = @" -public class Bar -{ - public void Test(string myString) - { - var a = myString switch - { - ""Hello"" => 1, - ""World"" => 2, - _ => 3 - };$$ - } -}"; + var expected = """ + public class Bar + { + public void Test(string myString) + { + var a = myString switch + { + "Hello" => 1, + "World" => 2, + _ => 3 + };$$ + } + } + """; VerifyTypingSemicolon(code, expected); } [WpfFact] public void TestNotInBracesSwitchExpression() { - var code = @" -public class Bar -{ - public void Test(string myString) - { - var a = myString switch - $${ - ""Hello"" => 1, - ""World"" => 2, - _ => 3 - } - } -}"; + var code = """ + public class Bar + { + public void Test(string myString) + { + var a = myString switch + $${ + "Hello" => 1, + "World" => 2, + _ => 3 + } + } + } + """; VerifyNoSpecialSemicolonHandling(code); } @@ -4963,21 +5166,118 @@ public void Test(string myString) [WpfFact, WorkItem("https://github.com/dotnet/roslyn/issues/70224")] public void TestNotBeforeKeywordInSwitchExpression() { - var code = @" -public class Bar -{ - public void Test(string myString) + var code = """ + public class Bar + { + public void Test(string myString) + { + var a = myString$$ switch + { + "Hello" => 1, + "World" => 2, + _ => 3 + } + } + } + """; + + VerifyNoSpecialSemicolonHandling(code); + } + + [WpfFact, WorkItem("https://github.com/dotnet/roslyn/issues/54213")] + public void AfterNewInField1() { - var a = myString$$ switch - { - ""Hello"" => 1, - ""World"" => 2, - _ => 3 - } + var code = """ + public class C + { + public List list = new$$ + } + """; + + var expected = """ + public class C + { + public List list = new();$$ + } + """; + + VerifyTypingSemicolon(code, expected); } -}"; - VerifyNoSpecialSemicolonHandling(code); + [WpfFact, WorkItem("https://github.com/dotnet/roslyn/issues/54213")] + public void AfterNewInField2() + { + var code = """ + public class C + { + List list1 = new$$ + List list2; + } + """; + + var expected = """ + public class C + { + List list1 = new();$$ + List list2; + } + """; + + VerifyTypingSemicolon(code, expected); + } + + [WpfFact, WorkItem("https://github.com/dotnet/roslyn/issues/54213")] + public void AfterNewInLocalDeclaration1() + { + var code = """ + public class C + { + void M() + { + List list = new$$ + } + } + """; + + var expected = """ + public class C + { + void M() + { + List list = new();$$ + } + } + """; + + VerifyTypingSemicolon(code, expected); + } + + [WpfFact, WorkItem("https://github.com/dotnet/roslyn/issues/54213")] + public void AfterNewInLocalDeclaration2() + { + var code = """ + public class C + { + void M() + { + List list = new$$ + List list2; + } + } + """; + + var expected = """ + public class C + { + void M() + { + List list = new();$$ + List list2; + } + } + """; + + VerifyTypingSemicolon(code, expected); } protected override EditorTestWorkspace CreateTestWorkspace(string code) diff --git a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/AwaitCompletionProviderTests.cs b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/AwaitCompletionProviderTests.cs index ec7316600ee77..9d29cc887002d 100644 --- a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/AwaitCompletionProviderTests.cs +++ b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/AwaitCompletionProviderTests.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using System; +using System.Diagnostics.CodeAnalysis; using System.Threading.Tasks; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Completion.Providers; @@ -14,32 +15,33 @@ namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Recommendations; /// -/// The adds async modifier if the return type is Task or ValueTask. -/// The tests here are only checking whether the completion item is provided or not. -/// Tests for checking adding async modifier are in: -/// src/EditorFeatures/Test2/IntelliSense/CSharpCompletionCommandHandlerTests_AwaitCompletion.vb +/// The adds async modifier if the return type is Task or ValueTask. The tests +/// here are only checking whether the completion item is provided or not. Tests for checking adding async modifier are +/// in: src/EditorFeatures/Test2/IntelliSense/CSharpCompletionCommandHandlerTests_AwaitCompletion.vb /// [Trait(Traits.Feature, Traits.Features.Completion)] -public class AwaitCompletionProviderTests : AbstractCSharpCompletionProviderTests +public sealed class AwaitCompletionProviderTests : AbstractCSharpCompletionProviderTests { internal override Type GetCompletionProviderType() => typeof(AwaitCompletionProvider); private const string CompletionDisplayTextAwait = "await"; private const string CompletionDisplayTextAwaitAndConfigureAwait = "awaitf"; - private async Task VerifyAbsenceAsync(string code) + private async Task VerifyAbsenceAsync([StringSyntax(PredefinedEmbeddedLanguageNames.CSharpTest)] string code) { await VerifyItemIsAbsentAsync(code, CompletionDisplayTextAwait); await VerifyItemIsAbsentAsync(code, CompletionDisplayTextAwaitAndConfigureAwait); } - private async Task VerifyAbsenceAsync(string code, LanguageVersion languageVersion = LanguageVersion.Default) + private async Task VerifyAbsenceAsync( + [StringSyntax(PredefinedEmbeddedLanguageNames.CSharpTest)] string code, LanguageVersion languageVersion = LanguageVersion.Default) { await VerifyItemIsAbsentAsync(GetMarkup(code, languageVersion), CompletionDisplayTextAwait); await VerifyItemIsAbsentAsync(GetMarkup(code, languageVersion), CompletionDisplayTextAwaitAndConfigureAwait); } - private async Task VerifyKeywordAsync(string code, LanguageVersion languageVersion = LanguageVersion.Default, string? inlineDescription = null, bool dotAwait = false, bool dotAwaitf = false) + private async Task VerifyKeywordAsync( + [StringSyntax(PredefinedEmbeddedLanguageNames.CSharpTest)] string code, LanguageVersion languageVersion = LanguageVersion.Default, string? inlineDescription = null, bool dotAwait = false, bool dotAwaitf = false) { var expectedDescription = dotAwait ? GetDescription(CompletionDisplayTextAwait, FeaturesResources.Await_the_preceding_expression) @@ -351,24 +353,24 @@ async Task F(Task someTask) public async Task TestDotAwaitSuggestAfterDotOnValueTask() { var valueTaskAssembly = typeof(ValueTask).Assembly.Location; - var markup = @$" - - - {valueTaskAssembly} - -using System.Threading.Tasks; + var markup = $$""" + + + {{valueTaskAssembly}} + + using System.Threading.Tasks; -class C -{{ - async Task F(ValueTask someTask) - {{ - someTask.$$ - }} -}} - - - -"; + class C + { + async Task F(ValueTask someTask) + { + someTask.$$ + } + } + + + + """; await VerifyItemExistsAsync(markup, "await"); await VerifyItemExistsAsync(markup, "awaitf"); } @@ -499,18 +501,19 @@ async Task Test() { } [InlineData("async Task Test() => await Task.FromResult(1);")] public async Task TestDotAwaitSuggestAfterDotBeforeDifferentStatements(string statement) { - await VerifyKeywordAsync($@" -using System; -using System.Threading.Tasks; + await VerifyKeywordAsync($$""" + using System; + using System.Threading.Tasks; -static class Program -{{ - static async Task Main(Task someTask) - {{ - someTask.$$ - {statement} - }} -}}", dotAwait: true, dotAwaitf: true); + static class Program + { + static async Task Main(Task someTask) + { + someTask.$$ + {{statement}} + } + } + """, dotAwait: true, dotAwaitf: true); } [Theory] @@ -546,38 +549,39 @@ static async Task Main(Task someTask) [InlineData("(null ?? Task.CompletedTask).$$")] public async Task TestDotAwaitSuggestAfterDifferentExpressions(string expression) { - await VerifyKeywordAsync($@" -using System; -using System.Threading.Tasks; + await VerifyKeywordAsync($$""" + using System; + using System.Threading.Tasks; -class C -{{ - public C Self => this; - public Task Field = Task.CompletedTask; - public Task Method() => Task.CompletedTask; - public Task Property => Task.CompletedTask; - public Task this[int i] => Task.CompletedTask; - public Func Function() => () => Task.CompletedTask; - public static Task operator +(C left, C right) => Task.CompletedTask; - public static explicit operator Task(C c) => Task.CompletedTask; -}} + class C + { + public C Self => this; + public Task Field = Task.CompletedTask; + public Task Method() => Task.CompletedTask; + public Task Property => Task.CompletedTask; + public Task this[int i] => Task.CompletedTask; + public Func Function() => () => Task.CompletedTask; + public static Task operator +(C left, C right) => Task.CompletedTask; + public static explicit operator Task(C c) => Task.CompletedTask; + } -static class Program -{{ - static Task StaticField = Task.CompletedTask; - static Task StaticProperty => Task.CompletedTask; - static Task StaticMethod() => Task.CompletedTask; + static class Program + { + static Task StaticField = Task.CompletedTask; + static Task StaticProperty => Task.CompletedTask; + static Task StaticMethod() => Task.CompletedTask; - static async Task Main(Task parameter) - {{ - Task local = Task.CompletedTask; - var c = new C(); + static async Task Main(Task parameter) + { + Task local = Task.CompletedTask; + var c = new C(); - {expression} + {{expression}} - Task LocalFunction() => Task.CompletedTask; - }} -}}", dotAwait: true, dotAwaitf: true); + Task LocalFunction() => Task.CompletedTask; + } + } + """, dotAwait: true, dotAwaitf: true); } [Fact(Skip = "Fails because speculative binding can't figure out that local is a Task.")] @@ -618,17 +622,18 @@ static async Task Main() [InlineData("await Task.Run(() => someTask.$$")] public async Task TestDotAwaitSuggestInLambdas(string lambda) { - await VerifyKeywordAsync($@" -using System.Threading.Tasks; + await VerifyKeywordAsync($$""" + using System.Threading.Tasks; -static class Program -{{ - static async Task Main() - {{ - var someTask = Task.CompletedTask; - {lambda} - }} -}}", dotAwait: true, dotAwaitf: true); + static class Program + { + static async Task Main() + { + var someTask = Task.CompletedTask; + {{lambda}} + } + } + """, dotAwait: true, dotAwaitf: true); } [Fact] @@ -854,25 +859,25 @@ async Task F(Task someTask) [InlineData("new C().M()?.Pro.M()?.M().SomeTask.$$")] public async Task TestDotAwaitNotAfterDotInConditionalAccessChain(string conditionalAccess) { - await VerifyAbsenceAsync($@" -using System.Threading.Tasks; -public class C -{{ - public Task SomeTask => Task.CompletedTask; - - public C Pro => this; - public C M() => this; -}} - -static class Program -{{ - public static async Task Main() - {{ - var c = new C(); - {conditionalAccess} - }} -}} -"); + await VerifyAbsenceAsync($$""" + using System.Threading.Tasks; + public class C + { + public Task SomeTask => Task.CompletedTask; + + public C Pro => this; + public C M() => this; + } + + static class Program + { + public static async Task Main() + { + var c = new C(); + {{conditionalAccess}} + } + } + """); } [Theory] @@ -895,41 +900,42 @@ public static async Task Main() [InlineData("new C().M()!.Pro.M()!.M().SomeTask.$$")] public async Task TestDotAwaitAfterNullForgivingOperatorAccessChain(string nullForgivingAccess) { - await VerifyKeywordAsync($@" -#nullable enable + await VerifyKeywordAsync($$""" + #nullable enable -using System.Threading.Tasks; -public class C -{{ - public Task? SomeTask => Task.CompletedTask; - - public C? Pro => this; - public C? M() => this; -}} - -static class Program -{{ - public static async Task Main(params string[] args) - {{ - var c = args[1] == string.Empty ? new C() : null; - {nullForgivingAccess} - }} -}} -", dotAwait: true, dotAwaitf: true); + using System.Threading.Tasks; + public class C + { + public Task? SomeTask => Task.CompletedTask; + + public C? Pro => this; + public C? M() => this; + } + + static class Program + { + public static async Task Main(params string[] args) + { + var c = args[1] == string.Empty ? new C() : null; + {{nullForgivingAccess}} + } + } + """, dotAwait: true, dotAwaitf: true); } [Theory, CombinatorialData] [WorkItem("https://github.com/dotnet/roslyn/issues/58921")] public async Task TestInCastExpressionThatMightBeParenthesizedExpression(bool hasNewline) { - var code = $@" -class C -{{ - void M() - {{ - var data = (n$$) {(hasNewline ? Environment.NewLine : string.Empty)} M(); - }} -}}"; + var code = $$""" + class C + { + void M() + { + var data = (n$$) {{(hasNewline ? Environment.NewLine : string.Empty)}} M(); + } + } + """; if (hasNewline) await VerifyKeywordAsync(code); else diff --git a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/CrefCompletionProviderTests.cs b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/CrefCompletionProviderTests.cs index b320d23d02b88..73ee6614a0c5b 100644 --- a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/CrefCompletionProviderTests.cs +++ b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/CrefCompletionProviderTests.cs @@ -447,7 +447,7 @@ class C var hostDocument = workspace.DocumentWithCursor; var document = workspace.CurrentSolution.GetRequiredDocument(hostDocument.Id); var service = GetCompletionService(document.Project); - var provider = Assert.IsType(service.GetTestAccessor().GetImportedAndBuiltInProviders(ImmutableHashSet.Empty).Single()); + var provider = Assert.IsType(service.GetTestAccessor().GetImportedAndBuiltInProviders([]).Single()); provider.GetTestAccessor().SetSpeculativeNodeCallback(n => { // asserts that we aren't be asked speculate on nodes inside documentation trivia. diff --git a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/DeclarationNameCompletionProviderTests.cs b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/DeclarationNameCompletionProviderTests.cs index e848f3223fa8c..d7daec38eeba2 100644 --- a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/DeclarationNameCompletionProviderTests.cs +++ b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/DeclarationNameCompletionProviderTests.cs @@ -22,7 +22,7 @@ namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Completion.CompletionSe using static SymbolSpecification; [Trait(Traits.Feature, Traits.Features.Completion)] -public class DeclarationNameCompletionProviderTests : AbstractCSharpCompletionProviderTests +public sealed class DeclarationNameCompletionProviderTests : AbstractCSharpCompletionProviderTests { private const string Span = """ namespace System @@ -337,13 +337,13 @@ internal override Type GetCompletionProviderType() [InlineData("record struct")] public async Task TreatRecordPositionalParameterAsProperty(string record) { - var markup = $@" -public class MyClass -{{ -}} + var markup = $$""" + public class MyClass + { + } -public {record} R(MyClass $$ -"; + public {{record}} R(MyClass $$ + """; await VerifyItemExistsAsync(markup, "MyClass", glyph: (int)Glyph.PropertyPublic); } @@ -352,13 +352,13 @@ public class MyClass [InlineData("struct")] public async Task DoNotTreatPrimaryConstructorParameterAsProperty(string record) { - var markup = $@" -public class MyClass -{{ -}} + var markup = $$""" + public class MyClass + { + } -public {record} R(MyClass $$ -"; + public {{record}} R(MyClass $$ + """; await VerifyItemIsAbsentAsync(markup, "MyClass"); } @@ -2916,6 +2916,25 @@ void M(IEnumerable $$) await VerifyItemExistsAsync(markup, "customers"); } + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/63943")] + public async Task InferOffOfGenericNameInPattern() + { + var markup = """ + using System.Collections.Generic; + + class Customer { } + + class V + { + void M(object o) + { + if (o is List $$ + } + } + """; + await VerifyItemExistsAsync(markup, "customers"); + } + private static NamingStylePreferences MultipleCamelCaseLocalRules() { var styles = new[] @@ -2925,9 +2944,9 @@ private static NamingStylePreferences MultipleCamelCaseLocalRules() }; return new NamingStylePreferences( - styles.Select(t => t.specification).ToImmutableArray(), - styles.Select(t => t.style).ToImmutableArray(), - styles.Select(t => CreateRule(t.specification, t.style)).ToImmutableArray()); + [.. styles.Select(t => t.specification)], + [.. styles.Select(t => t.style)], + [.. styles.Select(t => CreateRule(t.specification, t.style))]); // Local functions @@ -2936,7 +2955,7 @@ private static NamingStylePreferences MultipleCamelCaseLocalRules() var symbolSpecification = new SymbolSpecification( Guid.NewGuid(), name, - ImmutableArray.Create(kind)); + [kind]); var namingStyle = new NamingStyle( Guid.NewGuid(), @@ -2959,9 +2978,9 @@ private static NamingStylePreferences NamesEndWithSuffixPreferences() }; return new NamingStylePreferences( - specificationStyles.Select(t => t.specification).ToImmutableArray(), - specificationStyles.Select(t => t.style).ToImmutableArray(), - specificationStyles.Select(t => CreateRule(t.specification, t.style)).ToImmutableArray()); + [.. specificationStyles.Select(t => t.specification)], + [.. specificationStyles.Select(t => t.style)], + [.. specificationStyles.Select(t => CreateRule(t.specification, t.style))]); // Local functions @@ -2970,7 +2989,7 @@ private static NamingStylePreferences NamesEndWithSuffixPreferences() var symbolSpecification = new SymbolSpecification( Guid.NewGuid(), name: suffix, - ImmutableArray.Create(kind), + [kind], accessibilityList: default, modifiers: default); @@ -2992,13 +3011,13 @@ private static NamingStylePreferences ParameterCamelCaseWithPascalCaseFallback() new SymbolSpecification( id: Guid.NewGuid(), name: "parameters", - ImmutableArray.Create(new SymbolKindOrTypeKind(SymbolKind.Parameter)), + [new SymbolKindOrTypeKind(SymbolKind.Parameter)], accessibilityList: default, modifiers: default), new SymbolSpecification( id: Guid.NewGuid(), name: "fallback", - ImmutableArray.Create(new SymbolKindOrTypeKind(SymbolKind.Parameter), new SymbolKindOrTypeKind(SymbolKind.Local)), + [new SymbolKindOrTypeKind(SymbolKind.Parameter), new SymbolKindOrTypeKind(SymbolKind.Local)], accessibilityList: default, modifiers: default)); var namingStyles = ImmutableArray.Create( @@ -3019,9 +3038,7 @@ private static NamingStylePreferences ParameterCamelCaseWithPascalCaseFallback() return new NamingStylePreferences( symbolSpecifications, namingStyles, - namingRules: ImmutableArray.Create( - CreateRule(symbolSpecifications[0], namingStyles[0]), - CreateRule(symbolSpecifications[1], namingStyles[1]))); + namingRules: [CreateRule(symbolSpecifications[0], namingStyles[0]), CreateRule(symbolSpecifications[1], namingStyles[1])]); } private static SerializableNamingRule CreateRule(SymbolSpecification specification, NamingStyle style) diff --git a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/ExplicitInterfaceMemberCompletionProviderTests.cs b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/ExplicitInterfaceMemberCompletionProviderTests.cs index 98d53747e6828..da1717ad8e0d8 100644 --- a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/ExplicitInterfaceMemberCompletionProviderTests.cs +++ b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/ExplicitInterfaceMemberCompletionProviderTests.cs @@ -134,14 +134,17 @@ interface IGoo class Bar : IGoo { - void IGoo.Goo() + void IGoo.Goo() + { + throw new System.NotImplementedException(); + } } """; await VerifyProviderCommitAsync(markup, "Goo()", expected, null); } - [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/709988")] + [WpfFact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/709988")] public async Task CommitOnParen() { var markup = """ @@ -164,11 +167,14 @@ interface IGoo class Bar : IGoo { - void IGoo.Goo( + void IGoo.Goo() + { + throw new System.NotImplementedException();$$ + } } """; - await VerifyProviderCommitAsync(markup, "Goo()", expected, '('); + await VerifyCustomCommitProviderAsync(markup, "Goo", expected, commitChar: '('); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/19947")] @@ -445,7 +451,10 @@ interface IGoo class Bar : IGoo { - void IGoo.Generic(K key, V value) + int IGoo.Generic(K key, V value) + { + throw new System.NotImplementedException(); + } } """; @@ -475,7 +484,7 @@ interface IGoo class Bar : IGoo { - void IGoo.Generic< + void IGoo.< } """; @@ -505,14 +514,17 @@ interface IGoo class Bar : IGoo { - void IGoo.Generic(K key, V value) + int IGoo.Generic(K key, V value) + { + throw new System.NotImplementedException(); + } } """; await VerifyProviderCommitAsync(markup, "Generic(K key, V value)", expected, '\t'); } - [Fact] + [WpfFact] public async Task VerifySignatureCommit_Method_OpenBrace() { var markup = """ @@ -535,11 +547,14 @@ interface IGoo class Bar : IGoo { - void IGoo.Generic( + int IGoo.Generic(K key, V value) + { + throw new System.NotImplementedException();$$ + } } """; - await VerifyProviderCommitAsync(markup, "Generic(K key, V value)", expected, '('); + await VerifyCustomCommitProviderAsync(markup, "Generic", expected, commitChar: '('); } [Fact] @@ -565,7 +580,7 @@ interface IGoo class Bar : IGoo { - void IGoo.this[K key, V value] + int IGoo.this[K key, V value] => throw new System.NotImplementedException(); } """; @@ -595,7 +610,67 @@ interface IGoo class Bar : IGoo { - void IGoo.this[ + void IGoo.[ + } + """; + + await VerifyProviderCommitAsync(markup, "this[K key, V value]", expected, '['); + } + + [Fact] + public async Task VerifySignatureCommit_IndexerGetSet_Tab() + { + var markup = """ + interface IGoo + { + int this[K key, V value] { get; set; } + } + + class Bar : IGoo + { + void IGoo.$$ + } + """; + + var expected = """ + interface IGoo + { + int this[K key, V value] { get; set; } + } + + class Bar : IGoo + { + int IGoo.this[K key, V value] { get => throw new System.NotImplementedException(); set => throw new System.NotImplementedException(); } + } + """; + + await VerifyProviderCommitAsync(markup, "this[K key, V value]", expected, '\t'); + } + + [Fact] + public async Task VerifySignatureCommit_IndexerGetSet_OpenBrace() + { + var markup = """ + interface IGoo + { + int this[K key, V value] { get; set; } + } + + class Bar : IGoo + { + void IGoo.$$ + } + """; + + var expected = """ + interface IGoo + { + int this[K key, V value] { get; set; } + } + + class Bar : IGoo + { + void IGoo.[ } """; @@ -606,33 +681,47 @@ void IGoo.this[ [InlineData("ref")] [InlineData("in")] [InlineData("out")] + [InlineData("ref readonly")] + [InlineData("scoped")] + [InlineData("scoped ref")] public async Task TestWithRefKind(string refKind) { - var markup = $@" -interface I -{{ - void M({refKind} string s); -}} - -class C : I -{{ - void I.$$ -}} -"; - - var expected = $@" -interface I -{{ - void M({refKind} string s); -}} - -class C : I -{{ - void I.M({refKind} string s) -}} -"; - - await VerifyProviderCommitAsync(markup, $"M({refKind} string s)", expected, '\t'); + var markup = $$""" + using System; + + ref struct S { } + + interface I + { + void M({{refKind}} S s); + } + + class C : I + { + void I.$$ + } + """; + + var expected = $$""" + using System; + + ref struct S { } + + interface I + { + void M({{refKind}} S s); + } + + class C : I + { + void I.M({{refKind}} S s) + { + throw new NotImplementedException(); + } + } + """; + + await VerifyProviderCommitAsync(markup, $"M({refKind} S s)", expected, '\t'); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/53924")] @@ -659,6 +748,9 @@ interface I2 where T : I2 class Test2 : I2 { static implicit I2.operator int(Test2 x) + { + throw new System.NotImplementedException(); + } } """; @@ -691,6 +783,9 @@ interface I where T : I class C : I { static bool I.operator true(C x) + { + throw new System.NotImplementedException(); + } } """; @@ -721,6 +816,9 @@ interface I where T : I class C : I { static C I.operator +(C x) + { + throw new System.NotImplementedException(); + } } """; @@ -751,6 +849,9 @@ interface I where T : I class C : I { static C I.operator +(C x, C y) + { + throw new System.NotImplementedException(); + } } """; @@ -781,14 +882,16 @@ interface I class C : I { void I.M(params string[] args) + { + throw new System.NotImplementedException(); + } } """; await VerifyProviderCommitAsync(markup, "M(params string[] args)", expected, '\t'); } - [Fact(Skip = "https://github.com/dotnet/roslyn/issues/72224")] - [WorkItem("https://github.com/dotnet/roslyn/issues/72224")] + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/72224")] public async Task TestWithParamsCollectionParameter() { var markup = """ @@ -816,6 +919,9 @@ interface I class C : I { void I.M(params IEnumerable args) + { + throw new System.NotImplementedException(); + } } """; @@ -849,7 +955,10 @@ interface I class C : I { - void I.M(T? x) + void I.M(T? x) where T : default + { + throw new System.NotImplementedException(); + } } """; @@ -880,6 +989,9 @@ interface I class C : I { void I.M(string @class) + { + throw new System.NotImplementedException(); + } } """; @@ -910,6 +1022,9 @@ interface I class C : I { void I.M<@class>() + { + throw new System.NotImplementedException(); + } } """; @@ -940,9 +1055,11 @@ interface I class C : I { void I.M(int x) + { + throw new System.NotImplementedException(); + } } """; - // TODO: Consider adding the default value too. await VerifyProviderCommitAsync(markup, "M(int x)", expected, '\t'); } @@ -974,6 +1091,9 @@ interface I1 where T : I1 class C : I1 { static C I1.operator checked -(C x) + { + throw new System.NotImplementedException(); + } } """; @@ -1008,6 +1128,9 @@ interface I1 where T : I1 class C : I1 { static C I1.operator checked +(C x, C y) + { + throw new System.NotImplementedException(); + } } """; @@ -1041,10 +1164,668 @@ interface I1 where T : I1 class C3 : I1 { - static C3 I1.operator checked string(C3 x) + static explicit I1.operator checked string(C3 x) + { + throw new System.NotImplementedException(); + } } """; await VerifyProviderCommitAsync(markup, "operator checked string(C3 x)", expected, '\t'); } + + [WpfFact, WorkItem("https://github.com/dotnet/roslyn/issues/70458")] + public async Task TestExlicitImplementationWithAttributesOnNullableParameters() + { + var markup = """ + #nullable enable + + using Example.Namespace; + + interface IFoo + { + static abstract bool TryDecode([NotNullWhen(false)] out DecodeError? decodeError, [NotNullWhen(false)] out string? errorMessage); + } + + class C : IFoo + { + IFoo.$$ + } + + class NotNullWhenAttribute(bool _) : System.Attribute; + + namespace Example.Namespace + { + public record DecodeError; + } + """; + + var expected = """ + #nullable enable + + using Example.Namespace; + + interface IFoo + { + static abstract bool TryDecode([NotNullWhen(false)] out DecodeError? decodeError, [NotNullWhen(false)] out string? errorMessage); + } + + class C : IFoo + { + static bool IFoo.TryDecode(out DecodeError? decodeError, out string? errorMessage) + { + throw new System.NotImplementedException();$$ + } + } + + class NotNullWhenAttribute(bool _) : System.Attribute; + + namespace Example.Namespace + { + public record DecodeError; + } + """; + + await VerifyCustomCommitProviderAsync(markup, "TryDecode", expected); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75435")] + public async Task MissingReturnTypeQualifiedInterface_01() + { + var markup = """ + interface IGoo + { + void Goo(); + static abstract void StaticGoo(); + } + + class Bar : IGoo + { + IGoo.$$ + } + """; + + await VerifyItemExistsAsync(markup, "Goo", displayTextSuffix: "()"); + await VerifyItemExistsAsync(markup, "StaticGoo", displayTextSuffix: "()"); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75435")] + public async Task MissingReturnTypeQualifiedInterface_02() + { + var markup = """ + interface IGoo + { + void Goo(); + } + + class Bar : IGoo + { + void Test() + { + IGoo.$$ + } + } + """; + + await VerifyItemIsAbsentAsync(markup, "Goo"); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75435")] + public async Task MissingReturnTypeQualifiedInterface_03() + { + var markup = """ + class Outer + { + public interface IGoo + { + void Goo(); + static abstract void StaticGoo(); + } + } + + class Bar : Outer.IGoo + { + Outer.IGoo.$$ + } + """; + + await VerifyItemExistsAsync(markup, "Goo", displayTextSuffix: "()"); + await VerifyItemExistsAsync(markup, "StaticGoo", displayTextSuffix: "()"); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75435")] + public async Task MissingReturnTypeQualifiedInterface_04() + { + var markup = """ + interface IGoo + { + int Generic(K key, V value); + } + + class Bar : IGoo + { + IGoo.$$ + } + """; + + var expected = """ + interface IGoo + { + int Generic(K key, V value); + } + + class Bar : IGoo + { + int IGoo.Generic(K key, V value) + { + throw new System.NotImplementedException(); + } + } + """; + + await VerifyProviderCommitAsync(markup, "Generic(K key, V value)", expected, '\t'); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75435")] + public async Task MissingReturnTypeQualifiedInterface_05() + { + var markup = """ + interface I where T : I + { + abstract static bool operator true(T x); + abstract static bool operator false(T x); + } + + class C : I + { + I.$$ + } + """; + + var expected = """ + interface I where T : I + { + abstract static bool operator true(T x); + abstract static bool operator false(T x); + } + + class C : I + { + static bool I.operator true(C x) + { + throw new System.NotImplementedException(); + } + } + """; + + await VerifyProviderCommitAsync(markup, "operator true(C x)", expected, '\t'); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75435")] + public async Task MissingReturnTypeQualifiedInterface_06() + { + var markup = """ + interface I where T : I + { + abstract static ref bool Goo(ref int a, out int b); + } + + class C : I + { + I.$$ + } + """; + + var expected = """ + interface I where T : I + { + abstract static ref bool Goo(ref int a, out int b); + } + + class C : I + { + static ref bool I.Goo(ref int a, out int b) + { + throw new System.NotImplementedException(); + } + } + """; + + await VerifyProviderCommitAsync(markup, "Goo(ref int a, out int b)", expected, '\t'); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75435")] + public async Task MissingReturnTypeQualifiedInterface_07() + { + var markup = """ + interface I where T : I + { + abstract static bool Goo { set; } + } + + class C : I + { + I.$$ + } + """; + + var expected = """ + interface I where T : I + { + abstract static bool Goo { set; } + } + + class C : I + { + static bool I.Goo { set => throw new System.NotImplementedException(); } + } + """; + + await VerifyProviderCommitAsync(markup, "Goo", expected, '\t'); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75435")] + public async Task MissingReturnTypeQualifiedInterface_08() + { + var markup = """ + interface I where T : I + { + abstract static event System.Action Goo; + } + + class C : I + { + I.$$ + } + """; + + var expected = """ + using System; + + interface I where T : I + { + abstract static event System.Action Goo; + } + + class C : I + { + static event Action I.Goo + { + add + { + throw new NotImplementedException(); + } + + remove + { + throw new NotImplementedException(); + } + } + } + """; + + await VerifyProviderCommitAsync(markup, "Goo", expected, '\t'); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75435")] + public async Task MissingReturnTypeQualifiedInterface_09() + { + var markup = """ + interface I where T : I + { + bool Goo { get; set; } + } + + class C : I + { + I.$$ + } + """; + + var expected = """ + interface I where T : I + { + bool Goo { get; set; } + } + + class C : I + { + bool I.Goo { get => throw new System.NotImplementedException(); set => throw new System.NotImplementedException(); } + } + """; + + await VerifyProviderCommitAsync(markup, "Goo", expected, '\t'); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75435")] + public async Task MissingReturnTypeQualifiedInterface_10() + { + var markup = """ + interface I where T : I + { + event System.Action Goo; + } + + class C : I + { + I.$$ + } + """; + + var expected = """ + using System; + + interface I where T : I + { + event System.Action Goo; + } + + class C : I + { + event Action I.Goo + { + add + { + throw new NotImplementedException(); + } + + remove + { + throw new NotImplementedException(); + } + } + } + """; + + await VerifyProviderCommitAsync(markup, "Goo", expected, '\t'); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75435")] + public async Task MissingReturnTypeQualifiedInterface_11() + { + var markup = """ + interface I where T : I + { + bool this[int a, T b] { get; set; } + } + + class C : I + { + I.$$ + } + """; + + var expected = """ + interface I where T : I + { + bool this[int a, T b] { get; set; } + } + + class C : I + { + bool I.this[int a, C b] { get => throw new System.NotImplementedException(); set => throw new System.NotImplementedException(); } + } + """; + + await VerifyProviderCommitAsync(markup, "this[int a, C b]", expected, '\t'); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75435")] + public async Task MissingReturnTypeQualifiedInterface_12() + { + var markup = """ + interface IOuter + { + void Method(); + + public interface IInner + { + void Method1(); + void Method2(); + } + } + + class C : IOuter + { + IOuter.$$ + } + """; + + await VerifyItemExistsAsync(markup, "Method", displayTextSuffix: "()"); + await VerifyItemIsAbsentAsync(markup, "Method1", displayTextSuffix: "()"); + await VerifyItemIsAbsentAsync(markup, "Method2", displayTextSuffix: "()"); + await VerifyItemIsAbsentAsync(markup, "IInner"); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75435")] + public async Task MissingReturnTypeQualifiedInterface_13() + { + var markup = """ + interface IOuter + { + void Method(); + + public interface IInner + { + void Method1(); + void Method2(); + } + } + + class C : IOuter + { + IOuter.$$ + } + """; + + var expected = """ + interface IOuter + { + void Method(); + + public interface IInner + { + void Method1(); + void Method2(); + } + } + + class C : IOuter + { + void IOuter.Method() + { + throw new System.NotImplementedException(); + } + } + """; + + await VerifyProviderCommitAsync(markup, "Method()", expected, '\t'); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75435")] + public async Task MissingReturnTypeQualifiedInterface_14() + { + var markup = """ + interface IOuter + { + void Method(); + + public interface IInner + { + void Method1(); + void Method2(); + } + } + + class C : IOuter.IInner + { + IOuter.IInner.$$ + } + """; + + await VerifyItemIsAbsentAsync(markup, "Method", displayTextSuffix: "()"); + await VerifyItemExistsAsync(markup, "Method1", displayTextSuffix: "()"); + await VerifyItemExistsAsync(markup, "Method2", displayTextSuffix: "()"); + await VerifyItemIsAbsentAsync(markup, "IInner"); + + // We do not provide that item, maybe consider this expansion in the future + await VerifyItemIsAbsentAsync(markup, "IInner.Method1", displayTextSuffix: "()"); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75435")] + public async Task MissingReturnTypeQualifiedInterface_15() + { + var markup = """ + interface IOuter + { + void Method(); + + public interface IInner + { + void Method1(); + void Method2(); + } + } + + class C : IOuter.IInner + { + IOuter.IInner.$$ + } + """; + + var expected = """ + interface IOuter + { + void Method(); + + public interface IInner + { + void Method1(); + void Method2(); + } + } + + class C : IOuter.IInner + { + void IOuter.IInner.Method1() + { + throw new System.NotImplementedException(); + } + } + """; + + await VerifyProviderCommitAsync(markup, "Method1()", expected, '\t'); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75435")] + public async Task MissingReturnTypeQualifiedInterface_16() + { + var markup = """ + interface IOuter + { + void Method(); + + public interface IInner + { + void Method1(); + void Method2(); + } + } + + class C : IOuter + { + IOuter.IInner.$$ + } + """; + + await VerifyItemIsAbsentAsync(markup, "Method1", displayTextSuffix: "()"); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75435")] + public async Task MissingReturnTypeQualifiedInterface_17() + { + var markup = """ + interface IInterface + { + void Method(); + } + + class C + { + IInterface.$$ + } + """; + + await VerifyItemIsAbsentAsync(markup, "Method", displayTextSuffix: "()"); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75435")] + public async Task MissingReturnTypeQualifiedInterface_18() + { + var markup = """ + interface IOuter + { + void Method(); + + public interface IInner + { + void Method1(); + void Method2(); + } + } + + class C + { + IOuter.$$ + } + """; + + await VerifyItemIsAbsentAsync(markup, "Method", displayTextSuffix: "()"); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75435")] + public async Task MissingReturnTypeQualifiedInterface_19() + { + var markup = """ + interface IOuter + { + void Method(); + + public interface IInner + { + void Method1(); + void Method2(); + } + } + + class C : IOuter.IInner + { + IOuter.$$ + } + """; + + await VerifyItemIsAbsentAsync(markup, "Method", displayTextSuffix: "()"); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75435")] + public async Task MissingReturnTypeQualifiedInterface_20() + { + var markup = """ + class Outer + { + public interface IInner + { + void Method1(); + void Method2(); + } + } + + class C : Outer.IInner + { + Outer.IInner.$$ + } + """; + + await VerifyItemExistsAsync(markup, "Method1", displayTextSuffix: "()"); + } } diff --git a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/ExplicitInterfaceTypeCompletionProviderTests.cs b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/ExplicitInterfaceTypeCompletionProviderTests.cs index 4c9491220a8cc..c8e6f4c6a6781 100644 --- a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/ExplicitInterfaceTypeCompletionProviderTests.cs +++ b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/ExplicitInterfaceTypeCompletionProviderTests.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System; using System.Threading.Tasks; using Microsoft.CodeAnalysis.CSharp.Completion.Providers; @@ -14,7 +12,7 @@ namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Completion.CompletionProviders; [Trait(Traits.Feature, Traits.Features.Completion)] -public class ExplicitInterfaceTypeCompletionProviderTests : AbstractCSharpCompletionProviderTests +public sealed class ExplicitInterfaceTypeCompletionProviderTests : AbstractCSharpCompletionProviderTests { internal override Type GetCompletionProviderType() => typeof(ExplicitInterfaceTypeCompletionProvider); @@ -358,4 +356,22 @@ class C : I await VerifyItemExistsAsync(markup, "I", displayTextSuffix: "<>"); } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/54005")] + public async Task TestWithStaticKeyword() + { + var markup = """ + interface I1 + { + static abstract void M1(); + } + + class C1 : I1 + { + static void $$ + } + """; + + await VerifyItemExistsAsync(markup, "I1", displayTextSuffix: ""); + } } diff --git a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/ObjectInitializerCompletionProviderTests.cs b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/ObjectInitializerCompletionProviderTests.cs index 40f4ff988e66c..e38c260d14b5e 100644 --- a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/ObjectInitializerCompletionProviderTests.cs +++ b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/ObjectInitializerCompletionProviderTests.cs @@ -998,7 +998,7 @@ public static T Create() } """; - await VerifyItemExistsAsync(markup, "Target"); + await VerifyItemIsAbsentAsync(markup, "Target"); await VerifyItemExistsAsync(markup, "Method"); } @@ -1022,6 +1022,74 @@ public static T Create() await VerifyNoItemsExistAsync(markup); } + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/74331")] + public async Task ObjectInitializerOnVariousMembers_01() + { + var markup = """ + using System.Collections; + using System.Collections.Generic; + + internal class Example + { + public object ObjectProp { get; } + public double DoubleProp { get; } + public string StringProp { get; } = "some name"; + public System.Enum EnumProp { get; } + public System.Array ArrayProp { get; } + public void* PointerProp { get; } + public delegate* FunctionPointerProp { get; } + public IEnumerable EnumerableProp { get; } + public IEnumerable StringEnumerableProp { get; } + public IEnumerator EnumeratorProp { get; } + public IEnumerator StringEnumeratorProp { get; } + + public static Example Create() + { + return new() + { + $$ + }; + } + } + """; + + await VerifyNoItemsExistAsync(markup); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/74331")] + public async Task ObjectInitializerOnVariousMembers_02() + { + var markup = """ + using System.Collections; + using System.Collections.Generic; + + internal class Example + { + public readonly object ObjectField; + public readonly double DoubleField; + public readonly string StringField = "some name"; + public readonly System.Enum EnumField; + public System.Array ArrayField { get; } + public readonly void* PointerField; + public readonly delegate* FunctionPointerField; + public readonly IEnumerable EnumerableField; + public readonly IEnumerable StringEnumerableField; + public readonly IEnumerator EnumeratorField; + public readonly IEnumerator StringEnumeratorField; + + public static Example Create() + { + return new() + { + $$ + }; + } + } + """; + + await VerifyNoItemsExistAsync(markup); + } + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/26560")] public async Task ObjectInitializerEscapeKeywords() { diff --git a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/SuggestionModeCompletionProviderTests.cs b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/SuggestionModeCompletionProviderTests.cs index b5e5e89c1cbf7..eea714b6f5cb6 100644 --- a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/SuggestionModeCompletionProviderTests.cs +++ b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/SuggestionModeCompletionProviderTests.cs @@ -17,7 +17,7 @@ namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Completion.CompletionProviders; [Trait(Traits.Feature, Traits.Features.Completion)] -public class SuggestionModeCompletionProviderTests : AbstractCSharpCompletionProviderTests +public sealed class SuggestionModeCompletionProviderTests : AbstractCSharpCompletionProviderTests { internal override Type GetCompletionProviderType() => typeof(CSharpSuggestionModeCompletionProvider); @@ -817,16 +817,17 @@ class C { await VerifyBuilderAsync(markup); } - [Fact(Skip = "https://github.com/dotnet/roslyn/issues/72225")] - [WorkItem("https://github.com/dotnet/roslyn/issues/72225")] + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/72225")] public async Task UnwrapParamsCollection() { var markup = """ using System; using System.Collections.Generic; - class C { - C(params IEnumerable> a) { + class C + { + C(params IEnumerable> a) + { new C($$ } } @@ -1528,7 +1529,7 @@ private async Task CheckResultsAsync(Document document, int position, bool isBui }; var service = GetCompletionService(document.Project); - var provider = Assert.Single(service.GetTestAccessor().GetImportedAndBuiltInProviders(ImmutableHashSet.Empty)); + var provider = Assert.Single(service.GetTestAccessor().GetImportedAndBuiltInProviders([])); foreach (var triggerInfo in triggerInfos) { diff --git a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/SymbolCompletionProviderTests.cs b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/SymbolCompletionProviderTests.cs index c98b9e085ab6b..1f7d1ed23eefb 100644 --- a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/SymbolCompletionProviderTests.cs +++ b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/SymbolCompletionProviderTests.cs @@ -1,11 +1,10 @@ -// Licensed to the .NET Foundation under one or more agreements. +// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Completion.Providers; using Microsoft.CodeAnalysis.CSharp; @@ -39,10 +38,14 @@ public async Task EmptyFile(SourceCodeKind sourceCodeKind) [InlineData(SourceCodeKind.Script)] public async Task EmptyFileWithUsing(SourceCodeKind sourceCodeKind) { - await VerifyItemExistsAsync(@"using System; -$$", @"String", expectedDescriptionOrNull: null, sourceCodeKind: sourceCodeKind); - await VerifyItemExistsAsync(@"using System; -$$", @"System", expectedDescriptionOrNull: null, sourceCodeKind: sourceCodeKind); + await VerifyItemExistsAsync(""" + using System; + $$ + """, @"String", expectedDescriptionOrNull: null, sourceCodeKind: sourceCodeKind); + await VerifyItemExistsAsync(""" + using System; + $$ + """, @"System", expectedDescriptionOrNull: null, sourceCodeKind: sourceCodeKind); } [Fact] @@ -65,189 +68,239 @@ public async Task UsingDirective() [Fact] public async Task InactiveRegion() { - await VerifyItemIsAbsentAsync(@"class C { -#if false -$$ -#endif", @"String"); - await VerifyItemIsAbsentAsync(@"class C { -#if false -$$ -#endif", @"System"); + await VerifyItemIsAbsentAsync(""" + class C { + #if false + $$ + #endif + """, @"String"); + await VerifyItemIsAbsentAsync(""" + class C { + #if false + $$ + #endif + """, @"System"); } [Fact] public async Task ActiveRegion() { - await VerifyItemIsAbsentAsync(@"class C { -#if true -$$ -#endif", @"String"); - await VerifyItemExistsAsync(@"class C { -#if true -$$ -#endif", @"System"); + await VerifyItemIsAbsentAsync(""" + class C { + #if true + $$ + #endif + """, @"String"); + await VerifyItemExistsAsync(""" + class C { + #if true + $$ + #endif + """, @"System"); } [Fact] public async Task InactiveRegionWithUsing() { - await VerifyItemIsAbsentAsync(@"using System; + await VerifyItemIsAbsentAsync(""" + using System; -class C { -#if false -$$ -#endif", @"String"); - await VerifyItemIsAbsentAsync(@"using System; + class C { + #if false + $$ + #endif + """, @"String"); + await VerifyItemIsAbsentAsync(""" + using System; -class C { -#if false -$$ -#endif", @"System"); + class C { + #if false + $$ + #endif + """, @"System"); } [Fact] public async Task ActiveRegionWithUsing() { - await VerifyItemExistsAsync(@"using System; + await VerifyItemExistsAsync(""" + using System; -class C { -#if true -$$ -#endif", @"String"); - await VerifyItemExistsAsync(@"using System; + class C { + #if true + $$ + #endif + """, @"String"); + await VerifyItemExistsAsync(""" + using System; -class C { -#if true -$$ -#endif", @"System"); + class C { + #if true + $$ + #endif + """, @"System"); } [Fact] public async Task SingleLineComment1() { - await VerifyItemIsAbsentAsync(@"using System; + await VerifyItemIsAbsentAsync(""" + using System; -class C { -// $$", @"String"); - await VerifyItemIsAbsentAsync(@"using System; + class C { + // $$ + """, @"String"); + await VerifyItemIsAbsentAsync(""" + using System; -class C { -// $$", @"System"); + class C { + // $$ + """, @"System"); } [Fact] public async Task SingleLineComment2() { - await VerifyItemIsAbsentAsync(@"using System; + await VerifyItemIsAbsentAsync(""" + using System; -class C { -// $$ -", @"String"); - await VerifyItemIsAbsentAsync(@"using System; + class C { + // $$ + """, @"String"); + await VerifyItemIsAbsentAsync(""" + using System; -class C { -// $$ -", @"System"); - await VerifyItemIsAbsentAsync(@"using System; + class C { + // $$ + """, @"System"); + await VerifyItemIsAbsentAsync(""" + using System; -class C { - // $$ -", @"System"); + class C { + // $$ + """, @"System"); } [Fact] public async Task MultiLineComment() { - await VerifyItemIsAbsentAsync(@"using System; + await VerifyItemIsAbsentAsync(""" + using System; -class C { -/* $$", @"String"); - await VerifyItemIsAbsentAsync(@"using System; + class C { + /* $$ + """, @"String"); + await VerifyItemIsAbsentAsync(""" + using System; -class C { -/* $$", @"System"); - await VerifyItemIsAbsentAsync(@"using System; + class C { + /* $$ + """, @"System"); + await VerifyItemIsAbsentAsync(""" + using System; -class C { -/* $$ */", @"String"); - await VerifyItemIsAbsentAsync(@"using System; + class C { + /* $$ */ + """, @"String"); + await VerifyItemIsAbsentAsync(""" + using System; -class C { -/* $$ */", @"System"); - await VerifyItemExistsAsync(@"using System; + class C { + /* $$ */ + """, @"System"); + await VerifyItemExistsAsync(""" + using System; -class C { -/* */$$", @"System"); - await VerifyItemExistsAsync(@"using System; + class C { + /* */$$ + """, @"System"); + await VerifyItemExistsAsync(""" + using System; -class C { -/* */$$ -", @"System"); - await VerifyItemExistsAsync(@"using System; + class C { + /* */$$ + """, @"System"); + await VerifyItemExistsAsync(""" + using System; -class C { - /* */$$ -", @"System"); + class C { + /* */$$ + """, @"System"); } [Fact] public async Task SingleLineXmlComment1() { - await VerifyItemIsAbsentAsync(@"using System; + await VerifyItemIsAbsentAsync(""" + using System; -class C { -/// $$", @"String"); - await VerifyItemIsAbsentAsync(@"using System; + class C { + /// $$ + """, @"String"); + await VerifyItemIsAbsentAsync(""" + using System; -class C { -/// $$", @"System"); + class C { + /// $$ + """, @"System"); } [Fact] public async Task SingleLineXmlComment2() { - await VerifyItemIsAbsentAsync(@"using System; + await VerifyItemIsAbsentAsync(""" + using System; -class C { -/// $$ -", @"String"); - await VerifyItemIsAbsentAsync(@"using System; + class C { + /// $$ + """, @"String"); + await VerifyItemIsAbsentAsync(""" + using System; -class C { -/// $$ -", @"System"); - await VerifyItemIsAbsentAsync(@"using System; + class C { + /// $$ + """, @"System"); + await VerifyItemIsAbsentAsync(""" + using System; -class C { - /// $$ -", @"System"); + class C { + /// $$ + """, @"System"); } [Fact] public async Task MultiLineXmlComment() { - await VerifyItemIsAbsentAsync(@"using System; + await VerifyItemIsAbsentAsync(""" + using System; -class C { -/** $$ */", @"String"); - await VerifyItemIsAbsentAsync(@"using System; + class C { + /** $$ */ + """, @"String"); + await VerifyItemIsAbsentAsync(""" + using System; -class C { -/** $$ */", @"System"); - await VerifyItemExistsAsync(@"using System; + class C { + /** $$ */ + """, @"System"); + await VerifyItemExistsAsync(""" + using System; -class C { -/** */$$", @"System"); - await VerifyItemExistsAsync(@"using System; + class C { + /** */$$ + """, @"System"); + await VerifyItemExistsAsync(""" + using System; -class C { -/** */$$ -", @"System"); - await VerifyItemExistsAsync(@"using System; + class C { + /** */$$ + """, @"System"); + await VerifyItemExistsAsync(""" + using System; -class C { - /** */$$ -", @"System"); + class C { + /** */$$ + """, @"System"); } [Fact] @@ -285,7 +338,9 @@ await VerifyExpectedItemsAsync(code, [ [Fact] public async Task StringLiteralInDirective() { - var code = "#r \"$$\""; + var code = """ + #r "$$" + """; await VerifyExpectedItemsAsync( code, [ ItemExpectation.Absent("String"), @@ -328,8 +383,10 @@ await VerifyExpectedItemsAsync(source, [ [Fact] public async Task SystemAttributeIsNotAnAttribute() { - var content = @"[$$] -class CL {}"; + var content = """ + [$$] + class CL {} + """; await VerifyItemIsAbsentAsync(AddUsingDirectives("using System;", content), @"Attribute"); } @@ -337,8 +394,10 @@ class CL {}"; [Fact] public async Task TypeAttribute() { - var content = @"[$$] -class CL {}"; + var content = """ + [$$] + class CL {} + """; await VerifyItemExistsAsync(AddUsingDirectives("using System;", content), @"AttributeUsage"); await VerifyItemExistsAsync(AddUsingDirectives("using System;", content), @"System"); @@ -357,10 +416,12 @@ await VerifyExpectedItemsAsync(code, [ [Fact] public async Task MethodAttribute() { - var content = @"class CL { - [$$] - void Method() {} -}"; + var content = """ + class CL { + [$$] + void Method() {} + } + """; var code = AddUsingDirectives("using System;", content); await VerifyExpectedItemsAsync(code, [ ItemExpectation.Exists("AttributeUsage"), @@ -371,9 +432,11 @@ await VerifyExpectedItemsAsync(code, [ [Fact] public async Task MethodTypeParamAttribute() { - var content = @"class CL{ - void Method<[A$$]T> () {} -}"; + var content = """ + class CL{ + void Method<[A$$]T> () {} + } + """; var code = AddUsingDirectives("using System;", content); await VerifyExpectedItemsAsync(code, [ ItemExpectation.Exists("AttributeUsage"), @@ -384,9 +447,11 @@ await VerifyExpectedItemsAsync(code, [ [Fact] public async Task MethodParamAttribute() { - var content = @"class CL{ - void Method ([$$]int i) {} -}"; + var content = """ + class CL{ + void Method ([$$]int i) {} + } + """; var code = AddUsingDirectives("using System;", content); await VerifyExpectedItemsAsync(code, [ ItemExpectation.Exists("AttributeUsage"), @@ -405,11 +470,13 @@ public async Task NamespaceName_EmptyNameSpan_TopLevel() [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/7213")] public async Task NamespaceName_EmptyNameSpan_Nested() { - var source = @"; -namespace System -{ - namespace $$ { } -}"; + var source = """ + ; + namespace System + { + namespace $$ { } + } + """; await VerifyItemExistsAsync(source, "Runtime", sourceCodeKind: SourceCodeKind.Regular); } @@ -417,9 +484,11 @@ namespace $$ { } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/7213")] public async Task NamespaceName_Unqualified_TopLevelNoPeers() { - var source = @"using System; + var source = """ + using System; -namespace $$"; + namespace $$ + """; await VerifyExpectedItemsAsync(source, [ @@ -432,9 +501,11 @@ await VerifyExpectedItemsAsync(source, [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/7213")] public async Task NamespaceName_Unqualified_TopLevelNoPeers_FileScopedNamespace() { - var source = @"using System; + var source = """ + using System; -namespace $$;"; + namespace $$; + """; await VerifyExpectedItemsAsync(source, [ @@ -447,10 +518,11 @@ await VerifyExpectedItemsAsync(source, [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/7213")] public async Task NamespaceName_Unqualified_TopLevelWithPeer() { - var source = @" -namespace A { } + var source = """ + namespace A { } -namespace $$"; + namespace $$ + """; await VerifyItemExistsAsync(source, "A", sourceCodeKind: SourceCodeKind.Regular); } @@ -458,11 +530,12 @@ namespace $$"; [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/7213")] public async Task NamespaceName_Unqualified_NestedWithNoPeers() { - var source = @" -namespace A -{ - namespace $$ -}"; + var source = """ + namespace A + { + namespace $$ + } + """; await VerifyNoItemsExistAsync(source, sourceCodeKind: SourceCodeKind.Regular); } @@ -470,13 +543,14 @@ namespace $$ [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/7213")] public async Task NamespaceName_Unqualified_NestedWithPeer() { - var source = @" -namespace A -{ - namespace B { } + var source = """ + namespace A + { + namespace B { } - namespace $$ -}"; + namespace $$ + } + """; await VerifyExpectedItemsAsync(source, [ @@ -497,14 +571,15 @@ public async Task NamespaceName_Unqualified_ExcludesCurrentDeclaration() [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/7213")] public async Task NamespaceName_Unqualified_WithNested() { - var source = @" -namespace A -{ - namespace $$ - { - namespace B { } - } -}"; + var source = """ + namespace A + { + namespace $$ + { + namespace B { } + } + } + """; await VerifyExpectedItemsAsync(source, [ @@ -517,16 +592,17 @@ await VerifyExpectedItemsAsync(source, [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/7213")] public async Task NamespaceName_Unqualified_WithNestedAndMatchingPeer() { - var source = @" -namespace A.B { } + var source = """ + namespace A.B { } -namespace A -{ - namespace $$ - { - namespace B { } - } -}"; + namespace A + { + namespace $$ + { + namespace B { } + } + } + """; await VerifyExpectedItemsAsync(source, [ @@ -552,18 +628,19 @@ await VerifyExpectedItemsAsync(source, [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/7213")] public async Task NamespaceName_Unqualified_IncompleteDeclaration() { - var source = @" -namespace A -{ - namespace B - { - namespace $$ - namespace C1 { } - } - namespace B.C2 { } -} + var source = """ + namespace A + { + namespace B + { + namespace $$ + namespace C1 { } + } + namespace B.C2 { } + } -namespace A.B.C3 { }"; + namespace A.B.C3 { } + """; await VerifyExpectedItemsAsync( source, [ @@ -598,10 +675,11 @@ public async Task NamespaceName_Qualified_NoPeers() [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/7213")] public async Task NamespaceName_Qualified_TopLevelWithPeer() { - var source = @" -namespace A.B { } + var source = """ + namespace A.B { } -namespace A.$$"; + namespace A.$$ + """; await VerifyItemExistsAsync(source, "B", sourceCodeKind: SourceCodeKind.Regular); } @@ -609,10 +687,11 @@ namespace A.$$"; [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/7213")] public async Task NamespaceName_Qualified_TopLevelWithPeer_FileScopedNamespace() { - var source = @" -namespace A.B { } + var source = """ + namespace A.B { } -namespace A.$$;"; + namespace A.$$; + """; await VerifyItemExistsAsync(source, "B", sourceCodeKind: SourceCodeKind.Regular); } @@ -620,13 +699,14 @@ namespace A.$$;"; [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/7213")] public async Task NamespaceName_Qualified_NestedWithPeer() { - var source = @" -namespace A -{ - namespace B.C { } + var source = """ + namespace A + { + namespace B.C { } - namespace B.$$ -}"; + namespace B.$$ + } + """; await VerifyExpectedItemsAsync(source, [ @@ -640,12 +720,12 @@ await VerifyExpectedItemsAsync(source, [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/7213")] public async Task NamespaceName_Qualified_WithNested() { - var source = @" -namespace A.$$ -{ - namespace B { } -} -"; + var source = """ + namespace A.$$ + { + namespace B { } + } + """; await VerifyExpectedItemsAsync(source, [ @@ -658,14 +738,14 @@ await VerifyExpectedItemsAsync(source, [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/7213")] public async Task NamespaceName_Qualified_WithNestedAndMatchingPeer() { - var source = @" -namespace A.B { } + var source = """ + namespace A.B { } -namespace A.$$ -{ - namespace B { } -} -"; + namespace A.$$ + { + namespace B { } + } + """; await VerifyExpectedItemsAsync(source, [ @@ -699,11 +779,12 @@ public async Task NamespaceName_OnKeyword() [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/7213")] public async Task NamespaceName_OnNestedKeyword() { - var source = @" -namespace System -{ - name$$space Runtime { } -}"; + var source = """ + namespace System + { + name$$space Runtime { } + } + """; await VerifyExpectedItemsAsync(source, [ @@ -716,20 +797,21 @@ await VerifyExpectedItemsAsync(source, [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/7213")] public async Task NamespaceName_Qualified_IncompleteDeclaration() { - var source = @" -namespace A -{ - namespace B - { - namespace C.$$ + var source = """ + namespace A + { + namespace B + { + namespace C.$$ - namespace C.D1 { } - } + namespace C.D1 { } + } - namespace B.C.D2 { } -} + namespace B.C.D2 { } + } -namespace A.B.C.D3 { }"; + namespace A.B.C.D3 { } + """; await VerifyExpectedItemsAsync( source, [ @@ -765,9 +847,11 @@ await VerifyExpectedItemsAsync(source, [ [Fact] public async Task OutsideOfType1() { - var source = @"namespace NS { -class CL {} -$$"; + var source = """ + namespace NS { + class CL {} + $$ + """; await VerifyExpectedItemsAsync(source, [ ItemExpectation.Absent("String"), ItemExpectation.Absent("System") @@ -777,9 +861,11 @@ await VerifyExpectedItemsAsync(source, [ [Fact] public async Task OutsideOfType2() { - var content = @"namespace NS { -class CL {} -$$"; + var content = """ + namespace NS { + class CL {} + $$ + """; var source = AddUsingDirectives("using System;", content); await VerifyExpectedItemsAsync(source, [ ItemExpectation.Absent("String"), @@ -790,14 +876,16 @@ await VerifyExpectedItemsAsync(source, [ [Fact] public async Task CompletionInsideProperty() { - var source = @"class C -{ - private string name; - public string Name - { - set - { - name = $$"; + var source = """ + class C + { + private string name; + public string Name + { + set + { + name = $$ + """; await VerifyExpectedItemsAsync(source, [ ItemExpectation.Exists("value"), ItemExpectation.Exists("C") @@ -827,9 +915,10 @@ await VerifyExpectedItemsAsync(source, [ [Fact] public async Task IncompleteMember() { - var content = @"class CL { - $$ -"; + var content = """ + class CL { + $$ + """; var source = AddUsingDirectives("using System;", content); await VerifyExpectedItemsAsync(source, [ ItemExpectation.Exists("String"), @@ -840,9 +929,10 @@ await VerifyExpectedItemsAsync(source, [ [Fact] public async Task IncompleteMemberAccessibility() { - var content = @"class CL { - public $$ -"; + var content = """ + class CL { + public $$ + """; var source = AddUsingDirectives("using System;", content); await VerifyExpectedItemsAsync(source, [ ItemExpectation.Exists("String"), @@ -993,8 +1083,10 @@ await VerifyExpectedItemsAsync(source, [ [Fact] public async Task FieldDeclaration() { - var content = @"class CL { - $$ i"; + var content = """ + class CL { + $$ i + """; var source = AddUsingDirectives("using System;", content); await VerifyExpectedItemsAsync(source, [ ItemExpectation.Exists("String"), @@ -1005,8 +1097,10 @@ await VerifyExpectedItemsAsync(source, [ [Fact] public async Task EventFieldDeclaration() { - var content = @"class CL { - event $$"; + var content = """ + class CL { + event $$ + """; var source = AddUsingDirectives("using System;", content); await VerifyExpectedItemsAsync(source, [ ItemExpectation.Exists("String"), @@ -1017,8 +1111,10 @@ await VerifyExpectedItemsAsync(source, [ [Fact] public async Task ConversionOperatorDeclaration() { - var content = @"class CL { - explicit operator $$"; + var content = """ + class CL { + explicit operator $$ + """; var source = AddUsingDirectives("using System;", content); await VerifyExpectedItemsAsync(source, [ ItemExpectation.Exists("String"), @@ -1029,8 +1125,10 @@ await VerifyExpectedItemsAsync(source, [ [Fact] public async Task ConversionOperatorDeclarationNoToken() { - var content = @"class CL { - explicit $$"; + var content = """ + class CL { + explicit $$ + """; var source = AddUsingDirectives("using System;", content); await VerifyExpectedItemsAsync(source, [ ItemExpectation.Absent("String"), @@ -1041,8 +1139,10 @@ await VerifyExpectedItemsAsync(source, [ [Fact] public async Task PropertyDeclaration() { - var content = @"class CL { - $$ Prop {"; + var content = """ + class CL { + $$ Prop { + """; var source = AddUsingDirectives("using System;", content); await VerifyExpectedItemsAsync(source, [ ItemExpectation.Exists("String"), @@ -1053,8 +1153,10 @@ await VerifyExpectedItemsAsync(source, [ [Fact] public async Task EventDeclaration() { - var content = @"class CL { - event $$ Event {"; + var content = """ + class CL { + event $$ Event { + """; var source = AddUsingDirectives("using System;", content); await VerifyExpectedItemsAsync(source, [ ItemExpectation.Exists("String"), @@ -1065,8 +1167,10 @@ await VerifyExpectedItemsAsync(source, [ [Fact] public async Task IndexerDeclaration() { - var content = @"class CL { - $$ this"; + var content = """ + class CL { + $$ this + """; var source = AddUsingDirectives("using System;", content); await VerifyExpectedItemsAsync(source, [ ItemExpectation.Exists("String"), @@ -1077,8 +1181,10 @@ await VerifyExpectedItemsAsync(source, [ [Fact] public async Task Parameter() { - var content = @"class CL { - void Method($$"; + var content = """ + class CL { + void Method($$ + """; var source = AddUsingDirectives("using System;", content); await VerifyExpectedItemsAsync(source, [ ItemExpectation.Exists("String"), @@ -1089,8 +1195,10 @@ await VerifyExpectedItemsAsync(source, [ [Fact] public async Task ArrayType() { - var content = @"class CL { - $$ ["; + var content = """ + class CL { + $$ [ + """; var source = AddUsingDirectives("using System;", content); await VerifyExpectedItemsAsync(source, [ ItemExpectation.Exists("String"), @@ -1101,8 +1209,10 @@ await VerifyExpectedItemsAsync(source, [ [Fact] public async Task PointerType() { - var content = @"class CL { - $$ *"; + var content = """ + class CL { + $$ * + """; var source = AddUsingDirectives("using System;", content); await VerifyExpectedItemsAsync(source, [ ItemExpectation.Exists("String"), @@ -1113,8 +1223,10 @@ await VerifyExpectedItemsAsync(source, [ [Fact] public async Task NullableType() { - var content = @"class CL { - $$ ?"; + var content = """ + class CL { + $$ ? + """; var source = AddUsingDirectives("using System;", content); await VerifyExpectedItemsAsync(source, [ ItemExpectation.Exists("String"), @@ -1125,8 +1237,10 @@ await VerifyExpectedItemsAsync(source, [ [Fact] public async Task DelegateDeclaration() { - var content = @"class CL { - delegate $$"; + var content = """ + class CL { + delegate $$ + """; var source = AddUsingDirectives("using System;", content); await VerifyExpectedItemsAsync(source, [ ItemExpectation.Exists("String"), @@ -1137,8 +1251,10 @@ await VerifyExpectedItemsAsync(source, [ [Fact] public async Task MethodDeclaration() { - var content = @"class CL { - $$ M("; + var content = """ + class CL { + $$ M( + """; var source = AddUsingDirectives("using System;", content); await VerifyExpectedItemsAsync(source, [ ItemExpectation.Exists("String"), @@ -1149,8 +1265,10 @@ await VerifyExpectedItemsAsync(source, [ [Fact] public async Task OperatorDeclaration() { - var content = @"class CL { - $$ operator"; + var content = """ + class CL { + $$ operator + """; var source = AddUsingDirectives("using System;", content); await VerifyExpectedItemsAsync(source, [ ItemExpectation.Exists("String"), @@ -1713,12 +1831,14 @@ public async Task TypeParameterConstraintClause_NotStaticClass() public async Task TypeParameterConstraintClause_StillShowStaticClassWhenHaveInternalType() { await VerifyItemExistsAsync( -@"static class Test -{ - public interface IInterface {} -} + """ + static class Test + { + public interface IInterface {} + } -class CL where T : $$", @"Test"); + class CL where T : $$ + """, @"Test"); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/30784")] @@ -1731,12 +1851,14 @@ public async Task TypeParameterConstraintClause_NotSealedClass() public async Task TypeParameterConstraintClause_StillShowSealedClassWhenHaveInternalType() { await VerifyItemExistsAsync( -@"sealed class Test -{ - public interface IInterface {} -} + """ + sealed class Test + { + public interface IInterface {} + } -class CL where T : $$", @"Test"); + class CL where T : $$ + """, @"Test"); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/30784")] @@ -1766,12 +1888,14 @@ public async Task TypeParameterConstraintClauseList_NotStaticClass() public async Task TypeParameterConstraintClauseList_StillShowStaticClassWhenHaveInternalType() { await VerifyItemExistsAsync( -@"static class Test -{ - public interface IInterface {} -} + """ + static class Test + { + public interface IInterface {} + } -class CL where T : A, $$", @"Test"); + class CL where T : A, $$ + """, @"Test"); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/30784")] @@ -1784,12 +1908,14 @@ public async Task TypeParameterConstraintClauseList_NotSealedClass() public async Task TypeParameterConstraintClauseList_StillShowSealedClassWhenHaveInternalType() { await VerifyItemExistsAsync( -@"sealed class Test -{ - public interface IInterface {} -} + """ + sealed class Test + { + public interface IInterface {} + } -class CL where T : A, $$", @"Test"); + class CL where T : A, $$ + """, @"Test"); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/30784")] @@ -1987,9 +2113,10 @@ public async Task Parameters_03(string prefix) [InlineData("args")] public async Task Parameters_04(string prefix) { - await VerifyItemExistsAsync(prefix + @"$$ -Systen.Console.WriteLine(); -", "args", sourceCodeKind: SourceCodeKind.Regular); + await VerifyItemExistsAsync(prefix + """ + $$ + Systen.Console.WriteLine(); + """, "args", sourceCodeKind: SourceCodeKind.Regular); } [Theory] @@ -1999,9 +2126,9 @@ await VerifyItemExistsAsync(prefix + @"$$ [InlineData("args")] public async Task Parameters_05(string prefix) { - await VerifyItemExistsAsync(@" -Systen.Console.WriteLine(); -" + prefix + "$$", "args", sourceCodeKind: SourceCodeKind.Regular); + await VerifyItemExistsAsync(""" + Systen.Console.WriteLine(); + """ + prefix + "$$", "args", sourceCodeKind: SourceCodeKind.Regular); } [Theory] @@ -2011,11 +2138,12 @@ await VerifyItemExistsAsync(@" [InlineData("args")] public async Task Parameters_06(string prefix) { - await VerifyItemExistsAsync(@" -Systen.Console.WriteLine(); -" + prefix + @"$$ -Systen.Console.WriteLine(); -", "args", sourceCodeKind: SourceCodeKind.Regular); + await VerifyItemExistsAsync(""" + Systen.Console.WriteLine(); + """ + prefix + """ + $$ + Systen.Console.WriteLine(); + """, "args", sourceCodeKind: SourceCodeKind.Regular); } [Theory] @@ -2035,15 +2163,19 @@ public async Task Parameters_TopLevelStatement_1() [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/55969")] public async Task Parameters_TopLevelStatement_2() => await VerifyItemExistsAsync( - @"using System; -Console.WriteLine(); -$$", "args", sourceCodeKind: SourceCodeKind.Regular); + """ + using System; + Console.WriteLine(); + $$ + """, "args", sourceCodeKind: SourceCodeKind.Regular); [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/55969")] public async Task Parameters_TopLevelStatement_3() => await VerifyItemIsAbsentAsync( - @"using System; -$$", "args", sourceCodeKind: SourceCodeKind.Regular); + """ + using System; + $$ + """, "args", sourceCodeKind: SourceCodeKind.Regular); [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/55969")] public async Task Parameters_TopLevelStatement_4() @@ -2152,20 +2284,20 @@ public async Task InstanceTypesAvailableInUsingAlias() [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/539812")] public async Task InheritedMember1() { - var markup = @" -class A -{ - private void Hidden() { } - protected void Goo() { } -} -class B : A -{ - void Bar() - { - $$ - } -} -"; + var markup = """ + class A + { + private void Hidden() { } + protected void Goo() { } + } + class B : A + { + void Bar() + { + $$ + } + } + """; await VerifyExpectedItemsAsync(markup, [ ItemExpectation.Absent("Hidden"), ItemExpectation.Exists("Goo") @@ -2175,20 +2307,20 @@ await VerifyExpectedItemsAsync(markup, [ [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/539812")] public async Task InheritedMember2() { - var markup = @" -class A -{ - private void Hidden() { } - protected void Goo() { } -} -class B : A -{ - void Bar() - { - this.$$ - } -} -"; + var markup = """ + class A + { + private void Hidden() { } + protected void Goo() { } + } + class B : A + { + void Bar() + { + this.$$ + } + } + """; await VerifyExpectedItemsAsync(markup, [ ItemExpectation.Absent("Hidden"), ItemExpectation.Exists("Goo") @@ -2198,20 +2330,20 @@ await VerifyExpectedItemsAsync(markup, [ [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/539812")] public async Task InheritedMember3() { - var markup = @" -class A -{ - private void Hidden() { } - protected void Goo() { } -} -class B : A -{ - void Bar() - { - base.$$ - } -} -"; + var markup = """ + class A + { + private void Hidden() { } + protected void Goo() { } + } + class B : A + { + void Bar() + { + base.$$ + } + } + """; await VerifyExpectedItemsAsync(markup, [ ItemExpectation.Absent("Hidden"), ItemExpectation.Exists("Goo"), @@ -2222,20 +2354,20 @@ await VerifyExpectedItemsAsync(markup, [ [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/539812")] public async Task InheritedStaticMember1() { - var markup = @" -class A -{ - private static void Hidden() { } - protected static void Goo() { } -} -class B : A -{ - void Bar() - { - $$ - } -} -"; + var markup = """ + class A + { + private static void Hidden() { } + protected static void Goo() { } + } + class B : A + { + void Bar() + { + $$ + } + } + """; await VerifyExpectedItemsAsync(markup, [ ItemExpectation.Absent("Hidden"), ItemExpectation.Exists("Goo") @@ -2245,21 +2377,21 @@ await VerifyExpectedItemsAsync(markup, [ [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/539812")] public async Task InheritedStaticMember2() { - var markup = @" -class A -{ - private static void Hidden() { } - protected static void Goo() { } -} -class B : A -{ - void Bar() - { - B.$$ - } -} -"; - await VerifyExpectedItemsAsync(markup, [ + var markup = """ + class A + { + private static void Hidden() { } + protected static void Goo() { } + } + class B : A + { + void Bar() + { + B.$$ + } + } + """; + await VerifyExpectedItemsAsync(markup, [ ItemExpectation.Absent("Hidden"), ItemExpectation.Exists("Goo") ]); @@ -2268,20 +2400,20 @@ await VerifyExpectedItemsAsync(markup, [ [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/539812")] public async Task InheritedStaticMember3() { - var markup = @" -class A -{ - private static void Hidden() { } - protected static void Goo() { } -} -class B : A -{ - void Bar() - { - A.$$ - } -} -"; + var markup = """ + class A + { + private static void Hidden() { } + protected static void Goo() { } + } + class B : A + { + void Bar() + { + A.$$ + } + } + """; await VerifyExpectedItemsAsync(markup, [ ItemExpectation.Absent("Hidden"), ItemExpectation.Exists("Goo") @@ -2291,23 +2423,23 @@ await VerifyExpectedItemsAsync(markup, [ [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/539812")] public async Task InheritedInstanceAndStaticMembers() { - var markup = @" -class A -{ - private static void HiddenStatic() { } - protected static void GooStatic() { } + var markup = """ + class A + { + private static void HiddenStatic() { } + protected static void GooStatic() { } - private void HiddenInstance() { } - protected void GooInstance() { } -} -class B : A -{ - void Bar() - { - $$ - } -} -"; + private void HiddenInstance() { } + protected void GooInstance() { } + } + class B : A + { + void Bar() + { + $$ + } + } + """; await VerifyExpectedItemsAsync(markup, [ ItemExpectation.Absent("HiddenStatic"), ItemExpectation.Exists("GooStatic"), @@ -2319,39 +2451,39 @@ await VerifyExpectedItemsAsync(markup, [ [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/540155")] public async Task ForLoopIndexer1() { - var markup = @" -class C -{ - void M() - { - for (int i = 0; $$ -"; + var markup = """ + class C + { + void M() + { + for (int i = 0; $$ + """; await VerifyItemExistsAsync(markup, "i"); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/540155")] public async Task ForLoopIndexer2() { - var markup = @" -class C -{ - void M() - { - for (int i = 0; i < 10; $$ -"; + var markup = """ + class C + { + void M() + { + for (int i = 0; i < 10; $$ + """; await VerifyItemExistsAsync(markup, "i"); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/540012")] public async Task NoInstanceMembersAfterType1() { - var markup = @" -class C -{ - void M() - { - System.IDisposable.$$ -"; + var markup = """ + class C + { + void M() + { + System.IDisposable.$$ + """; await VerifyItemIsAbsentAsync(markup, "Dispose"); } @@ -2359,27 +2491,27 @@ void M() [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/540012")] public async Task NoInstanceMembersAfterType2() { - var markup = @" -class C -{ - void M() - { - (System.IDisposable).$$ -"; + var markup = """ + class C + { + void M() + { + (System.IDisposable).$$ + """; await VerifyItemIsAbsentAsync(markup, "Dispose"); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/540012")] public async Task NoInstanceMembersAfterType3() { - var markup = @" -using System; -class C -{ - void M() - { - IDisposable.$$ -"; + var markup = """ + using System; + class C + { + void M() + { + IDisposable.$$ + """; await VerifyItemIsAbsentAsync(markup, "Dispose"); } @@ -2387,14 +2519,14 @@ void M() [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/540012")] public async Task NoInstanceMembersAfterType4() { - var markup = @" -using System; -class C -{ - void M() - { - (IDisposable).$$ -"; + var markup = """ + using System; + class C + { + void M() + { + (IDisposable).$$ + """; await VerifyItemIsAbsentAsync(markup, "Dispose"); } @@ -2402,13 +2534,13 @@ void M() [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/540012")] public async Task StaticMembersAfterType1() { - var markup = @" -class C -{ - void M() - { - System.IDisposable.$$ -"; + var markup = """ + class C + { + void M() + { + System.IDisposable.$$ + """; await VerifyItemExistsAsync(markup, "ReferenceEquals"); } @@ -2416,27 +2548,27 @@ void M() [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/540012")] public async Task StaticMembersAfterType2() { - var markup = @" -class C -{ - void M() - { - (System.IDisposable).$$ -"; + var markup = """ + class C + { + void M() + { + (System.IDisposable).$$ + """; await VerifyItemIsAbsentAsync(markup, "ReferenceEquals"); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/540012")] public async Task StaticMembersAfterType3() { - var markup = @" -using System; -class C -{ - void M() - { - IDisposable.$$ -"; + var markup = """ + using System; + class C + { + void M() + { + IDisposable.$$ + """; await VerifyItemExistsAsync(markup, "ReferenceEquals"); } @@ -2444,14 +2576,14 @@ void M() [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/540012")] public async Task StaticMembersAfterType4() { - var markup = @" -using System; -class C -{ - void M() - { - (IDisposable).$$ -"; + var markup = """ + using System; + class C + { + void M() + { + (IDisposable).$$ + """; await VerifyItemIsAbsentAsync(markup, "ReferenceEquals"); } @@ -2459,28 +2591,28 @@ void M() [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/540197")] public async Task TypeParametersInClass() { - var markup = @" -class C -{ - $$ -} -"; + var markup = """ + class C + { + $$ + } + """; await VerifyItemExistsAsync(markup, "T"); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/540212")] public async Task AfterRefInLambda_TypeOnly() { - var markup = @" -using System; -class C -{ - void M(String parameter) - { - Func f = (ref $$ - } -} -"; + var markup = """ + using System; + class C + { + void M(String parameter) + { + Func f = (ref $$ + } + } + """; await VerifyExpectedItemsAsync(markup, [ ItemExpectation.Exists("String"), ItemExpectation.Absent("parameter") @@ -2490,16 +2622,16 @@ await VerifyExpectedItemsAsync(markup, [ [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/540212")] public async Task AfterOutInLambda_TypeOnly() { - var markup = @" -using System; -class C -{ - void M(String parameter) - { - Func f = (out $$ - } -} -"; + var markup = """ + using System; + class C + { + void M(String parameter) + { + Func f = (out $$ + } + } + """; await VerifyExpectedItemsAsync(markup, [ ItemExpectation.Exists("String"), ItemExpectation.Absent("parameter") @@ -2509,16 +2641,16 @@ await VerifyExpectedItemsAsync(markup, [ [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/24326")] public async Task AfterInInLambda_TypeOnly() { - var markup = @" -using System; -class C -{ - void M(String parameter) - { - Func f = (in $$ - } -} -"; + var markup = """ + using System; + class C + { + void M(String parameter) + { + Func f = (in $$ + } + } + """; await VerifyExpectedItemsAsync(markup, [ ItemExpectation.Exists("String"), ItemExpectation.Absent("parameter") @@ -2528,16 +2660,16 @@ await VerifyExpectedItemsAsync(markup, [ [Fact] public async Task AfterRefInMethodDeclaration_TypeOnly() { - var markup = @" -using System; -class C -{ - String field; - void M(ref $$) - { - } -} -"; + var markup = """ + using System; + class C + { + String field; + void M(ref $$) + { + } + } + """; await VerifyExpectedItemsAsync(markup, [ ItemExpectation.Exists("String"), ItemExpectation.Absent("field") @@ -2547,16 +2679,16 @@ await VerifyExpectedItemsAsync(markup, [ [Fact] public async Task AfterOutInMethodDeclaration_TypeOnly() { - var markup = @" -using System; -class C -{ - String field; - void M(out $$) - { - } -} -"; + var markup = """ + using System; + class C + { + String field; + void M(out $$) + { + } + } + """; await VerifyExpectedItemsAsync(markup, [ ItemExpectation.Exists("String"), ItemExpectation.Absent("field") @@ -2566,16 +2698,16 @@ await VerifyExpectedItemsAsync(markup, [ [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/24326")] public async Task AfterInInMethodDeclaration_TypeOnly() { - var markup = @" -using System; -class C -{ - String field; - void M(in $$) - { - } -} -"; + var markup = """ + using System; + class C + { + String field; + void M(in $$) + { + } + } + """; await VerifyExpectedItemsAsync(markup, [ ItemExpectation.Exists("String"), ItemExpectation.Absent("field") @@ -2585,16 +2717,16 @@ await VerifyExpectedItemsAsync(markup, [ [Fact] public async Task AfterRefInInvocation_TypeAndVariable() { - var markup = @" -using System; -class C -{ - void M(ref String parameter) - { - M(ref $$ - } -} -"; + var markup = """ + using System; + class C + { + void M(ref String parameter) + { + M(ref $$ + } + } + """; await VerifyExpectedItemsAsync(markup, [ ItemExpectation.Exists("String"), ItemExpectation.Exists("parameter") @@ -2604,16 +2736,16 @@ await VerifyExpectedItemsAsync(markup, [ [Fact] public async Task AfterOutInInvocation_TypeAndVariable() { - var markup = @" -using System; -class C -{ - void M(out String parameter) - { - M(out $$ - } -} -"; + var markup = """ + using System; + class C + { + void M(out String parameter) + { + M(out $$ + } + } + """; await VerifyExpectedItemsAsync(markup, [ ItemExpectation.Exists("String"), ItemExpectation.Exists("parameter") @@ -2623,16 +2755,16 @@ await VerifyExpectedItemsAsync(markup, [ [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/24326")] public async Task AfterInInInvocation_TypeAndVariable() { - var markup = @" -using System; -class C -{ - void M(in String parameter) - { - M(in $$ - } -} -"; + var markup = """ + using System; + class C + { + void M(in String parameter) + { + M(in $$ + } + } + """; await VerifyExpectedItemsAsync(markup, [ ItemExpectation.Exists("String"), ItemExpectation.Exists("parameter") @@ -2642,35 +2774,35 @@ await VerifyExpectedItemsAsync(markup, [ [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/25569")] public async Task AfterRefExpression_TypeAndVariable() { - var markup = @" -using System; -class C -{ - void M(String parameter) - { - ref var x = ref $$ - } -} -"; - await VerifyExpectedItemsAsync(markup, [ - ItemExpectation.Exists("String"), - ItemExpectation.Exists("parameter") + var markup = """ + using System; + class C + { + void M(String parameter) + { + ref var x = ref $$ + } + } + """; + await VerifyExpectedItemsAsync(markup, [ + ItemExpectation.Exists("String"), + ItemExpectation.Exists("parameter") ]); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/25569")] public async Task AfterRefInStatementContext_TypeOnly() { - var markup = @" -using System; -class C -{ - void M(String parameter) - { - ref $$ - } -} -"; + var markup = """ + using System; + class C + { + void M(String parameter) + { + ref $$ + } + } + """; await VerifyExpectedItemsAsync(markup, [ ItemExpectation.Exists("String"), ItemExpectation.Absent("parameter") @@ -2680,16 +2812,16 @@ await VerifyExpectedItemsAsync(markup, [ [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/25569")] public async Task AfterRefReadonlyInStatementContext_TypeOnly() { - var markup = @" -using System; -class C -{ - void M(String parameter) - { - ref readonly $$ - } -} -"; + var markup = """ + using System; + class C + { + void M(String parameter) + { + ref readonly $$ + } + } + """; await VerifyExpectedItemsAsync(markup, [ ItemExpectation.Exists("String"), ItemExpectation.Absent("parameter") @@ -2699,16 +2831,16 @@ await VerifyExpectedItemsAsync(markup, [ [Fact] public async Task AfterRefLocalDeclaration_TypeOnly() { - var markup = @" -using System; -class C -{ - void M(String parameter) - { - ref $$ int local; - } -} -"; + var markup = """ + using System; + class C + { + void M(String parameter) + { + ref $$ int local; + } + } + """; await VerifyExpectedItemsAsync(markup, [ ItemExpectation.Exists("String"), ItemExpectation.Absent("parameter") @@ -2718,16 +2850,16 @@ await VerifyExpectedItemsAsync(markup, [ [Fact] public async Task AfterRefReadonlyLocalDeclaration_TypeOnly() { - var markup = @" -using System; -class C -{ - void M(String parameter) - { - ref readonly $$ int local; - } -} -"; + var markup = """ + using System; + class C + { + void M(String parameter) + { + ref readonly $$ int local; + } + } + """; await VerifyExpectedItemsAsync(markup, [ ItemExpectation.Exists("String"), ItemExpectation.Absent("parameter") @@ -2737,16 +2869,16 @@ await VerifyExpectedItemsAsync(markup, [ [Fact] public async Task AfterRefLocalFunction_TypeOnly() { - var markup = @" -using System; -class C -{ - void M(String parameter) - { - ref $$ int Function(); - } -} -"; + var markup = """ + using System; + class C + { + void M(String parameter) + { + ref $$ int Function(); + } + } + """; await VerifyExpectedItemsAsync(markup, [ ItemExpectation.Exists("String"), ItemExpectation.Absent("parameter") @@ -2756,16 +2888,16 @@ await VerifyExpectedItemsAsync(markup, [ [Fact] public async Task AfterRefReadonlyLocalFunction_TypeOnly() { - var markup = @" -using System; -class C -{ - void M(String parameter) - { - ref readonly $$ int Function(); - } -} -"; + var markup = """ + using System; + class C + { + void M(String parameter) + { + ref readonly $$ int Function(); + } + } + """; await VerifyExpectedItemsAsync(markup, [ ItemExpectation.Exists("String"), ItemExpectation.Absent("parameter") @@ -2775,37 +2907,37 @@ await VerifyExpectedItemsAsync(markup, [ [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/35178")] public async Task RefStructMembersEmptyByDefault() { - var markup = @" -ref struct Test {} -class C -{ - void M() - { - var test = new Test(); - test.$$ - } -} -"; + var markup = """ + ref struct Test {} + class C + { + void M() + { + var test = new Test(); + test.$$ + } + } + """; await VerifyNoItemsExistAsync(markup); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/35178")] public async Task RefStructMembersHasMethodIfItWasOverriden() { - var markup = @" -ref struct Test -{ - public override string ToString() => string.Empty; -} -class C -{ - void M() - { - var test = new Test(); - test.$$ - } -} -"; + var markup = """ + ref struct Test + { + public override string ToString() => string.Empty; + } + class C + { + void M() + { + var test = new Test(); + test.$$ + } + } + """; await VerifyExpectedItemsAsync(markup, [ ItemExpectation.Exists("ToString"), ItemExpectation.Absent("GetType"), @@ -2817,17 +2949,17 @@ await VerifyExpectedItemsAsync(markup, [ [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/35178")] public async Task RefStructMembersHasMethodsForNameof() { - var markup = @" -ref struct Test {} -class C -{ - void M() - { - var test = new Test(); - _ = nameof(test.$$); - } -} -"; + var markup = """ + ref struct Test {} + class C + { + void M() + { + var test = new Test(); + _ = nameof(test.$$); + } + } + """; await VerifyExpectedItemsAsync(markup, [ ItemExpectation.Exists("ToString"), ItemExpectation.Exists("GetType"), @@ -2839,16 +2971,16 @@ await VerifyExpectedItemsAsync(markup, [ [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/53585")] public async Task AfterStaticLocalFunction_TypeOnly() { - var markup = @" -using System; -class C -{ - void M(String parameter) - { - static $$ - } -} -"; + var markup = """ + using System; + class C + { + void M(String parameter) + { + static $$ + } + } + """; await VerifyExpectedItemsAsync(markup, [ ItemExpectation.Exists("String"), ItemExpectation.Absent("parameter") @@ -2867,16 +2999,16 @@ await VerifyExpectedItemsAsync(markup, [ [InlineData("extern unsafe")] public async Task AfterLocalFunction_TypeOnly(string keyword) { - var markup = $@" -using System; -class C -{{ - void M(String parameter) - {{ - {keyword} $$ - }} -}} -"; + var markup = $$""" + using System; + class C + { + void M(String parameter) + { + {{keyword}} $$ + } + } + """; await VerifyExpectedItemsAsync(markup, [ ItemExpectation.Exists("String"), ItemExpectation.Absent("parameter") @@ -2893,16 +3025,16 @@ await VerifyExpectedItemsAsync(markup, [ [InlineData("extern unsafe async static")] public async Task AfterLocalFunction_TypeOnly_Async(string keyword) { - var markup = $@" -using System; -class C -{{ - void M(String parameter) - {{ - {keyword} $$ - }} -}} -"; + var markup = $$""" + using System; + class C + { + void M(String parameter) + { + {{keyword}} $$ + } + } + """; await VerifyExpectedItemsAsync(markup, [ ItemExpectation.Absent("String"), ItemExpectation.Absent("parameter") @@ -2912,16 +3044,16 @@ await VerifyExpectedItemsAsync(markup, [ [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/60341")] public async Task AfterAsyncLocalFunctionWithTwoAsyncs() { - var markup = @" -using System; -class C -{ - void M(string parameter) - { - async async $$ - } -} -"; + var markup = """ + using System; + class C + { + void M(string parameter) + { + async async $$ + } + } + """; await VerifyExpectedItemsAsync(markup, [ ItemExpectation.Absent("String"), ItemExpectation.Absent("parameter") @@ -2938,16 +3070,16 @@ await VerifyExpectedItemsAsync(markup, [ [InlineData("int Function")] public async Task NotAfterReturnTypeInLocalFunction(string returnType) { - var markup = @$" -using System; -class C -{{ - void M(String parameter) - {{ - static {returnType} $$ - }} -}} -"; + var markup = $$""" + using System; + class C + { + void M(String parameter) + { + static {{returnType}} $$ + } + } + """; await VerifyExpectedItemsAsync(markup, [ ItemExpectation.Absent("String"), ItemExpectation.Absent("parameter") @@ -2957,14 +3089,14 @@ await VerifyExpectedItemsAsync(markup, [ [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/25569")] public async Task AfterRefInMemberContext_TypeOnly() { - var markup = @" -using System; -class C -{ - String field; - ref $$ -} -"; + var markup = """ + using System; + class C + { + String field; + ref $$ + } + """; await VerifyExpectedItemsAsync(markup, [ ItemExpectation.Exists("String"), ItemExpectation.Absent("field") @@ -2974,14 +3106,14 @@ await VerifyExpectedItemsAsync(markup, [ [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/25569")] public async Task AfterRefReadonlyInMemberContext_TypeOnly() { - var markup = @" -using System; -class C -{ - String field; - ref readonly $$ -} -"; + var markup = """ + using System; + class C + { + String field; + ref readonly $$ + } + """; await VerifyExpectedItemsAsync(markup, [ ItemExpectation.Exists("String"), ItemExpectation.Absent("field") @@ -2991,16 +3123,16 @@ await VerifyExpectedItemsAsync(markup, [ [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/539217")] public async Task NestedType1() { - var markup = @" -class Q -{ - $$ - class R - { + var markup = """ + class Q + { + $$ + class R + { - } -} -"; + } + } + """; await VerifyExpectedItemsAsync(markup, [ ItemExpectation.Exists("Q"), ItemExpectation.Exists("R") @@ -3010,15 +3142,15 @@ await VerifyExpectedItemsAsync(markup, [ [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/539217")] public async Task NestedType2() { - var markup = @" -class Q -{ - class R - { - $$ - } -} -"; + var markup = """ + class Q + { + class R + { + $$ + } + } + """; await VerifyExpectedItemsAsync(markup, [ ItemExpectation.Exists("Q"), ItemExpectation.Exists("R") @@ -3028,15 +3160,15 @@ await VerifyExpectedItemsAsync(markup, [ [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/539217")] public async Task NestedType3() { - var markup = @" -class Q -{ - class R - { - } - $$ -} -"; + var markup = """ + class Q + { + class R + { + } + $$ + } + """; await VerifyExpectedItemsAsync(markup, [ ItemExpectation.Exists("Q"), ItemExpectation.Exists("R") @@ -3046,14 +3178,15 @@ await VerifyExpectedItemsAsync(markup, [ [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/539217")] public async Task NestedType4_Regular() { - var markup = @" -class Q -{ - class R - { - } -} -$$"; // At EOF + var markup = """ + class Q + { + class R + { + } + } + $$ + """; // At EOF // Top-level statements are not allowed to follow classes, but we still offer it in completion for a few // reasons: @@ -3068,14 +3201,15 @@ class R [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/539217")] public async Task NestedType4_Script() { - var markup = @" -class Q -{ - class R - { - } -} -$$"; // At EOF + var markup = """ + class Q + { + class R + { + } + } + $$ + """; // At EOF await VerifyItemExistsAsync(markup, "Q", expectedDescriptionOrNull: null, sourceCodeKind: SourceCodeKind.Script); await VerifyItemIsAbsentAsync(markup, "R", expectedDescriptionOrNull: null, sourceCodeKind: SourceCodeKind.Script); } @@ -3083,13 +3217,14 @@ class R [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/539217")] public async Task NestedType5() { - var markup = @" -class Q -{ - class R - { - } - $$"; // At EOF + var markup = """ + class Q + { + class R + { + } + $$ + """; // At EOF await VerifyExpectedItemsAsync(markup, [ ItemExpectation.Exists("Q"), ItemExpectation.Exists("R") @@ -3099,12 +3234,13 @@ await VerifyExpectedItemsAsync(markup, [ [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/539217")] public async Task NestedType6() { - var markup = @" -class Q -{ - class R - { - $$"; // At EOF + var markup = """ + class Q + { + class R + { + $$ + """; // At EOF await VerifyExpectedItemsAsync(markup, [ ItemExpectation.Exists("Q"), ItemExpectation.Exists("R") @@ -3114,19 +3250,20 @@ await VerifyExpectedItemsAsync(markup, [ [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/540574")] public async Task AmbiguityBetweenTypeAndLocal() { - var markup = @" -using System; -using System.Collections.Generic; -using System.Linq; + var markup = """ + using System; + using System.Collections.Generic; + using System.Linq; -class Program -{ - public void goo() { - int i = 5; - i.$$ - List ml = new List(); - } -}"; + class Program + { + public void goo() { + int i = 5; + i.$$ + List ml = new List(); + } + } + """; await VerifyItemExistsAsync(markup, "CompareTo"); } @@ -3134,40 +3271,41 @@ public void goo() { [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/21596")] public async Task AmbiguityBetweenExpressionAndLocalFunctionReturnType() { - var markup = @" -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; + var markup = """ + using System; + using System.Collections.Generic; + using System.Linq; + using System.Text; + using System.Threading.Tasks; -class Program -{ - static void Main(string[] args) - { - AwaitTest test = new AwaitTest(); - test.Test1().Wait(); - } -} + class Program + { + static void Main(string[] args) + { + AwaitTest test = new AwaitTest(); + test.Test1().Wait(); + } + } -class AwaitTest -{ - List stringList = new List(); + class AwaitTest + { + List stringList = new List(); - public async Task Test1() - { - stringList.$$ + public async Task Test1() + { + stringList.$$ - await Test2(); + await Test2(); - return true; - } + return true; + } - public async Task Test2() - { - return true; - } -}"; + public async Task Test2() + { + return true; + } + } + """; await VerifyItemExistsAsync(markup, "Add"); } @@ -3175,10 +3313,11 @@ public async Task Test2() [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/540750")] public async Task CompletionAfterNewInScript() { - var markup = @" -using System; + var markup = """ + using System; -new $$"; + new $$ + """; await VerifyItemExistsAsync(markup, "String", expectedDescriptionOrNull: null, sourceCodeKind: SourceCodeKind.Script); } @@ -3186,10 +3325,11 @@ public async Task CompletionAfterNewInScript() [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/540933")] public async Task ExtensionMethodsInScript() { - var markup = @" -using System.Linq; -var a = new int[] { 1, 2 }; -a.$$"; + var markup = """ + using System.Linq; + var a = new int[] { 1, 2 }; + a.$$ + """; await VerifyItemExistsAsync(markup, "ElementAt", displayTextSuffix: "<>", expectedDescriptionOrNull: null, sourceCodeKind: SourceCodeKind.Script); } @@ -3197,14 +3337,14 @@ public async Task ExtensionMethodsInScript() [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/541019")] public async Task ExpressionsInForLoopInitializer() { - var markup = @" -public class C -{ - public void M() - { - int count = 0; - for ($$ -"; + var markup = """ + public class C + { + public void M() + { + int count = 0; + for ($$ + """; await VerifyItemExistsAsync(markup, "count"); } @@ -3212,15 +3352,15 @@ public void M() [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/541108")] public async Task AfterLambdaExpression1() { - var markup = @" -public class C -{ - public void M() - { - System.Func f = arg => { arg = 2; return arg; }.$$ - } -} -"; + var markup = """ + public class C + { + public void M() + { + System.Func f = arg => { arg = 2; return arg; }.$$ + } + } + """; await VerifyItemIsAbsentAsync(markup, "ToString"); } @@ -3228,15 +3368,15 @@ public void M() [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/541108")] public async Task AfterLambdaExpression2() { - var markup = @" -public class C -{ - public void M() - { - ((System.Func)(arg => { arg = 2; return arg; })).$$ - } -} -"; + var markup = """ + public class C + { + public void M() + { + ((System.Func)(arg => { arg = 2; return arg; })).$$ + } + } + """; await VerifyExpectedItemsAsync(markup, [ ItemExpectation.Exists("ToString"), @@ -3247,9 +3387,10 @@ await VerifyExpectedItemsAsync(markup, [ [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/541216")] public async Task InMultiLineCommentAtEndOfFile() { - var markup = @" -using System; -/*$$"; + var markup = """ + using System; + /*$$ + """; await VerifyItemIsAbsentAsync(markup, "Console", expectedDescriptionOrNull: null, sourceCodeKind: SourceCodeKind.Script); } @@ -3257,22 +3398,23 @@ public async Task InMultiLineCommentAtEndOfFile() [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/541218")] public async Task TypeParametersAtEndOfFile() { - var markup = @" -using System; -using System.Collections.Generic; -using System.Linq; + var markup = """ + using System; + using System.Collections.Generic; + using System.Linq; -class Outer -{ -class Inner -{ -static void F(T t, U u) -{ -return; -} -public static void F(T t) -{ -Outer<$$"; + class Outer + { + class Inner + { + static void F(T t, U u) + { + return; + } + public static void F(T t) + { + Outer<$$ + """; await VerifyItemExistsAsync(markup, "T"); } @@ -3280,16 +3422,17 @@ public static void F(T t) [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/552717")] public async Task LabelInCaseSwitchAbsentForCase() { - var markup = @" -class Program -{ - static void Main() - { - int x; - switch (x) - { - case 0: - goto $$"; + var markup = """ + class Program + { + static void Main() + { + int x; + switch (x) + { + case 0: + goto $$ + """; await VerifyItemIsAbsentAsync(markup, "case 0:"); } @@ -3297,16 +3440,17 @@ static void Main() [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/552717")] public async Task LabelInCaseSwitchAbsentForDefaultWhenAbsent() { - var markup = @" -class Program -{ - static void Main() - { - int x; - switch (x) - { - case 0: - goto $$"; + var markup = """ + class Program + { + static void Main() + { + int x; + switch (x) + { + case 0: + goto $$ + """; await VerifyItemIsAbsentAsync(markup, "default:"); } @@ -3314,16 +3458,17 @@ static void Main() [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/552717")] public async Task LabelInCaseSwitchPresentForDefault() { - var markup = @" -class Program -{ - static void Main() - { - int x; - switch (x) - { - default: - goto $$"; + var markup = """ + class Program + { + static void Main() + { + int x; + switch (x) + { + default: + goto $$ + """; await VerifyItemExistsAsync(markup, "default"); } @@ -3331,14 +3476,15 @@ static void Main() [Fact] public async Task LabelAfterGoto1() { - var markup = @" -class Program -{ - static void Main() - { - Goo: - int Goo; - goto $$"; + var markup = """ + class Program + { + static void Main() + { + Goo: + int Goo; + goto $$ + """; await VerifyItemExistsAsync(markup, "Goo"); } @@ -3346,14 +3492,15 @@ static void Main() [Fact] public async Task LabelAfterGoto2() { - var markup = @" -class Program -{ - static void Main() - { - Goo: - int Goo; - goto Goo $$"; + var markup = """ + class Program + { + static void Main() + { + Goo: + int Goo; + goto Goo $$ + """; await VerifyItemIsAbsentAsync(markup, "Goo"); } @@ -3361,9 +3508,10 @@ static void Main() [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/542225")] public async Task AttributeName() { - var markup = @" -using System; -[$$"; + var markup = """ + using System; + [$$ + """; await VerifyExpectedItemsAsync(markup, [ ItemExpectation.Exists("CLSCompliant"), @@ -3374,10 +3522,10 @@ await VerifyExpectedItemsAsync(markup, [ [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/542225")] public async Task AttributeNameAfterSpecifier() { - var markup = @" -using System; -[assembly:$$ -"; + var markup = """ + using System; + [assembly:$$ + """; await VerifyExpectedItemsAsync(markup, [ ItemExpectation.Exists("CLSCompliant"), @@ -3388,9 +3536,10 @@ await VerifyExpectedItemsAsync(markup, [ [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/542225")] public async Task AttributeNameInAttributeList() { - var markup = @" -using System; -[CLSCompliant, $$"; + var markup = """ + using System; + [CLSCompliant, $$ + """; await VerifyExpectedItemsAsync(markup, [ ItemExpectation.Exists("CLSCompliant"), @@ -3401,10 +3550,11 @@ await VerifyExpectedItemsAsync(markup, [ [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/542225")] public async Task AttributeNameBeforeClass() { - var markup = @" -using System; -[$$ -class C { }"; + var markup = """ + using System; + [$$ + class C { } + """; await VerifyExpectedItemsAsync(markup, [ ItemExpectation.Exists("CLSCompliant"), @@ -3415,10 +3565,11 @@ await VerifyExpectedItemsAsync(markup, [ [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/542225")] public async Task AttributeNameAfterSpecifierBeforeClass() { - var markup = @" -using System; -[assembly:$$ -class C { }"; + var markup = """ + using System; + [assembly:$$ + class C { } + """; await VerifyExpectedItemsAsync(markup, [ ItemExpectation.Exists("CLSCompliant"), @@ -3429,10 +3580,11 @@ await VerifyExpectedItemsAsync(markup, [ [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/542225")] public async Task AttributeNameInAttributeArgumentList() { - var markup = @" -using System; -[CLSCompliant($$ -class C { }"; + var markup = """ + using System; + [CLSCompliant($$ + class C { } + """; await VerifyExpectedItemsAsync(markup, [ ItemExpectation.Exists("CLSCompliantAttribute"), @@ -3443,9 +3595,10 @@ await VerifyExpectedItemsAsync(markup, [ [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/542225")] public async Task AttributeNameInsideClass() { - var markup = @" -using System; -class C { $$ }"; + var markup = """ + using System; + class C { $$ } + """; await VerifyExpectedItemsAsync(markup, [ ItemExpectation.Exists("CLSCompliantAttribute"), @@ -3456,11 +3609,12 @@ await VerifyExpectedItemsAsync(markup, [ [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/542954")] public async Task NamespaceAliasInAttributeName1() { - var markup = @" -using Alias = System; + var markup = """ + using Alias = System; -[$$ -class C { }"; + [$$ + class C { } + """; await VerifyItemExistsAsync(markup, "Alias"); } @@ -3468,13 +3622,14 @@ class C { }"; [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/542954")] public async Task NamespaceAliasInAttributeName2() { - var markup = @" -using Alias = Goo; + var markup = """ + using Alias = Goo; -namespace Goo { } + namespace Goo { } -[$$ -class C { }"; + [$$ + class C { } + """; await VerifyItemIsAbsentAsync(markup, "Alias"); } @@ -3482,13 +3637,14 @@ class C { }"; [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/542954")] public async Task NamespaceAliasInAttributeName3() { - var markup = @" -using Alias = Goo; + var markup = """ + using Alias = Goo; -namespace Goo { class A : System.Attribute { } } + namespace Goo { class A : System.Attribute { } } -[$$ -class C { }"; + [$$ + class C { } + """; await VerifyItemExistsAsync(markup, "Alias"); } @@ -3496,13 +3652,14 @@ class C { }"; [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/545121")] public async Task AttributeNameAfterNamespace() { - var markup = @" -namespace Test -{ - class MyAttribute : System.Attribute { } - [Test.$$ - class Program { } -}"; + var markup = """ + namespace Test + { + class MyAttribute : System.Attribute { } + [Test.$$ + class Program { } + } + """; await VerifyExpectedItemsAsync(markup, [ ItemExpectation.Exists("My"), ItemExpectation.Absent("MyAttribute") @@ -3512,16 +3669,17 @@ await VerifyExpectedItemsAsync(markup, [ [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/545121")] public async Task AttributeNameAfterNamespace2() { - var markup = @" -namespace Test -{ - namespace Two - { - class MyAttribute : System.Attribute { } - [Test.Two.$$ - class Program { } - } -}"; + var markup = """ + namespace Test + { + namespace Two + { + class MyAttribute : System.Attribute { } + [Test.Two.$$ + class Program { } + } + } + """; await VerifyExpectedItemsAsync(markup, [ ItemExpectation.Exists("My"), ItemExpectation.Absent("MyAttribute") @@ -3531,13 +3689,14 @@ await VerifyExpectedItemsAsync(markup, [ [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/545121")] public async Task AttributeNameWhenSuffixlessFormIsKeyword() { - var markup = @" -namespace Test -{ - class namespaceAttribute : System.Attribute { } - [$$ - class Program { } -}"; + var markup = """ + namespace Test + { + class namespaceAttribute : System.Attribute { } + [$$ + class Program { } + } + """; await VerifyExpectedItemsAsync(markup, [ ItemExpectation.Exists("namespaceAttribute"), ItemExpectation.Absent("namespace"), @@ -3548,13 +3707,14 @@ await VerifyExpectedItemsAsync(markup, [ [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/545121")] public async Task AttributeNameAfterNamespaceWhenSuffixlessFormIsKeyword() { - var markup = @" -namespace Test -{ - class namespaceAttribute : System.Attribute { } - [Test.$$ - class Program { } -}"; + var markup = """ + namespace Test + { + class namespaceAttribute : System.Attribute { } + [Test.$$ + class Program { } + } + """; await VerifyExpectedItemsAsync(markup, [ ItemExpectation.Exists("namespaceAttribute"), ItemExpectation.Absent("namespace"), @@ -3565,17 +3725,18 @@ await VerifyExpectedItemsAsync(markup, [ [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/545348")] public async Task KeywordsUsedAsLocals() { - var markup = @" -class C -{ - void M() - { - var error = 0; - var method = 0; - var @int = 0; - Console.Write($$ - } -}"; + var markup = """ + class C + { + void M() + { + var error = 0; + var method = 0; + var @int = 0; + Console.Write($$ + } + } + """; await VerifyExpectedItemsAsync(markup, [ // preprocessor keyword @@ -3595,15 +3756,16 @@ await VerifyExpectedItemsAsync(markup, [ [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/545348")] public async Task QueryContextualKeywords1() { - var markup = @" -class C -{ - void M() - { - var from = new[]{1,2,3}; - var r = from x in $$ - } -}"; + var markup = """ + class C + { + void M() + { + var from = new[]{1,2,3}; + var r = from x in $$ + } + } + """; await VerifyExpectedItemsAsync(markup, [ ItemExpectation.Exists("@from"), @@ -3614,17 +3776,18 @@ await VerifyExpectedItemsAsync(markup, [ [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/545348")] public async Task QueryContextualKeywords2() { - var markup = @" -class C -{ - void M() - { - var where = new[] { 1, 2, 3 }; - var x = from @from in @where - where $$ == @where.Length - select @from; - } -}"; + var markup = """ + class C + { + void M() + { + var where = new[] { 1, 2, 3 }; + var x = from @from in @where + where $$ == @where.Length + select @from; + } + } + """; await VerifyExpectedItemsAsync(markup, [ ItemExpectation.Exists("@from"), @@ -3637,17 +3800,18 @@ await VerifyExpectedItemsAsync(markup, [ [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/545348")] public async Task QueryContextualKeywords3() { - var markup = @" -class C -{ - void M() - { - var where = new[] { 1, 2, 3 }; - var x = from @from in @where - where @from == @where.Length - select $$; - } -}"; + var markup = """ + class C + { + void M() + { + var where = new[] { 1, 2, 3 }; + var x = from @from in @where + where @from == @where.Length + select $$; + } + } + """; await VerifyExpectedItemsAsync(markup, [ ItemExpectation.Exists("@from"), @@ -3660,10 +3824,11 @@ await VerifyExpectedItemsAsync(markup, [ [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/545121")] public async Task AttributeNameAfterGlobalAlias() { - var markup = @" -class MyAttribute : System.Attribute { } -[global::$$ -class Program { }"; + var markup = """ + class MyAttribute : System.Attribute { } + [global::$$ + class Program { } + """; await VerifyExpectedItemsAsync( markup, [ ItemExpectation.Exists("My"), @@ -3675,10 +3840,11 @@ await VerifyExpectedItemsAsync( [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/545121")] public async Task AttributeNameAfterGlobalAliasWhenSuffixlessFormIsKeyword() { - var markup = @" -class namespaceAttribute : System.Attribute { } -[global::$$ -class Program { }"; + var markup = """ + class namespaceAttribute : System.Attribute { } + [global::$$ + class Program { } + """; await VerifyExpectedItemsAsync( markup, [ ItemExpectation.Exists("namespaceAttribute"), @@ -3691,28 +3857,30 @@ await VerifyExpectedItemsAsync( [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/25589")] public async Task AttributeSearch_NamespaceWithNestedAttribute1() { - var markup = @" -namespace Namespace1 -{ - namespace Namespace2 { class NonAttribute { } } - namespace Namespace3.Namespace4 { class CustomAttribute : System.Attribute { } } -} + var markup = """ + namespace Namespace1 + { + namespace Namespace2 { class NonAttribute { } } + namespace Namespace3.Namespace4 { class CustomAttribute : System.Attribute { } } + } -[$$]"; + [$$] + """; await VerifyItemExistsAsync(markup, "Namespace1"); } [Fact] public async Task AttributeSearch_NamespaceWithNestedAttribute2() { - var markup = @" -namespace Namespace1 -{ - namespace Namespace2 { class NonAttribute { } } - namespace Namespace3.Namespace4 { class CustomAttribute : System.Attribute { } } -} + var markup = """ + namespace Namespace1 + { + namespace Namespace2 { class NonAttribute { } } + namespace Namespace3.Namespace4 { class CustomAttribute : System.Attribute { } } + } -[Namespace1.$$]"; + [Namespace1.$$] + """; await VerifyExpectedItemsAsync(markup, [ ItemExpectation.Absent("Namespace2"), ItemExpectation.Exists("Namespace3"), @@ -3722,47 +3890,50 @@ await VerifyExpectedItemsAsync(markup, [ [Fact] public async Task AttributeSearch_NamespaceWithNestedAttribute3() { - var markup = @" -namespace Namespace1 -{ - namespace Namespace2 { class NonAttribute { } } - namespace Namespace3.Namespace4 { class CustomAttribute : System.Attribute { } } -} + var markup = """ + namespace Namespace1 + { + namespace Namespace2 { class NonAttribute { } } + namespace Namespace3.Namespace4 { class CustomAttribute : System.Attribute { } } + } -[Namespace1.Namespace3.$$]"; + [Namespace1.Namespace3.$$] + """; await VerifyItemExistsAsync(markup, "Namespace4"); } [Fact] public async Task AttributeSearch_NamespaceWithNestedAttribute4() { - var markup = @" -namespace Namespace1 -{ - namespace Namespace2 { class NonAttribute { } } - namespace Namespace3.Namespace4 { class CustomAttribute : System.Attribute { } } -} - -[Namespace1.Namespace3.Namespace4.$$]"; + var markup = """ + namespace Namespace1 + { + namespace Namespace2 { class NonAttribute { } } + namespace Namespace3.Namespace4 { class CustomAttribute : System.Attribute { } } + } + + [Namespace1.Namespace3.Namespace4.$$] + """; await VerifyItemExistsAsync(markup, "Custom"); } [Fact] public async Task AttributeSearch_NamespaceWithNestedAttribute_NamespaceAlias() { - var markup = @" -using Namespace1Alias = Namespace1; -using Namespace2Alias = Namespace1.Namespace2; -using Namespace3Alias = Namespace1.Namespace3; -using Namespace4Alias = Namespace1.Namespace3.Namespace4; + var markup = """ + using Namespace1Alias = Namespace1; + using Namespace2Alias = Namespace1.Namespace2; + using Namespace3Alias = Namespace1.Namespace3; + using Namespace4Alias = Namespace1.Namespace3.Namespace4; -namespace Namespace1 -{ - namespace Namespace2 { class NonAttribute { } } - namespace Namespace3.Namespace4 { class CustomAttribute : System.Attribute { } } -} + namespace Namespace1 + { + namespace Namespace2 { class NonAttribute { } } + namespace Namespace3.Namespace4 { class CustomAttribute : System.Attribute { } } + } -[$$]"; + [$$] + """; await VerifyExpectedItemsAsync(markup, [ ItemExpectation.Exists("Namespace1Alias"), ItemExpectation.Absent("Namespace2Alias"), @@ -3774,29 +3945,31 @@ await VerifyExpectedItemsAsync(markup, [ [Fact] public async Task AttributeSearch_NamespaceWithoutNestedAttribute() { - var markup = @" -namespace Namespace1 -{ - namespace Namespace2 { class NonAttribute { } } - namespace Namespace3.Namespace4 { class NonAttribute : System.NonAttribute { } } -} + var markup = """ + namespace Namespace1 + { + namespace Namespace2 { class NonAttribute { } } + namespace Namespace3.Namespace4 { class NonAttribute : System.NonAttribute { } } + } -[$$]"; + [$$] + """; await VerifyItemIsAbsentAsync(markup, "Namespace1"); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/542230")] public async Task RangeVariableInQuerySelect() { - var markup = @" -using System.Linq; -class P -{ - void M() - { - var src = new string[] { ""Goo"", ""Bar"" }; - var q = from x in src - select x.$$"; + var markup = """ + using System.Linq; + class P + { + void M() + { + var src = new string[] { "Goo", "Bar" }; + var q = from x in src + select x.$$ + """; await VerifyItemExistsAsync(markup, "Length"); } @@ -3804,14 +3977,15 @@ void M() [Fact] public async Task ConstantsInIsExpression() { - var markup = @" -class C -{ - public const int MAX_SIZE = 10; - void M() - { - int i = 10; - if (i is $$ int"; // 'int' to force this to be parsed as an IsExpression rather than IsPatternExpression + var markup = """ + class C + { + public const int MAX_SIZE = 10; + void M() + { + int i = 10; + if (i is $$ int + """; // 'int' to force this to be parsed as an IsExpression rather than IsPatternExpression await VerifyItemExistsAsync(markup, "MAX_SIZE"); } @@ -3819,14 +3993,15 @@ void M() [Fact] public async Task ConstantsInIsPatternExpression() { - var markup = @" -class C -{ - public const int MAX_SIZE = 10; - void M() - { - int i = 10; - if (i is $$ 1"; + var markup = """ + class C + { + public const int MAX_SIZE = 10; + void M() + { + int i = 10; + if (i is $$ 1 + """; await VerifyItemExistsAsync(markup, "MAX_SIZE"); } @@ -3834,16 +4009,17 @@ void M() [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/542429")] public async Task ConstantsInSwitchCase() { - var markup = @" -class C -{ - public const int MAX_SIZE = 10; - void M() - { - int i = 10; - switch (i) - { - case $$"; + var markup = """ + class C + { + public const int MAX_SIZE = 10; + void M() + { + int i = 10; + switch (i) + { + case $$ + """; await VerifyItemExistsAsync(markup, "MAX_SIZE"); } @@ -3851,16 +4027,17 @@ void M() [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/25084#issuecomment-370148553")] public async Task ConstantsInSwitchPatternCase() { - var markup = @" -class C -{ - public const int MAX_SIZE = 10; - void M() - { - int i = 10; - switch (i) - { - case $$ when"; + var markup = """ + class C + { + public const int MAX_SIZE = 10; + void M() + { + int i = 10; + switch (i) + { + case $$ when + """; await VerifyItemExistsAsync(markup, "MAX_SIZE"); } @@ -3868,19 +4045,20 @@ void M() [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/542429")] public async Task ConstantsInSwitchGotoCase() { - var markup = @" -class C -{ - public const int MAX_SIZE = 10; - void M() - { - int i = 10; - switch (i) - { - case MAX_SIZE: - break; - case GOO: - goto case $$"; + var markup = """ + class C + { + public const int MAX_SIZE = 10; + void M() + { + int i = 10; + switch (i) + { + case MAX_SIZE: + break; + case GOO: + goto case $$ + """; await VerifyItemExistsAsync(markup, "MAX_SIZE"); } @@ -3888,13 +4066,14 @@ void M() [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/542429")] public async Task ConstantsInEnumMember() { - var markup = @" -class C -{ - public const int GOO = 0; - enum E - { - A = $$"; + var markup = """ + class C + { + public const int GOO = 0; + enum E + { + A = $$ + """; await VerifyItemExistsAsync(markup, "GOO"); } @@ -3902,11 +4081,12 @@ enum E [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/542429")] public async Task ConstantsInAttribute1() { - var markup = @" -class C -{ - public const int GOO = 0; - [System.AttributeUsage($$"; + var markup = """ + class C + { + public const int GOO = 0; + [System.AttributeUsage($$ + """; await VerifyItemExistsAsync(markup, "GOO"); } @@ -3914,11 +4094,12 @@ class C [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/542429")] public async Task ConstantsInAttribute2() { - var markup = @" -class C -{ - public const int GOO = 0; - [System.AttributeUsage(GOO, $$"; + var markup = """ + class C + { + public const int GOO = 0; + [System.AttributeUsage(GOO, $$ + """; await VerifyItemExistsAsync(markup, "GOO"); } @@ -3926,11 +4107,12 @@ class C [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/542429")] public async Task ConstantsInAttribute3() { - var markup = @" -class C -{ - public const int GOO = 0; - [System.AttributeUsage(validOn: $$"; + var markup = """ + class C + { + public const int GOO = 0; + [System.AttributeUsage(validOn: $$ + """; await VerifyItemExistsAsync(markup, "GOO"); } @@ -3938,11 +4120,12 @@ class C [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/542429")] public async Task ConstantsInAttribute4() { - var markup = @" -class C -{ - public const int GOO = 0; - [System.AttributeUsage(AllowMultiple = $$"; + var markup = """ + class C + { + public const int GOO = 0; + [System.AttributeUsage(AllowMultiple = $$ + """; await VerifyItemExistsAsync(markup, "GOO"); } @@ -3950,11 +4133,12 @@ class C [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/542429")] public async Task ConstantsInParameterDefaultValue() { - var markup = @" -class C -{ - public const int GOO = 0; - void M(int x = $$"; + var markup = """ + class C + { + public const int GOO = 0; + void M(int x = $$ + """; await VerifyItemExistsAsync(markup, "GOO"); } @@ -3962,11 +4146,12 @@ class C [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/542429")] public async Task ConstantsInConstField() { - var markup = @" -class C -{ - public const int GOO = 0; - const int BAR = $$"; + var markup = """ + class C + { + public const int GOO = 0; + const int BAR = $$ + """; await VerifyItemExistsAsync(markup, "GOO"); } @@ -3974,13 +4159,14 @@ class C [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/542429")] public async Task ConstantsInConstLocal() { - var markup = @" -class C -{ - public const int GOO = 0; - void M() - { - const int BAR = $$"; + var markup = """ + class C + { + public const int GOO = 0; + void M() + { + const int BAR = $$ + """; await VerifyItemExistsAsync(markup, "GOO"); } @@ -3988,13 +4174,14 @@ void M() [Fact] public async Task DescriptionWith1Overload() { - var markup = @" -class C -{ - void M(int i) { } - void M() - { - $$"; + var markup = """ + class C + { + void M(int i) { } + void M() + { + $$ + """; await VerifyItemExistsAsync(markup, "M", expectedDescriptionOrNull: $"void C.M(int i) (+ 1 {FeaturesResources.overload})"); } @@ -4002,14 +4189,15 @@ void M() [Fact] public async Task DescriptionWith2Overloads() { - var markup = @" -class C -{ - void M(int i) { } - void M(out int i) { } - void M() - { - $$"; + var markup = """ + class C + { + void M(int i) { } + void M(out int i) { } + void M() + { + $$ + """; await VerifyItemExistsAsync(markup, "M", expectedDescriptionOrNull: $"void C.M(int i) (+ 2 {FeaturesResources.overloads_})"); } @@ -4017,13 +4205,14 @@ void M() [Fact] public async Task DescriptionWith1GenericOverload() { - var markup = @" -class C -{ - void M(T i) { } - void M() - { - $$"; + var markup = """ + class C + { + void M(T i) { } + void M() + { + $$ + """; await VerifyItemExistsAsync(markup, "M", displayTextSuffix: "<>", expectedDescriptionOrNull: $"void C.M(T i) (+ 1 {FeaturesResources.generic_overload})"); } @@ -4031,14 +4220,15 @@ void M() [Fact] public async Task DescriptionWith2GenericOverloads() { - var markup = @" -class C -{ - void M(int i) { } - void M(out int i) { } - void M() - { - $$"; + var markup = """ + class C + { + void M(int i) { } + void M(out int i) { } + void M() + { + $$ + """; await VerifyItemExistsAsync(markup, "M", displayTextSuffix: "<>", expectedDescriptionOrNull: $"void C.M(int i) (+ 2 {FeaturesResources.generic_overloads})"); } @@ -4046,12 +4236,13 @@ void M() [Fact] public async Task DescriptionNamedGenericType() { - var markup = @" -class C -{ - void M() - { - $$"; + var markup = """ + class C + { + void M() + { + $$ + """; await VerifyItemExistsAsync(markup, "C", displayTextSuffix: "<>", expectedDescriptionOrNull: "class C"); } @@ -4059,12 +4250,13 @@ void M() [Fact] public async Task DescriptionParameter() { - var markup = @" -class C -{ - void M(T goo) - { - $$"; + var markup = """ + class C + { + void M(T goo) + { + $$ + """; await VerifyItemExistsAsync(markup, "goo", expectedDescriptionOrNull: $"({FeaturesResources.parameter}) T goo"); } @@ -4072,12 +4264,13 @@ void M(T goo) [Fact] public async Task DescriptionGenericTypeParameter() { - var markup = @" -class C -{ - void M() - { - $$"; + var markup = """ + class C + { + void M() + { + $$ + """; await VerifyItemExistsAsync(markup, "T", expectedDescriptionOrNull: $"T {FeaturesResources.in_} C"); } @@ -4085,20 +4278,22 @@ void M() [Fact] public async Task DescriptionAnonymousType() { - var markup = @" -class C -{ - void M() - { - var a = new { }; - $$ -"; + var markup = """ + class C + { + void M() + { + var a = new { }; + $$ + """; var expectedDescription = -$@"({FeaturesResources.local_variable}) 'a a + $$""" + ({{FeaturesResources.local_variable}}) 'a a -{FeaturesResources.Types_colon} - 'a {FeaturesResources.is_} new {{ }}"; + {{FeaturesResources.Types_colon}} + 'a {{FeaturesResources.is_}} new { } + """; await VerifyItemExistsAsync(markup, "a", expectedDescription); } @@ -4106,14 +4301,14 @@ void M() [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/543288")] public async Task AfterNewInAnonymousType() { - var markup = @" -class Program { - string field = 0; - static void Main() { - var an = new { new $$ }; - } -} -"; + var markup = """ + class Program { + string field = 0; + static void Main() { + var an = new { new $$ }; + } + } + """; await VerifyItemExistsAsync(markup, "Program"); } @@ -4121,16 +4316,16 @@ static void Main() { [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/543601")] public async Task NoInstanceFieldsInStaticMethod() { - var markup = @" -class C -{ - int x = 0; - static void M() - { - $$ - } -} -"; + var markup = """ + class C + { + int x = 0; + static void M() + { + $$ + } + } + """; await VerifyItemIsAbsentAsync(markup, "x"); } @@ -4138,13 +4333,13 @@ static void M() [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/543601")] public async Task NoInstanceFieldsInStaticFieldInitializer() { - var markup = @" -class C -{ - int x = 0; - static int y = $$ -} -"; + var markup = """ + class C + { + int x = 0; + static int y = $$ + } + """; await VerifyItemIsAbsentAsync(markup, "x"); } @@ -4152,16 +4347,16 @@ class C [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/543601")] public async Task StaticFieldsInStaticMethod() { - var markup = @" -class C -{ - static int x = 0; - static void M() - { - $$ - } -} -"; + var markup = """ + class C + { + static int x = 0; + static void M() + { + $$ + } + } + """; await VerifyItemExistsAsync(markup, "x"); } @@ -4169,13 +4364,13 @@ static void M() [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/543601")] public async Task StaticFieldsInStaticFieldInitializer() { - var markup = @" -class C -{ - static int x = 0; - static int y = $$ -} -"; + var markup = """ + class C + { + static int x = 0; + static int y = $$ + } + """; await VerifyItemExistsAsync(markup, "x"); } @@ -4183,19 +4378,19 @@ class C [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/543680")] public async Task NoInstanceFieldsFromOuterClassInInstanceMethod() { - var markup = @" -class outer -{ - int i; - class inner - { - void M() - { - $$ - } - } -} -"; + var markup = """ + class outer + { + int i; + class inner + { + void M() + { + $$ + } + } + } + """; await VerifyItemIsAbsentAsync(markup, "i"); } @@ -4203,19 +4398,19 @@ void M() [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/543680")] public async Task StaticFieldsFromOuterClassInInstanceMethod() { - var markup = @" -class outer -{ - static int i; - class inner - { - void M() - { - $$ - } - } -} -"; + var markup = """ + class outer + { + static int i; + class inner + { + void M() + { + $$ + } + } + } + """; await VerifyItemExistsAsync(markup, "i"); } @@ -4223,16 +4418,16 @@ void M() [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/543104")] public async Task OnlyEnumMembersInEnumMemberAccess() { - var markup = @" -class C -{ - enum x {a,b,c} - void M() - { - x.$$ - } -} -"; + var markup = """ + class C + { + enum x {a,b,c} + void M() + { + x.$$ + } + } + """; await VerifyExpectedItemsAsync(markup, [ ItemExpectation.Exists("a"), @@ -4245,18 +4440,18 @@ await VerifyExpectedItemsAsync(markup, [ [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/543104")] public async Task NoEnumMembersInEnumLocalAccess() { - var markup = @" -class C -{ - enum x {a,b,c} - void M() - { - var y = x.a; - y.$$ - } -} -"; - + var markup = """ + class C + { + enum x {a,b,c} + void M() + { + var y = x.a; + y.$$ + } + } + """; + await VerifyExpectedItemsAsync(markup, [ ItemExpectation.Absent("a"), ItemExpectation.Absent("b"), @@ -4268,22 +4463,22 @@ await VerifyExpectedItemsAsync(markup, [ [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/529138")] public async Task AfterLambdaParameterDot() { - var markup = @" -using System; -using System.Linq; -class A -{ - public event Func E; -} - -class Program -{ - static void Main(string[] args) - { - new A().E += ss => ss.$$ - } -} -"; + var markup = """ + using System; + using System.Linq; + class A + { + public event Func E; + } + + class Program + { + static void Main(string[] args) + { + new A().E += ss => ss.$$ + } + } + """; await VerifyItemExistsAsync(markup, "Substring"); } @@ -4291,20 +4486,21 @@ static void Main(string[] args) [Fact, WorkItem(61343, "https://github.com/dotnet/roslyn/issues/61343")] public async Task LambdaParameterMemberAccessOverloads() { - var markup = @" -using System.Linq; + var markup = """ + using System.Linq; -public class C -{ - public void M() { } - public void M(int i) { } - public int P { get; } + public class C + { + public void M() { } + public void M(int i) { } + public int P { get; } - void Test() - { - new C[0].Select(x => x.$$) - } -}"; + void Test() + { + new C[0].Select(x => x.$$) + } + } + """; await VerifyItemExistsAsync(markup, "M", expectedDescriptionOrNull: $"void C.M() (+ 1 {FeaturesResources.overload})"); await VerifyItemExistsAsync(markup, "P", expectedDescriptionOrNull: "int C.P { get; }"); @@ -4323,8 +4519,10 @@ await VerifyItemIsAbsentAsync( public async Task ValueNotAfterClass_Interactive() { await VerifyItemIsAbsentAsync( -@"class C { } -$$", + """ + class C { } + $$ + """, "value", expectedDescriptionOrNull: null, sourceCodeKind: SourceCodeKind.Script); } @@ -4333,8 +4531,10 @@ await VerifyItemIsAbsentAsync( public async Task ValueNotAfterGlobalStatement_Interactive() { await VerifyItemIsAbsentAsync( -@"System.Console.WriteLine(); -$$", + """ + System.Console.WriteLine(); + $$ + """, "value", expectedDescriptionOrNull: null, sourceCodeKind: SourceCodeKind.Script); } @@ -4343,8 +4543,10 @@ await VerifyItemIsAbsentAsync( public async Task ValueNotAfterGlobalVariableDeclaration_Interactive() { await VerifyItemIsAbsentAsync( -@"int i = 0; -$$", + """ + int i = 0; + $$ + """, "value", expectedDescriptionOrNull: null, sourceCodeKind: SourceCodeKind.Script); } @@ -4369,10 +4571,12 @@ await VerifyItemIsAbsentAsync(AddInsideMethod( public async Task ValueInsideSetter() { await VerifyItemExistsAsync( -@"class C { - int Goo { - set { - $$", + """ + class C { + int Goo { + set { + $$ + """, "value"); } @@ -4380,10 +4584,12 @@ int Goo { public async Task ValueInsideAdder() { await VerifyItemExistsAsync( -@"class C { - event int Goo { - add { - $$", + """ + class C { + event int Goo { + add { + $$ + """, "value"); } @@ -4391,10 +4597,12 @@ event int Goo { public async Task ValueInsideRemover() { await VerifyItemExistsAsync( -@"class C { - event int Goo { - remove { - $$", + """ + class C { + event int Goo { + remove { + $$ + """, "value"); } @@ -4402,10 +4610,12 @@ event int Goo { public async Task ValueNotAfterDot() { await VerifyItemIsAbsentAsync( -@"class C { - int Goo { - set { - this.$$", + """ + class C { + int Goo { + set { + this.$$ + """, "value"); } @@ -4413,10 +4623,12 @@ int Goo { public async Task ValueNotAfterArrow() { await VerifyItemIsAbsentAsync( -@"class C { - int Goo { - set { - a->$$", + """ + class C { + int Goo { + set { + a->$$ + """, "value"); } @@ -4424,10 +4636,12 @@ int Goo { public async Task ValueNotAfterColonColon() { await VerifyItemIsAbsentAsync( -@"class C { - int Goo { - set { - a::$$", + """ + class C { + int Goo { + set { + a::$$ + """, "value"); } @@ -4435,10 +4649,12 @@ int Goo { public async Task ValueNotInGetter() { await VerifyItemIsAbsentAsync( -@"class C { - int Goo { - get { - $$", + """ + class C { + int Goo { + get { + $$ + """, "value"); } @@ -4446,10 +4662,12 @@ int Goo { public async Task NotAfterNullableType() { await VerifyItemIsAbsentAsync( -@"class C { - void M() { - int goo = 0; - C? $$", + """ + class C { + void M() { + int goo = 0; + C? $$ + """, "goo"); } @@ -4457,11 +4675,13 @@ void M() { public async Task NotAfterNullableTypeAlias() { await VerifyItemIsAbsentAsync( -@"using A = System.Int32; -class C { - void M() { - int goo = 0; - A? $$", + """ + using A = System.Int32; + class C { + void M() { + int goo = 0; + A? $$ + """, "goo"); } @@ -4470,10 +4690,12 @@ void M() { public async Task NotAfterNullableTypeAndPartialIdentifier() { await VerifyItemIsAbsentAsync( -@"class C { - void M() { - int goo = 0; - C? f$$", + """ + class C { + void M() { + int goo = 0; + C? f$$ + """, "goo"); } @@ -4481,11 +4703,13 @@ void M() { public async Task AfterQuestionMarkInConditional() { await VerifyItemExistsAsync( -@"class C { - void M() { - bool b = false; - int goo = 0; - b? $$", + """ + class C { + void M() { + bool b = false; + int goo = 0; + b? $$ + """, "goo"); } @@ -4493,11 +4717,13 @@ void M() { public async Task AfterQuestionMarkAndPartialIdentifierInConditional() { await VerifyItemExistsAsync( -@"class C { - void M() { - bool b = false; - int goo = 0; - b? f$$", + """ + class C { + void M() { + bool b = false; + int goo = 0; + b? f$$ + """, "goo"); } @@ -4505,10 +4731,12 @@ void M() { public async Task NotAfterPointerType() { await VerifyItemIsAbsentAsync( -@"class C { - void M() { - int goo = 0; - C* $$", + """ + class C { + void M() { + int goo = 0; + C* $$ + """, "goo"); } @@ -4516,11 +4744,13 @@ void M() { public async Task NotAfterPointerTypeAlias() { await VerifyItemIsAbsentAsync( -@"using A = System.Int32; -class C { - void M() { - int goo = 0; - A* $$", + """ + using A = System.Int32; + class C { + void M() { + int goo = 0; + A* $$ + """, "goo"); } @@ -4528,10 +4758,12 @@ void M() { public async Task NotAfterPointerTypeAndPartialIdentifier() { await VerifyItemIsAbsentAsync( -@"class C { - void M() { - int goo = 0; - C* f$$", + """ + class C { + void M() { + int goo = 0; + C* f$$ + """, "goo"); } @@ -4539,11 +4771,13 @@ void M() { public async Task AfterAsteriskInMultiplication() { await VerifyItemExistsAsync( -@"class C { - void M() { - int i = 0; - int goo = 0; - i* $$", + """ + class C { + void M() { + int i = 0; + int goo = 0; + i* $$ + """, "goo"); } @@ -4551,11 +4785,13 @@ void M() { public async Task AfterAsteriskAndPartialIdentifierInMultiplication() { await VerifyItemExistsAsync( -@"class C { - void M() { - int i = 0; - int goo = 0; - i* f$$", + """ + class C { + void M() { + int i = 0; + int goo = 0; + i* f$$ + """, "goo"); } @@ -4563,10 +4799,12 @@ void M() { public async Task AfterEventFieldDeclaredInSameType() { await VerifyItemExistsAsync( -@"class C { - public event System.EventHandler E; - void M() { - E.$$", + """ + class C { + public event System.EventHandler E; + void M() { + E.$$ + """, "Invoke"); } @@ -4574,10 +4812,12 @@ void M() { public async Task NotAfterFullEventDeclaredInSameType() { await VerifyItemIsAbsentAsync( -@"class C { - public event System.EventHandler E { add { } remove { } } - void M() { - E.$$", + """ + class C { + public event System.EventHandler E { add { } remove { } } + void M() { + E.$$ + """, "Invoke"); } @@ -4585,9 +4825,11 @@ void M() { public async Task NotAfterEventDeclaredInDifferentType() { await VerifyItemIsAbsentAsync( -@"class C { - void M() { - System.Console.CancelKeyPress.$$", + """ + class C { + void M() { + System.Console.CancelKeyPress.$$ + """, "Invoke"); } @@ -4595,13 +4837,14 @@ void M() { [WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/544219")] public async Task NotInObjectInitializerMemberContext() { - await VerifyItemIsAbsentAsync(@" -class C -{ - public int x, y; - void M() - { - var c = new C { x = 2, y = 3, $$", + await VerifyItemIsAbsentAsync(""" + class C + { + public int x, y; + void M() + { + var c = new C { x = 2, y = 3, $$ + """, "x"); } @@ -4609,20 +4852,21 @@ void M() [WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/544219")] public async Task AfterPointerMemberAccess() { - await VerifyItemExistsAsync(@" -struct MyStruct -{ - public int MyField; -} + await VerifyItemExistsAsync(""" + struct MyStruct + { + public int MyField; + } -class Program -{ - static unsafe void Main(string[] args) - { - MyStruct s = new MyStruct(); - MyStruct* ptr = &s; - ptr->$$ - }}", + class Program + { + static unsafe void Main(string[] args) + { + MyStruct s = new MyStruct(); + MyStruct* ptr = &s; + ptr->$$ + }} + """, "MyField"); } @@ -4632,18 +4876,18 @@ static unsafe void Main(string[] args) [WorkItem(11931, "DevDiv_Projects/Roslyn")] public async Task VerbatimAttributes() { - var code = @" -using System; -public class X : Attribute -{ } - -public class XAttribute : Attribute -{ } - - -[@X$$] -class Class3 { } -"; + var code = """ + using System; + public class X : Attribute + { } + + public class XAttribute : Attribute + { } + + + [@X$$] + class Class3 { } + """; await VerifyItemExistsAsync(code, "X"); await Assert.ThrowsAsync(() => VerifyItemExistsAsync(code, "XAttribute")); } @@ -4652,176 +4896,184 @@ class Class3 { } [WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/544928")] public async Task InForLoopIncrementor1() { - await VerifyItemExistsAsync(@" -using System; - -class Program -{ - static void Main() - { - for (; ; $$ - } -} -", "Console"); + await VerifyItemExistsAsync(""" + using System; + + class Program + { + static void Main() + { + for (; ; $$ + } + } + """, "Console"); } [Fact, Trait(Traits.Feature, Traits.Features.KeywordRecommending)] [WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/544928")] public async Task InForLoopIncrementor2() { - await VerifyItemExistsAsync(@" -using System; - -class Program -{ - static void Main() - { - for (; ; Console.WriteLine(), $$ - } -} -", "Console"); + await VerifyItemExistsAsync(""" + using System; + + class Program + { + static void Main() + { + for (; ; Console.WriteLine(), $$ + } + } + """, "Console"); } [Fact, Trait(Traits.Feature, Traits.Features.KeywordRecommending)] [WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/544931")] public async Task InForLoopInitializer1() { - await VerifyItemExistsAsync(@" -using System; - -class Program -{ - static void Main() - { - for ($$ - } -} -", "Console"); + await VerifyItemExistsAsync(""" + using System; + + class Program + { + static void Main() + { + for ($$ + } + } + """, "Console"); } [Fact, Trait(Traits.Feature, Traits.Features.KeywordRecommending)] [WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/544931")] public async Task InForLoopInitializer2() { - await VerifyItemExistsAsync(@" -using System; - -class Program -{ - static void Main() - { - for (Console.WriteLine(), $$ - } -} -", "Console"); + await VerifyItemExistsAsync(""" + using System; + + class Program + { + static void Main() + { + for (Console.WriteLine(), $$ + } + } + """, "Console"); } [Fact, WorkItem(10572, "DevDiv_Projects/Roslyn")] public async Task LocalVariableInItsDeclaration() { // "int goo = goo = 1" is a legal declaration - await VerifyItemExistsAsync(@" -class Program -{ - void M() - { - int goo = $$ - } -}", "goo"); + await VerifyItemExistsAsync(""" + class Program + { + void M() + { + int goo = $$ + } + } + """, "goo"); } [Fact, WorkItem(10572, "DevDiv_Projects/Roslyn")] public async Task LocalVariableInItsDeclarator() { // "int bar = bar = 1" is legal in a declarator - await VerifyItemExistsAsync(@" -class Program -{ - void M() - { - int goo = 0, int bar = $$, int baz = 0; - } -}", "bar"); + await VerifyItemExistsAsync(""" + class Program + { + void M() + { + int goo = 0, int bar = $$, int baz = 0; + } + } + """, "bar"); } [Fact, WorkItem(10572, "DevDiv_Projects/Roslyn")] public async Task LocalVariableNotBeforeDeclaration() { - await VerifyItemIsAbsentAsync(@" -class Program -{ - void M() - { - $$ - int goo = 0; - } -}", "goo"); + await VerifyItemIsAbsentAsync(""" + class Program + { + void M() + { + $$ + int goo = 0; + } + } + """, "goo"); } [Fact, WorkItem(10572, "DevDiv_Projects/Roslyn")] public async Task LocalVariableNotBeforeDeclarator() { - await VerifyItemIsAbsentAsync(@" -class Program -{ - void M() - { - int goo = $$, bar = 0; - } -}", "bar"); + await VerifyItemIsAbsentAsync(""" + class Program + { + void M() + { + int goo = $$, bar = 0; + } + } + """, "bar"); } [Fact, WorkItem(10572, "DevDiv_Projects/Roslyn")] public async Task LocalVariableAfterDeclarator() { - await VerifyItemExistsAsync(@" -class Program -{ - void M() - { - int goo = 0, int bar = $$ - } -}", "goo"); + await VerifyItemExistsAsync(""" + class Program + { + void M() + { + int goo = 0, int bar = $$ + } + } + """, "goo"); } [Fact, WorkItem(10572, "DevDiv_Projects/Roslyn")] public async Task LocalVariableAsOutArgumentInInitializerExpression() { - await VerifyItemExistsAsync(@" -class Program -{ - void M() - { - int goo = Bar(out $$ - } - int Bar(out int x) - { - x = 3; - return 5; - } -}", "goo"); + await VerifyItemExistsAsync(""" + class Program + { + void M() + { + int goo = Bar(out $$ + } + int Bar(out int x) + { + x = 3; + return 5; + } + } + """, "goo"); } [Fact, WorkItem(7336, "DevDiv_Projects/Roslyn")] public async Task EditorBrowsable_Method_BrowsableStateAlways() { - var markup = @" -class Program -{ - void M() - { - Goo.$$ - } -}"; + var markup = """ + class Program + { + void M() + { + Goo.$$ + } + } + """; - var referencedCode = @" -public class Goo -{ - [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Always)] - public static void Bar() - { - } -}"; + var referencedCode = """ + public class Goo + { + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Always)] + public static void Bar() + { + } + } + """; await VerifyItemInEditorBrowsableContextsAsync( markup: markup, referencedCode: referencedCode, @@ -4835,23 +5087,25 @@ await VerifyItemInEditorBrowsableContextsAsync( [Fact, WorkItem(7336, "DevDiv_Projects/Roslyn")] public async Task EditorBrowsable_Method_BrowsableStateNever() { - var markup = @" -class Program -{ - void M() - { - Goo.$$ - } -}"; + var markup = """ + class Program + { + void M() + { + Goo.$$ + } + } + """; - var referencedCode = @" -public class Goo -{ - [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] - public static void Bar() - { - } -}"; + var referencedCode = """ + public class Goo + { + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] + public static void Bar() + { + } + } + """; await VerifyItemInEditorBrowsableContextsAsync( markup: markup, referencedCode: referencedCode, @@ -4865,23 +5119,25 @@ await VerifyItemInEditorBrowsableContextsAsync( [Fact, WorkItem(7336, "DevDiv_Projects/Roslyn")] public async Task EditorBrowsable_Method_BrowsableStateAdvanced() { - var markup = @" -class Program -{ - void M() - { - Goo.$$ - } -}"; + var markup = """ + class Program + { + void M() + { + Goo.$$ + } + } + """; - var referencedCode = @" -public class Goo -{ - [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] - public static void Bar() - { - } -}"; + var referencedCode = """ + public class Goo + { + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] + public static void Bar() + { + } + } + """; HideAdvancedMembers = false; await VerifyItemInEditorBrowsableContextsAsync( @@ -4908,28 +5164,30 @@ await VerifyItemInEditorBrowsableContextsAsync( [Fact, WorkItem(7336, "DevDiv_Projects/Roslyn")] public async Task EditorBrowsable_Method_Overloads_BothBrowsableAlways() { - var markup = @" -class Program -{ - void M() - { - Goo.$$ - } -}"; + var markup = """ + class Program + { + void M() + { + Goo.$$ + } + } + """; - var referencedCode = @" -public class Goo -{ - [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Always)] - public static void Bar() - { - } + var referencedCode = """ + public class Goo + { + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Always)] + public static void Bar() + { + } - [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Always)] - public static void Bar(int x) - { - } -}"; + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Always)] + public static void Bar(int x) + { + } + } + """; await VerifyItemInEditorBrowsableContextsAsync( markup: markup, @@ -4944,28 +5202,30 @@ await VerifyItemInEditorBrowsableContextsAsync( [Fact, WorkItem(7336, "DevDiv_Projects/Roslyn")] public async Task EditorBrowsable_Method_Overloads_OneBrowsableAlways_OneBrowsableNever() { - var markup = @" -class Program -{ - void M() - { - Goo.$$ - } -}"; + var markup = """ + class Program + { + void M() + { + Goo.$$ + } + } + """; - var referencedCode = @" -public class Goo -{ - [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Always)] - public static void Bar() - { - } + var referencedCode = """ + public class Goo + { + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Always)] + public static void Bar() + { + } - [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] - public static void Bar(int x) - { - } -}"; + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] + public static void Bar(int x) + { + } + } + """; await VerifyItemInEditorBrowsableContextsAsync( markup: markup, @@ -4980,28 +5240,30 @@ await VerifyItemInEditorBrowsableContextsAsync( [Fact, WorkItem(7336, "DevDiv_Projects/Roslyn")] public async Task EditorBrowsable_Method_Overloads_BothBrowsableNever() { - var markup = @" -class Program -{ - void M() - { - Goo.$$ - } -}"; + var markup = """ + class Program + { + void M() + { + Goo.$$ + } + } + """; - var referencedCode = @" -public class Goo -{ - [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] - public static void Bar() - { - } + var referencedCode = """ + public class Goo + { + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] + public static void Bar() + { + } - [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] - public static void Bar(int x) - { - } -}"; + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] + public static void Bar(int x) + { + } + } + """; await VerifyItemInEditorBrowsableContextsAsync( markup: markup, @@ -5016,27 +5278,29 @@ await VerifyItemInEditorBrowsableContextsAsync( [Fact, WorkItem(7336, "DevDiv_Projects/Roslyn")] public async Task EditorBrowsable_ExtensionMethod_BrowsableAlways() { - var markup = @" -class Program -{ - void M() - { - new Goo().$$ - } -}"; + var markup = """ + class Program + { + void M() + { + new Goo().$$ + } + } + """; - var referencedCode = @" -public class Goo -{ -} + var referencedCode = """ + public class Goo + { + } -public static class GooExtensions -{ - [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Always)] - public static void Bar(this Goo goo, int x) - { - } -}"; + public static class GooExtensions + { + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Always)] + public static void Bar(this Goo goo, int x) + { + } + } + """; await VerifyItemInEditorBrowsableContextsAsync( markup: markup, @@ -5051,27 +5315,29 @@ await VerifyItemInEditorBrowsableContextsAsync( [Fact, WorkItem(7336, "DevDiv_Projects/Roslyn")] public async Task EditorBrowsable_ExtensionMethod_BrowsableNever() { - var markup = @" -class Program -{ - void M() - { - new Goo().$$ - } -}"; + var markup = """ + class Program + { + void M() + { + new Goo().$$ + } + } + """; - var referencedCode = @" -public class Goo -{ -} + var referencedCode = """ + public class Goo + { + } -public static class GooExtensions -{ - [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] - public static void Bar(this Goo goo, int x) - { - } -}"; + public static class GooExtensions + { + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] + public static void Bar(this Goo goo, int x) + { + } + } + """; await VerifyItemInEditorBrowsableContextsAsync( markup: markup, @@ -5086,27 +5352,29 @@ await VerifyItemInEditorBrowsableContextsAsync( [Fact, WorkItem(7336, "DevDiv_Projects/Roslyn")] public async Task EditorBrowsable_ExtensionMethod_BrowsableAdvanced() { - var markup = @" -class Program -{ - void M() - { - new Goo().$$ - } -}"; + var markup = """ + class Program + { + void M() + { + new Goo().$$ + } + } + """; - var referencedCode = @" -public class Goo -{ -} + var referencedCode = """ + public class Goo + { + } -public static class GooExtensions -{ - [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] - public static void Bar(this Goo goo, int x) - { - } -}"; + public static class GooExtensions + { + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] + public static void Bar(this Goo goo, int x) + { + } + } + """; HideAdvancedMembers = false; @@ -5134,32 +5402,34 @@ await VerifyItemInEditorBrowsableContextsAsync( [Fact, WorkItem(7336, "DevDiv_Projects/Roslyn")] public async Task EditorBrowsable_ExtensionMethod_BrowsableMixed() { - var markup = @" -class Program -{ - void M() - { - new Goo().$$ - } -}"; + var markup = """ + class Program + { + void M() + { + new Goo().$$ + } + } + """; - var referencedCode = @" -public class Goo -{ -} + var referencedCode = """ + public class Goo + { + } -public static class GooExtensions -{ - [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Always)] - public static void Bar(this Goo goo, int x) - { - } + public static class GooExtensions + { + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Always)] + public static void Bar(this Goo goo, int x) + { + } - [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] - public static void Bar(this Goo goo, int x, int y) - { - } -}"; + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] + public static void Bar(this Goo goo, int x, int y) + { + } + } + """; await VerifyItemInEditorBrowsableContextsAsync( markup: markup, @@ -5174,31 +5444,33 @@ await VerifyItemInEditorBrowsableContextsAsync( [Fact, WorkItem(7336, "DevDiv_Projects/Roslyn")] public async Task EditorBrowsable_OverloadExtensionMethodAndMethod_BrowsableAlways() { - var markup = @" -class Program -{ - void M() - { - new Goo().$$ - } -}"; + var markup = """ + class Program + { + void M() + { + new Goo().$$ + } + } + """; - var referencedCode = @" -public class Goo -{ - [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Always)] - public void Bar(int x) - { - } -} + var referencedCode = """ + public class Goo + { + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Always)] + public void Bar(int x) + { + } + } -public static class GooExtensions -{ - [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Always)] - public static void Bar(this Goo goo, int x, int y) - { - } -}"; + public static class GooExtensions + { + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Always)] + public static void Bar(this Goo goo, int x, int y) + { + } + } + """; await VerifyItemInEditorBrowsableContextsAsync( markup: markup, @@ -5213,31 +5485,33 @@ await VerifyItemInEditorBrowsableContextsAsync( [Fact, WorkItem(7336, "DevDiv_Projects/Roslyn")] public async Task EditorBrowsable_OverloadExtensionMethodAndMethod_BrowsableMixed() { - var markup = @" -class Program -{ - void M() - { - new Goo().$$ - } -}"; + var markup = """ + class Program + { + void M() + { + new Goo().$$ + } + } + """; - var referencedCode = @" -public class Goo -{ - [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] - public void Bar(int x) - { - } -} + var referencedCode = """ + public class Goo + { + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] + public void Bar(int x) + { + } + } -public static class GooExtensions -{ - [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Always)] - public static void Bar(this Goo goo, int x, int y) - { - } -}"; + public static class GooExtensions + { + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Always)] + public static void Bar(this Goo goo, int x, int y) + { + } + } + """; await VerifyItemInEditorBrowsableContextsAsync( markup: markup, @@ -5252,31 +5526,33 @@ await VerifyItemInEditorBrowsableContextsAsync( [Fact, WorkItem(7336, "DevDiv_Projects/Roslyn")] public async Task EditorBrowsable_SameSigExtensionMethodAndMethod_InstanceMethodBrowsableNever() { - var markup = @" -class Program -{ - void M() - { - new Goo().$$ - } -}"; + var markup = """ + class Program + { + void M() + { + new Goo().$$ + } + } + """; - var referencedCode = @" -public class Goo -{ - [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] - public void Bar(int x) - { - } -} + var referencedCode = """ + public class Goo + { + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] + public void Bar(int x) + { + } + } -public static class GooExtensions -{ - [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Always)] - public static void Bar(this Goo goo, int x) - { - } -}"; + public static class GooExtensions + { + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Always)] + public static void Bar(this Goo goo, int x) + { + } + } + """; await VerifyItemInEditorBrowsableContextsAsync( markup: markup, @@ -5291,30 +5567,32 @@ await VerifyItemInEditorBrowsableContextsAsync( [Fact, WorkItem(7336, "DevDiv_Projects/Roslyn")] public async Task OverriddenSymbolsFilteredFromCompletionList() { - var markup = @" -class Program -{ - void M() - { - D d = new D(); - d.$$ - } -}"; + var markup = """ + class Program + { + void M() + { + D d = new D(); + d.$$ + } + } + """; - var referencedCode = @" -public class B -{ - public virtual void Goo(int original) - { - } -} + var referencedCode = """ + public class B + { + public virtual void Goo(int original) + { + } + } -public class D : B -{ - public override void Goo(int derived) - { - } -}"; + public class D : B + { + public override void Goo(int derived) + { + } + } + """; await VerifyItemInEditorBrowsableContextsAsync( markup: markup, @@ -5329,27 +5607,29 @@ await VerifyItemInEditorBrowsableContextsAsync( [Fact, WorkItem(7336, "DevDiv_Projects/Roslyn")] public async Task EditorBrowsable_BrowsableStateAlwaysMethodInBrowsableStateNeverClass() { - var markup = @" -class Program -{ - void M() - { - C c = new C(); - c.$$ - } -}"; - - var referencedCode = @" -[System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] -public class C -{ - public void Goo() - { - } -}"; + var markup = """ + class Program + { + void M() + { + C c = new C(); + c.$$ + } + } + """; - await VerifyItemInEditorBrowsableContextsAsync( - markup: markup, + var referencedCode = """ + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] + public class C + { + public void Goo() + { + } + } + """; + + await VerifyItemInEditorBrowsableContextsAsync( + markup: markup, referencedCode: referencedCode, item: "Goo", expectedSymbolsSameSolution: 1, @@ -5361,31 +5641,33 @@ await VerifyItemInEditorBrowsableContextsAsync( [Fact, WorkItem(7336, "DevDiv_Projects/Roslyn")] public async Task EditorBrowsable_BrowsableStateAlwaysMethodInBrowsableStateNeverBaseClass() { - var markup = @" -class Program -{ - void M() - { - D d = new D(); - d.$$ - } -}"; + var markup = """ + class Program + { + void M() + { + D d = new D(); + d.$$ + } + } + """; - var referencedCode = @" -[System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] -public class B -{ - public void Goo() - { - } -} + var referencedCode = """ + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] + public class B + { + public void Goo() + { + } + } -public class D : B -{ - public void Goo(int x) - { - } -}"; + public class D : B + { + public void Goo(int x) + { + } + } + """; await VerifyItemInEditorBrowsableContextsAsync( markup: markup, @@ -5400,23 +5682,25 @@ await VerifyItemInEditorBrowsableContextsAsync( [Fact, WorkItem(7336, "DevDiv_Projects/Roslyn")] public async Task EditorBrowsable_BrowsableStateNeverMethodsInBaseClass() { - var markup = @" -class Program : B -{ - void M() - { - $$ - } -}"; + var markup = """ + class Program : B + { + void M() + { + $$ + } + } + """; - var referencedCode = @" -public class B -{ - [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] - public void Goo() - { - } -}"; + var referencedCode = """ + public class B + { + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] + public void Goo() + { + } + } + """; await VerifyItemInEditorBrowsableContextsAsync( markup: markup, @@ -5431,22 +5715,24 @@ await VerifyItemInEditorBrowsableContextsAsync( [Fact, WorkItem(7336, "DevDiv_Projects/Roslyn")] public async Task EditorBrowsable_GenericTypeCausingMethodSignatureEquality_BothBrowsableAlways() { - var markup = @" -class Program -{ - void M() - { - var ci = new C(); - ci.$$ - } -}"; + var markup = """ + class Program + { + void M() + { + var ci = new C(); + ci.$$ + } + } + """; - var referencedCode = @" -public class C -{ - public void Goo(T t) { } - public void Goo(int i) { } -}"; + var referencedCode = """ + public class C + { + public void Goo(T t) { } + public void Goo(int i) { } + } + """; await VerifyItemInEditorBrowsableContextsAsync( markup: markup, @@ -5461,23 +5747,25 @@ await VerifyItemInEditorBrowsableContextsAsync( [Fact, WorkItem(7336, "DevDiv_Projects/Roslyn")] public async Task EditorBrowsable_GenericTypeCausingMethodSignatureEquality_BrowsableMixed1() { - var markup = @" -class Program -{ - void M() - { - var ci = new C(); - ci.$$ - } -}"; + var markup = """ + class Program + { + void M() + { + var ci = new C(); + ci.$$ + } + } + """; - var referencedCode = @" -public class C -{ - [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] - public void Goo(T t) { } - public void Goo(int i) { } -}"; + var referencedCode = """ + public class C + { + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] + public void Goo(T t) { } + public void Goo(int i) { } + } + """; await VerifyItemInEditorBrowsableContextsAsync( markup: markup, @@ -5492,23 +5780,25 @@ await VerifyItemInEditorBrowsableContextsAsync( [Fact, WorkItem(7336, "DevDiv_Projects/Roslyn")] public async Task EditorBrowsable_GenericTypeCausingMethodSignatureEquality_BrowsableMixed2() { - var markup = @" -class Program -{ - void M() - { - var ci = new C(); - ci.$$ - } -}"; + var markup = """ + class Program + { + void M() + { + var ci = new C(); + ci.$$ + } + } + """; - var referencedCode = @" -public class C -{ - public void Goo(T t) { } - [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] - public void Goo(int i) { } -}"; + var referencedCode = """ + public class C + { + public void Goo(T t) { } + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] + public void Goo(int i) { } + } + """; await VerifyItemInEditorBrowsableContextsAsync( markup: markup, @@ -5523,24 +5813,26 @@ await VerifyItemInEditorBrowsableContextsAsync( [Fact, WorkItem(7336, "DevDiv_Projects/Roslyn")] public async Task EditorBrowsable_GenericTypeCausingMethodSignatureEquality_BothBrowsableNever() { - var markup = @" -class Program -{ - void M() - { - var ci = new C(); - ci.$$ - } -}"; + var markup = """ + class Program + { + void M() + { + var ci = new C(); + ci.$$ + } + } + """; - var referencedCode = @" -public class C -{ - [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] - public void Goo(T t) { } - [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] - public void Goo(int i) { } -}"; + var referencedCode = """ + public class C + { + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] + public void Goo(T t) { } + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] + public void Goo(int i) { } + } + """; await VerifyItemInEditorBrowsableContextsAsync( markup: markup, @@ -5555,22 +5847,24 @@ await VerifyItemInEditorBrowsableContextsAsync( [Fact, WorkItem(7336, "DevDiv_Projects/Roslyn")] public async Task EditorBrowsable_GenericType2CausingMethodSignatureEquality_BothBrowsableAlways() { - var markup = @" -class Program -{ - void M() - { - var cii = new C(); - cii.$$ - } -}"; + var markup = """ + class Program + { + void M() + { + var cii = new C(); + cii.$$ + } + } + """; - var referencedCode = @" -public class C -{ - public void Goo(T t) { } - public void Goo(U u) { } -}"; + var referencedCode = """ + public class C + { + public void Goo(T t) { } + public void Goo(U u) { } + } + """; await VerifyItemInEditorBrowsableContextsAsync( markup: markup, @@ -5585,23 +5879,25 @@ await VerifyItemInEditorBrowsableContextsAsync( [Fact, WorkItem(7336, "DevDiv_Projects/Roslyn")] public async Task EditorBrowsable_GenericType2CausingMethodSignatureEquality_BrowsableMixed() { - var markup = @" -class Program -{ - void M() - { - var cii = new C(); - cii.$$ - } -}"; + var markup = """ + class Program + { + void M() + { + var cii = new C(); + cii.$$ + } + } + """; - var referencedCode = @" -public class C -{ - [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] - public void Goo(T t) { } - public void Goo(U u) { } -}"; + var referencedCode = """ + public class C + { + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] + public void Goo(T t) { } + public void Goo(U u) { } + } + """; await VerifyItemInEditorBrowsableContextsAsync( markup: markup, @@ -5616,24 +5912,26 @@ await VerifyItemInEditorBrowsableContextsAsync( [Fact, WorkItem(7336, "DevDiv_Projects/Roslyn")] public async Task EditorBrowsable_GenericType2CausingMethodSignatureEquality_BothBrowsableNever() { - var markup = @" -class Program -{ - void M() - { - var cii = new C(); - cii.$$ - } -}"; + var markup = """ + class Program + { + void M() + { + var cii = new C(); + cii.$$ + } + } + """; - var referencedCode = @" -public class C -{ - [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] - public void Goo(T t) { } - [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] - public void Goo(U u) { } -}"; + var referencedCode = """ + public class C + { + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] + public void Goo(T t) { } + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] + public void Goo(U u) { } + } + """; await VerifyItemInEditorBrowsableContextsAsync( markup: markup, @@ -5648,21 +5946,23 @@ await VerifyItemInEditorBrowsableContextsAsync( [Fact, WorkItem(7336, "DevDiv_Projects/Roslyn")] public async Task EditorBrowsable_Field_BrowsableStateNever() { - var markup = @" -class Program -{ - void M() - { - new Goo().$$ - } -}"; + var markup = """ + class Program + { + void M() + { + new Goo().$$ + } + } + """; - var referencedCode = @" -public class Goo -{ - [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] - public int bar; -}"; + var referencedCode = """ + public class Goo + { + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] + public int bar; + } + """; await VerifyItemInEditorBrowsableContextsAsync( markup: markup, @@ -5677,21 +5977,23 @@ await VerifyItemInEditorBrowsableContextsAsync( [Fact, WorkItem(7336, "DevDiv_Projects/Roslyn")] public async Task EditorBrowsable_Field_BrowsableStateAlways() { - var markup = @" -class Program -{ - void M() - { - new Goo().$$ - } -}"; + var markup = """ + class Program + { + void M() + { + new Goo().$$ + } + } + """; - var referencedCode = @" -public class Goo -{ - [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Always)] - public int bar; -}"; + var referencedCode = """ + public class Goo + { + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Always)] + public int bar; + } + """; await VerifyItemInEditorBrowsableContextsAsync( markup: markup, referencedCode: referencedCode, @@ -5705,21 +6007,23 @@ await VerifyItemInEditorBrowsableContextsAsync( [Fact, WorkItem(7336, "DevDiv_Projects/Roslyn")] public async Task EditorBrowsable_Field_BrowsableStateAdvanced() { - var markup = @" -class Program -{ - void M() - { - new Goo().$$ - } -}"; + var markup = """ + class Program + { + void M() + { + new Goo().$$ + } + } + """; - var referencedCode = @" -public class Goo -{ - [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] - public int bar; -}"; + var referencedCode = """ + public class Goo + { + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] + public int bar; + } + """; HideAdvancedMembers = true; await VerifyItemInEditorBrowsableContextsAsync( @@ -5747,21 +6051,23 @@ await VerifyItemInEditorBrowsableContextsAsync( [WpfFact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/674611")] public async Task EditorBrowsable_Property_BrowsableStateNever() { - var markup = @" -class Program -{ - void M() - { - new Goo().$$ - } -}"; + var markup = """ + class Program + { + void M() + { + new Goo().$$ + } + } + """; - var referencedCode = @" -public class Goo -{ - [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] - public int Bar {get; set;} -}"; + var referencedCode = """ + public class Goo + { + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] + public int Bar {get; set;} + } + """; await VerifyItemInEditorBrowsableContextsAsync( markup: markup, referencedCode: referencedCode, @@ -5775,25 +6081,27 @@ await VerifyItemInEditorBrowsableContextsAsync( [Fact, WorkItem(7336, "DevDiv_Projects/Roslyn")] public async Task EditorBrowsable_Property_IgnoreBrowsabilityOfGetSetMethods() { - var markup = @" -class Program -{ - void M() - { - new Goo().$$ - } -}"; + var markup = """ + class Program + { + void M() + { + new Goo().$$ + } + } + """; - var referencedCode = @" -public class Goo -{ - public int Bar { - [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] - get { return 5; } - [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] - set { } - } -}"; + var referencedCode = """ + public class Goo + { + public int Bar { + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] + get { return 5; } + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] + set { } + } + } + """; await VerifyItemInEditorBrowsableContextsAsync( markup: markup, referencedCode: referencedCode, @@ -5807,21 +6115,23 @@ await VerifyItemInEditorBrowsableContextsAsync( [Fact, WorkItem(7336, "DevDiv_Projects/Roslyn")] public async Task EditorBrowsable_Property_BrowsableStateAlways() { - var markup = @" -class Program -{ - void M() - { - new Goo().$$ - } -}"; + var markup = """ + class Program + { + void M() + { + new Goo().$$ + } + } + """; - var referencedCode = @" -public class Goo -{ - [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Always)] - public int Bar {get; set;} -}"; + var referencedCode = """ + public class Goo + { + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Always)] + public int Bar {get; set;} + } + """; await VerifyItemInEditorBrowsableContextsAsync( markup: markup, referencedCode: referencedCode, @@ -5835,21 +6145,23 @@ await VerifyItemInEditorBrowsableContextsAsync( [Fact, WorkItem(7336, "DevDiv_Projects/Roslyn")] public async Task EditorBrowsable_Property_BrowsableStateAdvanced() { - var markup = @" -class Program -{ - void M() - { - new Goo().$$ - } -}"; + var markup = """ + class Program + { + void M() + { + new Goo().$$ + } + } + """; - var referencedCode = @" -public class Goo -{ - [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] - public int Bar {get; set;} -}"; + var referencedCode = """ + public class Goo + { + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] + public int Bar {get; set;} + } + """; HideAdvancedMembers = true; await VerifyItemInEditorBrowsableContextsAsync( @@ -5876,23 +6188,25 @@ await VerifyItemInEditorBrowsableContextsAsync( [Fact, WorkItem(7336, "DevDiv_Projects/Roslyn")] public async Task EditorBrowsable_Constructor_BrowsableStateNever() { - var markup = @" -class Program -{ - void M() - { - new $$ - } -}"; - - var referencedCode = @" -public class Goo -{ - [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] - public Goo() - { - } -}"; + var markup = """ + class Program + { + void M() + { + new $$ + } + } + """; + + var referencedCode = """ + public class Goo + { + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] + public Goo() + { + } + } + """; await VerifyItemInEditorBrowsableContextsAsync( markup: markup, referencedCode: referencedCode, @@ -5906,23 +6220,25 @@ await VerifyItemInEditorBrowsableContextsAsync( [Fact, WorkItem(7336, "DevDiv_Projects/Roslyn")] public async Task EditorBrowsable_Constructor_BrowsableStateAlways() { - var markup = @" -class Program -{ - void M() - { - new $$ - } -}"; + var markup = """ + class Program + { + void M() + { + new $$ + } + } + """; - var referencedCode = @" -public class Goo -{ - [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Always)] - public Goo() - { - } -}"; + var referencedCode = """ + public class Goo + { + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Always)] + public Goo() + { + } + } + """; await VerifyItemInEditorBrowsableContextsAsync( markup: markup, referencedCode: referencedCode, @@ -5936,23 +6252,25 @@ await VerifyItemInEditorBrowsableContextsAsync( [Fact, WorkItem(7336, "DevDiv_Projects/Roslyn")] public async Task EditorBrowsable_Constructor_BrowsableStateAdvanced() { - var markup = @" -class Program -{ - void M() - { - new $$ - } -}"; + var markup = """ + class Program + { + void M() + { + new $$ + } + } + """; - var referencedCode = @" -public class Goo -{ - [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] - public Goo() - { - } -}"; + var referencedCode = """ + public class Goo + { + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] + public Goo() + { + } + } + """; HideAdvancedMembers = true; await VerifyItemInEditorBrowsableContextsAsync( @@ -5979,27 +6297,29 @@ await VerifyItemInEditorBrowsableContextsAsync( [Fact, WorkItem(7336, "DevDiv_Projects/Roslyn")] public async Task EditorBrowsable_Constructor_MixedOverloads1() { - var markup = @" -class Program -{ - void M() - { - new $$ - } -}"; + var markup = """ + class Program + { + void M() + { + new $$ + } + } + """; - var referencedCode = @" -public class Goo -{ - [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] - public Goo() - { - } + var referencedCode = """ + public class Goo + { + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] + public Goo() + { + } - public Goo(int x) - { - } -}"; + public Goo(int x) + { + } + } + """; await VerifyItemInEditorBrowsableContextsAsync( markup: markup, referencedCode: referencedCode, @@ -6013,28 +6333,30 @@ await VerifyItemInEditorBrowsableContextsAsync( [Fact, WorkItem(7336, "DevDiv_Projects/Roslyn")] public async Task EditorBrowsable_Constructor_MixedOverloads2() { - var markup = @" -class Program -{ - void M() - { - new $$ - } -}"; + var markup = """ + class Program + { + void M() + { + new $$ + } + } + """; - var referencedCode = @" -public class Goo -{ - [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] - public Goo() - { - } + var referencedCode = """ + public class Goo + { + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] + public Goo() + { + } - [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] - public Goo(int x) - { - } -}"; + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] + public Goo(int x) + { + } + } + """; await VerifyItemInEditorBrowsableContextsAsync( markup: markup, referencedCode: referencedCode, @@ -6048,23 +6370,25 @@ await VerifyItemInEditorBrowsableContextsAsync( [Fact, WorkItem(7336, "DevDiv_Projects/Roslyn")] public async Task EditorBrowsable_Event_BrowsableStateNever() { - var markup = @" -class Program -{ - void M() - { - new C().$$ - } -}"; + var markup = """ + class Program + { + void M() + { + new C().$$ + } + } + """; - var referencedCode = @" -public delegate void Handler(); + var referencedCode = """ + public delegate void Handler(); -public class C -{ - [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] - public event Handler Changed; -}"; + public class C + { + [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] + public event Handler Changed; + } + """; await VerifyItemInEditorBrowsableContextsAsync( markup: markup, referencedCode: referencedCode, @@ -6078,23 +6402,25 @@ await VerifyItemInEditorBrowsableContextsAsync( [Fact, WorkItem(7336, "DevDiv_Projects/Roslyn")] public async Task EditorBrowsable_Event_BrowsableStateAlways() { - var markup = @" -class Program -{ - void M() - { - new C().$$ - } -}"; + var markup = """ + class Program + { + void M() + { + new C().$$ + } + } + """; - var referencedCode = @" -public delegate void Handler(); + var referencedCode = """ + public delegate void Handler(); -public class C -{ - [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Always)] - public event Handler Changed; -}"; + public class C + { + [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Always)] + public event Handler Changed; + } + """; await VerifyItemInEditorBrowsableContextsAsync( markup: markup, referencedCode: referencedCode, @@ -6108,23 +6434,25 @@ await VerifyItemInEditorBrowsableContextsAsync( [Fact, WorkItem(7336, "DevDiv_Projects/Roslyn")] public async Task EditorBrowsable_Event_BrowsableStateAdvanced() { - var markup = @" -class Program -{ - void M() - { - new C().$$ - } -}"; + var markup = """ + class Program + { + void M() + { + new C().$$ + } + } + """; - var referencedCode = @" -public delegate void Handler(); + var referencedCode = """ + public delegate void Handler(); -public class C -{ - [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Advanced)] - public event Handler Changed; -}"; + public class C + { + [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Advanced)] + public event Handler Changed; + } + """; HideAdvancedMembers = false; @@ -6152,15 +6480,17 @@ await VerifyItemInEditorBrowsableContextsAsync( [Fact, WorkItem(7336, "DevDiv_Projects/Roslyn")] public async Task EditorBrowsable_Delegate_BrowsableStateNever() { - var markup = @" -class Program -{ - public event $$ -}"; + var markup = """ + class Program + { + public event $$ + } + """; - var referencedCode = @" -[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] -public delegate void Handler();"; + var referencedCode = """ + [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] + public delegate void Handler(); + """; await VerifyItemInEditorBrowsableContextsAsync( markup: markup, @@ -6175,15 +6505,17 @@ await VerifyItemInEditorBrowsableContextsAsync( [Fact, WorkItem(7336, "DevDiv_Projects/Roslyn")] public async Task EditorBrowsable_Delegate_BrowsableStateAlways() { - var markup = @" -class Program -{ - public event $$ -}"; + var markup = """ + class Program + { + public event $$ + } + """; - var referencedCode = @" -[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Always)] -public delegate void Handler();"; + var referencedCode = """ + [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Always)] + public delegate void Handler(); + """; await VerifyItemInEditorBrowsableContextsAsync( markup: markup, @@ -6198,15 +6530,17 @@ await VerifyItemInEditorBrowsableContextsAsync( [Fact, WorkItem(7336, "DevDiv_Projects/Roslyn")] public async Task EditorBrowsable_Delegate_BrowsableStateAdvanced() { - var markup = @" -class Program -{ - public event $$ -}"; + var markup = """ + class Program + { + public event $$ + } + """; - var referencedCode = @" -[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Advanced)] -public delegate void Handler();"; + var referencedCode = """ + [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Advanced)] + public delegate void Handler(); + """; HideAdvancedMembers = false; @@ -6234,20 +6568,22 @@ await VerifyItemInEditorBrowsableContextsAsync( [Fact, WorkItem(7336, "DevDiv_Projects/Roslyn")] public async Task EditorBrowsable_Class_BrowsableStateNever_DeclareLocal() { - var markup = @" -class Program -{ - public void M() - { - $$ - } -}"; + var markup = """ + class Program + { + public void M() + { + $$ + } + } + """; - var referencedCode = @" -[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] -public class Goo -{ -}"; + var referencedCode = """ + [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] + public class Goo + { + } + """; await VerifyItemInEditorBrowsableContextsAsync( markup: markup, referencedCode: referencedCode, @@ -6261,16 +6597,18 @@ await VerifyItemInEditorBrowsableContextsAsync( [Fact, WorkItem(7336, "DevDiv_Projects/Roslyn")] public async Task EditorBrowsable_Class_BrowsableStateNever_DeriveFrom() { - var markup = @" -class Program : $$ -{ -}"; + var markup = """ + class Program : $$ + { + } + """; - var referencedCode = @" -[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] -public class Goo -{ -}"; + var referencedCode = """ + [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] + public class Goo + { + } + """; await VerifyItemInEditorBrowsableContextsAsync( markup: markup, referencedCode: referencedCode, @@ -6284,26 +6622,28 @@ await VerifyItemInEditorBrowsableContextsAsync( [Fact, WorkItem(7336, "DevDiv_Projects/Roslyn")] public async Task EditorBrowsable_Class_BrowsableStateNever_FullyQualifiedInUsing() { - var markup = @" -class Program -{ - void M() - { - using (var x = new NS.$$ - } -}"; + var markup = """ + class Program + { + void M() + { + using (var x = new NS.$$ + } + } + """; - var referencedCode = @" -namespace NS -{ - [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] - public class Goo : System.IDisposable - { - public void Dispose() - { - } - } -}"; + var referencedCode = """ + namespace NS + { + [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] + public class Goo : System.IDisposable + { + public void Dispose() + { + } + } + } + """; await VerifyItemInEditorBrowsableContextsAsync( markup: markup, referencedCode: referencedCode, @@ -6317,20 +6657,22 @@ await VerifyItemInEditorBrowsableContextsAsync( [Fact, WorkItem(7336, "DevDiv_Projects/Roslyn")] public async Task EditorBrowsable_Class_BrowsableStateAlways_DeclareLocal() { - var markup = @" -class Program -{ - public void M() - { - $$ - } -}"; + var markup = """ + class Program + { + public void M() + { + $$ + } + } + """; - var referencedCode = @" -[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Always)] -public class Goo -{ -}"; + var referencedCode = """ + [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Always)] + public class Goo + { + } + """; await VerifyItemInEditorBrowsableContextsAsync( markup: markup, referencedCode: referencedCode, @@ -6344,16 +6686,18 @@ await VerifyItemInEditorBrowsableContextsAsync( [Fact, WorkItem(7336, "DevDiv_Projects/Roslyn")] public async Task EditorBrowsable_Class_BrowsableStateAlways_DeriveFrom() { - var markup = @" -class Program : $$ -{ -}"; + var markup = """ + class Program : $$ + { + } + """; - var referencedCode = @" -[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Always)] -public class Goo -{ -}"; + var referencedCode = """ + [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Always)] + public class Goo + { + } + """; await VerifyItemInEditorBrowsableContextsAsync( markup: markup, referencedCode: referencedCode, @@ -6367,26 +6711,28 @@ await VerifyItemInEditorBrowsableContextsAsync( [Fact, WorkItem(7336, "DevDiv_Projects/Roslyn")] public async Task EditorBrowsable_Class_BrowsableStateAlways_FullyQualifiedInUsing() { - var markup = @" -class Program -{ - void M() - { - using (var x = new NS.$$ - } -}"; + var markup = """ + class Program + { + void M() + { + using (var x = new NS.$$ + } + } + """; - var referencedCode = @" -namespace NS -{ - [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Always)] - public class Goo : System.IDisposable - { - public void Dispose() - { - } - } -}"; + var referencedCode = """ + namespace NS + { + [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Always)] + public class Goo : System.IDisposable + { + public void Dispose() + { + } + } + } + """; await VerifyItemInEditorBrowsableContextsAsync( markup: markup, referencedCode: referencedCode, @@ -6400,20 +6746,22 @@ await VerifyItemInEditorBrowsableContextsAsync( [Fact, WorkItem(7336, "DevDiv_Projects/Roslyn")] public async Task EditorBrowsable_Class_BrowsableStateAdvanced_DeclareLocal() { - var markup = @" -class Program -{ - public void M() - { - $$ - } -}"; + var markup = """ + class Program + { + public void M() + { + $$ + } + } + """; - var referencedCode = @" -[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Advanced)] -public class Goo -{ -}"; + var referencedCode = """ + [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Advanced)] + public class Goo + { + } + """; HideAdvancedMembers = false; await VerifyItemInEditorBrowsableContextsAsync( @@ -6440,16 +6788,18 @@ await VerifyItemInEditorBrowsableContextsAsync( [Fact, WorkItem(7336, "DevDiv_Projects/Roslyn")] public async Task EditorBrowsable_Class_BrowsableStateAdvanced_DeriveFrom() { - var markup = @" -class Program : $$ -{ -}"; + var markup = """ + class Program : $$ + { + } + """; - var referencedCode = @" -[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Advanced)] -public class Goo -{ -}"; + var referencedCode = """ + [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Advanced)] + public class Goo + { + } + """; HideAdvancedMembers = false; @@ -6477,26 +6827,28 @@ await VerifyItemInEditorBrowsableContextsAsync( [Fact, WorkItem(7336, "DevDiv_Projects/Roslyn")] public async Task EditorBrowsable_Class_BrowsableStateAdvanced_FullyQualifiedInUsing() { - var markup = @" -class Program -{ - void M() - { - using (var x = new NS.$$ - } -}"; + var markup = """ + class Program + { + void M() + { + using (var x = new NS.$$ + } + } + """; - var referencedCode = @" -namespace NS -{ - [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Advanced)] - public class Goo : System.IDisposable - { - public void Dispose() - { - } - } -}"; + var referencedCode = """ + namespace NS + { + [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Advanced)] + public class Goo : System.IDisposable + { + public void Dispose() + { + } + } + } + """; HideAdvancedMembers = false; await VerifyItemInEditorBrowsableContextsAsync( @@ -6523,24 +6875,26 @@ await VerifyItemInEditorBrowsableContextsAsync( [Fact, WorkItem(7336, "DevDiv_Projects/Roslyn")] public async Task EditorBrowsable_Class_IgnoreBaseClassBrowsableNever() { - var markup = @" -class Program -{ - public void M() - { - $$ - } -}"; + var markup = """ + class Program + { + public void M() + { + $$ + } + } + """; - var referencedCode = @" -public class Goo : Bar -{ -} + var referencedCode = """ + public class Goo : Bar + { + } -[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] -public class Bar -{ -}"; + [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] + public class Bar + { + } + """; await VerifyItemInEditorBrowsableContextsAsync( markup: markup, referencedCode: referencedCode, @@ -6554,20 +6908,22 @@ await VerifyItemInEditorBrowsableContextsAsync( [Fact, WorkItem(7336, "DevDiv_Projects/Roslyn")] public async Task EditorBrowsable_Struct_BrowsableStateNever_DeclareLocal() { - var markup = @" -class Program -{ - public void M() - { - $$ - } -}"; + var markup = """ + class Program + { + public void M() + { + $$ + } + } + """; - var referencedCode = @" -[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] -public struct Goo -{ -}"; + var referencedCode = """ + [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] + public struct Goo + { + } + """; await VerifyItemInEditorBrowsableContextsAsync( markup: markup, referencedCode: referencedCode, @@ -6581,16 +6937,18 @@ await VerifyItemInEditorBrowsableContextsAsync( [Fact, WorkItem(7336, "DevDiv_Projects/Roslyn")] public async Task EditorBrowsable_Struct_BrowsableStateNever_DeriveFrom() { - var markup = @" -class Program : $$ -{ -}"; + var markup = """ + class Program : $$ + { + } + """; - var referencedCode = @" -[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] -public struct Goo -{ -}"; + var referencedCode = """ + [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] + public struct Goo + { + } + """; await VerifyItemInEditorBrowsableContextsAsync( markup: markup, referencedCode: referencedCode, @@ -6604,20 +6962,22 @@ await VerifyItemInEditorBrowsableContextsAsync( [Fact, WorkItem(7336, "DevDiv_Projects/Roslyn")] public async Task EditorBrowsable_Struct_BrowsableStateAlways_DeclareLocal() { - var markup = @" -class Program -{ - public void M() - { - $$ - } -}"; + var markup = """ + class Program + { + public void M() + { + $$ + } + } + """; - var referencedCode = @" -[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Always)] -public struct Goo -{ -}"; + var referencedCode = """ + [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Always)] + public struct Goo + { + } + """; await VerifyItemInEditorBrowsableContextsAsync( markup: markup, referencedCode: referencedCode, @@ -6631,16 +6991,18 @@ await VerifyItemInEditorBrowsableContextsAsync( [Fact, WorkItem(7336, "DevDiv_Projects/Roslyn")] public async Task EditorBrowsable_Struct_BrowsableStateAlways_DeriveFrom() { - var markup = @" -class Program : $$ -{ -}"; + var markup = """ + class Program : $$ + { + } + """; - var referencedCode = @" -[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Always)] -public struct Goo -{ -}"; + var referencedCode = """ + [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Always)] + public struct Goo + { + } + """; await VerifyItemInEditorBrowsableContextsAsync( markup: markup, referencedCode: referencedCode, @@ -6654,20 +7016,22 @@ await VerifyItemInEditorBrowsableContextsAsync( [Fact, WorkItem(7336, "DevDiv_Projects/Roslyn")] public async Task EditorBrowsable_Struct_BrowsableStateAdvanced_DeclareLocal() { - var markup = @" -class Program -{ - public void M() - { - $$ - } -}"; + var markup = """ + class Program + { + public void M() + { + $$ + } + } + """; - var referencedCode = @" -[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Advanced)] -public struct Goo -{ -}"; + var referencedCode = """ + [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Advanced)] + public struct Goo + { + } + """; HideAdvancedMembers = false; await VerifyItemInEditorBrowsableContextsAsync( @@ -6694,16 +7058,18 @@ await VerifyItemInEditorBrowsableContextsAsync( [Fact, WorkItem(7336, "DevDiv_Projects/Roslyn")] public async Task EditorBrowsable_Struct_BrowsableStateAdvanced_DeriveFrom() { - var markup = @" -class Program : $$ -{ -}"; + var markup = """ + class Program : $$ + { + } + """; - var referencedCode = @" -[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Advanced)] -public struct Goo -{ -}"; + var referencedCode = """ + [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Advanced)] + public struct Goo + { + } + """; HideAdvancedMembers = false; await VerifyItemInEditorBrowsableContextsAsync( @@ -6730,20 +7096,22 @@ await VerifyItemInEditorBrowsableContextsAsync( [Fact, WorkItem(7336, "DevDiv_Projects/Roslyn")] public async Task EditorBrowsable_Enum_BrowsableStateNever() { - var markup = @" -class Program -{ - public void M() - { - $$ - } -}"; + var markup = """ + class Program + { + public void M() + { + $$ + } + } + """; - var referencedCode = @" -[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] -public enum Goo -{ -}"; + var referencedCode = """ + [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] + public enum Goo + { + } + """; await VerifyItemInEditorBrowsableContextsAsync( markup: markup, referencedCode: referencedCode, @@ -6757,20 +7125,22 @@ await VerifyItemInEditorBrowsableContextsAsync( [Fact, WorkItem(7336, "DevDiv_Projects/Roslyn")] public async Task EditorBrowsable_Enum_BrowsableStateAlways() { - var markup = @" -class Program -{ - public void M() - { - $$ - } -}"; + var markup = """ + class Program + { + public void M() + { + $$ + } + } + """; - var referencedCode = @" -[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Always)] -public enum Goo -{ -}"; + var referencedCode = """ + [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Always)] + public enum Goo + { + } + """; await VerifyItemInEditorBrowsableContextsAsync( markup: markup, referencedCode: referencedCode, @@ -6784,20 +7154,22 @@ await VerifyItemInEditorBrowsableContextsAsync( [Fact, WorkItem(7336, "DevDiv_Projects/Roslyn")] public async Task EditorBrowsable_Enum_BrowsableStateAdvanced() { - var markup = @" -class Program -{ - public void M() - { - $$ - } -}"; + var markup = """ + class Program + { + public void M() + { + $$ + } + } + """; - var referencedCode = @" -[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Advanced)] -public enum Goo -{ -}"; + var referencedCode = """ + [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Advanced)] + public enum Goo + { + } + """; HideAdvancedMembers = false; await VerifyItemInEditorBrowsableContextsAsync( @@ -6824,20 +7196,22 @@ await VerifyItemInEditorBrowsableContextsAsync( [Fact, WorkItem(7336, "DevDiv_Projects/Roslyn")] public async Task EditorBrowsable_Interface_BrowsableStateNever_DeclareLocal() { - var markup = @" -class Program -{ - public void M() - { - $$ - } -}"; + var markup = """ + class Program + { + public void M() + { + $$ + } + } + """; - var referencedCode = @" -[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] -public interface Goo -{ -}"; + var referencedCode = """ + [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] + public interface Goo + { + } + """; await VerifyItemInEditorBrowsableContextsAsync( markup: markup, referencedCode: referencedCode, @@ -6851,16 +7225,18 @@ await VerifyItemInEditorBrowsableContextsAsync( [Fact, WorkItem(7336, "DevDiv_Projects/Roslyn")] public async Task EditorBrowsable_Interface_BrowsableStateNever_DeriveFrom() { - var markup = @" -class Program : $$ -{ -}"; + var markup = """ + class Program : $$ + { + } + """; - var referencedCode = @" -[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] -public interface Goo -{ -}"; + var referencedCode = """ + [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] + public interface Goo + { + } + """; await VerifyItemInEditorBrowsableContextsAsync( markup: markup, referencedCode: referencedCode, @@ -6874,20 +7250,22 @@ await VerifyItemInEditorBrowsableContextsAsync( [Fact, WorkItem(7336, "DevDiv_Projects/Roslyn")] public async Task EditorBrowsable_Interface_BrowsableStateAlways_DeclareLocal() { - var markup = @" -class Program -{ - public void M() - { - $$ - } -}"; + var markup = """ + class Program + { + public void M() + { + $$ + } + } + """; - var referencedCode = @" -[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Always)] -public interface Goo -{ -}"; + var referencedCode = """ + [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Always)] + public interface Goo + { + } + """; await VerifyItemInEditorBrowsableContextsAsync( markup: markup, referencedCode: referencedCode, @@ -6901,16 +7279,18 @@ await VerifyItemInEditorBrowsableContextsAsync( [Fact, WorkItem(7336, "DevDiv_Projects/Roslyn")] public async Task EditorBrowsable_Interface_BrowsableStateAlways_DeriveFrom() { - var markup = @" -class Program : $$ -{ -}"; + var markup = """ + class Program : $$ + { + } + """; - var referencedCode = @" -[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Always)] -public interface Goo -{ -}"; + var referencedCode = """ + [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Always)] + public interface Goo + { + } + """; await VerifyItemInEditorBrowsableContextsAsync( markup: markup, referencedCode: referencedCode, @@ -6924,20 +7304,22 @@ await VerifyItemInEditorBrowsableContextsAsync( [Fact, WorkItem(7336, "DevDiv_Projects/Roslyn")] public async Task EditorBrowsable_Interface_BrowsableStateAdvanced_DeclareLocal() { - var markup = @" -class Program -{ - public void M() - { - $$ - } -}"; + var markup = """ + class Program + { + public void M() + { + $$ + } + } + """; - var referencedCode = @" -[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Advanced)] -public interface Goo -{ -}"; + var referencedCode = """ + [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Advanced)] + public interface Goo + { + } + """; HideAdvancedMembers = false; await VerifyItemInEditorBrowsableContextsAsync( @@ -6964,16 +7346,18 @@ await VerifyItemInEditorBrowsableContextsAsync( [Fact, WorkItem(7336, "DevDiv_Projects/Roslyn")] public async Task EditorBrowsable_Interface_BrowsableStateAdvanced_DeriveFrom() { - var markup = @" -class Program : $$ -{ -}"; + var markup = """ + class Program : $$ + { + } + """; - var referencedCode = @" -[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Advanced)] -public interface Goo -{ -}"; + var referencedCode = """ + [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Advanced)] + public interface Goo + { + } + """; HideAdvancedMembers = false; await VerifyItemInEditorBrowsableContextsAsync( @@ -7000,19 +7384,21 @@ await VerifyItemInEditorBrowsableContextsAsync( [Fact, WorkItem(7336, "DevDiv_Projects/Roslyn")] public async Task EditorBrowsable_CrossLanguage_CStoVB_Always() { - var markup = @" -class Program -{ - void M() - { - $$ - } -}"; + var markup = """ + class Program + { + void M() + { + $$ + } + } + """; - var referencedCode = @" - -Public Class Goo -End Class"; + var referencedCode = """ + + Public Class Goo + End Class + """; await VerifyItemInEditorBrowsableContextsAsync( markup: markup, @@ -7027,19 +7413,21 @@ await VerifyItemInEditorBrowsableContextsAsync( [Fact, WorkItem(7336, "DevDiv_Projects/Roslyn")] public async Task EditorBrowsable_CrossLanguage_CStoVB_Never() { - var markup = @" -class Program -{ - void M() - { - $$ - } -}"; + var markup = """ + class Program + { + void M() + { + $$ + } + } + """; - var referencedCode = @" - -Public Class Goo -End Class"; + var referencedCode = """ + + Public Class Goo + End Class + """; await VerifyItemInEditorBrowsableContextsAsync( markup: markup, referencedCode: referencedCode, @@ -7053,20 +7441,22 @@ await VerifyItemInEditorBrowsableContextsAsync( [Fact, WorkItem(7336, "DevDiv_Projects/Roslyn")] public async Task EditorBrowsable_TypeLibType_NotHidden() { - var markup = @" -class Program -{ - void M() - { - new $$ - } -}"; + var markup = """ + class Program + { + void M() + { + new $$ + } + } + """; - var referencedCode = @" -[System.Runtime.InteropServices.TypeLibType(System.Runtime.InteropServices.TypeLibTypeFlags.FLicensed)] -public class Goo -{ -}"; + var referencedCode = """ + [System.Runtime.InteropServices.TypeLibType(System.Runtime.InteropServices.TypeLibTypeFlags.FLicensed)] + public class Goo + { + } + """; await VerifyItemInEditorBrowsableContextsAsync( markup: markup, referencedCode: referencedCode, @@ -7080,23 +7470,25 @@ await VerifyItemInEditorBrowsableContextsAsync( [Fact, WorkItem(7336, "DevDiv_Projects/Roslyn")] public async Task EditorBrowsable_TypeLibType_Hidden() { - var markup = @" -class Program -{ - void M() - { - new $$ - } -}"; - - var referencedCode = @" -[System.Runtime.InteropServices.TypeLibType(System.Runtime.InteropServices.TypeLibTypeFlags.FHidden)] -public class Goo -{ -}"; - await VerifyItemInEditorBrowsableContextsAsync( - markup: markup, - referencedCode: referencedCode, + var markup = """ + class Program + { + void M() + { + new $$ + } + } + """; + + var referencedCode = """ + [System.Runtime.InteropServices.TypeLibType(System.Runtime.InteropServices.TypeLibTypeFlags.FHidden)] + public class Goo + { + } + """; + await VerifyItemInEditorBrowsableContextsAsync( + markup: markup, + referencedCode: referencedCode, item: "Goo", expectedSymbolsSameSolution: 1, expectedSymbolsMetadataReference: 0, @@ -7107,20 +7499,22 @@ await VerifyItemInEditorBrowsableContextsAsync( [Fact, WorkItem(7336, "DevDiv_Projects/Roslyn")] public async Task EditorBrowsable_TypeLibType_HiddenAndOtherFlags() { - var markup = @" -class Program -{ - void M() - { - new $$ - } -}"; + var markup = """ + class Program + { + void M() + { + new $$ + } + } + """; - var referencedCode = @" -[System.Runtime.InteropServices.TypeLibType(System.Runtime.InteropServices.TypeLibTypeFlags.FHidden | System.Runtime.InteropServices.TypeLibTypeFlags.FLicensed)] -public class Goo -{ -}"; + var referencedCode = """ + [System.Runtime.InteropServices.TypeLibType(System.Runtime.InteropServices.TypeLibTypeFlags.FHidden | System.Runtime.InteropServices.TypeLibTypeFlags.FLicensed)] + public class Goo + { + } + """; await VerifyItemInEditorBrowsableContextsAsync( markup: markup, referencedCode: referencedCode, @@ -7134,20 +7528,22 @@ await VerifyItemInEditorBrowsableContextsAsync( [Fact, WorkItem(7336, "DevDiv_Projects/Roslyn")] public async Task EditorBrowsable_TypeLibType_NotHidden_Int16Constructor() { - var markup = @" -class Program -{ - void M() - { - new $$ - } -}"; + var markup = """ + class Program + { + void M() + { + new $$ + } + } + """; - var referencedCode = @" -[System.Runtime.InteropServices.TypeLibType((short)System.Runtime.InteropServices.TypeLibTypeFlags.FLicensed)] -public class Goo -{ -}"; + var referencedCode = """ + [System.Runtime.InteropServices.TypeLibType((short)System.Runtime.InteropServices.TypeLibTypeFlags.FLicensed)] + public class Goo + { + } + """; await VerifyItemInEditorBrowsableContextsAsync( markup: markup, referencedCode: referencedCode, @@ -7161,20 +7557,22 @@ await VerifyItemInEditorBrowsableContextsAsync( [Fact, WorkItem(7336, "DevDiv_Projects/Roslyn")] public async Task EditorBrowsable_TypeLibType_Hidden_Int16Constructor() { - var markup = @" -class Program -{ - void M() - { - new $$ - } -}"; + var markup = """ + class Program + { + void M() + { + new $$ + } + } + """; - var referencedCode = @" -[System.Runtime.InteropServices.TypeLibType((short)System.Runtime.InteropServices.TypeLibTypeFlags.FHidden)] -public class Goo -{ -}"; + var referencedCode = """ + [System.Runtime.InteropServices.TypeLibType((short)System.Runtime.InteropServices.TypeLibTypeFlags.FHidden)] + public class Goo + { + } + """; await VerifyItemInEditorBrowsableContextsAsync( markup: markup, referencedCode: referencedCode, @@ -7188,20 +7586,22 @@ await VerifyItemInEditorBrowsableContextsAsync( [Fact, WorkItem(7336, "DevDiv_Projects/Roslyn")] public async Task EditorBrowsable_TypeLibType_HiddenAndOtherFlags_Int16Constructor() { - var markup = @" -class Program -{ - void M() - { - new $$ - } -}"; + var markup = """ + class Program + { + void M() + { + new $$ + } + } + """; - var referencedCode = @" -[System.Runtime.InteropServices.TypeLibType((short)(System.Runtime.InteropServices.TypeLibTypeFlags.FHidden | System.Runtime.InteropServices.TypeLibTypeFlags.FLicensed))] -public class Goo -{ -}"; + var referencedCode = """ + [System.Runtime.InteropServices.TypeLibType((short)(System.Runtime.InteropServices.TypeLibTypeFlags.FHidden | System.Runtime.InteropServices.TypeLibTypeFlags.FLicensed))] + public class Goo + { + } + """; await VerifyItemInEditorBrowsableContextsAsync( markup: markup, referencedCode: referencedCode, @@ -7215,23 +7615,25 @@ await VerifyItemInEditorBrowsableContextsAsync( [Fact, WorkItem(7336, "DevDiv_Projects/Roslyn")] public async Task EditorBrowsable_TypeLibFunc_NotHidden() { - var markup = @" -class Program -{ - void M() - { - new Goo().$$ - } -}"; + var markup = """ + class Program + { + void M() + { + new Goo().$$ + } + } + """; - var referencedCode = @" -public class Goo -{ - [System.Runtime.InteropServices.TypeLibFunc(System.Runtime.InteropServices.TypeLibFuncFlags.FReplaceable)] - public void Bar() - { - } -}"; + var referencedCode = """ + public class Goo + { + [System.Runtime.InteropServices.TypeLibFunc(System.Runtime.InteropServices.TypeLibFuncFlags.FReplaceable)] + public void Bar() + { + } + } + """; await VerifyItemInEditorBrowsableContextsAsync( markup: markup, referencedCode: referencedCode, @@ -7245,23 +7647,25 @@ await VerifyItemInEditorBrowsableContextsAsync( [Fact, WorkItem(7336, "DevDiv_Projects/Roslyn")] public async Task EditorBrowsable_TypeLibFunc_Hidden() { - var markup = @" -class Program -{ - void M() - { - new Goo().$$ - } -}"; + var markup = """ + class Program + { + void M() + { + new Goo().$$ + } + } + """; - var referencedCode = @" -public class Goo -{ - [System.Runtime.InteropServices.TypeLibFunc(System.Runtime.InteropServices.TypeLibFuncFlags.FHidden)] - public void Bar() - { - } -}"; + var referencedCode = """ + public class Goo + { + [System.Runtime.InteropServices.TypeLibFunc(System.Runtime.InteropServices.TypeLibFuncFlags.FHidden)] + public void Bar() + { + } + } + """; await VerifyItemInEditorBrowsableContextsAsync( markup: markup, referencedCode: referencedCode, @@ -7275,23 +7679,25 @@ await VerifyItemInEditorBrowsableContextsAsync( [Fact, WorkItem(7336, "DevDiv_Projects/Roslyn")] public async Task EditorBrowsable_TypeLibFunc_HiddenAndOtherFlags() { - var markup = @" -class Program -{ - void M() - { - new Goo().$$ - } -}"; + var markup = """ + class Program + { + void M() + { + new Goo().$$ + } + } + """; - var referencedCode = @" -public class Goo -{ - [System.Runtime.InteropServices.TypeLibFunc(System.Runtime.InteropServices.TypeLibFuncFlags.FHidden | System.Runtime.InteropServices.TypeLibFuncFlags.FReplaceable)] - public void Bar() - { - } -}"; + var referencedCode = """ + public class Goo + { + [System.Runtime.InteropServices.TypeLibFunc(System.Runtime.InteropServices.TypeLibFuncFlags.FHidden | System.Runtime.InteropServices.TypeLibFuncFlags.FReplaceable)] + public void Bar() + { + } + } + """; await VerifyItemInEditorBrowsableContextsAsync( markup: markup, referencedCode: referencedCode, @@ -7305,23 +7711,25 @@ await VerifyItemInEditorBrowsableContextsAsync( [Fact, WorkItem(7336, "DevDiv_Projects/Roslyn")] public async Task EditorBrowsable_TypeLibFunc_NotHidden_Int16Constructor() { - var markup = @" -class Program -{ - void M() - { - new Goo().$$ - } -}"; + var markup = """ + class Program + { + void M() + { + new Goo().$$ + } + } + """; - var referencedCode = @" -public class Goo -{ - [System.Runtime.InteropServices.TypeLibFunc((short)System.Runtime.InteropServices.TypeLibFuncFlags.FReplaceable)] - public void Bar() - { - } -}"; + var referencedCode = """ + public class Goo + { + [System.Runtime.InteropServices.TypeLibFunc((short)System.Runtime.InteropServices.TypeLibFuncFlags.FReplaceable)] + public void Bar() + { + } + } + """; await VerifyItemInEditorBrowsableContextsAsync( markup: markup, referencedCode: referencedCode, @@ -7335,23 +7743,25 @@ await VerifyItemInEditorBrowsableContextsAsync( [Fact, WorkItem(7336, "DevDiv_Projects/Roslyn")] public async Task EditorBrowsable_TypeLibFunc_Hidden_Int16Constructor() { - var markup = @" -class Program -{ - void M() - { - new Goo().$$ - } -}"; + var markup = """ + class Program + { + void M() + { + new Goo().$$ + } + } + """; - var referencedCode = @" -public class Goo -{ - [System.Runtime.InteropServices.TypeLibFunc((short)System.Runtime.InteropServices.TypeLibFuncFlags.FHidden)] - public void Bar() - { - } -}"; + var referencedCode = """ + public class Goo + { + [System.Runtime.InteropServices.TypeLibFunc((short)System.Runtime.InteropServices.TypeLibFuncFlags.FHidden)] + public void Bar() + { + } + } + """; await VerifyItemInEditorBrowsableContextsAsync( markup: markup, referencedCode: referencedCode, @@ -7365,23 +7775,25 @@ await VerifyItemInEditorBrowsableContextsAsync( [Fact, WorkItem(7336, "DevDiv_Projects/Roslyn")] public async Task EditorBrowsable_TypeLibFunc_HiddenAndOtherFlags_Int16Constructor() { - var markup = @" -class Program -{ - void M() - { - new Goo().$$ - } -}"; + var markup = """ + class Program + { + void M() + { + new Goo().$$ + } + } + """; - var referencedCode = @" -public class Goo -{ - [System.Runtime.InteropServices.TypeLibFunc((short)(System.Runtime.InteropServices.TypeLibFuncFlags.FHidden | System.Runtime.InteropServices.TypeLibFuncFlags.FReplaceable))] - public void Bar() - { - } -}"; + var referencedCode = """ + public class Goo + { + [System.Runtime.InteropServices.TypeLibFunc((short)(System.Runtime.InteropServices.TypeLibFuncFlags.FHidden | System.Runtime.InteropServices.TypeLibFuncFlags.FReplaceable))] + public void Bar() + { + } + } + """; await VerifyItemInEditorBrowsableContextsAsync( markup: markup, referencedCode: referencedCode, @@ -7395,21 +7807,23 @@ await VerifyItemInEditorBrowsableContextsAsync( [Fact, WorkItem(7336, "DevDiv_Projects/Roslyn")] public async Task EditorBrowsable_TypeLibVar_NotHidden() { - var markup = @" -class Program -{ - void M() - { - new Goo().$$ - } -}"; + var markup = """ + class Program + { + void M() + { + new Goo().$$ + } + } + """; - var referencedCode = @" -public class Goo -{ - [System.Runtime.InteropServices.TypeLibVar(System.Runtime.InteropServices.TypeLibVarFlags.FReplaceable)] - public int bar; -}"; + var referencedCode = """ + public class Goo + { + [System.Runtime.InteropServices.TypeLibVar(System.Runtime.InteropServices.TypeLibVarFlags.FReplaceable)] + public int bar; + } + """; await VerifyItemInEditorBrowsableContextsAsync( markup: markup, referencedCode: referencedCode, @@ -7423,21 +7837,23 @@ await VerifyItemInEditorBrowsableContextsAsync( [Fact, WorkItem(7336, "DevDiv_Projects/Roslyn")] public async Task EditorBrowsable_TypeLibVar_Hidden() { - var markup = @" -class Program -{ - void M() - { - new Goo().$$ - } -}"; + var markup = """ + class Program + { + void M() + { + new Goo().$$ + } + } + """; - var referencedCode = @" -public class Goo -{ - [System.Runtime.InteropServices.TypeLibVar(System.Runtime.InteropServices.TypeLibVarFlags.FHidden)] - public int bar; -}"; + var referencedCode = """ + public class Goo + { + [System.Runtime.InteropServices.TypeLibVar(System.Runtime.InteropServices.TypeLibVarFlags.FHidden)] + public int bar; + } + """; await VerifyItemInEditorBrowsableContextsAsync( markup: markup, referencedCode: referencedCode, @@ -7451,21 +7867,23 @@ await VerifyItemInEditorBrowsableContextsAsync( [Fact, WorkItem(7336, "DevDiv_Projects/Roslyn")] public async Task EditorBrowsable_TypeLibVar_HiddenAndOtherFlags() { - var markup = @" -class Program -{ - void M() - { - new Goo().$$ - } -}"; + var markup = """ + class Program + { + void M() + { + new Goo().$$ + } + } + """; - var referencedCode = @" -public class Goo -{ - [System.Runtime.InteropServices.TypeLibVar(System.Runtime.InteropServices.TypeLibVarFlags.FHidden | System.Runtime.InteropServices.TypeLibVarFlags.FReplaceable)] - public int bar; -}"; + var referencedCode = """ + public class Goo + { + [System.Runtime.InteropServices.TypeLibVar(System.Runtime.InteropServices.TypeLibVarFlags.FHidden | System.Runtime.InteropServices.TypeLibVarFlags.FReplaceable)] + public int bar; + } + """; await VerifyItemInEditorBrowsableContextsAsync( markup: markup, referencedCode: referencedCode, @@ -7479,21 +7897,23 @@ await VerifyItemInEditorBrowsableContextsAsync( [Fact, WorkItem(7336, "DevDiv_Projects/Roslyn")] public async Task EditorBrowsable_TypeLibVar_NotHidden_Int16Constructor() { - var markup = @" -class Program -{ - void M() - { - new Goo().$$ - } -}"; + var markup = """ + class Program + { + void M() + { + new Goo().$$ + } + } + """; - var referencedCode = @" -public class Goo -{ - [System.Runtime.InteropServices.TypeLibVar((short)System.Runtime.InteropServices.TypeLibVarFlags.FReplaceable)] - public int bar; -}"; + var referencedCode = """ + public class Goo + { + [System.Runtime.InteropServices.TypeLibVar((short)System.Runtime.InteropServices.TypeLibVarFlags.FReplaceable)] + public int bar; + } + """; await VerifyItemInEditorBrowsableContextsAsync( markup: markup, referencedCode: referencedCode, @@ -7507,21 +7927,23 @@ await VerifyItemInEditorBrowsableContextsAsync( [Fact, WorkItem(7336, "DevDiv_Projects/Roslyn")] public async Task EditorBrowsable_TypeLibVar_Hidden_Int16Constructor() { - var markup = @" -class Program -{ - void M() - { - new Goo().$$ - } -}"; + var markup = """ + class Program + { + void M() + { + new Goo().$$ + } + } + """; - var referencedCode = @" -public class Goo -{ - [System.Runtime.InteropServices.TypeLibVar((short)System.Runtime.InteropServices.TypeLibVarFlags.FHidden)] - public int bar; -}"; + var referencedCode = """ + public class Goo + { + [System.Runtime.InteropServices.TypeLibVar((short)System.Runtime.InteropServices.TypeLibVarFlags.FHidden)] + public int bar; + } + """; await VerifyItemInEditorBrowsableContextsAsync( markup: markup, referencedCode: referencedCode, @@ -7535,24 +7957,26 @@ await VerifyItemInEditorBrowsableContextsAsync( [Fact, WorkItem(7336, "DevDiv_Projects/Roslyn")] public async Task EditorBrowsable_TypeLibVar_HiddenAndOtherFlags_Int16Constructor() { - var markup = @" -class Program -{ - void M() - { - new Goo().$$ - } -}"; - - var referencedCode = @" -public class Goo -{ - [System.Runtime.InteropServices.TypeLibVar((short)(System.Runtime.InteropServices.TypeLibVarFlags.FHidden | System.Runtime.InteropServices.TypeLibVarFlags.FReplaceable))] - public int bar; -}"; - await VerifyItemInEditorBrowsableContextsAsync( - markup: markup, - referencedCode: referencedCode, + var markup = """ + class Program + { + void M() + { + new Goo().$$ + } + } + """; + + var referencedCode = """ + public class Goo + { + [System.Runtime.InteropServices.TypeLibVar((short)(System.Runtime.InteropServices.TypeLibVarFlags.FHidden | System.Runtime.InteropServices.TypeLibVarFlags.FReplaceable))] + public int bar; + } + """; + await VerifyItemInEditorBrowsableContextsAsync( + markup: markup, + referencedCode: referencedCode, item: "bar", expectedSymbolsSameSolution: 1, expectedSymbolsMetadataReference: 0, @@ -7563,18 +7987,19 @@ await VerifyItemInEditorBrowsableContextsAsync( [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/545557")] public async Task TestColorColor1() { - var markup = @" -class A -{ - static void Goo() { } - void Bar() { } - - static void Main() - { - A A = new A(); - A.$$ - } -}"; + var markup = """ + class A + { + static void Goo() { } + void Bar() { } + + static void Main() + { + A A = new A(); + A.$$ + } + } + """; await VerifyExpectedItemsAsync(markup, [ ItemExpectation.Exists("Goo"), ItemExpectation.Exists("Bar"), @@ -7584,16 +8009,17 @@ await VerifyExpectedItemsAsync(markup, [ [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/545647")] public async Task TestLaterLocalHidesType1() { - var markup = @" -using System; -class C -{ - public static void Main() - { - $$ - Console.WriteLine(); - } -}"; + var markup = """ + using System; + class C + { + public static void Main() + { + $$ + Console.WriteLine(); + } + } + """; await VerifyItemExistsAsync(markup, "Console"); } @@ -7601,16 +8027,17 @@ public static void Main() [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/545647")] public async Task TestLaterLocalHidesType2() { - var markup = @" -using System; -class C -{ - public static void Main() - { - C$$ - Console.WriteLine(); - } -}"; + var markup = """ + using System; + class C + { + public static void Main() + { + C$$ + Console.WriteLine(); + } + } + """; await VerifyItemExistsAsync(markup, "Console"); } @@ -7618,42 +8045,46 @@ public static void Main() [Fact] public async Task TestIndexedProperty() { - var markup = @"class Program -{ - void M() - { - CCC c = new CCC(); - c.$$ - } -}"; + var markup = """ + class Program + { + void M() + { + CCC c = new CCC(); + c.$$ + } + } + """; // Note that is required by compiler. Bug 17013 tracks enabling indexed property for non-COM types. - var referencedCode = @"Imports System.Runtime.InteropServices - - - -Public Class CCC - -#Region ""COM GUIDs"" - Public Const ClassId As String = ""9d965fd2-1514-44f6-accd-257ce77c46b0"" - Public Const InterfaceId As String = ""a9415060-fdf0-47e3-bc80-9c18f7f39cf6"" - Public Const EventsId As String = ""c6a866a5-5f97-4b53-a5df-3739dc8ff1bb"" -# End Region - - ''' - ''' An index property from VB - ''' - ''' p1 is an integer index - ''' A string - Public Property IndexProp(ByVal p1 As Integer, Optional ByVal p2 As Integer = 0) As String - Get - Return Nothing - End Get - Set(ByVal value As String) - - End Set - End Property -End Class"; + var referencedCode = """ + Imports System.Runtime.InteropServices + + + + Public Class CCC + + #Region "COM GUIDs" + Public Const ClassId As String = "9d965fd2-1514-44f6-accd-257ce77c46b0" + Public Const InterfaceId As String = "a9415060-fdf0-47e3-bc80-9c18f7f39cf6" + Public Const EventsId As String = "c6a866a5-5f97-4b53-a5df-3739dc8ff1bb" + # End Region + + ''' + ''' An index property from VB + ''' + ''' p1 is an integer index + ''' A string + Public Property IndexProp(ByVal p1 As Integer, Optional ByVal p2 As Integer = 0) As String + Get + Return Nothing + End Get + Set(ByVal value As String) + + End Set + End Property + End Class + """; await VerifyItemInEditorBrowsableContextsAsync( markup: markup, @@ -7668,17 +8099,18 @@ await VerifyItemInEditorBrowsableContextsAsync( [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/546841")] public async Task TestDeclarationAmbiguity() { - var markup = @" -using System; + var markup = """ + using System; -class Program -{ - void Main() - { - Environment.$$ - var v; - } -}"; + class Program + { + void Main() + { + Environment.$$ + var v; + } + } + """; await VerifyItemExistsAsync(markup, "CommandLine"); } @@ -7686,11 +8118,12 @@ void Main() [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/12781")] public async Task TestFieldDeclarationAmbiguity() { - var markup = @" -using System; -Environment.$$ -var v; -}"; + var markup = """ + using System; + Environment.$$ + var v; + } + """; await VerifyItemExistsAsync(markup, "CommandLine", sourceCodeKind: SourceCodeKind.Script); } @@ -7698,14 +8131,15 @@ public async Task TestFieldDeclarationAmbiguity() [Fact] public async Task TestCursorOnClassCloseBrace() { - var markup = @" -using System; + var markup = """ + using System; -class Outer -{ - class Inner { } + class Outer + { + class Inner { } -$$}"; + $$} + """; await VerifyItemExistsAsync(markup, "Inner"); } @@ -7713,12 +8147,13 @@ class Inner { } [Fact] public async Task AfterAsync1() { - var markup = @" -using System.Threading.Tasks; -class Program -{ - async $$ -}"; + var markup = """ + using System.Threading.Tasks; + class Program + { + async $$ + } + """; await VerifyItemExistsAsync(markup, "Task"); } @@ -7726,12 +8161,13 @@ class Program [Fact] public async Task AfterAsync2() { - var markup = @" -using System.Threading.Tasks; -class Program -{ - public async T$$ -}"; + var markup = """ + using System.Threading.Tasks; + class Program + { + public async T$$ + } + """; await VerifyItemExistsAsync(markup, "Task"); } @@ -7739,14 +8175,15 @@ public async T$$ [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/60341")] public async Task AfterAsync3() { - var markup = @" -using System.Threading.Tasks; -class Program -{ - public async $$ - - public void M() {} -}"; + var markup = """ + using System.Threading.Tasks; + class Program + { + public async $$ + + public void M() {} + } + """; await VerifyItemExistsAsync(markup, "Task"); } @@ -7754,13 +8191,14 @@ public void M() {} [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/60341")] public async Task AfterAsync4() { - var markup = @" -using System; -using System.Threading.Tasks; -class Program -{ - public async $$ -}"; + var markup = """ + using System; + using System.Threading.Tasks; + class Program + { + public async $$ + } + """; await VerifyExpectedItemsAsync(markup, [ ItemExpectation.Exists("Task"), @@ -7771,14 +8209,15 @@ await VerifyExpectedItemsAsync(markup, [ [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/60341")] public async Task AfterAsync5() { - var markup = @" -using System.Threading.Tasks; -class Program -{ - public async $$ -} + var markup = """ + using System.Threading.Tasks; + class Program + { + public async $$ + } -class Test {}"; + class Test {} + """; await VerifyExpectedItemsAsync(markup, [ ItemExpectation.Exists("Task"), @@ -7789,15 +8228,16 @@ await VerifyExpectedItemsAsync(markup, [ [Fact] public async Task NotAfterAsyncInMethodBody() { - var markup = @" -using System.Threading.Tasks; -class Program -{ - void goo() - { - var x = async $$ - } -}"; + var markup = """ + using System.Threading.Tasks; + class Program + { + void goo() + { + var x = async $$ + } + } + """; await VerifyItemIsAbsentAsync(markup, "Task"); } @@ -7805,14 +8245,15 @@ void goo() [Fact] public async Task NotAwaitable1() { - var markup = @" -class Program -{ - void goo() - { - $$ - } -}"; + var markup = """ + class Program + { + void goo() + { + $$ + } + } + """; await VerifyItemWithMscorlib45Async(markup, "goo", "void Program.goo()", "C#"); } @@ -7820,14 +8261,15 @@ void goo() [Fact] public async Task NotAwaitable2() { - var markup = @" -class Program -{ - async void goo() - { - $$ - } -}"; + var markup = """ + class Program + { + async void goo() + { + $$ + } + } + """; await VerifyItemWithMscorlib45Async(markup, "goo", "void Program.goo()", "C#"); } @@ -7835,17 +8277,18 @@ async void goo() [Fact] public async Task Awaitable1() { - var markup = @" -using System.Threading; -using System.Threading.Tasks; + var markup = """ + using System.Threading; + using System.Threading.Tasks; -class Program -{ - async Task goo() - { - $$ - } -}"; + class Program + { + async Task goo() + { + $$ + } + } + """; var description = $@"({CSharpFeaturesResources.awaitable}) Task Program.goo()"; @@ -7855,16 +8298,17 @@ async Task goo() [Fact] public async Task Awaitable2() { - var markup = @" -using System.Threading.Tasks; + var markup = """ + using System.Threading.Tasks; -class Program -{ - async Task goo() - { - $$ - } -}"; + class Program + { + async Task goo() + { + $$ + } + } + """; var description = $@"({CSharpFeaturesResources.awaitable}) Task Program.goo()"; @@ -7874,26 +8318,27 @@ async Task goo() [Fact] public async Task AwaitableDotsLikeRangeExpression() { - var markup = @" -using System.IO; -using System.Threading.Tasks; + var markup = """ + using System.IO; + using System.Threading.Tasks; -namespace N -{ - class C - { - async Task M() - { - var request = new Request(); - var m = await request.$$.ReadAsStreamAsync(); - } - } + namespace N + { + class C + { + async Task M() + { + var request = new Request(); + var m = await request.$$.ReadAsStreamAsync(); + } + } - class Request - { - public Task ReadAsStreamAsync() => null; - } -}"; + class Request + { + public Task ReadAsStreamAsync() => null; + } + } + """; await VerifyItemExistsAsync(markup, "ReadAsStreamAsync"); } @@ -7901,26 +8346,27 @@ class Request [Fact] public async Task AwaitableDotsLikeRangeExpressionWithParentheses() { - var markup = @" -using System.IO; -using System.Threading.Tasks; + var markup = """ + using System.IO; + using System.Threading.Tasks; -namespace N -{ - class C - { - async Task M() - { - var request = new Request(); - var m = (await request).$$.ReadAsStreamAsync(); - } - } + namespace N + { + class C + { + async Task M() + { + var request = new Request(); + var m = (await request).$$.ReadAsStreamAsync(); + } + } - class Request - { - public Task ReadAsStreamAsync() => null; - } -}"; + class Request + { + public Task ReadAsStreamAsync() => null; + } + } + """; // Nothing should be found: no awaiter for request. await VerifyExpectedItemsAsync(markup, [ ItemExpectation.Absent("Result"), @@ -7931,26 +8377,27 @@ await VerifyExpectedItemsAsync(markup, [ [Fact] public async Task AwaitableDotsLikeRangeExpressionWithTaskAndParentheses() { - var markup = @" -using System.IO; -using System.Threading.Tasks; + var markup = """ + using System.IO; + using System.Threading.Tasks; -namespace N -{ - class C - { - async Task M() - { - var request = new Task(); - var m = (await request).$$.ReadAsStreamAsync(); - } - } + namespace N + { + class C + { + async Task M() + { + var request = new Task(); + var m = (await request).$$.ReadAsStreamAsync(); + } + } - class Request - { - public Task ReadAsStreamAsync() => null; - } -}"; + class Request + { + public Task ReadAsStreamAsync() => null; + } + } + """; await VerifyExpectedItemsAsync(markup, [ ItemExpectation.Absent("Result"), @@ -7961,87 +8408,90 @@ await VerifyExpectedItemsAsync(markup, [ [Fact] public async Task ObsoleteItem() { - var markup = @" -using System; + var markup = """ + using System; -class Program -{ - [Obsolete] - public void goo() - { - $$ - } -}"; + class Program + { + [Obsolete] + public void goo() + { + $$ + } + } + """; await VerifyItemExistsAsync(markup, "goo", $"[{CSharpFeaturesResources.deprecated}] void Program.goo()"); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/568986")] public async Task NoMembersOnDottingIntoUnboundType() { - var markup = @" -class Program -{ - RegistryKey goo; - - static void Main(string[] args) - { - goo.$$ - } -}"; + var markup = """ + class Program + { + RegistryKey goo; + + static void Main(string[] args) + { + goo.$$ + } + } + """; await VerifyNoItemsExistAsync(markup); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/550717")] public async Task TypeArgumentsInConstraintAfterBaselist() { - var markup = @" -public class Goo : System.Object where $$ -{ -}"; + var markup = """ + public class Goo : System.Object where $$ + { + } + """; await VerifyItemExistsAsync(markup, "T"); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/647175")] public async Task NoDestructor() { - var markup = @" -class C -{ - ~C() - { - $$ -"; + var markup = """ + class C + { + ~C() + { + $$ + """; await VerifyItemIsAbsentAsync(markup, "Finalize"); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/669624")] public async Task ExtensionMethodOnCovariantInterface() { - var markup = @" -class Schema { } - -interface ISet { } + var markup = """ + class Schema { } -static class SetMethods -{ - public static void ForSchemaSet(this ISet> set) { } -} + interface ISet { } -class Context -{ - public ISet Set() { return null; } -} + static class SetMethods + { + public static void ForSchemaSet(this ISet> set) { } + } -class CustomSchema : Schema { } + class Context + { + public ISet Set() { return null; } + } -class Program -{ - static void Main(string[] args) - { - var set = new Context().Set(); + class CustomSchema : Schema { } - set.$$ -"; + class Program + { + static void Main(string[] args) + { + var set = new Context().Set(); + + set.$$ + """; await VerifyItemExistsAsync(markup, "ForSchemaSet", displayTextSuffix: "<>", sourceCodeKind: SourceCodeKind.Regular); } @@ -8049,14 +8499,14 @@ static void Main(string[] args) [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/667752")] public async Task ForEachInsideParentheses() { - var markup = @" -using System; -class C -{ - void M() - { - foreach($$) -"; + var markup = """ + using System; + class C + { + void M() + { + foreach($$) + """; await VerifyItemExistsAsync(markup, "String"); } @@ -8064,33 +8514,36 @@ void M() [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/766869")] public async Task TestFieldInitializerInP2P() { - var markup = @" -class Class -{ - int i = Consts.$$; -}"; + var markup = """ + class Class + { + int i = Consts.$$; + } + """; - var referencedCode = @" -public static class Consts -{ - public const int C = 1; -}"; + var referencedCode = """ + public static class Consts + { + public const int C = 1; + } + """; await VerifyItemWithProjectReferenceAsync(markup, referencedCode, "C", 1, LanguageNames.CSharp, LanguageNames.CSharp); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/834605")] public async Task ShowWithEqualsSign() { - var markup = @" -class c { public int value {set; get; }} + var markup = """ + class c { public int value {set; get; }} -class d -{ - void goo() - { - c goo = new c { value$$= - } -}"; + class d + { + void goo() + { + c goo = new c { value$$= + } + } + """; await VerifyNoItemsExistAsync(markup); } @@ -8098,16 +8551,17 @@ void goo() [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/825661")] public async Task NothingAfterThisDotInStaticContext() { - var markup = @" -class C -{ - void M1() { } + var markup = """ + class C + { + void M1() { } - static void M2() - { - this.$$ - } -}"; + static void M2() + { + this.$$ + } + } + """; await VerifyNoItemsExistAsync(markup); } @@ -8115,16 +8569,17 @@ static void M2() [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/825661")] public async Task NothingAfterBaseDotInStaticContext() { - var markup = @" -class C -{ - void M1() { } + var markup = """ + class C + { + void M1() { } - static void M2() - { - base.$$ - } -}"; + static void M2() + { + base.$$ + } + } + """; await VerifyNoItemsExistAsync(markup); } @@ -8136,18 +8591,19 @@ public async Task NothingAfterBaseDotInScriptContext() [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/858086")] public async Task NoNestedTypeWhenDisplayingInstance() { - var markup = @" -class C -{ - class D - { - } + var markup = """ + class C + { + class D + { + } - void M2() - { - new C().$$ - } -}"; + void M2() + { + new C().$$ + } + } + """; await VerifyItemIsAbsentAsync(markup, "D"); } @@ -8155,15 +8611,16 @@ void M2() [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/876031")] public async Task CatchVariableInExceptionFilter() { - var markup = @" -class C -{ - void M() - { - try - { - } - catch (System.Exception myExn) when ($$"; + var markup = """ + class C + { + void M() + { + try + { + } + catch (System.Exception myExn) when ($$ + """; await VerifyItemExistsAsync(markup, "myExn"); } @@ -8171,14 +8628,15 @@ void M() [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/849698")] public async Task CompletionAfterExternAlias() { - var markup = @" -class C -{ - void goo() - { - global::$$ - } -}"; + var markup = """ + class C + { + void goo() + { + global::$$ + } + } + """; await VerifyItemExistsAsync(markup, "System", usePreviousCharAsTrigger: true); } @@ -8186,29 +8644,31 @@ void goo() [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/849698")] public async Task ExternAliasSuggested() { - var markup = @" -extern alias Bar; -class C -{ - void goo() - { - $$ - } -}"; + var markup = """ + extern alias Bar; + class C + { + void goo() + { + $$ + } + } + """; await VerifyItemWithAliasedMetadataReferencesAsync(markup, "Bar", "Bar", 1, "C#", "C#"); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/635957")] public async Task ClassDestructor() { - var markup = @" -class C -{ - class N - { - ~$$ - } -}"; + var markup = """ + class C + { + class N + { + ~$$ + } + } + """; await VerifyItemExistsAsync(markup, "N"); await VerifyItemIsAbsentAsync(markup, "C"); } @@ -8217,14 +8677,15 @@ class N [WorkItem("https://github.com/dotnet/roslyn/issues/44423")] public async Task TildeOutsideClass() { - var markup = @" -class C -{ - class N - { - } -} -~$$"; + var markup = """ + class C + { + class N + { + } + } + ~$$ + """; await VerifyItemExistsAsync(markup, "C"); await VerifyItemIsAbsentAsync(markup, "N"); } @@ -8232,11 +8693,12 @@ class N [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/635957")] public async Task StructDestructor() { - var markup = @" -struct C -{ - ~$$ -}"; + var markup = """ + struct C + { + ~$$ + } + """; await VerifyItemIsAbsentAsync(markup, "C"); } @@ -8245,46 +8707,50 @@ struct C [InlineData("record class")] public async Task RecordDestructor(string record) { - var markup = $@" -{record} C -{{ - ~$$ -}}"; + var markup = $$""" + {{record}} C + { + ~$$ + } + """; await VerifyItemExistsAsync(markup, "C"); } [Fact] public async Task RecordStructDestructor() { - var markup = $@" -record struct C -{{ - ~$$ -}}"; + var markup = $$""" + record struct C + { + ~$$ + } + """; await VerifyItemIsAbsentAsync(markup, "C"); } [Fact] public async Task FieldAvailableInBothLinkedFiles() { - var markup = @" - - - - - - - -"; + var markup = """ + + + + + + + + + + """; await VerifyItemInLinkedFilesAsync(markup, "x", $"({FeaturesResources.field}) int C.x"); } @@ -8292,27 +8758,36 @@ void goo() [Fact] public async Task FieldUnavailableInOneLinkedFile() { - var markup = @" - - - - - - - -"; - var expectedDescription = $"({FeaturesResources.field}) int C.x\r\n\r\n{string.Format(FeaturesResources._0_1, "Proj1", FeaturesResources.Available)}\r\n{string.Format(FeaturesResources._0_1, "Proj2", FeaturesResources.Not_Available)}\r\n\r\n{FeaturesResources.You_can_use_the_navigation_bar_to_switch_contexts}"; + var markup = """ + + + + + + + + + + """; + var expectedDescription = $""" + ({FeaturesResources.field}) int C.x + + {string.Format(FeaturesResources._0_1, "Proj1", FeaturesResources.Available)} + {string.Format(FeaturesResources._0_1, "Proj2", FeaturesResources.Not_Available)} + + {FeaturesResources.You_can_use_the_navigation_bar_to_switch_contexts} + """; await VerifyItemInLinkedFilesAsync(markup, "x", expectedDescription); } @@ -8320,30 +8795,40 @@ void goo() [Fact] public async Task FieldUnavailableInTwoLinkedFiles() { - var markup = @" - - - - - - - - - - -"; - var expectedDescription = $"({FeaturesResources.field}) int C.x\r\n\r\n{string.Format(FeaturesResources._0_1, "Proj1", FeaturesResources.Available)}\r\n{string.Format(FeaturesResources._0_1, "Proj2", FeaturesResources.Not_Available)}\r\n{string.Format(FeaturesResources._0_1, "Proj3", FeaturesResources.Not_Available)}\r\n\r\n{FeaturesResources.You_can_use_the_navigation_bar_to_switch_contexts}"; + var markup = """ + + + + + + + + + + + + + """; + var expectedDescription = $""" + ({FeaturesResources.field}) int C.x + + {string.Format(FeaturesResources._0_1, "Proj1", FeaturesResources.Available)} + {string.Format(FeaturesResources._0_1, "Proj2", FeaturesResources.Not_Available)} + {string.Format(FeaturesResources._0_1, "Proj3", FeaturesResources.Not_Available)} + + {FeaturesResources.You_can_use_the_navigation_bar_to_switch_contexts} + """; await VerifyItemInLinkedFilesAsync(markup, "x", expectedDescription); } @@ -8351,33 +8836,42 @@ void goo() [Fact] public async Task ExcludeFilesWithInactiveRegions() { - var markup = @" - - + + - - - - - - - - -"; - var expectedDescription = $"({FeaturesResources.field}) int C.x\r\n\r\n{string.Format(FeaturesResources._0_1, "Proj1", FeaturesResources.Available)}\r\n{string.Format(FeaturesResources._0_1, "Proj3", FeaturesResources.Not_Available)}\r\n\r\n{FeaturesResources.You_can_use_the_navigation_bar_to_switch_contexts}"; + #if BAR + void goo() + { + $$ + } + #endif + } + ]]> + + + + + + + + + + """; + var expectedDescription = $""" + ({FeaturesResources.field}) int C.x + + {string.Format(FeaturesResources._0_1, "Proj1", FeaturesResources.Available)} + {string.Format(FeaturesResources._0_1, "Proj3", FeaturesResources.Not_Available)} + + {FeaturesResources.You_can_use_the_navigation_bar_to_switch_contexts} + """; await VerifyItemInLinkedFilesAsync(markup, "x", expectedDescription); } @@ -8385,37 +8879,47 @@ void goo() [Fact] public async Task UnionOfItemsFromBothContexts() { - var markup = @" - - + + - - - - - - - - -"; - var expectedDescription = $"void G.DoGStuff()\r\n\r\n{string.Format(FeaturesResources._0_1, "Proj1", FeaturesResources.Not_Available)}\r\n{string.Format(FeaturesResources._0_1, "Proj2", FeaturesResources.Available)}\r\n{string.Format(FeaturesResources._0_1, "Proj3", FeaturesResources.Not_Available)}\r\n\r\n{FeaturesResources.You_can_use_the_navigation_bar_to_switch_contexts}"; + #if BAR + class G + { + public void DoGStuff() {} + } + #endif + void goo() + { + new G().$$ + } + } + ]]> + + + + + + + + + + """; + var expectedDescription = $""" + void G.DoGStuff() + + {string.Format(FeaturesResources._0_1, "Proj1", FeaturesResources.Not_Available)} + {string.Format(FeaturesResources._0_1, "Proj2", FeaturesResources.Available)} + {string.Format(FeaturesResources._0_1, "Proj3", FeaturesResources.Not_Available)} + + {FeaturesResources.You_can_use_the_navigation_bar_to_switch_contexts} + """; await VerifyItemInLinkedFilesAsync(markup, "DoGStuff", expectedDescription); } @@ -8423,24 +8927,26 @@ void goo() [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1020944")] public async Task LocalsValidInLinkedDocuments() { - var markup = @" - - - - - - - -"; + var markup = """ + + + + + + + + + + """; var expectedDescription = $"({FeaturesResources.local_variable}) int xyz"; await VerifyItemInLinkedFilesAsync(markup, "xyz", expectedDescription); } @@ -8448,51 +8954,62 @@ void M() [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1020944")] public async Task LocalWarningInLinkedDocuments() { - var markup = @" - - - - - - - -"; - var expectedDescription = $"({FeaturesResources.local_variable}) int xyz\r\n\r\n{string.Format(FeaturesResources._0_1, "Proj1", FeaturesResources.Available)}\r\n{string.Format(FeaturesResources._0_1, "Proj2", FeaturesResources.Not_Available)}\r\n\r\n{FeaturesResources.You_can_use_the_navigation_bar_to_switch_contexts}"; + var markup = """ + + + + + + + + + + """; + var expectedDescription = $""" + ({FeaturesResources.local_variable}) int xyz + + {string.Format(FeaturesResources._0_1, "Proj1", FeaturesResources.Available)} + {string.Format(FeaturesResources._0_1, "Proj2", FeaturesResources.Not_Available)} + + {FeaturesResources.You_can_use_the_navigation_bar_to_switch_contexts} + """; await VerifyItemInLinkedFilesAsync(markup, "xyz", expectedDescription); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1020944")] public async Task LabelsValidInLinkedDocuments() { - var markup = @" - - - - - - - -"; + var markup = """ + + + + + + + + + + """; var expectedDescription = $"({FeaturesResources.label}) LABEL"; await VerifyItemInLinkedFilesAsync(markup, "LABEL", expectedDescription); } @@ -8500,24 +9017,26 @@ void M() [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1020944")] public async Task RangeVariablesValidInLinkedDocuments() { - var markup = @" - - - - - - - -"; + var markup = """ + + + + + + + + + + """; var expectedDescription = $"({FeaturesResources.range_variable}) ? y"; await VerifyItemInLinkedFilesAsync(markup, "y", expectedDescription); } @@ -8525,31 +9044,33 @@ void M() [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1063403")] public async Task MethodOverloadDifferencesIgnored() { - var markup = @" - - + + - - - - - -"; + } + ]]> + + + + + + + """; var expectedDescription = $"void C.Do(int x)"; await VerifyItemInLinkedFilesAsync(markup, "Do", expectedDescription); @@ -8558,37 +9079,39 @@ void Shared() [Fact] public async Task MethodOverloadDifferencesIgnored_ExtensionMethod() { - var markup = @" - - + + - - - - - -"; + public static class Extensions + { + #if TWO + public static void Do (this C c, string x) + { + } + #endif + } + ]]> + + + + + + + """; var expectedDescription = $"void C.Do(int x)"; await VerifyItemInLinkedFilesAsync(markup, "Do", expectedDescription); @@ -8597,37 +9120,39 @@ public static void Do (this C c, string x) [Fact] public async Task MethodOverloadDifferencesIgnored_ExtensionMethod2() { - var markup = @" - - + + - - - - - -"; + public static class Extensions + { + #if TWO + public static void Do (this C c, string x) + { + } + #endif + } + ]]> + + + + + + + """; var expectedDescription = $"({CSharpFeaturesResources.extension}) void C.Do(string x)"; await VerifyItemInLinkedFilesAsync(markup, "Do", expectedDescription); @@ -8636,52 +9161,54 @@ public static void Do (this C c, string x) [Fact] public async Task MethodOverloadDifferencesIgnored_ContainingType() { - var markup = @" - - + + - - - - - -"; + #if TWO + public class Methods2 + { + public void Do(string x) { } + } + #endif + ]]> + + + + + + + """; var expectedDescription = $"void Methods1.Do(string x)"; await VerifyItemInLinkedFilesAsync(markup, "Do", expectedDescription); @@ -8690,29 +9217,31 @@ public void Do(string x) { } [Fact] public async Task SharedProjectFieldAndPropertiesTreatedAsIdentical() { - var markup = @" - - - - - - - -"; + var markup = """ + + + + + + + + + + """; var expectedDescription = $"({FeaturesResources.field}) int C.x"; await VerifyItemInLinkedFilesAsync(markup, "x", expectedDescription); @@ -8721,29 +9250,31 @@ void goo() [Fact] public async Task SharedProjectFieldAndPropertiesTreatedAsIdentical2() { - var markup = @" - - - - - - - -"; + var markup = """ + + + + + + + + + + """; var expectedDescription = "int C.x { get; set; }"; await VerifyItemInLinkedFilesAsync(markup, "x", expectedDescription); @@ -8752,25 +9283,26 @@ void goo() [Fact] public async Task ConditionalAccessWalkUp() { - var markup = @" -public class B -{ - public A BA; - public B BB; -} + var markup = """ + public class B + { + public A BA; + public B BB; + } -class A -{ - public A AA; - public A AB; - public int? x; + class A + { + public A AA; + public A AB; + public int? x; - public void goo() - { - A a = null; - var q = a?.$$AB.BA.AB.BA; - } -}"; + public void goo() + { + A a = null; + var q = a?.$$AB.BA.AB.BA; + } + } + """; await VerifyExpectedItemsAsync(markup, [ ItemExpectation.Exists("AA"), ItemExpectation.Exists("AB"), @@ -8780,22 +9312,23 @@ await VerifyExpectedItemsAsync(markup, [ [Fact] public async Task ConditionalAccessNullableIsUnwrapped() { - var markup = @" -public struct S -{ - public int? i; -} + var markup = """ + public struct S + { + public int? i; + } -class A -{ - public S? s; + class A + { + public S? s; - public void goo() - { - A a = null; - var q = a?.s?.$$; - } -}"; + public void goo() + { + A a = null; + var q = a?.s?.$$; + } + } + """; await VerifyExpectedItemsAsync(markup, [ ItemExpectation.Exists("i"), ItemExpectation.Absent("Value"), @@ -8805,21 +9338,22 @@ await VerifyExpectedItemsAsync(markup, [ [Fact] public async Task ConditionalAccessNullableIsUnwrapped2() { - var markup = @" -public struct S -{ - public int? i; -} + var markup = """ + public struct S + { + public int? i; + } -class A -{ - public S? s; + class A + { + public S? s; - public void goo() - { - var q = s?.$$i?.ToString(); - } -}"; + public void goo() + { + var q = s?.$$i?.ToString(); + } + } + """; await VerifyExpectedItemsAsync(markup, [ ItemExpectation.Exists("i"), ItemExpectation.Absent("Value"), @@ -8829,15 +9363,15 @@ await VerifyExpectedItemsAsync(markup, [ [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/54361")] public async Task ConditionalAccessNullableIsUnwrappedOnParameter() { - var markup = @" -class A -{ - void M(System.DateTime? dt) - { - dt?.$$ - } -} -"; + var markup = """ + class A + { + void M(System.DateTime? dt) + { + dt?.$$ + } + } + """; await VerifyExpectedItemsAsync(markup, [ ItemExpectation.Exists("Day"), ItemExpectation.Absent("Value"), @@ -8847,15 +9381,15 @@ await VerifyExpectedItemsAsync(markup, [ [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/54361")] public async Task NullableIsNotUnwrappedOnParameter() { - var markup = @" -class A -{ - void M(System.DateTime? dt) - { - dt.$$ - } -} -"; + var markup = """ + class A + { + void M(System.DateTime? dt) + { + dt.$$ + } + } + """; await VerifyExpectedItemsAsync(markup, [ ItemExpectation.Exists("Value"), ItemExpectation.Absent("Day"), @@ -8865,413 +9399,436 @@ await VerifyExpectedItemsAsync(markup, [ [Fact] public async Task CompletionAfterConditionalIndexing() { - var markup = @" -public struct S -{ - public int? i; -} + var markup = """ + public struct S + { + public int? i; + } -class A -{ - public S[] s; + class A + { + public S[] s; - public void goo() - { - A a = null; - var q = a?.s?[$$; - } -}"; + public void goo() + { + A a = null; + var q = a?.s?[$$; + } + } + """; await VerifyItemExistsAsync(markup, "System"); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1109319")] public async Task WithinChainOfConditionalAccesses1() { - var markup = @" -class Program -{ - static void Main(string[] args) - { - A a; - var x = a?.$$b?.c?.d.e; - } -} + var markup = """ + class Program + { + static void Main(string[] args) + { + A a; + var x = a?.$$b?.c?.d.e; + } + } -class A { public B b; } -class B { public C c; } -class C { public D d; } -class D { public int e; }"; + class A { public B b; } + class B { public C c; } + class C { public D d; } + class D { public int e; } + """; await VerifyItemExistsAsync(markup, "b"); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1109319")] public async Task WithinChainOfConditionalAccesses2() { - var markup = @" -class Program -{ - static void Main(string[] args) - { - A a; - var x = a?.b?.$$c?.d.e; - } -} + var markup = """ + class Program + { + static void Main(string[] args) + { + A a; + var x = a?.b?.$$c?.d.e; + } + } -class A { public B b; } -class B { public C c; } -class C { public D d; } -class D { public int e; }"; + class A { public B b; } + class B { public C c; } + class C { public D d; } + class D { public int e; } + """; await VerifyItemExistsAsync(markup, "c"); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1109319")] public async Task WithinChainOfConditionalAccesses3() { - var markup = @" -class Program -{ - static void Main(string[] args) - { - A a; - var x = a?.b?.c?.$$d.e; - } -} + var markup = """ + class Program + { + static void Main(string[] args) + { + A a; + var x = a?.b?.c?.$$d.e; + } + } -class A { public B b; } -class B { public C c; } -class C { public D d; } -class D { public int e; }"; + class A { public B b; } + class B { public C c; } + class C { public D d; } + class D { public int e; } + """; await VerifyItemExistsAsync(markup, "d"); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/843466")] public async Task NestedAttributeAccessibleOnSelf() { - var markup = @"using System; -[My] -class X -{ - [My$$] - class MyAttribute : Attribute - { + var markup = """ + using System; + [My] + class X + { + [My$$] + class MyAttribute : Attribute + { - } -}"; - await VerifyItemExistsAsync(markup, "My"); - } + } + } + """; + await VerifyItemExistsAsync(markup, "My"); + } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/843466")] public async Task NestedAttributeAccessibleOnOuterType() { - var markup = @"using System; + var markup = """ + using System; -[My] -class Y -{ + [My] + class Y + { -} + } -[$$] -class X -{ - [My] - class MyAttribute : Attribute - { + [$$] + class X + { + [My] + class MyAttribute : Attribute + { - } -}"; + } + } + """; await VerifyItemExistsAsync(markup, "My"); } [Fact] public async Task InstanceMembersFromBaseOuterType() { - var markup = @"abstract class Test -{ - private int _field; + var markup = """ + abstract class Test + { + private int _field; - public sealed class InnerTest : Test - { - - public void SomeTest() - { - $$ - } - } -}"; + public sealed class InnerTest : Test + { + + public void SomeTest() + { + $$ + } + } + } + """; await VerifyItemExistsAsync(markup, "_field"); } [Fact] public async Task InstanceMembersFromBaseOuterType2() { - var markup = @"class C -{ - void M() { } - class N : C - { - void Test() - { - $$ // M recommended and accessible - } - - class NN - { - void Test2() + var markup = """ + class C { - // M inaccessible and not recommended + void M() { } + class N : C + { + void Test() + { + $$ // M recommended and accessible + } + + class NN + { + void Test2() + { + // M inaccessible and not recommended + } + } + } } - } - } -}"; + """; await VerifyItemExistsAsync(markup, "M"); } [Fact] public async Task InstanceMembersFromBaseOuterType3() { - var markup = @"class C -{ - void M() { } - class N : C - { - void Test() - { - M(); // M recommended and accessible - } - - class NN - { - void Test2() + var markup = """ + class C { - $$ // M inaccessible and not recommended + void M() { } + class N : C + { + void Test() + { + M(); // M recommended and accessible + } + + class NN + { + void Test2() + { + $$ // M inaccessible and not recommended + } + } + } } - } - } -}"; + """; await VerifyItemIsAbsentAsync(markup, "M"); } [Fact] public async Task InstanceMembersFromBaseOuterType4() { - var markup = @"class C -{ - void M() { } - class N : C - { - void Test() - { - M(); // M recommended and accessible - } - - class NN : N - { - void Test2() + var markup = """ + class C { - $$ // M accessible and recommended. + void M() { } + class N : C + { + void Test() + { + M(); // M recommended and accessible + } + + class NN : N + { + void Test2() + { + $$ // M accessible and recommended. + } + } + } } - } - } -}"; + """; await VerifyItemExistsAsync(markup, "M"); } [Fact] public async Task InstanceMembersFromBaseOuterType5() { - var markup = @" -class D -{ - public void Q() { } -} -class C : D -{ - class N - { - void Test() - { - $$ - } - } -}"; + var markup = """ + class D + { + public void Q() { } + } + class C : D + { + class N + { + void Test() + { + $$ + } + } + } + """; await VerifyItemIsAbsentAsync(markup, "Q"); } [Fact] public async Task InstanceMembersFromBaseOuterType6() { - var markup = @" -class Base -{ - public int X; -} + var markup = """ + class Base + { + public int X; + } -class Derived : Base -{ - class Nested - { - void Test() - { - $$ - } - } -}"; + class Derived : Base + { + class Nested + { + void Test() + { + $$ + } + } + } + """; await VerifyItemIsAbsentAsync(markup, "X"); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/983367")] public async Task NoTypeParametersDefinedInCrefs() { - var markup = @"using System; + var markup = """ + using System; -/// -class Program { }"; + /// + class Program { } + """; await VerifyItemIsAbsentAsync(markup, "T"); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/988025")] public async Task ShowTypesInGenericMethodTypeParameterList1() { - var markup = @" -class Class1 -{ - public static Class1 Create() { return null; } -} -static class Class2 -{ - public static void Test(this Class1 arg) - { - } -} -class Program -{ - static void Main(string[] args) - { - Class1.Create().Test<$$ - } -} -"; + var markup = """ + class Class1 + { + public static Class1 Create() { return null; } + } + static class Class2 + { + public static void Test(this Class1 arg) + { + } + } + class Program + { + static void Main(string[] args) + { + Class1.Create().Test<$$ + } + } + """; await VerifyItemExistsAsync(markup, "Class1", displayTextSuffix: "<>", sourceCodeKind: SourceCodeKind.Regular); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/988025")] public async Task ShowTypesInGenericMethodTypeParameterList2() { - var markup = @" -class Class1 -{ - public static Class1 Create() { return null; } -} -static class Class2 -{ - public static void Test(this Class1 arg) - { - } -} -class Program -{ - static void Main(string[] args) - { - Class1.Create().Test + { + public static Class1 Create() { return null; } + } + static class Class2 + { + public static void Test(this Class1 arg) + { + } + } + class Program + { + static void Main(string[] args) + { + Class1.Create().Test", sourceCodeKind: SourceCodeKind.Regular); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/991466")] public async Task DescriptionInAliasedType() { - var markup = @" -using IAlias = IGoo; -///summary for interface IGoo -interface IGoo { } -class C -{ - I$$ -} -"; - await VerifyItemExistsAsync(markup, "IAlias", expectedDescriptionOrNull: "interface IGoo\r\nsummary for interface IGoo"); + var markup = """ + using IAlias = IGoo; + ///summary for interface IGoo + interface IGoo { } + class C + { + I$$ + } + """; + await VerifyItemExistsAsync(markup, "IAlias", expectedDescriptionOrNull: """ + interface IGoo + summary for interface IGoo + """); } [Fact] public async Task WithinNameOf() { - var markup = @" -class C -{ - void goo() - { - var x = nameof($$) - } -} -"; + var markup = """ + class C + { + void goo() + { + var x = nameof($$) + } + } + """; await VerifyAnyItemExistsAsync(markup); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/997410")] public async Task InstanceMemberInNameOfInStaticContext() { - var markup = @" -class C -{ - int y1 = 15; - static int y2 = 1; - static string x = nameof($$ -"; + var markup = """ + class C + { + int y1 = 15; + static int y2 = 1; + static string x = nameof($$ + """; await VerifyItemExistsAsync(markup, "y1"); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/997410")] public async Task StaticMemberInNameOfInStaticContext() { - var markup = @" -class C -{ - int y1 = 15; - static int y2 = 1; - static string x = nameof($$ -"; + var markup = """ + class C + { + int y1 = 15; + static int y2 = 1; + static string x = nameof($$ + """; await VerifyItemExistsAsync(markup, "y2"); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/883293")] public async Task IncompleteDeclarationExpressionType() { - var markup = @" -using System; -class C -{ - void goo() - { - var x = Console.$$ - var y = 3; - } -} -"; + var markup = """ + using System; + class C + { + void goo() + { + var x = Console.$$ + var y = 3; + } + } + """; await VerifyItemExistsAsync(markup, "WriteLine"); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1024380")] public async Task StaticAndInstanceInNameOf() { - var markup = @" -using System; -class C -{ - class D - { - public int x; - public static int y; - } + var markup = """ + using System; + class C + { + class D + { + public int x; + public static int y; + } - void goo() - { - var z = nameof(C.D.$$ - } -} -"; + void goo() + { + var z = nameof(C.D.$$ + } + } + """; await VerifyExpectedItemsAsync(markup, [ ItemExpectation.Exists("x"), ItemExpectation.Exists("y"), @@ -9281,178 +9838,185 @@ await VerifyExpectedItemsAsync(markup, [ [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/1663")] public async Task NameOfMembersListedForLocals() { - var markup = @"class C -{ - void M() - { - var x = nameof(T.z.$$) - } -} - -public class T -{ - public U z; -} - -public class U -{ - public int nope; -} -"; + var markup = """ + class C + { + void M() + { + var x = nameof(T.z.$$) + } + } + + public class T + { + public U z; + } + + public class U + { + public int nope; + } + """; await VerifyItemExistsAsync(markup, "nope"); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1029522")] public async Task NameOfMembersListedForNamespacesAndTypes2() { - var markup = @"class C -{ - void M() - { - var x = nameof(U.$$) - } -} - -public class T -{ - public U z; -} - -public class U -{ - public int nope; -} -"; + var markup = """ + class C + { + void M() + { + var x = nameof(U.$$) + } + } + + public class T + { + public U z; + } + + public class U + { + public int nope; + } + """; await VerifyItemExistsAsync(markup, "nope"); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1029522")] public async Task NameOfMembersListedForNamespacesAndTypes3() { - var markup = @"class C -{ - void M() - { - var x = nameof(N.$$) - } -} + var markup = """ + class C + { + void M() + { + var x = nameof(N.$$) + } + } -namespace N -{ -public class U -{ - public int nope; -} -} "; + namespace N + { + public class U + { + public int nope; + } + } + """; await VerifyItemExistsAsync(markup, "U"); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1029522")] public async Task NameOfMembersListedForNamespacesAndTypes4() { - var markup = @" -using z = System; -class C -{ - void M() - { - var x = nameof(z.$$) - } -} -"; + var markup = """ + using z = System; + class C + { + void M() + { + var x = nameof(z.$$) + } + } + """; await VerifyItemExistsAsync(markup, "Console"); } [Fact] public async Task InterpolatedStrings1() { - var markup = @" -class C -{ - void M() - { - var a = ""Hello""; - var b = ""World""; - var c = $""{$$ -"; + var markup = """ + class C + { + void M() + { + var a = "Hello"; + var b = "World"; + var c = $"{$$ + """; await VerifyItemExistsAsync(markup, "a"); } [Fact] public async Task InterpolatedStrings2() { - var markup = @" -class C -{ - void M() - { - var a = ""Hello""; - var b = ""World""; - var c = $""{$$}""; - } -}"; + var markup = """ + class C + { + void M() + { + var a = "Hello"; + var b = "World"; + var c = $"{$$}"; + } + } + """; await VerifyItemExistsAsync(markup, "a"); } [Fact] public async Task InterpolatedStrings3() { - var markup = @" -class C -{ - void M() - { - var a = ""Hello""; - var b = ""World""; - var c = $""{a}, {$$ -"; + var markup = """ + class C + { + void M() + { + var a = "Hello"; + var b = "World"; + var c = $"{a}, {$$ + """; await VerifyItemExistsAsync(markup, "b"); } [Fact] public async Task InterpolatedStrings4() { - var markup = @" -class C -{ - void M() - { - var a = ""Hello""; - var b = ""World""; - var c = $""{a}, {$$}""; - } -}"; + var markup = """ + class C + { + void M() + { + var a = "Hello"; + var b = "World"; + var c = $"{a}, {$$}"; + } + } + """; await VerifyItemExistsAsync(markup, "b"); } [Fact] public async Task InterpolatedStrings5() { - var markup = @" -class C -{ - void M() - { - var a = ""Hello""; - var b = ""World""; - var c = $@""{a}, {$$ -"; + var markup = """ + class C + { + void M() + { + var a = "Hello"; + var b = "World"; + var c = $@"{a}, {$$ + """; await VerifyItemExistsAsync(markup, "b"); } [Fact] public async Task InterpolatedStrings6() { - var markup = @" -class C -{ - void M() - { - var a = ""Hello""; - var b = ""World""; - var c = $@""{a}, {$$}""; - } -}"; + var markup = """ + class C + { + void M() + { + var a = "Hello"; + var b = "World"; + var c = $@"{a}, {$$}"; + } + } + """; await VerifyItemExistsAsync(markup, "b"); } @@ -9461,7 +10025,9 @@ void M() public async Task NotBeforeFirstStringHole() { await VerifyNoItemsExistAsync(AddInsideMethod( -@"var x = ""\{0}$$\{1}\{2}""")); + """ + var x = "\{0}$$\{1}\{2}" + """)); } [Fact, Trait(Traits.Feature, Traits.Features.KeywordRecommending)] @@ -9469,7 +10035,9 @@ await VerifyNoItemsExistAsync(AddInsideMethod( public async Task NotBetweenStringHoles() { await VerifyNoItemsExistAsync(AddInsideMethod( -@"var x = ""\{0}\{1}$$\{2}""")); + """ + var x = "\{0}\{1}$$\{2}" + """)); } [Fact, Trait(Traits.Feature, Traits.Features.KeywordRecommending)] @@ -9477,7 +10045,9 @@ await VerifyNoItemsExistAsync(AddInsideMethod( public async Task NotAfterStringHoles() { await VerifyNoItemsExistAsync(AddInsideMethod( -@"var x = ""\{0}\{1}\{2}$$""")); + """ + var x = "\{0}\{1}\{2}$$" + """)); } [Fact, Trait(Traits.Feature, Traits.Features.KeywordRecommending)] @@ -9491,19 +10061,20 @@ await VerifyItemExistsAsync(AddInsideMethod( [Fact] public async Task UsingDirectives1() { - var markup = @" -using $$ + var markup = """ + using $$ -class A { } -static class B { } + class A { } + static class B { } -namespace N -{ - class C { } - static class D { } + namespace N + { + class C { } + static class D { } - namespace M { } -}"; + namespace M { } + } + """; await VerifyExpectedItemsAsync(markup, [ ItemExpectation.Absent("A"), @@ -9515,19 +10086,20 @@ await VerifyExpectedItemsAsync(markup, [ [Fact] public async Task UsingDirectives2() { - var markup = @" -using N.$$ + var markup = """ + using N.$$ -class A { } -static class B { } + class A { } + static class B { } -namespace N -{ - class C { } - static class D { } + namespace N + { + class C { } + static class D { } - namespace M { } -}"; + namespace M { } + } + """; await VerifyExpectedItemsAsync(markup, [ ItemExpectation.Absent("C"), @@ -9539,19 +10111,20 @@ await VerifyExpectedItemsAsync(markup, [ [Fact] public async Task UsingDirectives3() { - var markup = @" -using G = $$ + var markup = """ + using G = $$ -class A { } -static class B { } + class A { } + static class B { } -namespace N -{ - class C { } - static class D { } + namespace N + { + class C { } + static class D { } - namespace M { } -}"; + namespace M { } + } + """; await VerifyExpectedItemsAsync(markup, [ ItemExpectation.Exists("A"), @@ -9563,19 +10136,20 @@ await VerifyExpectedItemsAsync(markup, [ [Fact] public async Task UsingDirectives4() { - var markup = @" -using G = N.$$ + var markup = """ + using G = N.$$ -class A { } -static class B { } + class A { } + static class B { } -namespace N -{ - class C { } - static class D { } + namespace N + { + class C { } + static class D { } - namespace M { } -}"; + namespace M { } + } + """; await VerifyExpectedItemsAsync(markup, [ ItemExpectation.Exists("C"), @@ -9587,19 +10161,20 @@ await VerifyExpectedItemsAsync(markup, [ [Fact] public async Task UsingDirectives5() { - var markup = @" -using static $$ + var markup = """ + using static $$ -class A { } -static class B { } + class A { } + static class B { } -namespace N -{ - class C { } - static class D { } + namespace N + { + class C { } + static class D { } - namespace M { } -}"; + namespace M { } + } + """; await VerifyExpectedItemsAsync(markup, [ ItemExpectation.Exists("A"), @@ -9611,19 +10186,20 @@ await VerifyExpectedItemsAsync(markup, [ [Fact] public async Task UsingDirectives6() { - var markup = @" -using static N.$$ + var markup = """ + using static N.$$ -class A { } -static class B { } + class A { } + static class B { } -namespace N -{ - class C { } - static class D { } + namespace N + { + class C { } + static class D { } - namespace M { } -}"; + namespace M { } + } + """; await VerifyExpectedItemsAsync(markup, [ ItemExpectation.Exists("C"), @@ -9635,19 +10211,20 @@ await VerifyExpectedItemsAsync(markup, [ [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/67985")] public async Task UsingDirectives7() { - var markup = @" -using static unsafe $$ + var markup = """ + using static unsafe $$ -class A { } -static class B { } + class A { } + static class B { } -namespace N -{ - class C { } - static class D { } + namespace N + { + class C { } + static class D { } - namespace M { } -}"; + namespace M { } + } + """; await VerifyExpectedItemsAsync(markup, [ ItemExpectation.Exists("A"), @@ -9659,19 +10236,20 @@ await VerifyExpectedItemsAsync(markup, [ [Fact] public async Task UsingStaticDoesNotShowDelegates1() { - var markup = @" -using static $$ + var markup = """ + using static $$ -class A { } -delegate void B(); + class A { } + delegate void B(); -namespace N -{ - class C { } - static class D { } + namespace N + { + class C { } + static class D { } - namespace M { } -}"; + namespace M { } + } + """; await VerifyExpectedItemsAsync(markup, [ ItemExpectation.Exists("A"), @@ -9683,19 +10261,20 @@ await VerifyExpectedItemsAsync(markup, [ [Fact] public async Task UsingStaticDoesNotShowDelegates2() { - var markup = @" -using static N.$$ + var markup = """ + using static N.$$ -class A { } -static class B { } + class A { } + static class B { } -namespace N -{ - class C { } - delegate void D(); + namespace N + { + class C { } + delegate void D(); - namespace M { } -}"; + namespace M { } + } + """; await VerifyExpectedItemsAsync(markup, [ ItemExpectation.Exists("C"), @@ -9707,19 +10286,20 @@ await VerifyExpectedItemsAsync(markup, [ [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/67985")] public async Task UsingStaticDoesNotShowDelegates3() { - var markup = @" -using static unsafe $$ + var markup = """ + using static unsafe $$ -class A { } -delegate void B(); + class A { } + delegate void B(); -namespace N -{ - class C { } - static class D { } + namespace N + { + class C { } + static class D { } - namespace M { } -}"; + namespace M { } + } + """; await VerifyExpectedItemsAsync(markup, [ ItemExpectation.Exists("A"), @@ -9732,19 +10312,20 @@ await VerifyExpectedItemsAsync(markup, [ public async Task UsingStaticShowInterfaces1() { // Interfaces can have implemented static methods - var markup = @" -using static N.$$ + var markup = """ + using static N.$$ -class A { } -static class B { } + class A { } + static class B { } -namespace N -{ - class C { } - interface I { } + namespace N + { + class C { } + interface I { } - namespace M { } -}"; + namespace M { } + } + """; await VerifyExpectedItemsAsync(markup, [ ItemExpectation.Exists("C"), @@ -9757,19 +10338,20 @@ await VerifyExpectedItemsAsync(markup, [ public async Task UsingStaticShowInterfaces2() { // Interfaces can have implemented static methods - var markup = @" -using static $$ + var markup = """ + using static $$ -class A { } -interface I { } + class A { } + interface I { } -namespace N -{ - class C { } - static class D { } + namespace N + { + class C { } + static class D { } - namespace M { } -}"; + namespace M { } + } + """; await VerifyExpectedItemsAsync(markup, [ ItemExpectation.Exists("A"), @@ -9782,19 +10364,20 @@ await VerifyExpectedItemsAsync(markup, [ public async Task UsingStaticShowInterfaces3() { // Interfaces can have implemented static methods - var markup = @" -using static unsafe $$ + var markup = """ + using static unsafe $$ -class A { } -interface I { } + class A { } + interface I { } -namespace N -{ - class C { } - static class D { } + namespace N + { + class C { } + static class D { } - namespace M { } -}"; + namespace M { } + } + """; await VerifyExpectedItemsAsync(markup, [ ItemExpectation.Exists("A"), @@ -9806,28 +10389,28 @@ await VerifyExpectedItemsAsync(markup, [ [Fact] public async Task UsingStaticAndExtensionMethods1() { - var markup = @" -using static A; -using static B; + var markup = """ + using static A; + using static B; -static class A -{ - public static void Goo(this string s) { } -} + static class A + { + public static void Goo(this string s) { } + } -static class B -{ - public static void Bar(this string s) { } -} + static class B + { + public static void Bar(this string s) { } + } -class C -{ - void M() - { - $$ - } -} -"; + class C + { + void M() + { + $$ + } + } + """; await VerifyExpectedItemsAsync(markup, [ ItemExpectation.Absent("Goo"), @@ -9838,30 +10421,30 @@ await VerifyExpectedItemsAsync(markup, [ [Fact] public async Task UsingStaticAndExtensionMethods2() { - var markup = @" -using N; + var markup = """ + using N; -namespace N -{ - static class A - { - public static void Goo(this string s) { } - } + namespace N + { + static class A + { + public static void Goo(this string s) { } + } - static class B - { - public static void Bar(this string s) { } - } -} + static class B + { + public static void Bar(this string s) { } + } + } -class C -{ - void M() - { - $$ - } -} -"; + class C + { + void M() + { + $$ + } + } + """; await VerifyExpectedItemsAsync(markup, [ ItemExpectation.Absent("Goo"), @@ -9872,31 +10455,31 @@ await VerifyExpectedItemsAsync(markup, [ [Fact] public async Task UsingStaticAndExtensionMethods3() { - var markup = @" -using N; + var markup = """ + using N; -namespace N -{ - static class A - { - public static void Goo(this string s) { } - } + namespace N + { + static class A + { + public static void Goo(this string s) { } + } - static class B - { - public static void Bar(this string s) { } - } -} + static class B + { + public static void Bar(this string s) { } + } + } -class C -{ - void M() - { - string s; - s.$$ - } -} -"; + class C + { + void M() + { + string s; + s.$$ + } + } + """; await VerifyExpectedItemsAsync(markup, [ ItemExpectation.Exists("Goo"), @@ -9907,32 +10490,32 @@ await VerifyExpectedItemsAsync(markup, [ [Fact] public async Task UsingStaticAndExtensionMethods4() { - var markup = @" -using static N.A; -using static N.B; + var markup = """ + using static N.A; + using static N.B; -namespace N -{ - static class A - { - public static void Goo(this string s) { } - } + namespace N + { + static class A + { + public static void Goo(this string s) { } + } - static class B - { - public static void Bar(this string s) { } - } -} + static class B + { + public static void Bar(this string s) { } + } + } -class C -{ - void M() - { - string s; - s.$$ - } -} -"; + class C + { + void M() + { + string s; + s.$$ + } + } + """; await VerifyExpectedItemsAsync(markup, [ ItemExpectation.Exists("Goo"), @@ -9943,31 +10526,31 @@ await VerifyExpectedItemsAsync(markup, [ [Fact] public async Task UsingStaticAndExtensionMethods5() { - var markup = @" -using static N.A; + var markup = """ + using static N.A; -namespace N -{ - static class A - { - public static void Goo(this string s) { } - } + namespace N + { + static class A + { + public static void Goo(this string s) { } + } - static class B - { - public static void Bar(this string s) { } - } -} + static class B + { + public static void Bar(this string s) { } + } + } -class C -{ - void M() - { - string s; - s.$$ - } -} -"; + class C + { + void M() + { + string s; + s.$$ + } + } + """; await VerifyExpectedItemsAsync(markup, [ ItemExpectation.Exists("Goo"), @@ -9978,31 +10561,31 @@ await VerifyExpectedItemsAsync(markup, [ [Fact] public async Task UsingStaticAndExtensionMethods6() { - var markup = @" -using static N.B; + var markup = """ + using static N.B; -namespace N -{ - static class A - { - public static void Goo(this string s) { } - } + namespace N + { + static class A + { + public static void Goo(this string s) { } + } - static class B - { - public static void Bar(this string s) { } - } -} + static class B + { + public static void Bar(this string s) { } + } + } -class C -{ - void M() - { - string s; - s.$$ - } -} -"; + class C + { + void M() + { + string s; + s.$$ + } + } + """; await VerifyExpectedItemsAsync(markup, [ ItemExpectation.Absent("Goo"), @@ -10013,32 +10596,32 @@ await VerifyExpectedItemsAsync(markup, [ [Fact] public async Task UsingStaticAndExtensionMethods7() { - var markup = @" -using N; -using static N.B; + var markup = """ + using N; + using static N.B; -namespace N -{ - static class A - { - public static void Goo(this string s) { } - } + namespace N + { + static class A + { + public static void Goo(this string s) { } + } - static class B - { - public static void Bar(this string s) { } - } -} + static class B + { + public static void Bar(this string s) { } + } + } -class C -{ - void M() - { - string s; - s.$$; - } -} -"; + class C + { + void M() + { + string s; + s.$$; + } + } + """; await VerifyExpectedItemsAsync(markup, [ ItemExpectation.Exists("Goo"), @@ -10049,54 +10632,54 @@ await VerifyExpectedItemsAsync(markup, [ [WpfFact, WorkItem("https://github.com/dotnet/roslyn/issues/7932")] public async Task ExtensionMethodWithinSameClassOfferedForCompletion() { - var markup = @" -public static class Test -{ - static void TestB() - { - $$ - } - static void TestA(this string s) { } -} -"; + var markup = """ + public static class Test + { + static void TestB() + { + $$ + } + static void TestA(this string s) { } + } + """; await VerifyItemExistsAsync(markup, "TestA"); } [WpfFact, WorkItem("https://github.com/dotnet/roslyn/issues/7932")] public async Task ExtensionMethodWithinParentClassOfferedForCompletion() { - var markup = @" -public static class Parent -{ - static void TestA(this string s) { } - static void TestC(string s) { } - public static class Test - { - static void TestB() - { - $$ - } - } -} -"; + var markup = """ + public static class Parent + { + static void TestA(this string s) { } + static void TestC(string s) { } + public static class Test + { + static void TestB() + { + $$ + } + } + } + """; await VerifyItemExistsAsync(markup, "TestA"); } [Fact] public async Task ExceptionFilter1() { - var markup = @" -using System; + var markup = """ + using System; -class C -{ - void M(bool x) - { - try - { - } - catch when ($$ -"; + class C + { + void M(bool x) + { + try + { + } + catch when ($$ + """; await VerifyItemExistsAsync(markup, "x"); } @@ -10104,18 +10687,18 @@ void M(bool x) [Fact] public async Task ExceptionFilter1_NotBeforeOpenParen() { - var markup = @" -using System; + var markup = """ + using System; -class C -{ - void M(bool x) - { - try - { - } - catch when $$ -"; + class C + { + void M(bool x) + { + try + { + } + catch when $$ + """; await VerifyNoItemsExistAsync(markup); } @@ -10123,18 +10706,18 @@ void M(bool x) [Fact] public async Task ExceptionFilter2() { - var markup = @" -using System; + var markup = """ + using System; -class C -{ - void M(bool x) - { - try - { - } - catch (Exception ex) when ($$ -"; + class C + { + void M(bool x) + { + try + { + } + catch (Exception ex) when ($$ + """; await VerifyItemExistsAsync(markup, "x"); } @@ -10142,18 +10725,18 @@ void M(bool x) [Fact] public async Task ExceptionFilter2_NotBeforeOpenParen() { - var markup = @" -using System; + var markup = """ + using System; -class C -{ - void M(bool x) - { - try - { - } - catch (Exception ex) when $$ -"; + class C + { + void M(bool x) + { + try + { + } + catch (Exception ex) when $$ + """; await VerifyNoItemsExistAsync(markup); } @@ -10161,15 +10744,15 @@ void M(bool x) [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/25084")] public async Task SwitchCaseWhenClause1() { - var markup = @" -class C -{ - void M(bool x) - { - switch (1) - { - case 1 when $$ -"; + var markup = """ + class C + { + void M(bool x) + { + switch (1) + { + case 1 when $$ + """; await VerifyItemExistsAsync(markup, "x"); } @@ -10177,15 +10760,15 @@ void M(bool x) [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/25084")] public async Task SwitchCaseWhenClause2() { - var markup = @" -class C -{ - void M(bool x) - { - switch (1) - { - case int i when $$ -"; + var markup = """ + class C + { + void M(bool x) + { + switch (1) + { + case int i when $$ + """; await VerifyItemExistsAsync(markup, "x"); } @@ -10193,141 +10776,142 @@ void M(bool x) [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/717")] public async Task ExpressionContextCompletionWithinCast() { - var markup = @" -class Program -{ - void M() - { - for (int i = 0; i < 5; i++) - { - var x = ($$) - var y = 1; - } - } -} -"; + var markup = """ + class Program + { + void M() + { + for (int i = 0; i < 5; i++) + { + var x = ($$) + var y = 1; + } + } + } + """; await VerifyItemExistsAsync(markup, "i"); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/1277")] public async Task NoInstanceMembersInPropertyInitializer() { - var markup = @" -class A { - int abc; - int B { get; } = $$ -} -"; + var markup = """ + class A { + int abc; + int B { get; } = $$ + } + """; await VerifyItemIsAbsentAsync(markup, "abc"); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/1277")] public async Task StaticMembersInPropertyInitializer() { - var markup = @" -class A { - static Action s_abc; - event Action B = $$ -} -"; + var markup = """ + class A { + static Action s_abc; + event Action B = $$ + } + """; await VerifyItemExistsAsync(markup, "s_abc"); } [Fact] public async Task NoInstanceMembersInFieldLikeEventInitializer() { - var markup = @" -class A { - Action abc; - event Action B = $$ -} -"; + var markup = """ + class A { + Action abc; + event Action B = $$ + } + """; await VerifyItemIsAbsentAsync(markup, "abc"); } [Fact] public async Task StaticMembersInFieldLikeEventInitializer() { - var markup = @" -class A { - static Action s_abc; - event Action B = $$ -} -"; + var markup = """ + class A { + static Action s_abc; + event Action B = $$ + } + """; await VerifyItemExistsAsync(markup, "s_abc"); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/5069")] public async Task InstanceMembersInTopLevelFieldInitializer() { - var markup = @" -int aaa = 1; -int bbb = $$ -"; + var markup = """ + int aaa = 1; + int bbb = $$ + """; await VerifyItemExistsAsync(markup, "aaa", sourceCodeKind: SourceCodeKind.Script); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/5069")] public async Task InstanceMembersInTopLevelFieldLikeEventInitializer() { - var markup = @" -Action aaa = null; -event Action bbb = $$ -"; + var markup = """ + Action aaa = null; + event Action bbb = $$ + """; await VerifyItemExistsAsync(markup, "aaa", sourceCodeKind: SourceCodeKind.Script); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/33")] public async Task NoConditionalAccessCompletionOnTypes1() { - var markup = @" -using A = System -class C -{ - A?.$$ -} -"; + var markup = """ + using A = System + class C + { + A?.$$ + } + """; await VerifyNoItemsExistAsync(markup); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/33")] public async Task NoConditionalAccessCompletionOnTypes2() { - var markup = @" -class C -{ - System?.$$ -} -"; + var markup = """ + class C + { + System?.$$ + } + """; await VerifyNoItemsExistAsync(markup); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/33")] public async Task NoConditionalAccessCompletionOnTypes3() { - var markup = @" -class C -{ - System.Console?.$$ -} -"; + var markup = """ + class C + { + System.Console?.$$ + } + """; await VerifyNoItemsExistAsync(markup); } [Fact] public async Task CompletionInIncompletePropertyDeclaration() { - var markup = @" -class Class1 -{ - public string Property1 { get; set; } -} + var markup = """ + class Class1 + { + public string Property1 { get; set; } + } -class Class2 -{ - public string Property { get { return this.Source.$$ - public Class1 Source { get; set; } -}"; + class Class2 + { + public string Property { get { return this.Source.$$ + public Class1 Source { get; set; } + } + """; await VerifyItemExistsAsync(markup, "Property1"); } @@ -10341,102 +10925,108 @@ public async Task NoCompletionInShebangComments() [Fact] public async Task CompoundNameTargetTypePreselection() { - var markup = @" -class Class1 -{ - void goo() - { - int x = 3; - string y = x.$$ - } -}"; + var markup = """ + class Class1 + { + void goo() + { + int x = 3; + string y = x.$$ + } + } + """; await VerifyItemExistsAsync(markup, "ToString", matchPriority: SymbolMatchPriority.PreferEventOrMethod); } [Fact] public async Task TargetTypeInCollectionInitializer1() { - var markup = @" -using System.Collections.Generic; + var markup = """ + using System.Collections.Generic; -class Program -{ - static void Main(string[] args) - { - int z; - string q; - List x = new List() { $$ } - } -}"; + class Program + { + static void Main(string[] args) + { + int z; + string q; + List x = new List() { $$ } + } + } + """; await VerifyItemExistsAsync(markup, "z", matchPriority: SymbolMatchPriority.PreferLocalOrParameterOrRangeVariable); } [Fact] public async Task TargetTypeInCollectionInitializer2() { - var markup = @" -using System.Collections.Generic; + var markup = """ + using System.Collections.Generic; -class Program -{ - static void Main(string[] args) - { - int z; - string q; - List x = new List() { 1, $$ } - } -}"; + class Program + { + static void Main(string[] args) + { + int z; + string q; + List x = new List() { 1, $$ } + } + } + """; await VerifyItemExistsAsync(markup, "z", matchPriority: SymbolMatchPriority.PreferLocalOrParameterOrRangeVariable); } [Fact] public async Task TargeTypeInObjectInitializer1() { - var markup = @" -class C -{ - public int X { get; set; } - public int Y { get; set; } + var markup = """ + class C + { + public int X { get; set; } + public int Y { get; set; } - void goo() - { - int i; - var c = new C() { X = $$ } - } -}"; + void goo() + { + int i; + var c = new C() { X = $$ } + } + } + """; await VerifyItemExistsAsync(markup, "i", matchPriority: SymbolMatchPriority.PreferLocalOrParameterOrRangeVariable); } [Fact] public async Task TargeTypeInObjectInitializer2() { - var markup = @" -class C -{ - public int X { get; set; } - public int Y { get; set; } + var markup = """ + class C + { + public int X { get; set; } + public int Y { get; set; } - void goo() - { - int i; - var c = new C() { X = 1, Y = $$ } - } -}"; + void goo() + { + int i; + var c = new C() { X = 1, Y = $$ } + } + } + """; await VerifyItemExistsAsync(markup, "i", matchPriority: SymbolMatchPriority.PreferLocalOrParameterOrRangeVariable); } [Fact] public async Task TupleElements() { - var markup = @" -class C -{ - void goo() - { - var t = (Alice: 1, Item2: 2, ITEM3: 3, 4, 5, 6, 7, 8, Bob: 9); - t.$$ - } -}" + TestResources.NetFX.ValueTuple.tuplelib_cs; + var markup = """ + class C + { + void goo() + { + var t = (Alice: 1, Item2: 2, ITEM3: 3, 4, 5, 6, 7, 8, Bob: 9); + t.$$ + } + } + """ + TestResources.NetFX.ValueTuple.tuplelib_cs; await VerifyExpectedItemsAsync(markup, [ ItemExpectation.Exists("Alice"), @@ -10464,14 +11054,15 @@ await VerifyExpectedItemsAsync(markup, [ [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/14546")] public async Task TupleElementsCompletionOffMethodGroup() { - var markup = @" -class C -{ - void goo() - { - new object().ToString.$$ - } -}" + TestResources.NetFX.ValueTuple.tuplelib_cs; + var markup = """ + class C + { + void goo() + { + new object().ToString.$$ + } + } + """ + TestResources.NetFX.ValueTuple.tuplelib_cs; // should not crash await VerifyNoItemsExistAsync(markup); @@ -10482,12 +11073,13 @@ void goo() [WorkItem("https://github.com/dotnet/roslyn/issues/13480")] public async Task NoCompletionInLocalFuncGenericParamList() { - var markup = @" -class C -{ - void M() - { - int Local<$$"; + var markup = """ + class C + { + void M() + { + int Local<$$ + """; await VerifyNoItemsExistAsync(markup); } @@ -10497,12 +11089,13 @@ void M() [WorkItem("https://github.com/dotnet/roslyn/issues/13480")] public async Task CompletionForAwaitWithoutAsync() { - var markup = @" -class C -{ - void M() - { - await Local<$$"; + var markup = """ + class C + { + void M() + { + await Local<$$ + """; await VerifyAnyItemExistsAsync(markup); } @@ -10510,141 +11103,151 @@ void M() [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/14127")] public async Task TupleTypeAtMemberLevel1() { - await VerifyItemExistsAsync(@" -class C -{ - ($$ -}", "C"); + await VerifyItemExistsAsync(""" + class C + { + ($$ + } + """, "C"); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/14127")] public async Task TupleTypeAtMemberLevel2() { - await VerifyItemExistsAsync(@" -class C -{ - ($$) -}", "C"); + await VerifyItemExistsAsync(""" + class C + { + ($$) + } + """, "C"); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/14127")] public async Task TupleTypeAtMemberLevel3() { - await VerifyItemExistsAsync(@" -class C -{ - (C, $$ -}", "C"); + await VerifyItemExistsAsync(""" + class C + { + (C, $$ + } + """, "C"); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/14127")] public async Task TupleTypeAtMemberLevel4() { - await VerifyItemExistsAsync(@" -class C -{ - (C, $$) -}", "C"); + await VerifyItemExistsAsync(""" + class C + { + (C, $$) + } + """, "C"); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/14127")] public async Task TupleTypeInForeach() { - await VerifyItemExistsAsync(@" -class C -{ - void M() - { - foreach ((C, $$ - } -}", "C"); + await VerifyItemExistsAsync(""" + class C + { + void M() + { + foreach ((C, $$ + } + } + """, "C"); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/14127")] public async Task TupleTypeInParameterList() { - await VerifyItemExistsAsync(@" -class C -{ - void M((C, $$) - { - } -}", "C"); + await VerifyItemExistsAsync(""" + class C + { + void M((C, $$) + { + } + } + """, "C"); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/14127")] public async Task TupleTypeInNameOf() { - await VerifyItemExistsAsync(@" -class C -{ - void M() - { - var x = nameof((C, $$ - } -}", "C"); + await VerifyItemExistsAsync(""" + class C + { + void M() + { + var x = nameof((C, $$ + } + } + """, "C"); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/14163")] [CompilerTrait(CompilerFeature.LocalFunctions)] public async Task LocalFunctionDescription() { - await VerifyItemExistsAsync(@" -class C -{ - void M() - { - void Local() { } - - $$ - } -}", "Local", "void Local()"); + await VerifyItemExistsAsync(""" + class C + { + void M() + { + void Local() { } + + $$ + } + } + """, "Local", "void Local()"); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/14163")] [CompilerTrait(CompilerFeature.LocalFunctions)] public async Task LocalFunctionDescription2() { - await VerifyItemExistsAsync(@" -using System; -class C -{ - class var { } - void M() - { - Action Local(string x, ref var @class, params Func f) - { - return () => 0; - } + await VerifyItemExistsAsync(""" + using System; + class C + { + class var { } + void M() + { + Action Local(string x, ref var @class, params Func f) + { + return () => 0; + } - $$ - } -}", "Local", "Action Local(string x, ref var @class, params Func f)"); + $$ + } + } + """, "Local", "Action Local(string x, ref var @class, params Func f)"); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/18359")] public async Task EnumMemberAfterDot() { var markup = -@"namespace ConsoleApplication253 -{ - class Program - { - static void Main(string[] args) - { - M(E.$$) - } + """ + namespace ConsoleApplication253 + { + class Program + { + static void Main(string[] args) + { + M(E.$$) + } - static void M(E e) { } - } + static void M(E e) { } + } - enum E - { - A, - B, - } -} -"; + enum E + { + A, + B, + } + } + """; // VerifyItemExistsAsync also tests with the item typed. await VerifyItemExistsAsync(markup, "A"); await VerifyItemExistsAsync(markup, "B"); @@ -10655,17 +11258,18 @@ enum E public async Task NotOnMethodGroup1() { var markup = -@"namespace ConsoleApp -{ - class Program - { - static void Main(string[] args) - { - Main.$$ - } - } -} -"; + """ + namespace ConsoleApp + { + class Program + { + static void Main(string[] args) + { + Main.$$ + } + } + } + """; await VerifyNoItemsExistAsync(markup); } @@ -10674,10 +11278,11 @@ static void Main(string[] args) public async Task NotOnMethodGroup2() { var markup = -@"class C { - void M() {M.$$ } -} -"; + """ + class C { + void M() {M.$$ } + } + """; await VerifyNoItemsExistAsync(markup); } @@ -10686,10 +11291,11 @@ void M() {M.$$ } public async Task NotOnMethodGroup3() { var markup = -@"class C { - void M() {M.$$} -} -"; + """ + class C { + void M() {M.$$} + } + """; await VerifyNoItemsExistAsync(markup); } @@ -10698,8 +11304,9 @@ void M() {M.$$} public async Task DoNotCrashInExtensionMethoWithExpressionBodiedMember() { var markup = -@"public static class Extensions { public static T Get(this object o) => $$} -"; + """ + public static class Extensions { public static T Get(this object o) => $$} + """; await VerifyItemExistsAsync(markup, "o"); } @@ -10707,8 +11314,9 @@ public async Task DoNotCrashInExtensionMethoWithExpressionBodiedMember() public async Task EnumConstraint() { var markup = -@"public class X where T : System.$$ -"; + """ + public class X where T : System.$$ + """; await VerifyItemExistsAsync(markup, "Enum"); } @@ -10716,8 +11324,9 @@ public async Task EnumConstraint() public async Task DelegateConstraint() { var markup = -@"public class X where T : System.$$ -"; + """ + public class X where T : System.$$ + """; await VerifyItemExistsAsync(markup, "Delegate"); } @@ -10725,62 +11334,64 @@ public async Task DelegateConstraint() public async Task MulticastDelegateConstraint() { var markup = -@"public class X where T : System.$$ -"; + """ + public class X where T : System.$$ + """; await VerifyItemExistsAsync(markup, "MulticastDelegate"); } private static string CreateThenIncludeTestCode(string lambdaExpressionString, string methodDeclarationString) { - var template = @" -using System; -using System.Collections.Generic; -using System.Linq; -using System.Linq.Expressions; + var template = """ + using System; + using System.Collections.Generic; + using System.Linq; + using System.Linq.Expressions; -namespace ThenIncludeIntellisenseBug -{ - class Program - { - static void Main(string[] args) - { - var registrations = new List().AsQueryable(); - var reg = registrations.Include(r => r.Activities).ThenInclude([1]); - } - } + namespace ThenIncludeIntellisenseBug + { + class Program + { + static void Main(string[] args) + { + var registrations = new List().AsQueryable(); + var reg = registrations.Include(r => r.Activities).ThenInclude([1]); + } + } - internal class Registration - { - public ICollection Activities { get; set; } - } + internal class Registration + { + public ICollection Activities { get; set; } + } - public class Activity - { - public Task Task { get; set; } - } + public class Activity + { + public Task Task { get; set; } + } - public class Task - { - public string Name { get; set; } - } + public class Task + { + public string Name { get; set; } + } - public interface IIncludableQueryable : IQueryable - { - } + public interface IIncludableQueryable : IQueryable + { + } - public static class EntityFrameworkQuerybleExtensions - { - public static IIncludableQueryable Include( - this IQueryable source, - Expression> navigationPropertyPath) - where TEntity : class - { - return default(IIncludableQueryable); - } + public static class EntityFrameworkQuerybleExtensions + { + public static IIncludableQueryable Include( + this IQueryable source, + Expression> navigationPropertyPath) + where TEntity : class + { + return default(IIncludableQueryable); + } - [2] - } -}"; + [2] + } + } + """; return template.Replace("[1]", lambdaExpressionString).Replace("[2]", methodDeclarationString); } @@ -10789,20 +11400,21 @@ public static IIncludableQueryable Include b.$$", -@" - public static IIncludableQueryable ThenInclude( - this IIncludableQueryable> source, - Expression> navigationPropertyPath) where TEntity : class - { - return default(IIncludableQueryable); - } + """ + public static IIncludableQueryable ThenInclude( + this IIncludableQueryable> source, + Expression> navigationPropertyPath) where TEntity : class + { + return default(IIncludableQueryable); + } - public static IIncludableQueryable ThenInclude( - this IIncludableQueryable source, - Expression> navigationPropertyPath) where TEntity : class - { - return default(IIncludableQueryable); - }"); + public static IIncludableQueryable ThenInclude( + this IIncludableQueryable source, + Expression> navigationPropertyPath) where TEntity : class + { + return default(IIncludableQueryable); + } + """); await VerifyItemExistsAsync(markup, "Task"); await VerifyItemExistsAsync(markup, "FirstOrDefault", displayTextSuffix: "<>"); @@ -10812,20 +11424,21 @@ public static IIncludableQueryable ThenInclude b.$$", -@" - public static IIncludableQueryable ThenInclude( - this IIncludableQueryable> source, - Func navigationPropertyPath) where TEntity : class - { - return default(IIncludableQueryable); - } + """ + public static IIncludableQueryable ThenInclude( + this IIncludableQueryable> source, + Func navigationPropertyPath) where TEntity : class + { + return default(IIncludableQueryable); + } - public static IIncludableQueryable ThenInclude( - this IIncludableQueryable source, - Func navigationPropertyPath) where TEntity : class - { - return default(IIncludableQueryable); - }"); + public static IIncludableQueryable ThenInclude( + this IIncludableQueryable source, + Func navigationPropertyPath) where TEntity : class + { + return default(IIncludableQueryable); + } + """); await VerifyItemExistsAsync(markup, "Task"); await VerifyItemExistsAsync(markup, "FirstOrDefault", displayTextSuffix: "<>"); @@ -10835,22 +11448,23 @@ public static IIncludableQueryable ThenInclude b.$$", -@" - public static IIncludableQueryable ThenInclude( - this IIncludableQueryable> source, - int a, - Expression> navigationPropertyPath) where TEntity : class - { - return default(IIncludableQueryable); - } + """ + public static IIncludableQueryable ThenInclude( + this IIncludableQueryable> source, + int a, + Expression> navigationPropertyPath) where TEntity : class + { + return default(IIncludableQueryable); + } - public static IIncludableQueryable ThenInclude( - this IIncludableQueryable source, - int a, - Expression> navigationPropertyPath) where TEntity : class - { - return default(IIncludableQueryable); - }"); + public static IIncludableQueryable ThenInclude( + this IIncludableQueryable source, + int a, + Expression> navigationPropertyPath) where TEntity : class + { + return default(IIncludableQueryable); + } + """); await VerifyItemExistsAsync(markup, "Task"); await VerifyItemExistsAsync(markup, "FirstOrDefault", displayTextSuffix: "<>"); @@ -10860,22 +11474,23 @@ public static IIncludableQueryable ThenInclude c.$$)", -@" - public static IIncludableQueryable ThenInclude( - this IIncludableQueryable> source, - int a, - Expression> navigationPropertyPath) where TEntity : class - { - return default(IIncludableQueryable); - } + """ + public static IIncludableQueryable ThenInclude( + this IIncludableQueryable> source, + int a, + Expression> navigationPropertyPath) where TEntity : class + { + return default(IIncludableQueryable); + } - public static IIncludableQueryable ThenInclude( - this IIncludableQueryable source, - int a, - Expression> navigationPropertyPath) where TEntity : class - { - return default(IIncludableQueryable); - }"); + public static IIncludableQueryable ThenInclude( + this IIncludableQueryable source, + int a, + Expression> navigationPropertyPath) where TEntity : class + { + return default(IIncludableQueryable); + } + """); await VerifyItemExistsAsync(markup, "Task"); await VerifyItemExistsAsync(markup, "FirstOrDefault", displayTextSuffix: "<>"); @@ -10885,22 +11500,22 @@ public static IIncludableQueryable ThenInclude b.Task, b =>b.$$", -@" - public static IIncludableQueryable ThenInclude( - this IIncludableQueryable> source, - Expression> navigationPropertyPath, - Expression> anotherNavigationPropertyPath) where TEntity : class - { - return default(IIncludableQueryable); - } - - public static IIncludableQueryable ThenInclude( - this IIncludableQueryable source, - Expression> navigationPropertyPath) where TEntity : class - { - return default(IIncludableQueryable); - } -"); + """ + public static IIncludableQueryable ThenInclude( + this IIncludableQueryable> source, + Expression> navigationPropertyPath, + Expression> anotherNavigationPropertyPath) where TEntity : class + { + return default(IIncludableQueryable); + } + + public static IIncludableQueryable ThenInclude( + this IIncludableQueryable source, + Expression> navigationPropertyPath) where TEntity : class + { + return default(IIncludableQueryable); + } + """); await VerifyItemExistsAsync(markup, "Task"); await VerifyItemIsAbsentAsync(markup, "FirstOrDefault", displayTextSuffix: "<>"); @@ -10910,23 +11525,23 @@ public static IIncludableQueryable ThenInclude c.$$", -@" - public static IIncludableQueryable ThenInclude( - this IIncludableQueryable> source, - int a, - Expression> navigationPropertyPath) where TEntity : class - { - return default(IIncludableQueryable); - } + """ + public static IIncludableQueryable ThenInclude( + this IIncludableQueryable> source, + int a, + Expression> navigationPropertyPath) where TEntity : class + { + return default(IIncludableQueryable); + } - public static IIncludableQueryable ThenInclude( - this IIncludableQueryable source, - int a, - Expression> navigationPropertyPath) where TEntity : class - { - return default(IIncludableQueryable); - } -"); + public static IIncludableQueryable ThenInclude( + this IIncludableQueryable source, + int a, + Expression> navigationPropertyPath) where TEntity : class + { + return default(IIncludableQueryable); + } + """); await VerifyItemIsAbsentAsync(markup, "Task"); await VerifyItemExistsAsync(markup, "FirstOrDefault", displayTextSuffix: "<>"); @@ -10936,21 +11551,21 @@ public static IIncludableQueryable ThenInclude c.$$", -@" - public static IIncludableQueryable ThenInclude( - this IIncludableQueryable> source, - Func navigationPropertyPath) - { - return default(IIncludableQueryable); - } - - public static IIncludableQueryable ThenInclude( - this IIncludableQueryable source, - Expression> navigationPropertyPath) where TEntity : class - { - return default(IIncludableQueryable); - } -"); + """ + public static IIncludableQueryable ThenInclude( + this IIncludableQueryable> source, + Func navigationPropertyPath) + { + return default(IIncludableQueryable); + } + + public static IIncludableQueryable ThenInclude( + this IIncludableQueryable source, + Expression> navigationPropertyPath) where TEntity : class + { + return default(IIncludableQueryable); + } + """); await VerifyItemExistsAsync(markup, "Task"); await VerifyItemExistsAsync(markup, "FirstOrDefault", displayTextSuffix: "<>"); @@ -10960,21 +11575,21 @@ public static IIncludableQueryable ThenInclude c.$$", -@" - public static IIncludableQueryable ThenInclude( - this IIncludableQueryable> source, - Func navigationPropertyPath) - { - return default(IIncludableQueryable); - } - - public static IIncludableQueryable ThenInclude( - this IIncludableQueryable> source, - Func, Activity> navigationPropertyPath) - { - return default(IIncludableQueryable); - } -"); + """ + public static IIncludableQueryable ThenInclude( + this IIncludableQueryable> source, + Func navigationPropertyPath) + { + return default(IIncludableQueryable); + } + + public static IIncludableQueryable ThenInclude( + this IIncludableQueryable> source, + Func, Activity> navigationPropertyPath) + { + return default(IIncludableQueryable); + } + """); await VerifyItemExistsAsync(markup, "Task"); await VerifyItemExistsAsync(markup, "FirstOrDefault", displayTextSuffix: "<>"); @@ -10983,43 +11598,44 @@ public static IIncludableQueryable ThenInclude( [Fact] public async Task CompletionForLambdaWithOverloads() { - var markup = @" -using System; -using System.Collections; -using System.Collections.Generic; -using System.Linq; -using System.Linq.Expressions; + var markup = """ + using System; + using System.Collections; + using System.Collections.Generic; + using System.Linq; + using System.Linq.Expressions; -namespace ClassLibrary1 -{ - class SomeItem - { - public string A; - public int B; - } - class SomeCollection : List - { - public virtual SomeCollection Include(string path) => null; - } + namespace ClassLibrary1 + { + class SomeItem + { + public string A; + public int B; + } + class SomeCollection : List + { + public virtual SomeCollection Include(string path) => null; + } - static class Extensions - { - public static IList Include(this IList source, Expression> path) - => null; + static class Extensions + { + public static IList Include(this IList source, Expression> path) + => null; - public static IList Include(this IList source, string path) => null; + public static IList Include(this IList source, string path) => null; - public static IList Include(this IList source, string path) => null; - } + public static IList Include(this IList source, string path) => null; + } - class Program - { - void M(SomeCollection c) - { - var a = from m in c.Include(t => t.$$); - } - } -}"; + class Program + { + void M(SomeCollection c) + { + var a = from m in c.Include(t => t.$$); + } + } + } + """; await VerifyExpectedItemsAsync(markup, [ ItemExpectation.Absent("Substring"), @@ -11031,19 +11647,20 @@ await VerifyExpectedItemsAsync(markup, [ [Fact, WorkItem("https://dev.azure.com/devdiv/DevDiv/_workitems/edit/1056325")] public async Task CompletionForLambdaWithOverloads2() { - var markup = @" -using System; + var markup = """ + using System; -class C -{ - void M(Action a) { } - void M(string s) { } + class C + { + void M(Action a) { } + void M(string s) { } - void Test() - { - M(p => p.$$); - } -}"; + void Test() + { + M(p => p.$$); + } + } + """; await VerifyItemIsAbsentAsync(markup, "Substring"); await VerifyItemExistsAsync(markup, "GetTypeCode"); @@ -11052,19 +11669,20 @@ void Test() [Fact, WorkItem("https://dev.azure.com/devdiv/DevDiv/_workitems/edit/1056325")] public async Task CompletionForLambdaWithOverloads3() { - var markup = @" -using System; + var markup = """ + using System; -class C -{ - void M(Action a) { } - void M(Action a) { } + class C + { + void M(Action a) { } + void M(Action a) { } - void Test() - { - M((int p) => p.$$); - } -}"; + void Test() + { + M((int p) => p.$$); + } + } + """; await VerifyItemIsAbsentAsync(markup, "Substring"); await VerifyItemExistsAsync(markup, "GetTypeCode"); @@ -11073,19 +11691,20 @@ void Test() [Fact, WorkItem("https://dev.azure.com/devdiv/DevDiv/_workitems/edit/1056325")] public async Task CompletionForLambdaWithOverloads4() { - var markup = @" -using System; + var markup = """ + using System; -class C -{ - void M(Action a) { } - void M(Action a) { } + class C + { + void M(Action a) { } + void M(Action a) { } - void Test() - { - M(p => p.$$); - } -}"; + void Test() + { + M(p => p.$$); + } + } + """; await VerifyItemExistsAsync(markup, "Substring"); await VerifyItemExistsAsync(markup, "GetTypeCode"); @@ -11094,21 +11713,22 @@ void Test() [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/42997")] public async Task CompletionForLambdaWithTypeParameters() { - var markup = @" -using System; -using System.Collections.Generic; + var markup = """ + using System; + using System.Collections.Generic; -class Program -{ - static void M() - { - Create(new List(), arg => arg.$$); - } + class Program + { + static void M() + { + Create(new List(), arg => arg.$$); + } - static void Create(List list, Action expression) { } -} + static void Create(List list, Action expression) { } + } -class Product { public void MyProperty() { } }"; + class Product { public void MyProperty() { } } + """; await VerifyItemExistsAsync(markup, "MyProperty"); } @@ -11116,23 +11736,24 @@ class Product { public void MyProperty() { } }"; [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/42997")] public async Task CompletionForLambdaWithTypeParametersAndOverloads() { - var markup = @" -using System; -using System.Collections.Generic; + var markup = """ + using System; + using System.Collections.Generic; -class Program -{ - static void M() - { - Create(new Dictionary(), arg => arg.$$); - } + class Program + { + static void M() + { + Create(new Dictionary(), arg => arg.$$); + } - static void Create(Dictionary list, Action expression) { } - static void Create(Dictionary list, Action expression) { } -} + static void Create(Dictionary list, Action expression) { } + static void Create(Dictionary list, Action expression) { } + } -class Product1 { public void MyProperty1() { } } -class Product2 { public void MyProperty2() { } }"; + class Product1 { public void MyProperty1() { } } + class Product2 { public void MyProperty2() { } } + """; await VerifyExpectedItemsAsync(markup, [ ItemExpectation.Exists("MyProperty1"), @@ -11143,25 +11764,26 @@ await VerifyExpectedItemsAsync(markup, [ [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/42997")] public async Task CompletionForLambdaWithTypeParametersAndOverloads2() { - var markup = @" -using System; -using System.Collections.Generic; + var markup = """ + using System; + using System.Collections.Generic; -class Program -{ - static void M() - { - Create(new Dictionary(),arg => arg.$$); - } + class Program + { + static void M() + { + Create(new Dictionary(),arg => arg.$$); + } - static void Create(Dictionary list, Action expression) { } - static void Create(Dictionary list, Action expression) { } - static void Create(Dictionary list, Action expression) { } -} + static void Create(Dictionary list, Action expression) { } + static void Create(Dictionary list, Action expression) { } + static void Create(Dictionary list, Action expression) { } + } -class Product1 { public void MyProperty1() { } } -class Product2 { public void MyProperty2() { } } -class Product3 { public void MyProperty3() { } }"; + class Product1 { public void MyProperty1() { } } + class Product2 { public void MyProperty2() { } } + class Product3 { public void MyProperty3() { } } + """; await VerifyExpectedItemsAsync(markup, [ ItemExpectation.Exists("MyProperty1"), @@ -11173,20 +11795,21 @@ await VerifyExpectedItemsAsync(markup, [ [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/42997")] public async Task CompletionForLambdaWithTypeParametersFromClass() { - var markup = @" -using System; + var markup = """ + using System; -class Program -{ - static void M() - { - Create(arg => arg.$$); - } + class Program + { + static void M() + { + Create(arg => arg.$$); + } - static void Create(Action expression) { } -} + static void Create(Action expression) { } + } -class Product { public void MyProperty() { } }"; + class Product { public void MyProperty() { } } + """; await VerifyItemExistsAsync(markup, "GetHashCode"); await VerifyItemIsAbsentAsync(markup, "MyProperty"); @@ -11195,20 +11818,21 @@ class Product { public void MyProperty() { } }"; [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/42997")] public async Task CompletionForLambdaWithTypeParametersFromClassWithConstraintOnType() { - var markup = @" -using System; + var markup = """ + using System; -class Program where T : Product -{ - static void M() - { - Create(arg => arg.$$); - } + class Program where T : Product + { + static void M() + { + Create(arg => arg.$$); + } - static void Create(Action expression) { } -} + static void Create(Action expression) { } + } -class Product { public void MyProperty() { } }"; + class Product { public void MyProperty() { } } + """; await VerifyItemExistsAsync(markup, "GetHashCode"); await VerifyItemExistsAsync(markup, "MyProperty"); @@ -11217,20 +11841,21 @@ class Product { public void MyProperty() { } }"; [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/42997")] public async Task CompletionForLambdaWithTypeParametersFromClassWithConstraintOnMethod() { - var markup = @" -using System; + var markup = """ + using System; -class Program -{ - static void M() - { - Create(arg => arg.$$); - } + class Program + { + static void M() + { + Create(arg => arg.$$); + } - static void Create(Action expression) where T : Product { } -} + static void Create(Action expression) where T : Product { } + } -class Product { public void MyProperty() { } }"; + class Product { public void MyProperty() { } } + """; await VerifyItemExistsAsync(markup, "GetHashCode"); await VerifyItemExistsAsync(markup, "MyProperty"); @@ -11239,19 +11864,19 @@ class Product { public void MyProperty() { } }"; [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/40216")] public async Task CompletionForLambdaPassedAsNamedArgumentAtDifferentPositionFromCorrespondingParameter1() { - var markup = @" -using System; + var markup = """ + using System; -class C -{ - void Test() - { - X(y: t => Console.WriteLine(t.$$)); - } + class C + { + void Test() + { + X(y: t => Console.WriteLine(t.$$)); + } - void X(int x = 7, Action y = null) { } -} -"; + void X(int x = 7, Action y = null) { } + } + """; await VerifyItemExistsAsync(markup, "Length"); } @@ -11259,19 +11884,19 @@ void X(int x = 7, Action y = null) { } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/40216")] public async Task CompletionForLambdaPassedAsNamedArgumentAtDifferentPositionFromCorrespondingParameter2() { - var markup = @" -using System; + var markup = """ + using System; -class C -{ - void Test() - { - X(y: t => Console.WriteLine(t.$$)); - } + class C + { + void Test() + { + X(y: t => Console.WriteLine(t.$$)); + } - void X(int x, int z, Action y) { } -} -"; + void X(int x, int z, Action y) { } + } + """; await VerifyItemExistsAsync(markup, "Length"); } @@ -11279,69 +11904,70 @@ void X(int x, int z, Action y) { } [Fact] public async Task CompletionForLambdaPassedAsArgumentInReducedExtensionMethod_NonInteractive() { - var markup = @" -using System; + var markup = """ + using System; -static class CExtensions -{ - public static void X(this C x, Action y) { } -} + static class CExtensions + { + public static void X(this C x, Action y) { } + } -class C -{ - void Test() - { - new C().X(t => Console.WriteLine(t.$$)); - } -} -"; + class C + { + void Test() + { + new C().X(t => Console.WriteLine(t.$$)); + } + } + """; await VerifyItemExistsAsync(markup, "Length", sourceCodeKind: SourceCodeKind.Regular); } [Fact] public async Task CompletionForLambdaPassedAsArgumentInReducedExtensionMethod_Interactive() { - var markup = @" -using System; + var markup = """ + using System; -public static void X(this C x, Action y) { } + public static void X(this C x, Action y) { } -public class C -{ - void Test() - { - new C().X(t => Console.WriteLine(t.$$)); - } -} -"; + public class C + { + void Test() + { + new C().X(t => Console.WriteLine(t.$$)); + } + } + """; await VerifyItemExistsAsync(markup, "Length", sourceCodeKind: SourceCodeKind.Script); } [Fact] public async Task CompletionInsideMethodsWithNonFunctionsAsArguments() { - var markup = @" -using System; -class c -{ - void M() - { - Goo(builder => - { - builder.$$ - }); - } + var markup = """ + using System; + class c + { + void M() + { + Goo(builder => + { + builder.$$ + }); + } - void Goo(Action configure) - { - var builder = new Builder(); - configure(builder); - } -} -class Builder -{ - public int Something { get; set; } -}"; + void Goo(Action configure) + { + var builder = new Builder(); + configure(builder); + } + } + class Builder + { + public int Something { get; set; } + } + """; await VerifyExpectedItemsAsync(markup, [ ItemExpectation.Exists("Something"), @@ -11355,22 +11981,23 @@ await VerifyExpectedItemsAsync(markup, [ [Fact] public async Task CompletionInsideMethodsWithDelegatesAsArguments() { - var markup = @" -using System; + var markup = """ + using System; -class Program -{ - public delegate void Delegate1(Uri u); - public delegate void Delegate2(Guid g); + class Program + { + public delegate void Delegate1(Uri u); + public delegate void Delegate2(Guid g); - public void M(Delegate1 d) { } - public void M(Delegate2 d) { } + public void M(Delegate1 d) { } + public void M(Delegate2 d) { } - public void Test() - { - M(d => d.$$) - } -}"; + public void Test() + { + M(d => d.$$) + } + } + """; await VerifyExpectedItemsAsync(markup, [ // Guid @@ -11392,22 +12019,23 @@ await VerifyExpectedItemsAsync(markup, [ [Fact] public async Task CompletionInsideMethodsWithDelegatesAndReversingArguments() { - var markup = @" -using System; + var markup = """ + using System; -class Program -{ - public delegate void Delegate1(T2 t2, T1 t1); - public delegate void Delegate2(T2 t2, int g, T1 t1); + class Program + { + public delegate void Delegate1(T2 t2, T1 t1); + public delegate void Delegate2(T2 t2, int g, T1 t1); - public void M(Delegate1 d) { } - public void M(Delegate2 d) { } + public void M(Delegate1 d) { } + public void M(Delegate2 d) { } - public void Test() - { - M(d => d.$$) - } -}"; + public void Test() + { + M(d => d.$$) + } + } + """; await VerifyExpectedItemsAsync(markup, [ // Guid ItemExpectation.Exists("ToByteArray"), @@ -11428,31 +12056,32 @@ await VerifyExpectedItemsAsync(markup, [ [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/36029")] public async Task CompletionInsideMethodWithParamsBeforeParams() { - var markup = @" -using System; -class C -{ - void M() - { - Goo(builder => - { - builder.$$ - }); - } + var markup = """ + using System; + class C + { + void M() + { + Goo(builder => + { + builder.$$ + }); + } - void Goo(Action action, params Action[] otherActions) - { - } -} -class Builder -{ - public int Something { get; set; } -}; + void Goo(Action action, params Action[] otherActions) + { + } + } + class Builder + { + public int Something { get; set; } + }; -class AnotherBuilder -{ - public int AnotherSomething { get; set; } -}"; + class AnotherBuilder + { + public int AnotherSomething { get; set; } + } + """; await VerifyExpectedItemsAsync(markup, [ ItemExpectation.Absent("AnotherSomething"), @@ -11464,28 +12093,29 @@ await VerifyExpectedItemsAsync(markup, [ [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/36029")] public async Task CompletionInsideMethodWithParamsInParams() { - var markup = @" -using System; -class C -{ - void M() - { - Goo(b0 => { }, b1 => {}, b2 => { b2.$$ }); - } + var markup = """ + using System; + class C + { + void M() + { + Goo(b0 => { }, b1 => {}, b2 => { b2.$$ }); + } - void Goo(Action action, params Action[] otherActions) - { - } -} -class Builder -{ - public int Something { get; set; } -}; + void Goo(Action action, params Action[] otherActions) + { + } + } + class Builder + { + public int Something { get; set; } + }; -class AnotherBuilder -{ - public int AnotherSomething { get; set; } -}"; + class AnotherBuilder + { + public int AnotherSomething { get; set; } + } + """; await VerifyExpectedItemsAsync(markup, [ ItemExpectation.Absent("Something"), @@ -11500,14 +12130,16 @@ public async Task TestTargetTypeFilterWithExperimentEnabled() ShowTargetTypedCompletionFilter = true; var markup = -@"public class C -{ - int intField; - void M(int x) - { - M($$); - } -}"; + """ + public class C + { + int intField; + void M(int x) + { + M($$); + } + } + """; await VerifyItemExistsAsync( markup, "intField", matchingFilters: [FilterSet.FieldFilter, FilterSet.TargetTypedFilter]); @@ -11519,14 +12151,16 @@ public async Task TestNoTargetTypeFilterWithExperimentDisabled() ShowTargetTypedCompletionFilter = false; var markup = -@"public class C -{ - int intField; - void M(int x) - { - M($$); - } -}"; + """ + public class C + { + int intField; + void M(int x) + { + M($$); + } + } + """; await VerifyItemExistsAsync( markup, "intField", matchingFilters: [FilterSet.FieldFilter]); @@ -11538,13 +12172,15 @@ public async Task TestTargetTypeFilter_NotOnObjectMembers() ShowTargetTypedCompletionFilter = true; var markup = -@"public class C -{ - void M(int x) - { - M($$); - } -}"; + """ + public class C + { + void M(int x) + { + M($$); + } + } + """; await VerifyItemExistsAsync( markup, "GetHashCode", matchingFilters: [FilterSet.MethodFilter]); @@ -11556,13 +12192,15 @@ public async Task TestTargetTypeFilter_NotNamedTypes() ShowTargetTypedCompletionFilter = true; var markup = -@"public class C -{ - void M(C c) - { - M($$); - } -}"; + """ + public class C + { + void M(C c) + { + M($$); + } + } + """; await VerifyItemExistsAsync( markup, "c", matchingFilters: [FilterSet.LocalAndParameterFilter, FilterSet.TargetTypedFilter]); @@ -11575,25 +12213,26 @@ await VerifyItemExistsAsync( [Fact] public async Task CompletionShouldNotProvideExtensionMethodsIfTypeConstraintDoesNotMatch() { - var markup = @" -public static class Ext -{ - public static void DoSomething(this T thing, string s) where T : class, I - { - } -} + var markup = """ + public static class Ext + { + public static void DoSomething(this T thing, string s) where T : class, I + { + } + } -public interface I -{ -} + public interface I + { + } -public class C -{ - public void M(string s) - { - this.$$ - } -}"; + public class C + { + public void M(string s) + { + this.$$ + } + } + """; await VerifyExpectedItemsAsync(markup, [ ItemExpectation.Exists("M"), @@ -11609,30 +12248,31 @@ await VerifyExpectedItemsAsync(markup, [ [CompilerTrait(CompilerFeature.LocalFunctions)] public async Task LocalFunctionInStaticMethod() { - await VerifyItemExistsAsync(@" -class C -{ - static void M() - { - void Local() { } + await VerifyItemExistsAsync(""" + class C + { + static void M() + { + void Local() { } - $$ - } -}", "Local"); + $$ + } + } + """, "Local"); } [Fact, WorkItem("https://devdiv.visualstudio.com/DevDiv/_workitems/edit/1152109")] public async Task NoItemWithEmptyDisplayName() { - var markup = @" -class C -{ - static void M() - { - int$$ - } -} -"; + var markup = """ + class C + { + static void M() + { + int$$ + } + } + """; await VerifyItemIsAbsentAsync( markup, "", matchingFilters: [FilterSet.LocalAndParameterFilter]); @@ -11643,38 +12283,40 @@ await VerifyItemIsAbsentAsync( [InlineData(';')] public async Task CompletionWithCustomizedCommitCharForMethod(char commitChar) { - var markup = @" -class Program -{ - private void Bar() - { - F$$ - } - - private void Foo(int i) - { - } + var markup = """ + class Program + { + private void Bar() + { + F$$ + } - private void Foo(int i, int c) - { - } -}"; - var expected = $@" -class Program -{{ - private void Bar() - {{ - Foo(){commitChar} - }} - - private void Foo(int i) - {{ - }} + private void Foo(int i) + { + } + + private void Foo(int i, int c) + { + } + } + """; + var expected = $$""" + class Program + { + private void Bar() + { + Foo(){{commitChar}} + } + + private void Foo(int i) + { + } - private void Foo(int i, int c) - {{ - }} -}}"; + private void Foo(int i, int c) + { + } + } + """; await VerifyProviderCommitAsync(markup, "Foo", expected, commitChar: commitChar); } @@ -11683,32 +12325,34 @@ private void Foo(int i, int c) [InlineData(';')] public async Task CompletionWithSemicolonInNestedMethod(char commitChar) { - var markup = @" -class Program -{ - private void Bar() - { - Foo(F$$); - } - - private int Foo(int i) - { - return 1; - } -}"; - var expected = $@" -class Program -{{ - private void Bar() - {{ - Foo(Foo(){commitChar}); - }} - - private int Foo(int i) - {{ - return 1; - }} -}}"; + var markup = """ + class Program + { + private void Bar() + { + Foo(F$$); + } + + private int Foo(int i) + { + return 1; + } + } + """; + var expected = $$""" + class Program + { + private void Bar() + { + Foo(Foo(){{commitChar}}); + } + + private int Foo(int i) + { + return 1; + } + } + """; await VerifyProviderCommitAsync(markup, "Foo", expected, commitChar: commitChar); } @@ -11717,36 +12361,38 @@ private int Foo(int i) [InlineData(';')] public async Task CompletionWithCustomizedCommitCharForDelegateInferredType(char commitChar) { - var markup = @" -using System; -class Program -{ - private void Bar() - { - Bar2(F$$); - } - - private void Foo() - { - } + var markup = """ + using System; + class Program + { + private void Bar() + { + Bar2(F$$); + } - void Bar2(Action t) { } -}"; - var expected = $@" -using System; -class Program -{{ - private void Bar() - {{ - Bar2(Foo{commitChar}); - }} - - private void Foo() - {{ - }} - - void Bar2(Action t) {{ }} -}}"; + private void Foo() + { + } + + void Bar2(Action t) { } + } + """; + var expected = $$""" + using System; + class Program + { + private void Bar() + { + Bar2(Foo{{commitChar}}); + } + + private void Foo() + { + } + + void Bar2(Action t) { } + } + """; await VerifyProviderCommitAsync(markup, "Foo", expected, commitChar: commitChar); } @@ -11755,22 +12401,24 @@ void Bar2(Action t) {{ }} [InlineData(';')] public async Task CompletionWithCustomizedCommitCharForConstructor(char commitChar) { - var markup = @" -class Program -{ - private static void Bar() - { - var o = new P$$ - } -}"; - var expected = $@" -class Program -{{ - private static void Bar() - {{ - var o = new Program(){commitChar} - }} -}}"; + var markup = """ + class Program + { + private static void Bar() + { + var o = new P$$ + } + } + """; + var expected = $$""" + class Program + { + private static void Bar() + { + var o = new Program(){{commitChar}} + } + } + """; await VerifyProviderCommitAsync(markup, "Program", expected, commitChar: commitChar); } @@ -11779,22 +12427,24 @@ private static void Bar() [InlineData(';')] public async Task CompletionWithCustomizedCharForTypeUnderNonObjectCreationContext(char commitChar) { - var markup = @" -class Program -{ - private static void Bar() - { - var o = P$$ - } -}"; - var expected = $@" -class Program -{{ - private static void Bar() - {{ - var o = Program{commitChar} - }} -}}"; + var markup = """ + class Program + { + private static void Bar() + { + var o = P$$ + } + } + """; + var expected = $$""" + class Program + { + private static void Bar() + { + var o = Program{{commitChar}} + } + } + """; await VerifyProviderCommitAsync(markup, "Program", expected, commitChar: commitChar); } @@ -11803,58 +12453,62 @@ private static void Bar() [InlineData(';')] public async Task CompletionWithCustomizedCommitCharForAliasConstructor(char commitChar) { - var markup = @" -using String2 = System.String; -namespace Bar1 -{ - class Program - { - private static void Bar() - { - var o = new S$$ - } - } -}"; - var expected = $@" -using String2 = System.String; -namespace Bar1 -{{ - class Program - {{ - private static void Bar() - {{ - var o = new String2(){commitChar} - }} - }} -}}"; + var markup = """ + using String2 = System.String; + namespace Bar1 + { + class Program + { + private static void Bar() + { + var o = new S$$ + } + } + } + """; + var expected = $$""" + using String2 = System.String; + namespace Bar1 + { + class Program + { + private static void Bar() + { + var o = new String2(){{commitChar}} + } + } + } + """; await VerifyProviderCommitAsync(markup, "String2", expected, commitChar: commitChar); } [Fact] public async Task CompletionWithSemicolonUnderNameofContext() { - var markup = @" -namespace Bar1 -{ - class Program - { - private static void Bar() - { - var o = nameof(B$$) - } - } -}"; - var expected = @" -namespace Bar1 -{ - class Program - { - private static void Bar() - { - var o = nameof(Bar;) - } - } -}"; + var markup = """ + namespace Bar1 + { + class Program + { + private static void Bar() + { + var o = nameof(B$$) + } + } + } + """; + var expected = """ + namespace Bar1 + { + class Program + { + private static void Bar() + { + var o = nameof(Bar;) + } + } + } + """; await VerifyProviderCommitAsync(markup, "Bar", expected, commitChar: ';'); } @@ -11862,22 +12516,24 @@ private static void Bar() public async Task EnumMemberAfterPatternMatch() { var markup = -@"namespace N -{ - enum RankedMusicians - { - BillyJoel, - EveryoneElse - } - - class C - { - void M(RankedMusicians m) - { - if (m is RankedMusicians.$$ - } - } -}"; + """ + namespace N + { + enum RankedMusicians + { + BillyJoel, + EveryoneElse + } + + class C + { + void M(RankedMusicians m) + { + if (m is RankedMusicians.$$ + } + } + } + """; // VerifyItemExistsAsync also tests with the item typed. await VerifyExpectedItemsAsync(markup, [ ItemExpectation.Exists("BillyJoel"), @@ -11890,24 +12546,26 @@ await VerifyExpectedItemsAsync(markup, [ public async Task EnumMemberAfterPatternMatchWithDeclaration() { var markup = -@"namespace N -{ - enum RankedMusicians - { - BillyJoel, - EveryoneElse - } - - class C - { - void M(RankedMusicians m) - { - if (m is RankedMusicians.$$ r) - { - } - } - } -}"; + """ + namespace N + { + enum RankedMusicians + { + BillyJoel, + EveryoneElse + } + + class C + { + void M(RankedMusicians m) + { + if (m is RankedMusicians.$$ r) + { + } + } + } + } + """; // VerifyItemExistsAsync also tests with the item typed. await VerifyExpectedItemsAsync(markup, [ ItemExpectation.Exists("BillyJoel"), @@ -11920,24 +12578,26 @@ await VerifyExpectedItemsAsync(markup, [ public async Task EnumMemberAfterPropertyPatternMatch() { var markup = -@"namespace N -{ - enum RankedMusicians - { - BillyJoel, - EveryoneElse - } - - class C - { - public RankedMusicians R; - - void M(C m) - { - if (m is { R: RankedMusicians.$$ - } - } -}"; + """ + namespace N + { + enum RankedMusicians + { + BillyJoel, + EveryoneElse + } + + class C + { + public RankedMusicians R; + + void M(C m) + { + if (m is { R: RankedMusicians.$$ + } + } + } + """; // VerifyItemExistsAsync also tests with the item typed. await VerifyExpectedItemsAsync(markup, [ ItemExpectation.Exists("BillyJoel"), @@ -11950,18 +12610,20 @@ await VerifyExpectedItemsAsync(markup, [ public async Task ChildClassAfterPatternMatch() { var markup = -@"namespace N -{ - public class D { public class E { } } - - class C - { - void M(object m) - { - if (m is D.$$ - } - } -}"; + """ + namespace N + { + public class D { public class E { } } + + class C + { + void M(object m) + { + if (m is D.$$ + } + } + } + """; // VerifyItemExistsAsync also tests with the item typed. await VerifyItemExistsAsync(markup, "E"); await VerifyItemIsAbsentAsync(markup, "Equals"); @@ -11971,22 +12633,24 @@ void M(object m) public async Task EnumMemberAfterBinaryExpression() { var markup = -@"namespace N -{ - enum RankedMusicians - { - BillyJoel, - EveryoneElse - } - - class C - { - void M(RankedMusicians m) - { - if (m == RankedMusicians.$$ - } - } -}"; + """ + namespace N + { + enum RankedMusicians + { + BillyJoel, + EveryoneElse + } + + class C + { + void M(RankedMusicians m) + { + if (m == RankedMusicians.$$ + } + } + } + """; // VerifyItemExistsAsync also tests with the item typed. await VerifyExpectedItemsAsync(markup, [ ItemExpectation.Exists("BillyJoel"), @@ -11999,24 +12663,26 @@ await VerifyExpectedItemsAsync(markup, [ public async Task EnumMemberAfterBinaryExpressionWithDeclaration() { var markup = -@"namespace N -{ - enum RankedMusicians - { - BillyJoel, - EveryoneElse - } - - class C - { - void M(RankedMusicians m) - { - if (m == RankedMusicians.$$ r) - { - } - } - } -}"; + """ + namespace N + { + enum RankedMusicians + { + BillyJoel, + EveryoneElse + } + + class C + { + void M(RankedMusicians m) + { + if (m == RankedMusicians.$$ r) + { + } + } + } + } + """; // VerifyItemExistsAsync also tests with the item typed. await VerifyExpectedItemsAsync(markup, [ ItemExpectation.Exists("BillyJoel"), @@ -12029,20 +12695,20 @@ await VerifyExpectedItemsAsync(markup, [ public async Task ObsoleteOverloadsAreSkippedIfNonObsoleteOverloadIsAvailable() { var markup = -@" -public class C -{ - [System.Obsolete] - public void M() { } + """ + public class C + { + [System.Obsolete] + public void M() { } - public void M(int i) { } - - public void Test() - { - this.$$ - } -} -"; + public void M(int i) { } + + public void Test() + { + this.$$ + } + } + """; await VerifyItemExistsAsync(markup, "M", expectedDescriptionOrNull: $"void C.M(int i) (+ 1 {FeaturesResources.overload})"); } @@ -12050,21 +12716,21 @@ public void Test() public async Task FirstObsoleteOverloadIsUsedIfAllOverloadsAreObsolete() { var markup = -@" -public class C -{ - [System.Obsolete] - public void M() { } + """ + public class C + { + [System.Obsolete] + public void M() { } - [System.Obsolete] - public void M(int i) { } - - public void Test() - { - this.$$ - } -} -"; + [System.Obsolete] + public void M(int i) { } + + public void Test() + { + this.$$ + } + } + """; await VerifyItemExistsAsync(markup, "M", expectedDescriptionOrNull: $"[{CSharpFeaturesResources.deprecated}] void C.M() (+ 1 {FeaturesResources.overload})"); } @@ -12072,24 +12738,24 @@ public void Test() public async Task IgnoreCustomObsoleteAttribute() { var markup = -@" -public class ObsoleteAttribute: System.Attribute -{ -} + """ + public class ObsoleteAttribute: System.Attribute + { + } -public class C -{ - [Obsolete] - public void M() { } + public class C + { + [Obsolete] + public void M() { } + + public void M(int i) { } - public void M(int i) { } - - public void Test() - { - this.$$ - } -} -"; + public void Test() + { + this.$$ + } + } + """; await VerifyItemExistsAsync(markup, "M", expectedDescriptionOrNull: $"void C.M() (+ 1 {FeaturesResources.overload})"); } @@ -12102,19 +12768,21 @@ public async Task TestTargetTypeCompletionDescription(string targetType, string ShowTargetTypedCompletionFilter = true; var markup = -$@"public class C -{{ - bool Bar(int a, int b) => false; - int Bar() => 0; - int[] Bar(int a) => null; - - bool N({targetType} x) => true; - - void M(C c) - {{ - N(c.$$); - }} -}}"; + $$""" + public class C + { + bool Bar(int a, int b) => false; + int Bar() => 0; + int[] Bar(int a) => null; + + bool N({{targetType}} x) => true; + + void M(C c) + { + N(c.$$); + } + } + """; await VerifyItemExistsAsync( markup, "Bar", expectedDescriptionOrNull: $"{targetType} C.Bar({expectedParameterList}) (+{NonBreakingSpaceString}2{NonBreakingSpaceString}{FeaturesResources.overloads_})", @@ -12124,41 +12792,44 @@ await VerifyItemExistsAsync( [Fact, Trait(Traits.Feature, Traits.Features.KeywordRecommending)] public async Task TestTypesNotSuggestedInDeclarationDeconstruction() { - await VerifyItemIsAbsentAsync(@" -class C -{ - int M() - { - var (x, $$) = (0, 0); - } -}", "C"); + await VerifyItemIsAbsentAsync(""" + class C + { + int M() + { + var (x, $$) = (0, 0); + } + } + """, "C"); } [Fact, Trait(Traits.Feature, Traits.Features.KeywordRecommending)] public async Task TestTypesSuggestedInMixedDeclarationAndAssignmentInDeconstruction() { - await VerifyItemExistsAsync(@" -class C -{ - int M() - { - (x, $$) = (0, 0); - } -}", "C"); + await VerifyItemExistsAsync(""" + class C + { + int M() + { + (x, $$) = (0, 0); + } + } + """, "C"); } [Fact, Trait(Traits.Feature, Traits.Features.KeywordRecommending)] public async Task TestLocalDeclaredBeforeDeconstructionSuggestedInMixedDeclarationAndAssignmentInDeconstruction() { - await VerifyItemExistsAsync(@" -class C -{ - int M() - { - int y; - (var x, $$) = (0, 0); - } -}", "y"); + await VerifyItemExistsAsync(""" + class C + { + int M() + { + int y; + (var x, $$) = (0, 0); + } + } + """, "y"); } [Fact, Trait(Traits.Feature, Traits.Features.KeywordRecommending)] @@ -12166,29 +12837,29 @@ int M() [WorkItem("https://github.com/dotnet/roslyn/issues/64733")] public async Task TestTypeParameterConstrainedToInterfaceWithStatics() { - var source = @" -interface I1 -{ - static void M0(); - static abstract void M1(); - abstract static int P1 { get; set; } - abstract static event System.Action E1; -} + var source = """ + interface I1 + { + static void M0(); + static abstract void M1(); + abstract static int P1 { get; set; } + abstract static event System.Action E1; + } -interface I2 -{ - static abstract void M2(); - static virtual void M3() { } -} + interface I2 + { + static abstract void M2(); + static virtual void M3() { } + } -class Test -{ - void M(T x) where T : I1, I2 - { - T.$$ - } -} -"; + class Test + { + void M(T x) where T : I1, I2 + { + T.$$ + } + } + """; await VerifyExpectedItemsAsync(source, [ ItemExpectation.Absent("M0"), @@ -12203,22 +12874,22 @@ await VerifyExpectedItemsAsync(source, [ [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/58081")] public async Task CompletionOnPointerParameter() { - var source = @" -struct TestStruct -{ - public int X; - public int Y { get; } - public void Method() { } -} + var source = """ + struct TestStruct + { + public int X; + public int Y { get; } + public void Method() { } + } -unsafe class Test -{ - void TestMethod(TestStruct* a) - { - a->$$ - } -} -"; + unsafe class Test + { + void TestMethod(TestStruct* a) + { + a->$$ + } + } + """; await VerifyExpectedItemsAsync(source, [ ItemExpectation.Exists("X"), ItemExpectation.Exists("Y"), @@ -12230,22 +12901,22 @@ await VerifyExpectedItemsAsync(source, [ [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/58081")] public async Task CompletionOnAwaitedPointerParameter() { - var source = @" -struct TestStruct -{ - public int X; - public int Y { get; } - public void Method() { } -} + var source = """ + struct TestStruct + { + public int X; + public int Y { get; } + public void Method() { } + } -unsafe class Test -{ - async void TestMethod(TestStruct* a) - { - await a->$$ - } -} -"; + unsafe class Test + { + async void TestMethod(TestStruct* a) + { + await a->$$ + } + } + """; await VerifyExpectedItemsAsync(source, [ ItemExpectation.Exists("X"), ItemExpectation.Exists("Y"), @@ -12257,24 +12928,24 @@ await VerifyExpectedItemsAsync(source, [ [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/58081")] public async Task CompletionOnLambdaPointerParameter() { - var source = @" -struct TestStruct -{ - public int X; - public int Y { get; } - public void Method() { } -} + var source = """ + struct TestStruct + { + public int X; + public int Y { get; } + public void Method() { } + } -unsafe class Test -{ - delegate void TestLambda(TestStruct* a); + unsafe class Test + { + delegate void TestLambda(TestStruct* a); - TestLambda TestMethod() - { - return a => a->$$ - } -} -"; + TestLambda TestMethod() + { + return a => a->$$ + } + } + """; await VerifyExpectedItemsAsync(source, [ ItemExpectation.Exists("X"), ItemExpectation.Exists("Y"), @@ -12287,34 +12958,34 @@ await VerifyExpectedItemsAsync(source, [ public async Task CompletionOnOverloadedLambdaPointerParameter() { - var source = @" -struct TestStruct1 -{ - public int X; -} + var source = """ + struct TestStruct1 + { + public int X; + } -struct TestStruct2 -{ - public int Y; -} + struct TestStruct2 + { + public int Y; + } -unsafe class Test -{ - delegate void TestLambda1(TestStruct1* a); - delegate void TestLambda2(TestStruct2* a); + unsafe class Test + { + delegate void TestLambda1(TestStruct1* a); + delegate void TestLambda2(TestStruct2* a); - void Overloaded(TestLambda1 lambda) - { - } + void Overloaded(TestLambda1 lambda) + { + } - void Overloaded(TestLambda2 lambda) - { - } + void Overloaded(TestLambda2 lambda) + { + } - void TestMethod() - => Overloaded(a => a->$$); -} -"; + void TestMethod() + => Overloaded(a => a->$$); + } + """; await VerifyExpectedItemsAsync(source, [ ItemExpectation.Exists("X"), ItemExpectation.Exists("Y") @@ -12325,34 +12996,34 @@ await VerifyExpectedItemsAsync(source, [ public async Task CompletionOnOverloadedLambdaPointerParameterWithExplicitType() { - var source = @" -struct TestStruct1 -{ - public int X; -} + var source = """ + struct TestStruct1 + { + public int X; + } -struct TestStruct2 -{ - public int Y; -} + struct TestStruct2 + { + public int Y; + } -unsafe class Test -{ - delegate void TestLambda1(TestStruct1* a); - delegate void TestLambda2(TestStruct2* a); + unsafe class Test + { + delegate void TestLambda1(TestStruct1* a); + delegate void TestLambda2(TestStruct2* a); - void Overloaded(TestLambda1 lambda) - { - } + void Overloaded(TestLambda1 lambda) + { + } - void Overloaded(TestLambda2 lambda) - { - } + void Overloaded(TestLambda2 lambda) + { + } - void TestMethod() - => Overloaded((TestStruct1* a) => a->$$); -} -"; + void TestMethod() + => Overloaded((TestStruct1* a) => a->$$); + } + """; await VerifyExpectedItemsAsync(source, [ ItemExpectation.Exists("X"), ItemExpectation.Absent("Y") @@ -12362,22 +13033,22 @@ await VerifyExpectedItemsAsync(source, [ [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/58081")] public async Task CompletionOnPointerParameterWithSimpleMemberAccess() { - var source = @" -struct TestStruct -{ - public int X; - public int Y { get; } - public void Method() { } -} + var source = """ + struct TestStruct + { + public int X; + public int Y { get; } + public void Method() { } + } -unsafe class Test -{ - void TestMethod(TestStruct* a) - { - a.$$ - } -} -"; + unsafe class Test + { + void TestMethod(TestStruct* a) + { + a.$$ + } + } + """; await VerifyItemIsAbsentAsync(source, "X"); } @@ -12385,34 +13056,34 @@ void TestMethod(TestStruct* a) public async Task CompletionOnOverloadedLambdaPointerParameterWithSimpleMemberAccess() { - var source = @" -struct TestStruct1 -{ - public int X; -} + var source = """ + struct TestStruct1 + { + public int X; + } -struct TestStruct2 -{ - public int Y; -} + struct TestStruct2 + { + public int Y; + } -unsafe class Test -{ - delegate void TestLambda1(TestStruct1* a); - delegate void TestLambda2(TestStruct2* a); + unsafe class Test + { + delegate void TestLambda1(TestStruct1* a); + delegate void TestLambda2(TestStruct2* a); - void Overloaded(TestLambda1 lambda) - { - } + void Overloaded(TestLambda1 lambda) + { + } - void Overloaded(TestLambda2 lambda) - { - } + void Overloaded(TestLambda2 lambda) + { + } - void TestMethod() - => Overloaded(a => a.$$); -} -"; + void TestMethod() + => Overloaded(a => a.$$); + } + """; await VerifyExpectedItemsAsync(source, [ ItemExpectation.Absent("X"), ItemExpectation.Absent("Y") @@ -12423,34 +13094,34 @@ await VerifyExpectedItemsAsync(source, [ public async Task CompletionOnOverloadedLambdaPointerParameterWithSimpleMemberAccessAndExplicitType() { - var source = @" -struct TestStruct1 -{ - public int X; -} + var source = """ + struct TestStruct1 + { + public int X; + } -struct TestStruct2 -{ - public int Y; -} + struct TestStruct2 + { + public int Y; + } -unsafe class Test -{ - delegate void TestLambda1(TestStruct1* a); - delegate void TestLambda2(TestStruct2* a); + unsafe class Test + { + delegate void TestLambda1(TestStruct1* a); + delegate void TestLambda2(TestStruct2* a); - void Overloaded(TestLambda1 lambda) - { - } + void Overloaded(TestLambda1 lambda) + { + } - void Overloaded(TestLambda2 lambda) - { - } + void Overloaded(TestLambda2 lambda) + { + } - void TestMethod() - => Overloaded((TestStruct1* a) => a.$$); -} -"; + void TestMethod() + => Overloaded((TestStruct1* a) => a.$$); + } + """; await VerifyExpectedItemsAsync(source, [ ItemExpectation.Absent("X"), ItemExpectation.Absent("Y") @@ -12464,39 +13135,41 @@ await VerifyExpectedItemsAsync(source, [ [WorkItem("https://github.com/dotnet/roslyn/issues/59714")] public async Task OptionalExclamationsAfterConditionalAccessShouldBeHandled(string conditionalAccessExpression) { - var source = $@" -class MyClass -{{ - public MyClass? MyObject {{ get; set; }} - public MyClass? MyValue() => null; - - public static void F() - {{ - var m = new MyClass(); - {conditionalAccessExpression}; - }} -}}"; + var source = $$""" + class MyClass + { + public MyClass? MyObject { get; set; } + public MyClass? MyValue() => null; + + public static void F() + { + var m = new MyClass(); + {{conditionalAccessExpression}}; + } + } + """; await VerifyItemExistsAsync(source, "MyValue"); } [Fact] public async Task TopLevelSymbolsAvailableAtTopLevel() { - var source = $@" -int goo; + var source = $$""" + int goo; -void Bar() -{{ -}} + void Bar() + { + } -$$ + $$ -class MyClass -{{ - public static void F() - {{ - }} -}}"; + class MyClass + { + public static void F() + { + } + } + """; await VerifyItemExistsAsync(source, "goo"); await VerifyItemExistsAsync(source, "Bar"); } @@ -12504,20 +13177,21 @@ public static void F() [Fact] public async Task TopLevelSymbolsAvailableInsideTopLevelFunction() { - var source = $@" -int goo; + var source = $$""" + int goo; -void Bar() -{{ - $$ -}} + void Bar() + { + $$ + } -class MyClass -{{ - public static void F() - {{ - }} -}}"; + class MyClass + { + public static void F() + { + } + } + """; await VerifyItemExistsAsync(source, "goo"); await VerifyItemExistsAsync(source, "Bar"); } @@ -12525,20 +13199,21 @@ public static void F() [Fact] public async Task TopLevelSymbolsNotAvailableInOtherTypes() { - var source = $@" -int goo; + var source = $$""" + int goo; -void Bar() -{{ -}} + void Bar() + { + } -class MyClass -{{ - public static void F() - {{ - $$ - }} -}}"; + class MyClass + { + public static void F() + { + $$ + } + } + """; await VerifyItemIsAbsentAsync(source, "goo"); await VerifyItemIsAbsentAsync(source, "Bar"); } @@ -12546,57 +13221,92 @@ public static void F() [Fact] public async Task ParameterAvailableInMethodAttributeNameof() { - var source = @" -class C -{ - [Some(nameof(p$$))] - void M(int parameter) { } -} -"; + var source = """ + class C + { + [Some(nameof(p$$))] + void M(int parameter) { } + } + """; await VerifyItemExistsAsync(MakeMarkup(source), "parameter"); await VerifyItemExistsAsync(MakeMarkup(source, languageVersion: "10"), "parameter"); } - [Fact] - public async Task ParameterNotAvailableInMethodAttributeNameofWithNoArgument() + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/60812")] + public async Task ParameterNotAvailableInMethodAttributeNameofWithNoArgument() + { + var source = """ + class C + { + [Some(nameof($$))] + void M(int parameter) { } + } + """; + await VerifyItemExistsAsync(MakeMarkup(source), "parameter"); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/66982")] + public async Task CapturedParameters1() + { + var source = """ + class C + { + void M(string args) + { + static void LocalFunc() + { + Console.WriteLine($$); + } + } + } + """; + await VerifyItemIsAbsentAsync(MakeMarkup(source), "args"); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/66982")] + public async Task CapturedParameters2() { - var source = @" -class C -{ - [Some(nameof($$))] - void M(int parameter) { } -} -"; - // Tracked by https://github.com/dotnet/roslyn/issues/60812 - await VerifyItemIsAbsentAsync(MakeMarkup(source), "parameter"); + var source = """ + class C + { + void M(string args) + { + static void LocalFunc() + { + Console.WriteLine(nameof($$)); + } + } + } + """; + await VerifyItemExistsAsync(MakeMarkup(source), "args"); } [Fact] public async Task ParameterAvailableInMethodParameterAttributeNameof() { - var source = @" -class C -{ - void M([Some(nameof(p$$))] int parameter) { } -} -"; + var source = """ + class C + { + void M([Some(nameof(p$$))] int parameter) { } + } + """; await VerifyItemExistsAsync(MakeMarkup(source), "parameter"); } [Fact] public async Task ParameterAvailableInLocalFunctionAttributeNameof() { - var source = @" -class C -{ - void M() - { - [Some(nameof(p$$))] - void local(int parameter) { } - } -} -"; + var source = """ + class C + { + void M() + { + [Some(nameof(p$$))] + void local(int parameter) { } + } + } + """; await VerifyItemExistsAsync(MakeMarkup(source), "parameter"); await VerifyItemExistsAsync(MakeMarkup(source, languageVersion: "10"), "parameter"); @@ -12605,15 +13315,15 @@ void local(int parameter) { } [Fact] public async Task ParameterAvailableInLocalFunctionParameterAttributeNameof() { - var source = @" -class C -{ - void M() - { - void local([Some(nameof(p$$))] int parameter) { } - } -} -"; + var source = """ + class C + { + void M() + { + void local([Some(nameof(p$$))] int parameter) { } + } + } + """; await VerifyItemExistsAsync(MakeMarkup(source), "parameter"); await VerifyItemExistsAsync(MakeMarkup(source, languageVersion: "10"), "parameter"); @@ -12622,15 +13332,15 @@ void local([Some(nameof(p$$))] int parameter) { } [Fact] public async Task ParameterAvailableInLambdaAttributeNameof() { - var source = @" -class C -{ - void M() - { - _ = [Some(nameof(p$$))] void(int parameter) => { }; - } -} -"; + var source = """ + class C + { + void M() + { + _ = [Some(nameof(p$$))] void(int parameter) => { }; + } + } + """; await VerifyItemExistsAsync(MakeMarkup(source), "parameter"); await VerifyItemExistsAsync(MakeMarkup(source, languageVersion: "10"), "parameter"); @@ -12639,15 +13349,15 @@ void M() [Fact] public async Task ParameterAvailableInLambdaParameterAttributeNameof() { - var source = @" -class C -{ - void M() - { - _ = void([Some(nameof(p$$))] int parameter) => { }; - } -} -"; + var source = """ + class C + { + void M() + { + _ = void([Some(nameof(p$$))] int parameter) => { }; + } + } + """; await VerifyItemExistsAsync(MakeMarkup(source), "parameter"); await VerifyItemExistsAsync(MakeMarkup(source, languageVersion: "10"), "parameter"); @@ -12656,10 +13366,10 @@ void M() [Fact] public async Task ParameterAvailableInDelegateAttributeNameof() { - var source = @" -[Some(nameof(p$$))] -delegate void MyDelegate(int parameter); -"; + var source = """ + [Some(nameof(p$$))] + delegate void MyDelegate(int parameter); + """; await VerifyItemExistsAsync(MakeMarkup(source), "parameter"); await VerifyItemExistsAsync(MakeMarkup(source, languageVersion: "10"), "parameter"); @@ -12668,9 +13378,9 @@ public async Task ParameterAvailableInDelegateAttributeNameof() [Fact] public async Task ParameterAvailableInDelegateParameterAttributeNameof() { - var source = @" -delegate void MyDelegate([Some(nameof(p$$))] int parameter); -"; + var source = """ + delegate void MyDelegate([Some(nameof(p$$))] int parameter); + """; await VerifyItemExistsAsync(MakeMarkup(source), "parameter"); await VerifyItemExistsAsync(MakeMarkup(source, languageVersion: "10"), "parameter"); @@ -12679,49 +13389,81 @@ public async Task ParameterAvailableInDelegateParameterAttributeNameof() [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/64585")] public async Task AfterRequired() { - var source = @" -class C -{ - required $$ -}"; + var source = """ + class C + { + required $$ + } + """; await VerifyAnyItemExistsAsync(source); } - [Fact] - public async Task AfterScopedInsideMethod() - { - var source = @" -class C -{ - void M() + [Theory, CombinatorialData] + public async Task AfterScopedInsideMethod(bool useRef) { - scoped $$ - } -} + var refKeyword = useRef ? "ref " : ""; + var source = $$""" + class C + { + void M() + { + scoped {{refKeyword}}$$ + } + } -ref struct MyRefStruct { } -"; + ref struct MyRefStruct { } + """; await VerifyItemExistsAsync(MakeMarkup(source), "MyRefStruct"); } - [Fact] - public async Task AfterScopedGlobalStatement_FollowedByType() + [Theory, CombinatorialData] + public async Task AfterScopedGlobalStatement_FollowedByRefStruct(bool useRef) { - var source = @" -scoped $$ + var refKeyword = useRef ? "ref " : ""; + var source = $$""" + scoped {{refKeyword}}$$ -ref struct MyRefStruct { } -"; + ref struct MyRefStruct { } + """; await VerifyItemExistsAsync(MakeMarkup(source), "MyRefStruct"); } - [Fact] - public async Task AfterScopedGlobalStatement_NotFollowedByType() + [Theory, CombinatorialData] + public async Task AfterScopedGlobalStatement_FollowedByStruct(bool useRef) { - var source = """ + var refKeyword = useRef ? "ref " : ""; + var source = $$""" using System; - scoped $$ + scoped {{refKeyword}}$$ + + struct S { } + """; + await VerifyItemExistsAsync(MakeMarkup(source), "ReadOnlySpan", displayTextSuffix: "<>"); + } + + [Theory, CombinatorialData] + public async Task AfterScopedGlobalStatement_FollowedByPartialStruct(bool useRef) + { + var refKeyword = useRef ? "ref " : ""; + var source = $$""" + using System; + + scoped {{refKeyword}}$$ + + partial struct S { } + """; + await VerifyItemExistsAsync(MakeMarkup(source), "ReadOnlySpan", displayTextSuffix: "<>"); + } + + [Theory, CombinatorialData] + public async Task AfterScopedGlobalStatement_NotFollowedByType(bool useRef) + { + var refKeyword = useRef ? "ref " : ""; + var source = $""" + using System; + + scoped {refKeyword}$$ """; await VerifyItemExistsAsync(MakeMarkup(source), "ReadOnlySpan", displayTextSuffix: "<>"); @@ -12730,37 +13472,37 @@ public async Task AfterScopedGlobalStatement_NotFollowedByType() [Fact] public async Task AfterScopedInParameter() { - var source = @" -class C -{ - void M(scoped $$) - { - } -} + var source = """ + class C + { + void M(scoped $$) + { + } + } -ref struct MyRefStruct { } -"; + ref struct MyRefStruct { } + """; await VerifyItemExistsAsync(MakeMarkup(source), "MyRefStruct"); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/65020")] public async Task DoNotProvideMemberOnSystemVoid() { - var source = @" -class C -{ - void M1(){} - void M2() - { - this.M1().$$ - } -} + var source = """ + class C + { + void M1(){} + void M2() + { + this.M1().$$ + } + } -public static class Extension -{ - public static bool ExtMethod(this object x) => false; -} -"; + public static class Extension + { + public static bool ExtMethod(this object x) => false; + } + """; await VerifyItemIsAbsentAsync(MakeMarkup(source), "ExtMethod"); } @@ -14075,7 +14817,211 @@ IEnumerable M() => [string.Empty, .. ($$ #endregion - private static string MakeMarkup(string source, string languageVersion = "Preview") + [Theory, WorkItem("https://github.com/dotnet/roslyn/issues/74327")] + [InlineData("class")] + [InlineData("struct")] + [InlineData("record class")] + [InlineData("record struct")] + public async Task RecommendedPrimaryConstructorParameters01(string typeKind) + { + var markup = $$""" + namespace PrimaryConstructor; + + public {{typeKind}} Point(int X, int Y) + { + public static Point Parse(string line) + { + $$ + } + } + """; + await VerifyExpectedItemsAsync(markup, [ + ItemExpectation.Absent("X"), + ItemExpectation.Absent("Y"), + ]); + } + + [Theory, WorkItem("https://github.com/dotnet/roslyn/issues/74327")] + [InlineData("class")] + [InlineData("record class")] + public async Task RecommendedPrimaryConstructorParameters02(string typeKind) + { + var markup = $$""" + namespace PrimaryConstructor; + + public abstract {{typeKind}} BasePoint(int X); + + public {{typeKind}} Point(int X, int Y) + : BasePoint(X) + { + public static Point Parse(string line) + { + $$ + } + } + """; + await VerifyExpectedItemsAsync(markup, [ + ItemExpectation.Absent("X"), + ItemExpectation.Absent("Y"), + ]); + } + + [Theory, WorkItem("https://github.com/dotnet/roslyn/issues/74327")] + [InlineData("class")] + [InlineData("record class")] + public async Task RecommendedPrimaryConstructorParameters03(string typeKind) + { + var markup = $$""" + namespace PrimaryConstructor; + + public abstract {{typeKind}} BasePoint(int X); + + public {{typeKind}} Point(int X, int Y) + : BasePoint(X) + { + public int Y { get; init; } = Y; + + public static Point Parse(string line) + { + $$ + } + } + """; + await VerifyExpectedItemsAsync(markup, [ + ItemExpectation.Absent("X"), + ItemExpectation.Absent("Y"), + ]); + } + + [Theory, WorkItem("https://github.com/dotnet/roslyn/issues/74327")] + [InlineData("class")] + [InlineData("struct")] + [InlineData("record class")] + [InlineData("record struct")] + public async Task RecommendedPrimaryConstructorParameters04(string typeKind) + { + var markup = $$""" + namespace PrimaryConstructor; + + public {{typeKind}} Point(int X, int Y) + { + public static Point Parse(string line) + { + var n = nameof($$ + } + } + """; + await VerifyExpectedItemsAsync(markup, [ + ItemExpectation.Exists("X"), + ItemExpectation.Exists("Y"), + ]); + } + + [Theory, WorkItem("https://github.com/dotnet/roslyn/issues/74327")] + [InlineData("record class")] + [InlineData("class")] + public async Task RecommendedPrimaryConstructorParameters05(string typeKind) + { + var markup = $$""" + namespace PrimaryConstructor; + + public abstract {{typeKind}} BasePoint(int X); + + public {{typeKind}} Point(int X, int Y) + : BasePoint(X) + { + public static Point Parse(string line) + { + var n = nameof($$ + } + } + """; + await VerifyExpectedItemsAsync(markup, [ + ItemExpectation.Exists("X"), + ItemExpectation.Exists("Y"), + ]); + } + + [Theory, WorkItem("https://github.com/dotnet/roslyn/issues/74327")] + [InlineData("record")] + [InlineData("class")] + public async Task RecommendedPrimaryConstructorParameters06(string typeKind) + { + var markup = $$""" + namespace PrimaryConstructor; + + public abstract {{typeKind}} BasePoint(int X); + + public {{typeKind}} Point(int X, int Y) + : BasePoint(X) + { + public int Y { get; init; } = Y; + + public static Point Parse(string line) + { + var n = nameof($$ + } + } + """; + await VerifyExpectedItemsAsync(markup, [ + ItemExpectation.Exists("X"), + ItemExpectation.Exists("Y"), + ]); + } + + [Theory, WorkItem("https://github.com/dotnet/roslyn/issues/74327")] + [InlineData("class")] + [InlineData("struct")] + [InlineData("record class")] + [InlineData("record struct")] + public async Task RecommendedPrimaryConstructorParameters07(string typeKind) + { + var markup = $$""" + namespace PrimaryConstructor; + + public {{typeKind}} Point(int X, int Y) + { + public static int Y { get; } = 0; + + public static Point Parse(string line) + { + $$ + } + } + """; + await VerifyExpectedItemsAsync(markup, [ + ItemExpectation.Absent("X"), + ItemExpectation.Exists("Y"), + ]); + } + + [Theory, WorkItem("https://github.com/dotnet/roslyn/issues/74327")] + [InlineData("class")] + [InlineData("struct")] + [InlineData("record class")] + [InlineData("record struct")] + public async Task RecommendedPrimaryConstructorParameters08(string typeKind) + { + var markup = $$""" + namespace PrimaryConstructor; + + public {{typeKind}} Point(int X, int Y) + { + public static int Y { get; } = 0; + + public static Point Parse(string line) + { + var n = nameof($$ + } + } + """; + await VerifyExpectedItemsAsync(markup, [ + ItemExpectation.Exists("X"), + ItemExpectation.Exists("Y"), + ]); + } + + private static string MakeMarkup([StringSyntax(PredefinedEmbeddedLanguageNames.CSharpTest)] string source, string languageVersion = "Preview") { return $$""" diff --git a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/TypeImportCompletionProviderTests.cs b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/TypeImportCompletionProviderTests.cs index 4230c5e7a1d25..5c67d7b282273 100644 --- a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/TypeImportCompletionProviderTests.cs +++ b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/TypeImportCompletionProviderTests.cs @@ -1032,7 +1032,7 @@ class Bat }"; var markup = CreateMarkupForSingleProject(file2, file1, LanguageNames.CSharp); var completionList = await GetCompletionListAsync(markup).ConfigureAwait(false); - AssertRelativeOrder(["SomeType", "SomeTypeWithLongerName"], completionList.ItemsList.ToImmutableArray()); + AssertRelativeOrder(["SomeType", "SomeTypeWithLongerName"], [.. completionList.ItemsList]); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/35540")] diff --git a/src/EditorFeatures/CSharpTest/Completion/CompletionServiceTests.cs b/src/EditorFeatures/CSharpTest/Completion/CompletionServiceTests.cs index ec8d2b1154af7..c94dd80e87699 100644 --- a/src/EditorFeatures/CSharpTest/Completion/CompletionServiceTests.cs +++ b/src/EditorFeatures/CSharpTest/Completion/CompletionServiceTests.cs @@ -93,7 +93,7 @@ private sealed class ThirdPartyOption : IOption public Type Type => typeof(int); public object DefaultValue => 0; public bool IsPerLanguage => true; - public ImmutableArray StorageLocations => ImmutableArray.Empty; + public ImmutableArray StorageLocations => []; } /// diff --git a/src/EditorFeatures/CSharpTest/Debugging/DataTipInfoGetterTests.cs b/src/EditorFeatures/CSharpTest/Debugging/DataTipInfoGetterTests.cs index 003dae44d87d9..c69fb7a0ae3ad 100644 --- a/src/EditorFeatures/CSharpTest/Debugging/DataTipInfoGetterTests.cs +++ b/src/EditorFeatures/CSharpTest/Debugging/DataTipInfoGetterTests.cs @@ -2,60 +2,20 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - -using System; -using System.Linq; -using System.Threading; using System.Threading.Tasks; -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CSharp.Debugging; using Microsoft.CodeAnalysis.Test.Utilities; -using Microsoft.CodeAnalysis.Text; +using Microsoft.CodeAnalysis.Test.Utilities.Debugging; using Roslyn.Test.Utilities; -using Roslyn.Utilities; using Xunit; namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Debugging; [UseExportProvider] [Trait(Traits.Feature, Traits.Features.DebuggingDataTips)] -public class DataTipInfoGetterTests +public sealed class DataTipInfoGetterTests : AbstractDataTipInfoGetterTests { - private static async Task TestAsync(string markup, string expectedText = null) - { - await TestSpanGetterAsync(markup, async (document, position, expectedSpan) => - { - var result = await DataTipInfoGetter.GetInfoAsync(document, position, CancellationToken.None); - - Assert.Equal(expectedSpan, result.Span); - Assert.Equal(expectedText, result.Text); - }); - } - - private static async Task TestNoDataTipAsync(string markup) - { - await TestSpanGetterAsync(markup, async (document, position, expectedSpan) => - { - var result = await DataTipInfoGetter.GetInfoAsync(document, position, CancellationToken.None); - Assert.True(result.IsDefault); - }); - } - - private static async Task TestSpanGetterAsync(string markup, Func continuation) - { - using var workspace = EditorTestWorkspace.CreateCSharp(markup); - var testHostDocument = workspace.Documents.Single(); - var position = testHostDocument.CursorPosition.Value; - var expectedSpan = testHostDocument.SelectedSpans.Any() - ? testHostDocument.SelectedSpans.Single() - : (TextSpan?)null; - - await continuation( - workspace.CurrentSolution.Projects.First().Documents.First(), - position, - expectedSpan); - } + protected override EditorTestWorkspace CreateWorkspace(string markup) + => EditorTestWorkspace.CreateCSharp(markup); [Fact] public async Task TestCSharpLanguageDebugInfoGetDataTipSpanAndText() @@ -460,104 +420,147 @@ object Goo(string[] args) """); } - [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1077843")] - public async Task TestConditionalAccessExpression() + [Theory, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1077843")] + // One level. + [InlineData("[|Me?.$$B|]")] + // Two levels. + [InlineData("[|Me?.$$B|].C")] + [InlineData("[|Me?.B.$$C|]")] + [InlineData("[|Me.$$B|]?.C")] + [InlineData("[|Me.B?.$$C|]")] + [InlineData("[|Me?.$$B|]?.C")] + [InlineData("[|Me?.B?.$$C|]")] + // Three levels. + [InlineData("[|Me?.$$B|].C.D")] + [InlineData("[|Me?.B.$$C|].D")] + [InlineData("[|Me?.B.C.$$D|]")] + [InlineData("[|Me.$$B|]?.C.D")] + [InlineData("[|Me.B?.$$C|].D")] + [InlineData("[|Me.B?.C.$$D|]")] + [InlineData("[|Me.$$B|].C?.D")] + [InlineData("[|Me.B.$$C|]?.D")] + [InlineData("[|Me.B.C?.$$D|]")] + [InlineData("[|Me?.$$B|]?.C.D")] + [InlineData("[|Me?.B?.$$C|].D")] + [InlineData("[|Me?.B?.C.$$D|]")] + [InlineData("[|Me?.$$B|].C?.D")] + [InlineData("[|Me?.B.$$C|]?.D")] + [InlineData("[|Me?.B.C?.$$D|]")] + [InlineData("[|Me.$$B|]?.C?.D")] + [InlineData("[|Me.B?.$$C|]?.D")] + [InlineData("[|Me.B?.C?.$$D|]")] + [InlineData("[|Me?.$$B|]?.C?.D")] + [InlineData("[|Me?.B?.$$C|]?.D")] + [InlineData("[|Me?.B?.C?.$$D|]")] + public async Task TestConditionalAccessExpression(string data) { - var sourceTemplate = """ + await TestAsync($$""" class A - {{ + { B B; object M() - {{ - return {0}; - }} - }} + { + return {{data}}; + } + } class B - {{ + { C C; - }} + } class C - {{ + { D D; - }} + } class D - {{ - }} - """; - - // One level. - await TestAsync(string.Format(sourceTemplate, "[|Me?.$$B|]")); + { + } + """); + } - // Two levels. - await TestAsync(string.Format(sourceTemplate, "[|Me?.$$B|].C")); - await TestAsync(string.Format(sourceTemplate, "[|Me?.B.$$C|]")); + [Theory, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1077843")] + [InlineData("/*1*/[|$$Me|]/*2*/?./*3*/B/*4*/?./*5*/C/*6*/")] + [InlineData("/*1*/[|Me/*2*/?./*3*/$$B|]/*4*/?./*5*/C/*6*/")] + [InlineData("/*1*/[|Me/*2*/?./*3*/B/*4*/?./*5*/$$C|]/*6*/")] + public async Task TestConditionalAccessExpression_Trivia(string data) + { + await TestAsync($$""" + class A + { + B B; - await TestAsync(string.Format(sourceTemplate, "[|Me.$$B|]?.C")); - await TestAsync(string.Format(sourceTemplate, "[|Me.B?.$$C|]")); + object M() + { + return {{data}}; + } + } - await TestAsync(string.Format(sourceTemplate, "[|Me?.$$B|]?.C")); - await TestAsync(string.Format(sourceTemplate, "[|Me?.B?.$$C|]")); + class B + { + C C; + } - // Three levels. - await TestAsync(string.Format(sourceTemplate, "[|Me?.$$B|].C.D")); - await TestAsync(string.Format(sourceTemplate, "[|Me?.B.$$C|].D")); - await TestAsync(string.Format(sourceTemplate, "[|Me?.B.C.$$D|]")); + class C + { + } + """); + } - await TestAsync(string.Format(sourceTemplate, "[|Me.$$B|]?.C.D")); - await TestAsync(string.Format(sourceTemplate, "[|Me.B?.$$C|].D")); - await TestAsync(string.Format(sourceTemplate, "[|Me.B?.C.$$D|]")); + [Fact] + public async Task TestLinq1() + { + await TestAsync(""" + using System.Linq; - await TestAsync(string.Format(sourceTemplate, "[|Me.$$B|].C?.D")); - await TestAsync(string.Format(sourceTemplate, "[|Me.B.$$C|]?.D")); - await TestAsync(string.Format(sourceTemplate, "[|Me.B.C?.$$D|]")); + int[] args; + var v = $$[|args|].Select(a => a.ToString()); + """); + } - await TestAsync(string.Format(sourceTemplate, "[|Me?.$$B|]?.C.D")); - await TestAsync(string.Format(sourceTemplate, "[|Me?.B?.$$C|].D")); - await TestAsync(string.Format(sourceTemplate, "[|Me?.B?.C.$$D|]")); + [Fact] + public async Task TestLinq2() + { + await TestAsync(""" + using System.Linq; - await TestAsync(string.Format(sourceTemplate, "[|Me?.$$B|].C?.D")); - await TestAsync(string.Format(sourceTemplate, "[|Me?.B.$$C|]?.D")); - await TestAsync(string.Format(sourceTemplate, "[|Me?.B.C?.$$D|]")); + int[] args; + var v = {|LinqExpression:[|args.$$Select|](a => a.ToString())|}; + """); + } - await TestAsync(string.Format(sourceTemplate, "[|Me.$$B|]?.C?.D")); - await TestAsync(string.Format(sourceTemplate, "[|Me.B?.$$C|]?.D")); - await TestAsync(string.Format(sourceTemplate, "[|Me.B?.C?.$$D|]")); + [Fact] + public async Task TestLinq3() + { + await TestAsync(""" + using System.Linq; - await TestAsync(string.Format(sourceTemplate, "[|Me?.$$B|]?.C?.D")); - await TestAsync(string.Format(sourceTemplate, "[|Me?.B?.$$C|]?.D")); - await TestAsync(string.Format(sourceTemplate, "[|Me?.B?.C?.$$D|]")); + int[] args; + var v = $$[|args|].Select(a => a.ToString()).Where(a => a.Length >= 0); + """); } - [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1077843")] - public async Task TestConditionalAccessExpression_Trivia() + [Fact] + public async Task TestLinq4() { - var sourceTemplate = """ - class A - {{ - B B; - - object M() - {{ - return {0}; - }} - }} + await TestAsync(""" + using System.Linq; - class B - {{ - C C; - }} + int[] args; + var v = {|LinqExpression:[|args.$$Select|](a => a.ToString())|}.Where(a => a.Length >= 0); + """); + } - class C - {{ - }} - """; + [Fact] + public async Task TestLinq5() + { + await TestAsync(""" + using System.Linq; - await TestAsync(string.Format(sourceTemplate, "/*1*/[|$$Me|]/*2*/?./*3*/B/*4*/?./*5*/C/*6*/")); - await TestAsync(string.Format(sourceTemplate, "/*1*/[|Me/*2*/?./*3*/$$B|]/*4*/?./*5*/C/*6*/")); - await TestAsync(string.Format(sourceTemplate, "/*1*/[|Me/*2*/?./*3*/B/*4*/?./*5*/$$C|]/*6*/")); + int[] args; + var v = {|LinqExpression:[|args.Select(a => a.ToString()).$$Where|](a => a.Length >= 0)|}; + """); } } diff --git a/src/EditorFeatures/CSharpTest/Diagnostics/DiagnosticAnalyzerDriver/DiagnosticAnalyzerDriverTests.cs b/src/EditorFeatures/CSharpTest/Diagnostics/DiagnosticAnalyzerDriver/DiagnosticAnalyzerDriverTests.cs index c4f33d130bbb8..898774278f37c 100644 --- a/src/EditorFeatures/CSharpTest/Diagnostics/DiagnosticAnalyzerDriver/DiagnosticAnalyzerDriverTests.cs +++ b/src/EditorFeatures/CSharpTest/Diagnostics/DiagnosticAnalyzerDriver/DiagnosticAnalyzerDriverTests.cs @@ -55,7 +55,7 @@ public async Task DiagnosticAnalyzerDriverAllInOne() var analyzer = new CSharpTrackingDiagnosticAnalyzer(); using var workspace = EditorTestWorkspace.CreateCSharp(source, TestOptions.Regular, composition: s_compositionWithMockDiagnosticUpdateSourceRegistrationService); - var analyzerReference = new AnalyzerImageReference(ImmutableArray.Create(analyzer)); + var analyzerReference = new AnalyzerImageReference([analyzer]); var newSolution = workspace.CurrentSolution.WithAnalyzerReferences([analyzerReference]) .Projects.Single().AddAdditionalDocument(name: "dummy.txt", text: "", filePath: "dummy.txt").Project.Solution; workspace.TryApplyChanges(newSolution); @@ -86,7 +86,7 @@ class C var ideEngineAnalyzer = new CSharpTrackingDiagnosticAnalyzer(); using (var ideEngineWorkspace = EditorTestWorkspace.CreateCSharp(source, composition: s_compositionWithMockDiagnosticUpdateSourceRegistrationService)) { - var analyzerReference = new AnalyzerImageReference(ImmutableArray.Create(ideEngineAnalyzer)); + var analyzerReference = new AnalyzerImageReference([ideEngineAnalyzer]); ideEngineWorkspace.TryApplyChanges(ideEngineWorkspace.CurrentSolution.WithAnalyzerReferences([analyzerReference])); var ideEngineDocument = ideEngineWorkspace.CurrentSolution.Projects.Single().Documents.Single(); @@ -122,7 +122,7 @@ await ThrowingDiagnosticAnalyzer.VerifyAnalyzerEngineIsSafeAgainstEx { using var workspace = EditorTestWorkspace.CreateCSharp(source, TestOptions.Regular, composition: s_compositionWithMockDiagnosticUpdateSourceRegistrationService); - var analyzerReference = new AnalyzerImageReference(ImmutableArray.Create(analyzer)); + var analyzerReference = new AnalyzerImageReference([analyzer]); workspace.TryApplyChanges(workspace.CurrentSolution.WithAnalyzerReferences([analyzerReference])); var document = workspace.CurrentSolution.Projects.Single().Documents.Single(); @@ -163,9 +163,9 @@ public async Task AnalyzerOptionsArePassedToAllAnalyzers() var additionalDocId = DocumentId.CreateNewId(workspace.CurrentSolution.Projects.Single().Id); var additionalText = new TestAdditionalText("add.config", SourceText.From("random text")); - var options = new AnalyzerOptions(ImmutableArray.Create(additionalText)); + var options = new AnalyzerOptions([additionalText]); var analyzer = new OptionsDiagnosticAnalyzer(expectedOptions: options); - var analyzerReference = new AnalyzerImageReference(ImmutableArray.Create(analyzer)); + var analyzerReference = new AnalyzerImageReference([analyzer]); workspace.TryApplyChanges(workspace.CurrentSolution .WithAnalyzerReferences([analyzerReference]) @@ -178,7 +178,7 @@ public async Task AnalyzerOptionsArePassedToAllAnalyzers() private static void AccessSupportedDiagnostics(DiagnosticAnalyzer analyzer) { - var diagnosticService = new HostDiagnosticAnalyzers([new AnalyzerImageReference(ImmutableArray.Create(analyzer))]); + var diagnosticService = new HostDiagnosticAnalyzers([new AnalyzerImageReference([analyzer])]); diagnosticService.GetDiagnosticDescriptorsPerReference(new DiagnosticAnalyzerInfoCache()); } @@ -198,7 +198,7 @@ public async Task AnalyzerCreatedAtCompilationLevelNeedNotBeCompilationAnalyzer( using var workspace = EditorTestWorkspace.CreateCSharp(source, composition: s_compositionWithMockDiagnosticUpdateSourceRegistrationService); var analyzer = new CompilationAnalyzerWithSyntaxTreeAnalyzer(); - var analyzerReference = new AnalyzerImageReference(ImmutableArray.Create(analyzer)); + var analyzerReference = new AnalyzerImageReference([analyzer]); workspace.TryApplyChanges(workspace.CurrentSolution.WithAnalyzerReferences([analyzerReference])); var ideEngineDocument = workspace.CurrentSolution.Projects.Single().Documents.Single(); @@ -220,7 +220,7 @@ public override ImmutableArray SupportedDiagnostics { get { - return ImmutableArray.Create(s_syntaxDiagnosticDescriptor); + return [s_syntaxDiagnosticDescriptor]; } } @@ -254,7 +254,7 @@ void F(int x = 0) var analyzer = new CodeBlockAnalyzerFactory(); using (var ideEngineWorkspace = EditorTestWorkspace.CreateCSharp(source, composition: s_compositionWithMockDiagnosticUpdateSourceRegistrationService)) { - var analyzerReference = new AnalyzerImageReference(ImmutableArray.Create(analyzer)); + var analyzerReference = new AnalyzerImageReference([analyzer]); ideEngineWorkspace.TryApplyChanges(ideEngineWorkspace.CurrentSolution.WithAnalyzerReferences([analyzerReference])); var ideEngineDocument = ideEngineWorkspace.CurrentSolution.Projects.Single().Documents.Single(); @@ -291,7 +291,7 @@ public override ImmutableArray SupportedDiagnostics { get { - return ImmutableArray.Create(Descriptor); + return [Descriptor]; } } @@ -311,7 +311,7 @@ public static ImmutableArray SyntaxKindsOfInterest { get { - return ImmutableArray.Create(SyntaxKind.MethodDeclaration, SyntaxKind.ExpressionStatement, SyntaxKind.EqualsValueClause); + return [SyntaxKind.MethodDeclaration, SyntaxKind.ExpressionStatement, SyntaxKind.EqualsValueClause]; } } @@ -346,7 +346,7 @@ private class InvalidSpanAnalyzer : DiagnosticAnalyzer public static DiagnosticDescriptor Descriptor = DescriptorFactory.CreateSimpleDescriptor("DummyDiagnostic"); public override ImmutableArray SupportedDiagnostics - => ImmutableArray.Create(Descriptor); + => [Descriptor]; public override void Initialize(AnalysisContext context) => context.RegisterSyntaxTreeAction(Analyze); @@ -378,12 +378,11 @@ await TestNuGetAndVsixAnalyzerCoreAsync( expectedNugetAnalyzerExecuted: true, vsixAnalyzer: null, expectedVsixAnalyzerExecuted: false, - new[] - { + [ (Diagnostic("A", "Class").WithLocation(1, 7), nameof(NuGetAnalyzer)), (Diagnostic("B", "Class").WithLocation(1, 7), nameof(NuGetAnalyzer)), (Diagnostic("C", "Class").WithLocation(1, 7), nameof(NuGetAnalyzer)), - }); + ]); // Only VSIX analyzer - verify diagnostics. await TestNuGetAndVsixAnalyzerCoreAsync( @@ -391,12 +390,11 @@ await TestNuGetAndVsixAnalyzerCoreAsync( expectedNugetAnalyzerExecuted: false, vsixAnalyzer, expectedVsixAnalyzerExecuted: true, - new[] - { + [ (Diagnostic("A", "Class").WithLocation(1, 7), nameof(VsixAnalyzer)), (Diagnostic("B", "Class").WithLocation(1, 7), nameof(VsixAnalyzer)), (Diagnostic("C", "Class").WithLocation(1, 7), nameof(VsixAnalyzer)), - }); + ]); // Both NuGet and VSIX analyzer, verify the following: // 1) No duplicate diagnostics @@ -406,12 +404,11 @@ await TestNuGetAndVsixAnalyzerCoreAsync( expectedNugetAnalyzerExecuted: true, vsixAnalyzer, expectedVsixAnalyzerExecuted: false, - new[] - { + [ (Diagnostic("A", "Class").WithLocation(1, 7), nameof(NuGetAnalyzer)), (Diagnostic("B", "Class").WithLocation(1, 7), nameof(NuGetAnalyzer)), (Diagnostic("C", "Class").WithLocation(1, 7), nameof(NuGetAnalyzer)), - }); + ]); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/18818")] @@ -431,10 +428,9 @@ await TestNuGetAndVsixAnalyzerCoreAsync( expectedNugetAnalyzerExecuted: true, vsixAnalyzer: null, expectedVsixAnalyzerExecuted: false, - new[] - { + [ (Diagnostic("B", "Class").WithLocation(1, 7), nameof(NuGetAnalyzer)) - }); + ]); // Only VSIX analyzer - verify diagnostics. await TestNuGetAndVsixAnalyzerCoreAsync( @@ -442,12 +438,11 @@ await TestNuGetAndVsixAnalyzerCoreAsync( expectedNugetAnalyzerExecuted: false, vsixAnalyzer, expectedVsixAnalyzerExecuted: true, - new[] - { + [ (Diagnostic("A", "Class").WithLocation(1, 7), nameof(VsixAnalyzer)), (Diagnostic("B", "Class").WithLocation(1, 7), nameof(VsixAnalyzer)), (Diagnostic("C", "Class").WithLocation(1, 7), nameof(VsixAnalyzer)), - }); + ]); // Both NuGet and VSIX analyzer, verify the following: // 1) No duplicate diagnostics @@ -458,12 +453,11 @@ await TestNuGetAndVsixAnalyzerCoreAsync( expectedNugetAnalyzerExecuted: true, vsixAnalyzer, expectedVsixAnalyzerExecuted: true, - new[] - { + [ (Diagnostic("A", "Class").WithLocation(1, 7), nameof(VsixAnalyzer)), (Diagnostic("B", "Class").WithLocation(1, 7), nameof(NuGetAnalyzer)), (Diagnostic("C", "Class").WithLocation(1, 7), nameof(VsixAnalyzer)), - }); + ]); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/18818")] @@ -483,12 +477,11 @@ await TestNuGetAndVsixAnalyzerCoreAsync( expectedNugetAnalyzerExecuted: true, vsixAnalyzer: null, expectedVsixAnalyzerExecuted: false, - new[] - { + [ (Diagnostic("A", "Class").WithLocation(1, 7), nameof(NuGetAnalyzer)), (Diagnostic("B", "Class").WithLocation(1, 7), nameof(NuGetAnalyzer)), (Diagnostic("C", "Class").WithLocation(1, 7), nameof(NuGetAnalyzer)) - }); + ]); // Only VSIX analyzer - verify diagnostics. await TestNuGetAndVsixAnalyzerCoreAsync( @@ -496,10 +489,9 @@ await TestNuGetAndVsixAnalyzerCoreAsync( expectedNugetAnalyzerExecuted: false, vsixAnalyzer, expectedVsixAnalyzerExecuted: true, - new[] - { + [ (Diagnostic("B", "Class").WithLocation(1, 7), nameof(VsixAnalyzer)) - }); + ]); // Both NuGet and VSIX analyzer, verify the following: // 1) No duplicate diagnostics @@ -509,12 +501,11 @@ await TestNuGetAndVsixAnalyzerCoreAsync( expectedNugetAnalyzerExecuted: true, vsixAnalyzer, expectedVsixAnalyzerExecuted: false, - new[] - { + [ (Diagnostic("A", "Class").WithLocation(1, 7), nameof(NuGetAnalyzer)), (Diagnostic("B", "Class").WithLocation(1, 7), nameof(NuGetAnalyzer)), (Diagnostic("C", "Class").WithLocation(1, 7), nameof(NuGetAnalyzer)), - }); + ]); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/18818")] @@ -535,59 +526,56 @@ public async Task TestNuGetAndVsixAnalyzer_MultipleNuGetAnalyzersCollectivelyRep // 1) No duplicate diagnostics // 2) Only NuGet analyzers execute await TestNuGetAndVsixAnalyzerCoreAsync( - nugetAnalyzers: ImmutableArray.Create(firstNugetAnalyzer, secondNugetAnalyzer), + nugetAnalyzers: [firstNugetAnalyzer, secondNugetAnalyzer], expectedNugetAnalyzersExecuted: true, - vsixAnalyzers: ImmutableArray.Empty, + vsixAnalyzers: [], expectedVsixAnalyzersExecuted: false, - nugetSuppressors: ImmutableArray.Empty, + nugetSuppressors: [], expectedNugetSuppressorsExecuted: false, - vsixSuppressors: ImmutableArray.Empty, + vsixSuppressors: [], expectedVsixSuppressorsExecuted: false, - new[] - { + [ (Diagnostic("A", "Class").WithLocation(1, 7), nameof(NuGetAnalyzer)), (Diagnostic("B", "Class").WithLocation(1, 7), nameof(NuGetAnalyzer)), (Diagnostic("C", "Class").WithLocation(1, 7), nameof(NuGetAnalyzer)) - }); + ]); // All NuGet analyzers and Vsix analyzer, verify the following: // 1) No duplicate diagnostics // 2) Only NuGet analyzers execute await TestNuGetAndVsixAnalyzerCoreAsync( - nugetAnalyzers: ImmutableArray.Create(firstNugetAnalyzer, secondNugetAnalyzer), + nugetAnalyzers: [firstNugetAnalyzer, secondNugetAnalyzer], expectedNugetAnalyzersExecuted: true, - vsixAnalyzers: ImmutableArray.Create(vsixAnalyzer), + vsixAnalyzers: [vsixAnalyzer], expectedVsixAnalyzersExecuted: false, - nugetSuppressors: ImmutableArray.Empty, + nugetSuppressors: [], expectedNugetSuppressorsExecuted: false, - vsixSuppressors: ImmutableArray.Empty, + vsixSuppressors: [], expectedVsixSuppressorsExecuted: false, - new[] - { + [ (Diagnostic("A", "Class").WithLocation(1, 7), nameof(NuGetAnalyzer)), (Diagnostic("B", "Class").WithLocation(1, 7), nameof(NuGetAnalyzer)), (Diagnostic("C", "Class").WithLocation(1, 7), nameof(NuGetAnalyzer)) - }); + ]); // Subset of NuGet analyzers and Vsix analyzer, verify the following: // 1) No duplicate diagnostics // 2) Both NuGet and Vsix analyzers execute // 3) Appropriate diagnostic filtering is done - NuGet analyzer reported diagnostic IDs are filtered from Vsix analyzer execution. await TestNuGetAndVsixAnalyzerCoreAsync( - nugetAnalyzers: ImmutableArray.Create(firstNugetAnalyzer), + nugetAnalyzers: [firstNugetAnalyzer], expectedNugetAnalyzersExecuted: true, - vsixAnalyzers: ImmutableArray.Create(vsixAnalyzer), + vsixAnalyzers: [vsixAnalyzer], expectedVsixAnalyzersExecuted: true, - nugetSuppressors: ImmutableArray.Empty, + nugetSuppressors: [], expectedNugetSuppressorsExecuted: false, - vsixSuppressors: ImmutableArray.Empty, + vsixSuppressors: [], expectedVsixSuppressorsExecuted: false, - new[] - { + [ (Diagnostic("A", "Class").WithLocation(1, 7), nameof(VsixAnalyzer)), (Diagnostic("B", "Class").WithLocation(1, 7), nameof(NuGetAnalyzer)), (Diagnostic("C", "Class").WithLocation(1, 7), nameof(VsixAnalyzer)) - }); + ]); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/46942")] @@ -614,64 +602,61 @@ public async Task TestNuGetAndVsixAnalyzer_SuppressorSuppressesVsixAnalyzer() // 1) No duplicate diagnostics // 2) The VSIX diagnostics are suppressed by the VSIX suppressor await TestNuGetAndVsixAnalyzerCoreAsync( - nugetAnalyzers: ImmutableArray.Empty, + nugetAnalyzers: [], expectedNugetAnalyzersExecuted: false, - vsixAnalyzers: ImmutableArray.Create(vsixAnalyzer), + vsixAnalyzers: [vsixAnalyzer], expectedVsixAnalyzersExecuted: true, - nugetSuppressors: ImmutableArray.Empty, + nugetSuppressors: [], expectedNugetSuppressorsExecuted: false, - vsixSuppressors: ImmutableArray.Create(vsixSuppressor), + vsixSuppressors: [vsixSuppressor], expectedVsixSuppressorsExecuted: true, - new[] - { + [ (Diagnostic("X", "Class", isSuppressed: true).WithLocation(1, 7), nameof(VsixAnalyzer)), (Diagnostic("Y", "Class", isSuppressed: true).WithLocation(1, 7), nameof(VsixAnalyzer)), (Diagnostic("Z", "Class", isSuppressed: true).WithLocation(1, 7), nameof(VsixAnalyzer)) - }); + ]); // All without overlap, the VSIX analyzer and suppressor still work when nuget analyzers are present: // 1) No duplicate diagnostics // 2) All analyzers execute // 3) VSIX diagnostics are suppressed. await TestNuGetAndVsixAnalyzerCoreAsync( - nugetAnalyzers: ImmutableArray.Create(firstNugetAnalyzer, secondNugetAnalyzer), + nugetAnalyzers: [firstNugetAnalyzer, secondNugetAnalyzer], expectedNugetAnalyzersExecuted: true, - vsixAnalyzers: ImmutableArray.Create(vsixAnalyzer), + vsixAnalyzers: [vsixAnalyzer], expectedVsixAnalyzersExecuted: true, - nugetSuppressors: ImmutableArray.Empty, + nugetSuppressors: [], expectedNugetSuppressorsExecuted: false, - vsixSuppressors: ImmutableArray.Create(vsixSuppressor), + vsixSuppressors: [vsixSuppressor], expectedVsixSuppressorsExecuted: true, - new[] - { + [ (Diagnostic("A", "Class").WithLocation(1, 7), nameof(NuGetAnalyzer)), (Diagnostic("B", "Class").WithLocation(1, 7), nameof(NuGetAnalyzer)), (Diagnostic("C", "Class").WithLocation(1, 7), nameof(NuGetAnalyzer)), (Diagnostic("X", "Class", isSuppressed: true).WithLocation(1, 7), nameof(VsixAnalyzer)), (Diagnostic("Y", "Class", isSuppressed: true).WithLocation(1, 7), nameof(VsixAnalyzer)), (Diagnostic("Z", "Class", isSuppressed: true).WithLocation(1, 7), nameof(VsixAnalyzer)) - }); + ]); // All without overlap, verify the following: // 1) No duplicate diagnostics // 2) Both NuGet and Vsix analyzers execute // 3) Appropriate diagnostic filtering is done - Nuget suppressor suppresses VSIX analyzer. await TestNuGetAndVsixAnalyzerCoreAsync( - nugetAnalyzers: ImmutableArray.Create(firstNugetAnalyzer), + nugetAnalyzers: [firstNugetAnalyzer], expectedNugetAnalyzersExecuted: true, - vsixAnalyzers: ImmutableArray.Create(vsixAnalyzer), + vsixAnalyzers: [vsixAnalyzer], expectedVsixAnalyzersExecuted: true, - nugetSuppressors: ImmutableArray.Create(nugetSuppressor), + nugetSuppressors: [nugetSuppressor], expectedNugetSuppressorsExecuted: true, - vsixSuppressors: ImmutableArray.Empty, + vsixSuppressors: [], expectedVsixSuppressorsExecuted: false, - new[] - { + [ (Diagnostic("A", "Class").WithLocation(1, 7), nameof(NuGetAnalyzer)), (Diagnostic("X", "Class", isSuppressed: true).WithLocation(1, 7), nameof(VsixAnalyzer)), (Diagnostic("Y", "Class", isSuppressed: true).WithLocation(1, 7), nameof(VsixAnalyzer)), (Diagnostic("Z", "Class", isSuppressed: true).WithLocation(1, 7), nameof(VsixAnalyzer)) - }); + ]); // Suppressors with duplicate support for VsixAnalyzer, but not 100% overlap. Verify the following: // 1) No duplicate diagnostics @@ -679,21 +664,20 @@ await TestNuGetAndVsixAnalyzerCoreAsync( // 3) Only Nuget suppressor executes // 4) Appropriate diagnostic filtering is done - Nuget suppressor suppresses VSIX analyzer. await TestNuGetAndVsixAnalyzerCoreAsync( - nugetAnalyzers: ImmutableArray.Create(firstNugetAnalyzer), + nugetAnalyzers: [firstNugetAnalyzer], expectedNugetAnalyzersExecuted: true, - vsixAnalyzers: ImmutableArray.Create(vsixAnalyzer), + vsixAnalyzers: [vsixAnalyzer], expectedVsixAnalyzersExecuted: true, - nugetSuppressors: ImmutableArray.Create(partialNugetSuppressor), + nugetSuppressors: [partialNugetSuppressor], expectedNugetSuppressorsExecuted: true, - vsixSuppressors: ImmutableArray.Create(vsixSuppressor), + vsixSuppressors: [vsixSuppressor], expectedVsixSuppressorsExecuted: false, - new[] - { + [ (Diagnostic("A", "Class").WithLocation(1, 7), nameof(NuGetAnalyzer)), (Diagnostic("X", "Class", isSuppressed: false).WithLocation(1, 7), nameof(VsixAnalyzer)), (Diagnostic("Y", "Class", isSuppressed: true).WithLocation(1, 7), nameof(VsixAnalyzer)), (Diagnostic("Z", "Class", isSuppressed: true).WithLocation(1, 7), nameof(VsixAnalyzer)) - }); + ]); // Suppressors with duplicate support for VsixAnalyzer, with 100% overlap. Verify the following: // 1) No duplicate diagnostics @@ -701,21 +685,20 @@ await TestNuGetAndVsixAnalyzerCoreAsync( // 3) Only Nuget suppressor executes // 4) Appropriate diagnostic filtering is done - Nuget suppressor suppresses VSIX analyzer. await TestNuGetAndVsixAnalyzerCoreAsync( - nugetAnalyzers: ImmutableArray.Create(firstNugetAnalyzer), + nugetAnalyzers: [firstNugetAnalyzer], expectedNugetAnalyzersExecuted: true, - vsixAnalyzers: ImmutableArray.Create(vsixAnalyzer), + vsixAnalyzers: [vsixAnalyzer], expectedVsixAnalyzersExecuted: true, - nugetSuppressors: ImmutableArray.Create(nugetSuppressor), + nugetSuppressors: [nugetSuppressor], expectedNugetSuppressorsExecuted: true, - vsixSuppressors: ImmutableArray.Create(vsixSuppressor), + vsixSuppressors: [vsixSuppressor], expectedVsixSuppressorsExecuted: false, - new[] - { + [ (Diagnostic("A", "Class").WithLocation(1, 7), nameof(NuGetAnalyzer)), (Diagnostic("X", "Class", isSuppressed: true).WithLocation(1, 7), nameof(VsixAnalyzer)), (Diagnostic("Y", "Class", isSuppressed: true).WithLocation(1, 7), nameof(VsixAnalyzer)), (Diagnostic("Z", "Class", isSuppressed: true).WithLocation(1, 7), nameof(VsixAnalyzer)) - }); + ]); } private static Task TestNuGetAndVsixAnalyzerCoreAsync( @@ -725,13 +708,13 @@ private static Task TestNuGetAndVsixAnalyzerCoreAsync( bool expectedVsixAnalyzerExecuted, params (DiagnosticDescription diagnostic, string message)[] expectedDiagnostics) => TestNuGetAndVsixAnalyzerCoreAsync( - nugetAnalyzer != null ? ImmutableArray.Create(nugetAnalyzer) : ImmutableArray.Empty, + nugetAnalyzer != null ? [nugetAnalyzer] : [], expectedNugetAnalyzerExecuted, - vsixAnalyzer != null ? ImmutableArray.Create(vsixAnalyzer) : ImmutableArray.Empty, + vsixAnalyzer != null ? [vsixAnalyzer] : [], expectedVsixAnalyzerExecuted, - ImmutableArray.Empty, + [], false, - ImmutableArray.Empty, + [], false, expectedDiagnostics); @@ -773,7 +756,7 @@ private static async Task TestNuGetAndVsixAnalyzerCoreAsync( Assert.True(workspace.TryApplyChanges(workspace.CurrentSolution.WithAnalyzerReferences( [ - new AnalyzerImageReference(vsixAnalyzerReferences.ToImmutableArray()) + new AnalyzerImageReference([.. vsixAnalyzerReferences]) ]))); var project = workspace.CurrentSolution.Projects.Single(); @@ -791,7 +774,7 @@ private static async Task TestNuGetAndVsixAnalyzerCoreAsync( if (nugetAnalyzerReferences.Count > 0) { - project = project.WithAnalyzerReferences([new AnalyzerImageReference(nugetAnalyzerReferences.ToImmutableArray())]); + project = project.WithAnalyzerReferences([new AnalyzerImageReference([.. nugetAnalyzerReferences])]); } var document = project.Documents.Single(); @@ -800,7 +783,7 @@ private static async Task TestNuGetAndVsixAnalyzerCoreAsync( var diagnostics = (await DiagnosticProviderTestUtilities.GetAllDiagnosticsAsync(workspace, document, root.FullSpan, includeSuppressedDiagnostics: true)) .OrderBy(d => d.Id).ToImmutableArray(); - diagnostics.Verify(expectedDiagnostics.Select(d => d.diagnostic).ToArray()); + diagnostics.Verify([.. expectedDiagnostics.Select(d => d.diagnostic)]); var index = 0; foreach (var (d, expectedMessage) in expectedDiagnostics) diff --git a/src/EditorFeatures/CSharpTest/Diagnostics/FixAllProvider/BatchFixerTests.cs b/src/EditorFeatures/CSharpTest/Diagnostics/FixAllProvider/BatchFixerTests.cs index 2e0433862dc49..8d70e8b605a63 100644 --- a/src/EditorFeatures/CSharpTest/Diagnostics/FixAllProvider/BatchFixerTests.cs +++ b/src/EditorFeatures/CSharpTest/Diagnostics/FixAllProvider/BatchFixerTests.cs @@ -37,7 +37,7 @@ public override ImmutableArray SupportedDiagnostics { get { - return ImmutableArray.Create(Descriptor); + return [Descriptor]; } } @@ -64,7 +64,7 @@ public override ImmutableArray FixableDiagnosticIds { get { - return ImmutableArray.Create(QualifyWithThisAnalyzer.Descriptor.Id); + return [QualifyWithThisAnalyzer.Descriptor.Id]; } } diff --git a/src/EditorFeatures/CSharpTest/Diagnostics/MockDiagnosticAnalyzerTests.cs b/src/EditorFeatures/CSharpTest/Diagnostics/MockDiagnosticAnalyzerTests.cs index 3975cfdfdd91a..53a9e65914187 100644 --- a/src/EditorFeatures/CSharpTest/Diagnostics/MockDiagnosticAnalyzerTests.cs +++ b/src/EditorFeatures/CSharpTest/Diagnostics/MockDiagnosticAnalyzerTests.cs @@ -26,7 +26,7 @@ public override ImmutableArray SupportedDiagnostics { get { - return ImmutableArray.Create(_descriptor); + return [_descriptor]; } } diff --git a/src/EditorFeatures/CSharpTest/Diagnostics/NamingStyles/EditorConfigNamingStyleParserTests.cs b/src/EditorFeatures/CSharpTest/Diagnostics/NamingStyles/EditorConfigNamingStyleParserTests.cs index 930e3cd84ca7d..a4e484bcc394f 100644 --- a/src/EditorFeatures/CSharpTest/Diagnostics/NamingStyles/EditorConfigNamingStyleParserTests.cs +++ b/src/EditorFeatures/CSharpTest/Diagnostics/NamingStyles/EditorConfigNamingStyleParserTests.cs @@ -463,7 +463,7 @@ public void TestEditorConfigParseForApplicableSymbolKinds() var symbolSpecifications = CreateDefaultSymbolSpecification(); foreach (var applicableSymbolKind in symbolSpecifications.ApplicableSymbolKindList) { - var editorConfigString = EditorConfigNamingStyleParser.ToEditorConfigString(ImmutableArray.Create(applicableSymbolKind)); + var editorConfigString = EditorConfigNamingStyleParser.ToEditorConfigString([applicableSymbolKind]); Assert.True(!string.IsNullOrEmpty(editorConfigString)); } } diff --git a/src/EditorFeatures/CSharpTest/DocumentationComments/DocumentationCommentTests.cs b/src/EditorFeatures/CSharpTest/DocumentationComments/DocumentationCommentTests.cs index 00c36eca01d29..73a6735475ae4 100644 --- a/src/EditorFeatures/CSharpTest/DocumentationComments/DocumentationCommentTests.cs +++ b/src/EditorFeatures/CSharpTest/DocumentationComments/DocumentationCommentTests.cs @@ -2778,6 +2778,108 @@ class C VerifyTypingCharacter(code, expected); } + [WpfFact, WorkItem("https://github.com/dotnet/roslyn/issues/75838")] + public void TypingCharacter_ExistingText1() + { + var code = + """ + /// foo$$ + class C + { + } + """; + + var expected = + """ + /// foo/$$ + class C + { + } + """; + + VerifyTypingCharacter(code, expected); + } + + [WpfFact, WorkItem("https://github.com/dotnet/roslyn/issues/75838")] + public void TypingCharacter_ExistingText2() + { + var code = + """ + namespace N + { + /// foo$$ + class C + { + } + } + """; + + var expected = + """ + namespace N + { + /// foo/$$ + class C + { + } + } + """; + + VerifyTypingCharacter(code, expected); + } + + [WpfFact, WorkItem("https://github.com/dotnet/roslyn/issues/75838")] + public void PressingEnter_ExistingText1() + { + var code = + """ + /// foo$$ + class C + { + } + """; + + var expected = + """ + /// foo + /// $$ + class C + { + } + """; + + VerifyPressingEnter(code, expected); + } + + [WpfFact, WorkItem("https://github.com/dotnet/roslyn/issues/75838")] + public void PressingEnter_ExistingText2() + { + var code = + """ + namespace N + { + /// foo$$ + class C + { + } + } + """; + + var expected = + """ + namespace N + { + /// foo + /// $$ + class C + { + } + } + """; + + VerifyPressingEnter(code, expected); + } + protected override char DocumentationCommentCharacter { get { return '/'; } diff --git a/src/EditorFeatures/CSharpTest/EditAndContinue/ActiveStatementTrackingServiceTests.cs b/src/EditorFeatures/CSharpTest/EditAndContinue/ActiveStatementTrackingServiceTests.cs index f8849caff44b1..ddf2ad8ecb760 100644 --- a/src/EditorFeatures/CSharpTest/EditAndContinue/ActiveStatementTrackingServiceTests.cs +++ b/src/EditorFeatures/CSharpTest/EditAndContinue/ActiveStatementTrackingServiceTests.cs @@ -37,18 +37,22 @@ public async Task TrackingService_GetLatestSpansAsync(bool scheduleInitialTracki var spanProvider = new MockActiveStatementSpanProvider(); - spanProvider.GetBaseActiveStatementSpansImpl = (_, documentIds) => ImmutableArray.Create( + spanProvider.GetBaseActiveStatementSpansImpl = (_, documentIds) => + [ ImmutableArray.Create( - new ActiveStatementSpan(new ActiveStatementId(0), span11, ActiveStatementFlags.NonLeafFrame), - new ActiveStatementSpan(new ActiveStatementId(1), span12, ActiveStatementFlags.LeafFrame)), - ImmutableArray.Empty); + new ActiveStatementSpan(new ActiveStatementId(0), span11, ActiveStatementFlags.NonLeafFrame), + new ActiveStatementSpan(new ActiveStatementId(1), span12, ActiveStatementFlags.LeafFrame)), + [], + ]; spanProvider.GetAdjustedActiveStatementSpansImpl = (document, _) => document.Name switch { - "1.cs" => ImmutableArray.Create( + "1.cs" => + [ new ActiveStatementSpan(new ActiveStatementId(0), span21, ActiveStatementFlags.NonLeafFrame), - new ActiveStatementSpan(new ActiveStatementId(1), span22, ActiveStatementFlags.LeafFrame)), - "2.cs" => ImmutableArray.Empty, + new ActiveStatementSpan(new ActiveStatementId(1), span22, ActiveStatementFlags.LeafFrame), + ], + "2.cs" => [], _ => throw ExceptionUtilities.Unreachable() }; @@ -111,7 +115,7 @@ public async Task TrackingService_GetLatestSpansAsync(bool scheduleInitialTracki } // we are not able to determine active statements in a document: - spanProvider.GetAdjustedActiveStatementSpansImpl = (_, _) => ImmutableArray.Empty; + spanProvider.GetAdjustedActiveStatementSpansImpl = (_, _) => []; var spans6 = await trackingSession.GetAdjustedTrackingSpansAsync(document1, snapshot1, CancellationToken.None); AssertEx.Equal( diff --git a/src/EditorFeatures/CSharpTest/ExtractInterface/ExtractInterfaceTests.cs b/src/EditorFeatures/CSharpTest/ExtractInterface/ExtractInterfaceTests.cs index 7d72e3e230cc1..2116634f0c926 100644 --- a/src/EditorFeatures/CSharpTest/ExtractInterface/ExtractInterfaceTests.cs +++ b/src/EditorFeatures/CSharpTest/ExtractInterface/ExtractInterfaceTests.cs @@ -11,6 +11,7 @@ using Microsoft.CodeAnalysis.CSharp.CodeStyle; using Microsoft.CodeAnalysis.CSharp.ExtractInterface; using Microsoft.CodeAnalysis.Editor.UnitTests; +using Microsoft.CodeAnalysis.Editor.UnitTests.CodeActions; using Microsoft.CodeAnalysis.Editor.UnitTests.Extensions; using Microsoft.CodeAnalysis.Editor.UnitTests.ExtractInterface; using Microsoft.CodeAnalysis.ExtractInterface; @@ -19,13 +20,13 @@ using Microsoft.VisualStudio.Text.Editor.Commanding.Commands; using Roslyn.Test.Utilities; using Xunit; -using Microsoft.CodeAnalysis.Editor.UnitTests.CodeActions; namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.ExtractInterface; -public class ExtractInterfaceTests : AbstractExtractInterfaceTests +[Trait(Traits.Feature, Traits.Features.ExtractInterface)] +public sealed class ExtractInterfaceTests : AbstractExtractInterfaceTests { - [WpfFact, Trait(Traits.Feature, Traits.Features.ExtractInterface)] + [WpfFact] public async Task ExtractInterface_Invocation_CaretInMethod() { var markup = """ @@ -42,7 +43,7 @@ public void Goo() await TestExtractInterfaceCommandCSharpAsync(markup, expectedSuccess: true); } - [WpfFact, Trait(Traits.Feature, Traits.Features.ExtractInterface)] + [WpfFact] public async Task ExtractInterface_Invocation_CaretAfterClassClosingBrace() { var markup = """ @@ -59,7 +60,7 @@ public void Goo() await TestExtractInterfaceCommandCSharpAsync(markup, expectedSuccess: true); } - [WpfFact, Trait(Traits.Feature, Traits.Features.ExtractInterface)] + [WpfFact] public async Task ExtractInterface_Invocation_CaretBeforeClassKeyword() { var markup = """ @@ -76,7 +77,7 @@ public void Goo() await TestExtractInterfaceCommandCSharpAsync(markup, expectedSuccess: true); } - [WpfFact, Trait(Traits.Feature, Traits.Features.ExtractInterface)] + [WpfFact] public async Task ExtractInterface_Invocation_FromInnerClass1() { var markup = """ @@ -100,7 +101,7 @@ class AnotherClass await TestExtractInterfaceCommandCSharpAsync(markup, expectedSuccess: true, expectedMemberName: "Bar"); } - [WpfFact, Trait(Traits.Feature, Traits.Features.ExtractInterface)] + [WpfFact] public async Task ExtractInterface_Invocation_FromInnerClass2() { var markup = """ @@ -124,7 +125,7 @@ public async Task Bar() await TestExtractInterfaceCommandCSharpAsync(markup, expectedSuccess: true, expectedMemberName: "Bar"); } - [WpfFact, Trait(Traits.Feature, Traits.Features.ExtractInterface)] + [WpfFact] public async Task ExtractInterface_Invocation_FromOuterClass() { var markup = """ @@ -148,7 +149,7 @@ public async Task Bar() await TestExtractInterfaceCommandCSharpAsync(markup, expectedSuccess: true, expectedMemberName: "Goo"); } - [WpfFact, Trait(Traits.Feature, Traits.Features.ExtractInterface)] + [WpfFact] public async Task ExtractInterface_Invocation_FromInterface_01() { var markup = """ @@ -162,7 +163,7 @@ interface IMyInterface await TestExtractInterfaceCommandCSharpAsync(markup, expectedSuccess: true, expectedMemberName: "Goo", expectedInterfaceName: "IMyInterface1"); } - [WpfFact, Trait(Traits.Feature, Traits.Features.ExtractInterface)] + [WpfFact] public async Task ExtractInterface_Invocation_FromInterface_02() { var markup = """ @@ -176,7 +177,7 @@ interface IMyInterface() await TestExtractInterfaceCommandCSharpAsync(markup, expectedSuccess: true, expectedMemberName: "Goo", expectedInterfaceName: "IMyInterface1"); } - [WpfFact, Trait(Traits.Feature, Traits.Features.ExtractInterface)] + [WpfFact] public async Task ExtractInterface_Invocation_FromStruct() { var markup = """ @@ -190,7 +191,7 @@ struct SomeStruct await TestExtractInterfaceCommandCSharpAsync(markup, expectedSuccess: true, expectedMemberName: "Goo", expectedInterfaceName: "ISomeStruct"); } - [WpfFact, Trait(Traits.Feature, Traits.Features.ExtractInterface)] + [WpfFact] public async Task ExtractInterface_Invocation_FromNamespace() { var markup = """ @@ -208,7 +209,7 @@ public async Task Goo() { } await TestExtractInterfaceCommandCSharpAsync(markup, expectedSuccess: false); } - [WpfFact, Trait(Traits.Feature, Traits.Features.ExtractInterface)] + [WpfFact] public async Task ExtractInterface_ExtractableMembers_DoesNotIncludeFields() { var markup = """ @@ -226,7 +227,7 @@ public void Goo() await TestExtractInterfaceCommandCSharpAsync(markup, expectedSuccess: true, expectedMemberName: "Goo"); } - [WpfFact, Trait(Traits.Feature, Traits.Features.ExtractInterface)] + [WpfFact] public async Task ExtractInterface_ExtractableMembers_IncludesPublicProperty_WithGetAndSet() { var markup = """ @@ -240,7 +241,7 @@ class MyClass await TestExtractInterfaceCommandCSharpAsync(markup, expectedSuccess: true, expectedMemberName: "Prop"); } - [WpfFact, Trait(Traits.Feature, Traits.Features.ExtractInterface)] + [WpfFact] public async Task ExtractInterfaceAction_ExtractableMembers_IncludesPublicProperty_WithGetAndSet() { var markup = """ @@ -265,7 +266,7 @@ class MyClass : IMyClass await TestExtractInterfaceCodeActionCSharpAsync(markup, expectedMarkup); } - [WpfFact, Trait(Traits.Feature, Traits.Features.ExtractInterface)] + [WpfFact] public async Task ExtractInterface_ExtractableMembers_IncludesPublicProperty_WithGetAndPrivateSet() { var markup = """ @@ -279,7 +280,7 @@ class MyClass await TestExtractInterfaceCommandCSharpAsync(markup, expectedSuccess: true, expectedMemberName: "Prop"); } - [WpfFact, Trait(Traits.Feature, Traits.Features.ExtractInterface)] + [WpfFact] public async Task ExtractInterface_ExtractableMembers_IncludesPublicProperty_WithGet() { var markup = """ @@ -293,7 +294,7 @@ class MyClass await TestExtractInterfaceCommandCSharpAsync(markup, expectedSuccess: true, expectedMemberName: "Prop"); } - [WpfFact, Trait(Traits.Feature, Traits.Features.ExtractInterface)] + [WpfFact] public async Task ExtractInterface_ExtractableMembers_ExcludesPublicProperty_WithPrivateGetAndPrivateSet() { var markup = """ @@ -307,7 +308,7 @@ class MyClass await TestExtractInterfaceCommandCSharpAsync(markup, expectedSuccess: false); } - [WpfFact, Trait(Traits.Feature, Traits.Features.ExtractInterface)] + [WpfFact] public async Task ExtractInterface_ExtractableMembers_IncludesPublicIndexer() { var markup = """ @@ -321,7 +322,7 @@ class MyClass await TestExtractInterfaceCommandCSharpAsync(markup, expectedSuccess: true, expectedMemberName: "this[]"); } - [WpfFact, Trait(Traits.Feature, Traits.Features.ExtractInterface)] + [WpfFact] public async Task ExtractInterface_ExtractableMembers_ExcludesInternalIndexer() { var markup = """ @@ -335,7 +336,7 @@ class MyClass await TestExtractInterfaceCommandCSharpAsync(markup, expectedSuccess: false); } - [WpfFact, Trait(Traits.Feature, Traits.Features.ExtractInterface)] + [WpfFact] public async Task ExtractInterface_ExtractableMembers_IncludesPublicMethod() { var markup = """ @@ -351,7 +352,7 @@ class MyClass await TestExtractInterfaceCommandCSharpAsync(markup, expectedSuccess: true, expectedMemberName: "M"); } - [WpfFact, Trait(Traits.Feature, Traits.Features.ExtractInterface)] + [WpfFact] public async Task ExtractInterface_ExtractableMembers_ExcludesInternalMethod() { var markup = """ @@ -367,7 +368,7 @@ class MyClass await TestExtractInterfaceCommandCSharpAsync(markup, expectedSuccess: false); } - [WpfFact, Trait(Traits.Feature, Traits.Features.ExtractInterface)] + [WpfFact] public async Task ExtractInterface_ExtractableMembers_IncludesAbstractMethod() { var markup = """ @@ -381,7 +382,7 @@ abstract class MyClass await TestExtractInterfaceCommandCSharpAsync(markup, expectedSuccess: true, expectedMemberName: "M"); } - [WpfFact, Trait(Traits.Feature, Traits.Features.ExtractInterface)] + [WpfFact] public async Task ExtractInterface_ExtractableMembers_IncludesPublicEvent() { var markup = """ @@ -395,7 +396,7 @@ class MyClass await TestExtractInterfaceCommandCSharpAsync(markup, expectedSuccess: true, expectedMemberName: "MyEvent"); } - [WpfFact, Trait(Traits.Feature, Traits.Features.ExtractInterface)] + [WpfFact] public async Task ExtractInterface_ExtractableMembers_ExcludesPrivateEvent() { var markup = """ @@ -409,7 +410,7 @@ class MyClass await TestExtractInterfaceCommandCSharpAsync(markup, expectedSuccess: false); } - [WpfFact, Trait(Traits.Feature, Traits.Features.ExtractInterface)] + [WpfFact] public async Task ExtractInterface_DefaultInterfaceName_DoesNotConflictWithOtherTypeNames() { var markup = """ @@ -427,7 +428,7 @@ class IMyClass2 { } await TestExtractInterfaceCommandCSharpAsync(markup, expectedSuccess: true, expectedInterfaceName: "IMyClass3"); } - [WpfFact, Trait(Traits.Feature, Traits.Features.ExtractInterface)] + [WpfFact] public async Task ExtractInterface_NamespaceName_NoNamespace() { var markup = """ @@ -441,7 +442,7 @@ class MyClass await TestExtractInterfaceCommandCSharpAsync(markup, expectedSuccess: true, expectedNamespaceName: ""); } - [WpfFact, Trait(Traits.Feature, Traits.Features.ExtractInterface)] + [WpfFact] public async Task ExtractInterface_NamespaceName_SingleNamespace() { var markup = """ @@ -458,7 +459,7 @@ class MyClass await TestExtractInterfaceCommandCSharpAsync(markup, expectedSuccess: true, expectedNamespaceName: "MyNamespace"); } - [WpfFact, Trait(Traits.Feature, Traits.Features.ExtractInterface)] + [WpfFact] public async Task ExtractInterface_NamespaceName_NestedNamespaces() { var markup = """ @@ -478,7 +479,7 @@ class MyClass await TestExtractInterfaceCommandCSharpAsync(markup, expectedSuccess: true, expectedNamespaceName: "OuterNamespace.InnerNamespace"); } - [WpfFact, Trait(Traits.Feature, Traits.Features.ExtractInterface)] + [WpfFact] public async Task ExtractInterface_NamespaceName_NestedNamespaces_FileScopedNamespace1() { var markup = """ @@ -518,7 +519,7 @@ internal interface IMyClass """, interfaceCode); } - [WpfFact, Trait(Traits.Feature, Traits.Features.ExtractInterface)] + [WpfFact] public async Task ExtractInterface_NamespaceName_NestedNamespaces_FileScopedNamespace2() { var markup = """ @@ -559,7 +560,7 @@ internal interface IMyClass """, interfaceCode); } - [WpfFact, Trait(Traits.Feature, Traits.Features.ExtractInterface)] + [WpfFact] public async Task ExtractInterface_NamespaceName_NestedNamespaces_FileScopedNamespace3() { var markup = """ @@ -600,7 +601,7 @@ internal interface IMyClass """, interfaceCode); } - [WpfFact, Trait(Traits.Feature, Traits.Features.ExtractInterface)] + [WpfFact] public async Task ExtractInterface_CodeGen_ClassesImplementExtractedInterface() { var markup = """ @@ -624,7 +625,7 @@ public void Goo() { } await TestExtractInterfaceCommandCSharpAsync(markup, expectedSuccess: true, expectedUpdatedOriginalDocumentCode: expectedCode); } - [WpfFact, Trait(Traits.Feature, Traits.Features.ExtractInterface)] + [WpfFact] public async Task ExtractInterface_CodeGen_StructsImplementExtractedInterface() { var markup = """ @@ -648,7 +649,7 @@ public void Goo() { } await TestExtractInterfaceCommandCSharpAsync(markup, expectedSuccess: true, expectedUpdatedOriginalDocumentCode: expectedCode); } - [WpfFact, Trait(Traits.Feature, Traits.Features.ExtractInterface)] + [WpfFact] public async Task ExtractInterface_CodeGen_InterfacesDoNotImplementExtractedInterface() { var markup = """ @@ -672,7 +673,7 @@ interface MyInterface await TestExtractInterfaceCommandCSharpAsync(markup, expectedSuccess: true, expectedUpdatedOriginalDocumentCode: expectedCode); } - [WpfFact, Trait(Traits.Feature, Traits.Features.ExtractInterface)] + [WpfFact] public async Task ExtractInterface_CodeGen_Methods() { var markup = """ @@ -707,7 +708,7 @@ interface IMyClass await TestExtractInterfaceCommandCSharpAsync(markup, expectedSuccess: true, expectedInterfaceCode: expectedInterfaceCode); } - [WpfFact, Trait(Traits.Feature, Traits.Features.ExtractInterface)] + [WpfFact] public async Task ExtractInterface_CodeGen_MethodsInRecord() { var markup = """ @@ -731,7 +732,7 @@ interface IR await TestExtractInterfaceCommandCSharpAsync(markup, expectedSuccess: true, expectedInterfaceCode: expectedInterfaceCode); } - [WpfFact, Trait(Traits.Feature, Traits.Features.ExtractInterface)] + [WpfFact] public async Task ExtractInterface_CodeGen_Events() { var markup = """ @@ -757,7 +758,7 @@ internal interface IMyClass await TestExtractInterfaceCommandCSharpAsync(markup, expectedSuccess: true, expectedInterfaceCode: expectedInterfaceCode); } - [WpfFact, Trait(Traits.Feature, Traits.Features.ExtractInterface)] + [WpfFact] public async Task ExtractInterface_CodeGen_Properties() { var markup = """ @@ -796,7 +797,7 @@ interface IMyClass await TestExtractInterfaceCommandCSharpAsync(markup, expectedSuccess: true, expectedInterfaceCode: expectedInterfaceCode); } - [WpfFact, Trait(Traits.Feature, Traits.Features.ExtractInterface)] + [WpfFact] public async Task ExtractInterface_CodeGen_Indexers() { var markup = """ @@ -824,7 +825,7 @@ interface IMyClass await TestExtractInterfaceCommandCSharpAsync(markup, expectedSuccess: true, expectedInterfaceCode: expectedInterfaceCode); } - [WpfFact, Trait(Traits.Feature, Traits.Features.ExtractInterface)] + [WpfFact] public async Task ExtractInterface_CodeGen_Imports() { var markup = """ @@ -854,7 +855,7 @@ public interface IClass await TestExtractInterfaceCommandCSharpAsync(markup, expectedSuccess: true, expectedInterfaceCode: expectedInterfaceCode); } - [WpfFact, Trait(Traits.Feature, Traits.Features.ExtractInterface)] + [WpfFact] public async Task ExtractInterface_CodeGen_ImportsInsideNamespace() { var markup = """ @@ -903,7 +904,7 @@ public interface IClass Assert.Equal(expectedInterfaceCode, interfaceCode); } - [WpfFact, Trait(Traits.Feature, Traits.Features.ExtractInterface)] + [WpfFact] public async Task ExtractInterface_CodeGen_TypeParameters1() { var markup = """ @@ -942,7 +943,7 @@ public interface IClass where E : F } [WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/706894")] - [WpfFact, Trait(Traits.Feature, Traits.Features.ExtractInterface)] + [WpfFact] public async Task ExtractInterface_CodeGen_TypeParameters2() { var markup = """ @@ -968,7 +969,7 @@ interface IProgram await TestExtractInterfaceCommandCSharpAsync(markup, expectedSuccess: true, expectedInterfaceCode: expectedInterfaceCode); } - [WpfFact, Trait(Traits.Feature, Traits.Features.ExtractInterface)] + [WpfFact] public async Task ExtractInterface_CodeGen_TypeParameters3() { var markup = """ @@ -994,7 +995,7 @@ interface IClass1 } [WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/706894")] - [WpfFact, Trait(Traits.Feature, Traits.Features.ExtractInterface)] + [WpfFact] public async Task ExtractInterface_CodeGen_TypeParameters4() { var markup = """ @@ -1033,7 +1034,7 @@ public interface IC4 await TestExtractInterfaceCommandCSharpAsync(markup, expectedSuccess: true, expectedInterfaceCode: expectedInterfaceCode); } - [WpfFact, Trait(Traits.Feature, Traits.Features.ExtractInterface)] + [WpfFact] public async Task ExtractInterface_CodeGen_AccessibilityModifiers() { var markup = """ @@ -1065,7 +1066,7 @@ internal interface IMyClass """, interfaceCode); } - [WpfFact, Trait(Traits.Feature, Traits.Features.ExtractInterface)] + [WpfFact] public async Task ExtractInterface_CodeGen_BaseList_NewBaseListNonGeneric() { var markup = """ @@ -1085,7 +1086,7 @@ public void Goo() { } await TestExtractInterfaceCommandCSharpAsync(markup, expectedSuccess: true, expectedUpdatedOriginalDocumentCode: expectedCode); } - [WpfFact, Trait(Traits.Feature, Traits.Features.ExtractInterface)] + [WpfFact] public async Task ExtractInterface_CodeGen_BaseList_NewBaseListGeneric() { var markup = """ @@ -1105,7 +1106,7 @@ public void Goo(T t) { } await TestExtractInterfaceCommandCSharpAsync(markup, expectedSuccess: true, expectedUpdatedOriginalDocumentCode: expectedCode); } - [WpfFact, Trait(Traits.Feature, Traits.Features.ExtractInterface)] + [WpfFact] public async Task ExtractInterface_CodeGen_BaseList_NewBaseListWithWhereClause() { var markup = """ @@ -1125,7 +1126,7 @@ public void Goo(T t, U u) { } await TestExtractInterfaceCommandCSharpAsync(markup, expectedSuccess: true, expectedUpdatedOriginalDocumentCode: expectedCode); } - [WpfFact, Trait(Traits.Feature, Traits.Features.ExtractInterface)] + [WpfFact] public async Task ExtractInterface_CodeGen_BaseList_LargerBaseList1() { var markup = """ @@ -1149,7 +1150,7 @@ interface ISomeInterface {} await TestExtractInterfaceCommandCSharpAsync(markup, expectedSuccess: true, expectedUpdatedOriginalDocumentCode: expectedCode); } - [WpfFact, Trait(Traits.Feature, Traits.Features.ExtractInterface)] + [WpfFact] public async Task ExtractInterface_CodeGen_BaseList_LargerBaseList2() { var markup = """ @@ -1173,7 +1174,7 @@ interface ISomeInterface {} await TestExtractInterfaceCommandCSharpAsync(markup, expectedSuccess: true, expectedUpdatedOriginalDocumentCode: expectedCode); } - [WpfFact, Trait(Traits.Feature, Traits.Features.ExtractInterface)] + [WpfFact] public async Task ExtractInterface_CodeGen_BaseList_LargerBaseList3() { var markup = """ @@ -1199,7 +1200,7 @@ interface ISomeInterface2 {} await TestExtractInterfaceCommandCSharpAsync(markup, expectedSuccess: true, expectedUpdatedOriginalDocumentCode: expectedCode); } - [WpfFact, Trait(Traits.Feature, Traits.Features.ExtractInterface)] + [WpfFact] public async Task ExtractInterface_CodeGen_BaseList_LargerBaseList4() { var markup = """ @@ -1225,7 +1226,7 @@ interface ISomeInterface2 {} await TestExtractInterfaceCommandCSharpAsync(markup, expectedSuccess: true, expectedUpdatedOriginalDocumentCode: expectedCode); } - [WpfFact, Trait(Traits.Feature, Traits.Features.ExtractInterface)] + [WpfFact] public async Task ExtractInterface_TypeDiscovery_NameOnly1() { var markup = """ @@ -1239,7 +1240,7 @@ class Program : ISomeInterface where T : U await TestTypeDiscoveryAsync(markup, TypeDiscoveryRule.TypeNameOnly, expectedExtractable: false); } - [WpfFact, Trait(Traits.Feature, Traits.Features.ExtractInterface)] + [WpfFact] public async Task ExtractInterface_TypeDiscovery_NameOnly2() { var markup = """ @@ -1253,7 +1254,7 @@ public void Goo(T t, U u) { } await TestTypeDiscoveryAsync(markup, TypeDiscoveryRule.TypeNameOnly, expectedExtractable: true); } - [WpfFact, Trait(Traits.Feature, Traits.Features.ExtractInterface)] + [WpfFact] public async Task ExtractInterface_TypeDiscovery_NameOnly3() { var markup = """ @@ -1267,7 +1268,7 @@ public void Goo(T t, U u) { } await TestTypeDiscoveryAsync(markup, TypeDiscoveryRule.TypeNameOnly, expectedExtractable: true); } - [WpfFact, Trait(Traits.Feature, Traits.Features.ExtractInterface)] + [WpfFact] public async Task ExtractInterface_TypeDiscovery_NameOnly4() { var markup = """ @@ -1281,7 +1282,7 @@ public void Goo(T t, U u) { } await TestTypeDiscoveryAsync(markup, TypeDiscoveryRule.TypeNameOnly, expectedExtractable: true); } - [WpfFact, Trait(Traits.Feature, Traits.Features.ExtractInterface)] + [WpfFact] public async Task ExtractInterface_TypeDiscovery_NameOnly5() { var markup = """ @@ -1295,7 +1296,7 @@ public void Goo(T t, U u) { } await TestTypeDiscoveryAsync(markup, TypeDiscoveryRule.TypeNameOnly, expectedExtractable: true); } - [WpfFact, Trait(Traits.Feature, Traits.Features.ExtractInterface)] + [WpfFact] public async Task ExtractInterface_TypeDiscovery_NameOnly6() { var markup = """ @@ -1309,7 +1310,7 @@ public void Goo(T t, U u) { } await TestTypeDiscoveryAsync(markup, TypeDiscoveryRule.TypeNameOnly, expectedExtractable: true); } - [WpfFact, Trait(Traits.Feature, Traits.Features.ExtractInterface)] + [WpfFact] public async Task ExtractInterface_TypeDiscovery_NameOnly7() { var markup = """ @@ -1323,7 +1324,7 @@ public void Goo() { } await TestTypeDiscoveryAsync(markup, TypeDiscoveryRule.TypeNameOnly, expectedExtractable: true); } - [WpfFact, Trait(Traits.Feature, Traits.Features.ExtractInterface)] + [WpfFact] public async Task ExtractInterface_TypeDiscovery_NameOnly8() { var markup = """ @@ -1337,7 +1338,7 @@ public void Goo() { } await TestTypeDiscoveryAsync(markup, TypeDiscoveryRule.TypeNameOnly, expectedExtractable: true); } - [WpfFact, Trait(Traits.Feature, Traits.Features.ExtractInterface)] + [WpfFact] public async Task ExtractInterface_TypeDiscovery_NameOnly9() { var markup = """ @@ -1351,7 +1352,7 @@ public void Goo() { } await TestTypeDiscoveryAsync(markup, TypeDiscoveryRule.TypeNameOnly, expectedExtractable: true); } - [WpfFact, Trait(Traits.Feature, Traits.Features.ExtractInterface)] + [WpfFact] public async Task ExtractInterface_TypeDiscovery_NameOnly10() { var markup = """ @@ -1365,7 +1366,7 @@ public void Goo() { } await TestTypeDiscoveryAsync(markup, TypeDiscoveryRule.TypeNameOnly, expectedExtractable: true); } - [WpfFact, Trait(Traits.Feature, Traits.Features.ExtractInterface)] + [WpfFact] public async Task ExtractInterface_TypeDiscovery_NameOnly11() { var markup = """ @@ -1391,7 +1392,7 @@ private static async Task TestTypeDiscoveryAsync( Assert.Equal(expectedExtractable, result.CanExtractInterface); } - [WpfFact, Trait(Traits.Feature, Traits.Features.ExtractInterface)] + [WpfFact] public async Task ExtractInterface_GeneratedNameTypeParameterSuffix1() { var markup = """ @@ -1405,7 +1406,7 @@ public void M(T a) { } await TestExtractInterfaceCommandCSharpAsync(markup, expectedSuccess: true, expectedTypeParameterSuffix: expectedTypeParameterSuffix); } - [WpfFact, Trait(Traits.Feature, Traits.Features.ExtractInterface)] + [WpfFact] public async Task ExtractInterface_GeneratedNameTypeParameterSuffix2() { var markup = """ @@ -1419,7 +1420,7 @@ public void M(T a) { } await TestExtractInterfaceCommandCSharpAsync(markup, expectedSuccess: true, expectedTypeParameterSuffix: expectedTypeParameterSuffix); } - [WpfFact, Trait(Traits.Feature, Traits.Features.ExtractInterface)] + [WpfFact] public async Task ExtractInterface_GeneratedNameTypeParameterSuffix3() { var markup = """ @@ -1433,9 +1434,7 @@ public void M(T a, U b) { } await TestExtractInterfaceCommandCSharpAsync(markup, expectedSuccess: true, expectedTypeParameterSuffix: expectedTypeParameterSuffix); } - [WpfFact] - [Trait(Traits.Feature, Traits.Features.ExtractInterface)] - [Trait(Traits.Feature, Traits.Features.Interactive)] + [WpfFact, Trait(Traits.Feature, Traits.Features.Interactive)] public void ExtractInterfaceCommandDisabledInSubmission() { using var workspace = EditorTestWorkspace.Create(XElement.Parse(""" @@ -1461,7 +1460,7 @@ public void M() { } Assert.True(state.IsUnspecified); } - [WpfFact, Trait(Traits.Feature, Traits.Features.ExtractInterface)] + [WpfFact] public async Task TestInWithMethod_Parameters() { var markup = """ @@ -1483,7 +1482,7 @@ interface ITestClass """); } - [WpfFact, Trait(Traits.Feature, Traits.Features.ExtractInterface)] + [WpfFact] public async Task TestRefReadOnlyWithMethod_ReturnType() { var markup = """ @@ -1503,7 +1502,7 @@ interface ITestClass """); } - [WpfFact, Trait(Traits.Feature, Traits.Features.ExtractInterface)] + [WpfFact] public async Task TestRefReadOnlyWithProperty() { var markup = """ @@ -1523,7 +1522,7 @@ interface ITestClass """); } - [WpfFact, Trait(Traits.Feature, Traits.Features.ExtractInterface)] + [WpfFact] public async Task TestInWithIndexer_Parameters() { var markup = """ @@ -1543,7 +1542,7 @@ interface ITestClass """); } - [WpfFact, Trait(Traits.Feature, Traits.Features.ExtractInterface)] + [WpfFact] public async Task TestRefReadOnlyWithIndexer_ReturnType() { var markup = """ @@ -1563,7 +1562,7 @@ interface ITestClass """); } - [WpfFact, Trait(Traits.Feature, Traits.Features.ExtractInterface)] + [WpfFact] public async Task TestUnmanagedConstraint_Type() { var markup = """ @@ -1582,7 +1581,7 @@ interface ITestClass where T : unmanaged """); } - [WpfFact, Trait(Traits.Feature, Traits.Features.ExtractInterface)] + [WpfFact] public async Task TestUnmanagedConstraint_Method() { var markup = """ @@ -1601,7 +1600,7 @@ interface ITestClass """); } - [WpfFact, Trait(Traits.Feature, Traits.Features.ExtractInterface)] + [WpfFact] public async Task TestNotNullConstraint_Type() { var markup = """ @@ -1620,7 +1619,7 @@ interface ITestClass where T : notnull """); } - [WpfFact, Trait(Traits.Feature, Traits.Features.ExtractInterface)] + [WpfFact] public async Task TestNotNullConstraint_Method() { var markup = """ @@ -1640,7 +1639,7 @@ interface ITestClass } [WorkItem("https://github.com/dotnet/roslyn/issues/23855")] - [WpfFact, Trait(Traits.Feature, Traits.Features.ExtractInterface)] + [WpfFact] public async Task TestExtractInterface_WithCopyright1() { var markup = @@ -1685,7 +1684,7 @@ await TestExtractInterfaceCommandCSharpAsync( } [WorkItem("https://github.com/dotnet/roslyn/issues/23855")] - [WpfFact, Trait(Traits.Feature, Traits.Features.ExtractInterface)] + [WpfFact] public async Task TestExtractInterface_WithCopyright2() { var markup = @@ -1736,7 +1735,7 @@ await TestExtractInterfaceCommandCSharpAsync( } [WorkItem("https://github.com/dotnet/roslyn/issues/49739")] - [WpfFact, Trait(Traits.Feature, Traits.Features.ExtractInterface)] + [WpfFact] public async Task TestRecord1() { var markup = @@ -1780,7 +1779,7 @@ await TestExtractInterfaceCommandCSharpAsync( expectedInterfaceCode: expectedInterfaceCode); } - [WpfFact, Trait(Traits.Feature, Traits.Features.ExtractInterface)] + [WpfFact] public async Task TestClass1() { var markup = @@ -1796,7 +1795,7 @@ await TestExtractInterfaceCommandCSharpAsync( expectedSuccess: false); } - [WpfFact, Trait(Traits.Feature, Traits.Features.ExtractInterface)] + [WpfFact] public async Task TestStruct1() { var markup = @@ -1813,7 +1812,7 @@ await TestExtractInterfaceCommandCSharpAsync( } [WorkItem("https://github.com/dotnet/roslyn/issues/49739")] - [WpfFact, Trait(Traits.Feature, Traits.Features.ExtractInterface)] + [WpfFact] public async Task TestRecord2() { var markup = @@ -1857,7 +1856,7 @@ await TestExtractInterfaceCommandCSharpAsync( expectedInterfaceCode: expectedInterfaceCode); } - [WpfFact, Trait(Traits.Feature, Traits.Features.ExtractInterface)] + [WpfFact] public async Task TestClass2() { var markup = @@ -1873,7 +1872,7 @@ await TestExtractInterfaceCommandCSharpAsync( expectedSuccess: false); } - [WpfFact, Trait(Traits.Feature, Traits.Features.ExtractInterface)] + [WpfFact] public async Task TestStruct2() { var markup = @@ -1890,7 +1889,7 @@ await TestExtractInterfaceCommandCSharpAsync( } [WorkItem("https://github.com/dotnet/roslyn/issues/49739")] - [WpfFact, Trait(Traits.Feature, Traits.Features.ExtractInterface)] + [WpfFact] public async Task TestRecord3() { var markup = @@ -1936,7 +1935,7 @@ await TestExtractInterfaceCommandCSharpAsync( expectedInterfaceCode: expectedInterfaceCode); } - [WpfFact, Trait(Traits.Feature, Traits.Features.ExtractInterface)] + [WpfFact] public async Task TestClass3() { var markup = @@ -1953,7 +1952,7 @@ await TestExtractInterfaceCommandCSharpAsync( expectedSuccess: false); } - [WpfFact, Trait(Traits.Feature, Traits.Features.ExtractInterface)] + [WpfFact] public async Task TestStruct3() { var markup = @@ -1970,7 +1969,7 @@ await TestExtractInterfaceCommandCSharpAsync( expectedSuccess: false); } - [WpfFact, Trait(Traits.Feature, Traits.Features.ExtractInterface)] + [WpfFact] public async Task TestStruct4() { var markup = @@ -2000,4 +1999,92 @@ await TestExtractInterfaceCommandCSharpAsync( expectedSuccess: true, expectedInterfaceCode: expectedInterfaceCode); } + + [WpfFact, WorkItem("https://github.com/dotnet/roslyn/issues/71718")] + public async Task RemoveEnumeratorCancellationAttribute() + { + var markup = """ + + + Foo([EnumeratorCancellation] CancellationToken token) + { + for (int i = 0; i < count; i++) + { + await Task.Yield(); + yield return i; + } + } + }]]> + + + """; + + var expectedMarkup = """ + using System; + using System.Collections.Generic; + using System.Runtime.CompilerServices; + + public interface IClass1 + { + IAsyncEnumerable Foo(CancellationToken token); + } + + public class Class1(int count) : IClass1 + { + public async IAsyncEnumerable Foo([EnumeratorCancellation] CancellationToken token) + { + for (int i = 0; i < count; i++) + { + await Task.Yield(); + yield return i; + } + } + } + """; + + await TestExtractInterfaceCodeActionCSharpAsync(markup, expectedMarkup); + } + + [WpfFact, WorkItem("https://github.com/dotnet/roslyn/issues/54019")] + public async Task TestStaticMember() + { + var markup = """ + using System; + + class MyClass$$ + { + public static void M() { } + public static int Prop { get; set; } + public static event Action Event; + } + """; + + var expectedMarkup = """ + using System; + + interface IMyClass + { + static abstract int Prop { get; set; } + + static abstract event Action Event; + + static abstract void M(); + } + + class MyClass : IMyClass + { + public static void M() { } + public static int Prop { get; set; } + public static event Action Event; + } + """; + + await TestExtractInterfaceCodeActionCSharpAsync(markup, expectedMarkup); + } } diff --git a/src/EditorFeatures/CSharpTest/ExtractMethod/ExtractMethodBase.cs b/src/EditorFeatures/CSharpTest/ExtractMethod/ExtractMethodBase.cs index 01ff3aaa94105..46d96e9c754df 100644 --- a/src/EditorFeatures/CSharpTest/ExtractMethod/ExtractMethodBase.cs +++ b/src/EditorFeatures/CSharpTest/ExtractMethod/ExtractMethodBase.cs @@ -4,6 +4,7 @@ #nullable disable +using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Threading; using System.Threading.Tasks; @@ -13,6 +14,7 @@ using Microsoft.CodeAnalysis.CSharp.ExtractMethod; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.ExtractMethod; +using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Test.Utilities; using Microsoft.CodeAnalysis.Text; using Roslyn.Test.Utilities; @@ -22,9 +24,10 @@ namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.ExtractMethod; [UseExportProvider] -public class ExtractMethodBase +public abstract class ExtractMethodBase { - protected static async Task ExpectExtractMethodToFailAsync(string codeWithMarker, string[] features = null) + protected static async Task ExpectExtractMethodToFailAsync( + [StringSyntax(PredefinedEmbeddedLanguageNames.CSharpTest)] string codeWithMarker, string[] features = null) { ParseOptions parseOptions = null; if (features != null) @@ -40,8 +43,8 @@ protected static async Task ExpectExtractMethodToFailAsync(string codeWithMarker } protected static async Task ExpectExtractMethodToFailAsync( - string codeWithMarker, - string expected, + [StringSyntax(PredefinedEmbeddedLanguageNames.CSharpTest)] string codeWithMarker, + [StringSyntax(PredefinedEmbeddedLanguageNames.CSharpTest)] string expected, CSharpParseOptions parseOptions = null) { using var workspace = EditorTestWorkspace.CreateCSharp(codeWithMarker, parseOptions: parseOptions); @@ -62,7 +65,8 @@ protected static async Task ExpectExtractMethodToFailAsync( Assert.Equal(expected, subjectBuffer.CurrentSnapshot.GetText()); } - protected static async Task NotSupported_ExtractMethodAsync(string codeWithMarker) + protected static async Task NotSupported_ExtractMethodAsync( + [StringSyntax(PredefinedEmbeddedLanguageNames.CSharpTest)] string codeWithMarker) { using var workspace = EditorTestWorkspace.CreateCSharp(codeWithMarker); Assert.NotNull(await Record.ExceptionAsync(async () => @@ -73,17 +77,17 @@ protected static async Task NotSupported_ExtractMethodAsync(string codeWithMarke } protected static async Task TestExtractMethodAsync( - string codeWithMarker, - string expected, + [StringSyntax(PredefinedEmbeddedLanguageNames.CSharpTest)] string codeWithMarker, + [StringSyntax(PredefinedEmbeddedLanguageNames.CSharpTest)] string expected, bool temporaryFailing = false, - CSharpParseOptions parseOptions = null) + CSharpParseOptions parseOptions = null, + bool localFunction = false) { using var workspace = EditorTestWorkspace.CreateCSharp(codeWithMarker, parseOptions: parseOptions); var testDocument = workspace.Documents.Single(); var subjectBuffer = testDocument.GetTextBuffer(); - var tree = await ExtractMethodAsync( - workspace, testDocument); + var tree = await ExtractMethodAsync(workspace, testDocument, localFunction: localFunction); using (var edit = subjectBuffer.CreateEdit()) { @@ -113,7 +117,8 @@ protected static async Task TestExtractMethodAsync( protected static async Task ExtractMethodAsync( EditorTestWorkspace workspace, EditorTestHostDocument testDocument, - bool succeed = true) + bool succeed = true, + bool localFunction = false) { var document = workspace.CurrentSolution.GetDocument(testDocument.Id); Assert.NotNull(document); @@ -124,19 +129,8 @@ protected static async Task ExtractMethodAsync( CodeCleanupOptions = await document.GetCodeCleanupOptionsAsync(CancellationToken.None), }; - var semanticDocument = await SemanticDocument.CreateAsync(document, CancellationToken.None); - var validator = new CSharpSelectionValidator(semanticDocument, testDocument.SelectedSpans.Single(), localFunction: false); - - var (selectedCode, status) = await validator.GetValidSelectionAsync(CancellationToken.None); - if (!succeed && status.Failed) - return null; - - Assert.NotNull(selectedCode); - - // extract method - var extractor = new CSharpMethodExtractor(selectedCode, options, localFunction: false); - var result = extractor.ExtractMethod(status, CancellationToken.None); - Assert.NotNull(result); + var result = await ExtractMethodService.ExtractMethodAsync( + document, testDocument.SelectedSpans.Single(), localFunction, options, CancellationToken.None); // If the test expects us to succeed, validate that we did. If it expects us to fail, ensure we either // failed or produced a message the user will have to confirm to continue. @@ -158,7 +152,9 @@ protected static async Task ExtractMethodAsync( : await doc.GetSyntaxRootAsync(); } - protected static async Task TestSelectionAsync(string codeWithMarker, bool expectedFail = false, CSharpParseOptions parseOptions = null, TextSpan? textSpanOverride = null) + protected static async Task TestSelectionAsync( + [StringSyntax(PredefinedEmbeddedLanguageNames.CSharpTest)] string codeWithMarker, + bool expectedFail = false, CSharpParseOptions parseOptions = null, TextSpan? textSpanOverride = null) { using var workspace = EditorTestWorkspace.CreateCSharp(codeWithMarker, parseOptions: parseOptions); var testDocument = workspace.Documents.Single(); @@ -168,7 +164,8 @@ protected static async Task TestSelectionAsync(string codeWithMarker, bool expec Assert.NotNull(document); var semanticDocument = await SemanticDocument.CreateAsync(document, CancellationToken.None); - var validator = new CSharpSelectionValidator(semanticDocument, textSpanOverride ?? namedSpans["b"].Single(), localFunction: false); + + var validator = new CSharpExtractMethodService.CSharpSelectionValidator(semanticDocument, textSpanOverride ?? namedSpans["b"].Single(), localFunction: false); var (result, status) = await validator.GetValidSelectionAsync(CancellationToken.None); if (expectedFail) @@ -180,11 +177,12 @@ protected static async Task TestSelectionAsync(string codeWithMarker, bool expec Assert.True(status.Succeeded); } - if (status.Succeeded && result.SelectionChanged) - Assert.Equal(namedSpans["r"].Single(), result.FinalSpan); + if (status.Succeeded && namedSpans.TryGetValue("r", out var revisedSpans)) + Assert.Equal(revisedSpans.Single(), result.FinalSpan); } - protected static async Task IterateAllAsync(string code) + protected static async Task IterateAllAsync( + [StringSyntax(PredefinedEmbeddedLanguageNames.CSharpTest)] string code) { using var workspace = EditorTestWorkspace.CreateCSharp(code, CodeAnalysis.CSharp.Test.Utilities.TestOptions.Regular); var document = workspace.CurrentSolution.GetDocument(workspace.Documents.First().Id); @@ -196,7 +194,7 @@ protected static async Task IterateAllAsync(string code) foreach (var node in iterator) { - var validator = new CSharpSelectionValidator(semanticDocument, node.Span, localFunction: false); + var validator = new CSharpExtractMethodService.CSharpSelectionValidator(semanticDocument, node.Span, localFunction: false); var (_, status) = await validator.GetValidSelectionAsync(CancellationToken.None); // check the obvious case diff --git a/src/EditorFeatures/CSharpTest/ExtractMethod/MiscTests.cs b/src/EditorFeatures/CSharpTest/ExtractMethod/ExtractMethodMiscellaneousTests.cs similarity index 81% rename from src/EditorFeatures/CSharpTest/ExtractMethod/MiscTests.cs rename to src/EditorFeatures/CSharpTest/ExtractMethod/ExtractMethodMiscellaneousTests.cs index 707ebecf88609..dda79afdf720f 100644 --- a/src/EditorFeatures/CSharpTest/ExtractMethod/MiscTests.cs +++ b/src/EditorFeatures/CSharpTest/ExtractMethod/ExtractMethodMiscellaneousTests.cs @@ -24,7 +24,7 @@ namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.ExtractMethod; [UseExportProvider] [Trait(Traits.Feature, Traits.Features.ExtractMethod)] -public class MiscTests +public sealed class ExtractMethodMiscellaneousTests { [Fact] public void ServiceTest1() @@ -126,6 +126,11 @@ class A } """; + await TestCommandHandler(markupCode, result: null, expectNotification: true); + } + + private static async Task TestCommandHandler(string markupCode, string? result, bool expectNotification) + { using var workspace = EditorTestWorkspace.CreateCSharp(markupCode, composition: EditorTestCompositions.EditorFeaturesWpf); var testDocument = workspace.Documents.Single(); @@ -133,9 +138,11 @@ class A view.Selection.Select(new SnapshotSpan( view.TextBuffer.CurrentSnapshot, testDocument.SelectedSpans[0].Start, testDocument.SelectedSpans[0].Length), isReversed: false); + result ??= view.TextBuffer.CurrentSnapshot.GetText(); + var callBackService = (INotificationServiceCallback)workspace.Services.GetRequiredService(); - var called = false; - callBackService.NotificationCallback = (_, _, _) => called = true; + var gotNotification = false; + callBackService.NotificationCallback = (_, _, _) => gotNotification = true; var handler = workspace.ExportProvider.GetCommandHandler(PredefinedCommandHandlerNames.ExtractMethod, ContentTypeNames.CSharpContentType); @@ -144,6 +151,24 @@ class A var waiter = workspace.ExportProvider.GetExportedValue().GetWaiter(FeatureAttribute.ExtractMethod); await waiter.ExpeditedWaitAsync(); - Assert.True(called); + Assert.Equal(expectNotification, gotNotification); + Assert.Equal(result, view.TextBuffer.CurrentSnapshot.GetText()); + } + + [WpfFact, WorkItem("https://github.com/dotnet/roslyn/issues/65465")] + public async Task TestExtractLocalFunctionInTopLevelFromCommandHandler() + { + var markupCode = """ + System.Console.WriteLine([|"string"|]); + """; + + await TestCommandHandler(markupCode, """ + System.Console.WriteLine(NewMethod()); + + static string NewMethod() + { + return "string"; + } + """, expectNotification: false); } } diff --git a/src/EditorFeatures/CSharpTest/ExtractMethod/ExtractMethodTests.LanguageInteraction.cs b/src/EditorFeatures/CSharpTest/ExtractMethod/ExtractMethodTests.LanguageInteraction.cs index 37fd08523f2a6..ebc2950154888 100644 --- a/src/EditorFeatures/CSharpTest/ExtractMethod/ExtractMethodTests.LanguageInteraction.cs +++ b/src/EditorFeatures/CSharpTest/ExtractMethod/ExtractMethodTests.LanguageInteraction.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System.Threading.Tasks; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.Test.Utilities; @@ -18,7 +16,7 @@ public partial class ExtractMethodTests { [UseExportProvider] [Trait(Traits.Feature, Traits.Features.ExtractMethod)] - public class LanguageInteraction : ExtractMethodBase + public sealed class LanguageInteraction : ExtractMethodBase { #region Generics @@ -1115,7 +1113,7 @@ public static void Main() p1 = NewMethod(p2); } - private static object NewMethod(object p2) + private static global::System.Object NewMethod(global::System.Object p2) { return p2; } @@ -2303,16 +2301,15 @@ void M3() { } void M() { - using Goo g = NewMethod(); + NewMethod(); } - private static Goo NewMethod() + private static void NewMethod() { - Goo g = new Goo(); + using Goo g = new Goo(); var s = g.S; g.M2(); g.M3(); - return g; } public void Dispose() diff --git a/src/EditorFeatures/CSharpTest/ExtractMethod/ExtractMethodTests.cs b/src/EditorFeatures/CSharpTest/ExtractMethod/ExtractMethodTests.cs index 58490388c89cc..4280d9e4e7f9a 100644 --- a/src/EditorFeatures/CSharpTest/ExtractMethod/ExtractMethodTests.cs +++ b/src/EditorFeatures/CSharpTest/ExtractMethod/ExtractMethodTests.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System.Linq; using System.Threading; using System.Threading.Tasks; @@ -13,6 +11,7 @@ using Microsoft.CodeAnalysis.Editor.UnitTests; using Microsoft.CodeAnalysis.Editor.UnitTests.Extensions; using Microsoft.CodeAnalysis.ExtractMethod; +using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Test.Utilities; using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.Text.Editor.Commanding.Commands; @@ -22,7 +21,7 @@ namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.ExtractMethod; [Trait(Traits.Feature, Traits.Features.ExtractMethod)] -public partial class ExtractMethodTests : ExtractMethodBase +public sealed partial class ExtractMethodTests : ExtractMethodBase { [Fact] public async Task ExtractMethod1() @@ -63,6 +62,48 @@ private static void NewMethod() await TestExtractMethodAsync(code, expected); } + [Fact] + public async Task ExtractMethod_KeywordName() + { + var code = """ + using System; + + class Program + { + void Test(string[] args) + { + int @class = 0; + int @interface = 0; + [|@class++; + @interface++;|] + Console.WriteLine(@class + @interface); + } + } + """; + var expected = """ + using System; + + class Program + { + void Test(string[] args) + { + int @class = 0; + int @interface = 0; + NewMethod(ref @class, ref @interface); + Console.WriteLine(@class + @interface); + } + + private static void NewMethod(ref int @class, ref int @interface) + { + @class++; + @interface++; + } + } + """; + + await TestExtractMethodAsync(code, expected); + } + [Fact] public async Task ExtractMethod2() { @@ -10627,7 +10668,7 @@ static void Inner(Action x, int y) { } static void Main() { - Outer(null, (Action)(y => Inner(x => { GetX(x).Ex(); }, y))); // Prints 1 + Outer(null, y => Inner(x => { GetX(x).Ex(); }, y)); // Prints 1 } private static string GetX(string x) @@ -10690,7 +10731,7 @@ static void Inner(Action x, int y) { } static void Main() { - Outer(null, (Action)(y => Inner(x => { NewMethod(x); }, y))); // Prints 1 + Outer(null, y => Inner(x => { NewMethod(x); }, y)); // Prints 1 } private static void NewMethod(string x) @@ -10753,7 +10794,7 @@ static void Inner(Action x, int y) { } static void Main() { - Outer(null, (Action)(y => Inner(x => { NewMethod(x); }, y))); // Prints 1 + Outer(null, y => Inner(x => { NewMethod(x); }, y)); // Prints 1 } private static void NewMethod(string x) @@ -10862,7 +10903,7 @@ private static int NewMethod() [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/574576")] public async Task TestAsyncMethodWithRefOrOutParameters() { - var code = + await TestExtractMethodAsync( """ using System.Threading.Tasks; @@ -10877,15 +10918,78 @@ public async void Goo() var s = p; } } - """; + """, - await ExpectExtractMethodToFailAsync(code); + """ + using System.Threading.Tasks; + + class C + { + public async void Goo() + { + (int q, int p) = await NewMethod(); + var r = q; + var s = p; + } + + private static async Task<(int q, int p)> NewMethod() + { + var q = 1; + var p = 2; + await Task.Yield(); + return (q, p); + } + } + """); + } + + [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/574576")] + public async Task TestAsyncLocalFunctionWithRefOrOutParameters() + { + await TestExtractMethodAsync( + """ + using System.Threading.Tasks; + + class C + { + public async void Goo() + { + [|var q = 1; + var p = 2; + await Task.Yield();|] + var r = q; + var s = p; + } + } + """, + + """ + using System.Threading.Tasks; + + class C + { + public async void Goo() + { + (int q, int p) = await NewMethod(); + var r = q; + var s = p; + + static async Task<(int q, int p)> NewMethod() + { + var q = 1; + var p = 2; + await Task.Yield(); + return (q, p); + } + } + } + """, localFunction: true); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1025272")] - public async Task TestAsyncMethodWithWellKnownValueType() + public async Task TestAsyncMethodWithWellKnownValueType1() { - var code = + await TestExtractMethodAsync( """ using System; using System.Threading; @@ -10909,8 +11013,7 @@ public async Task Hello() Console.WriteLine(i); } } - """; - var expected = """ + """, """ using System; using System.Threading; using System.Threading.Tasks; @@ -10921,31 +11024,31 @@ public async Task Hello() { var cancellationToken = CancellationToken.None; - int i = await NewMethod(ref cancellationToken); + (int i, cancellationToken) = await NewMethod(cancellationToken); cancellationToken.ThrowIfCancellationRequested(); Console.WriteLine(i); } - private static async Task NewMethod(ref CancellationToken cancellationToken) + private static async Task<(int i, CancellationToken cancellationToken)> NewMethod(CancellationToken cancellationToken) { - return await Task.Run(() => + var i = await Task.Run(() => { Console.WriteLine(); cancellationToken.ThrowIfCancellationRequested(); return 1; }, cancellationToken); + return (i, cancellationToken); } } - """; - await ExpectExtractMethodToFailAsync(code, expected); + """); } - [Fact] - public async Task TestAsyncMethodWithWellKnownValueType1() + [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1025272")] + public async Task TestAsyncMethodWithWellKnownValueType2() { - var code = + await TestExtractMethodAsync( """ using System; using System.Threading; @@ -10960,7 +11063,8 @@ public async Task Hello() [|var i = await Task.Run(() => { Console.WriteLine(); - cancellationToken = CancellationToken.None; + cancellationToken.ThrowIfCancellationRequested(); + cancellationToken = default; return 1; }, cancellationToken);|] @@ -10969,8 +11073,37 @@ public async Task Hello() Console.WriteLine(i); } } - """; - await ExpectExtractMethodToFailAsync(code); + """, """ + using System; + using System.Threading; + using System.Threading.Tasks; + + class Program + { + public async Task Hello() + { + var cancellationToken = CancellationToken.None; + + (int i, cancellationToken) = await NewMethod(cancellationToken); + + cancellationToken.ThrowIfCancellationRequested(); + Console.WriteLine(i); + } + + private static async Task<(int i, CancellationToken cancellationToken)> NewMethod(CancellationToken cancellationToken) + { + var i = await Task.Run(() => + { + Console.WriteLine(); + cancellationToken.ThrowIfCancellationRequested(); + cancellationToken = default; + + return 1; + }, cancellationToken); + return (i, cancellationToken); + } + } + """); } [Fact] @@ -11051,34 +11184,38 @@ public async Task TestExtractMethodEventAccessorUnresolvedName(string testedAcce { // This code intentionally omits a 'using System;' var code = -$@"namespace ClassLibrary9 -{{ - public class Class - {{ - public event EventHandler Event - {{ - {testedAccessor} {{ [|throw new NotImplementedException();|] }} - {untestedAccessor} {{ throw new NotImplementedException(); }} - }} - }} -}}"; + $$""" + namespace ClassLibrary9 + { + public class Class + { + public event EventHandler Event + { + {{testedAccessor}} { [|throw new NotImplementedException();|] } + {{untestedAccessor}} { throw new NotImplementedException(); } + } + } + } + """; var expected = -$@"namespace ClassLibrary9 -{{ - public class Class - {{ - public event EventHandler Event - {{ - {testedAccessor} {{ NewMethod(); }} - {untestedAccessor} {{ throw new NotImplementedException(); }} - }} + $$""" + namespace ClassLibrary9 + { + public class Class + { + public event EventHandler Event + { + {{testedAccessor}} { NewMethod(); } + {{untestedAccessor}} { throw new NotImplementedException(); } + } - private static void NewMethod() - {{ - throw new NotImplementedException(); - }} - }} -}}"; + private static void NewMethod() + { + throw new NotImplementedException(); + } + } + } + """; await TestExtractMethodAsync(code, expected); } @@ -11203,7 +11340,7 @@ public async Task ExtractMethod_Argument1() var service = new CSharpExtractMethodService(); Assert.NotNull(await Record.ExceptionAsync(async () => { - var tree = await service.ExtractMethodAsync(document: null, textSpan: default, localFunction: false, options: default, CancellationToken.None); + var tree = await service.ExtractMethodAsync(document: null!, textSpan: default, localFunction: false, options: default, CancellationToken.None); })); } @@ -11212,7 +11349,9 @@ public async Task ExtractMethod_Argument2() { var solution = new AdhocWorkspace().CurrentSolution; var projectId = ProjectId.CreateNewId(); - var project = solution.AddProject(projectId, "Project", "Project.dll", LanguageNames.CSharp).GetProject(projectId); + var project = solution + .AddProject(projectId, "Project", "Project.dll", LanguageNames.CSharp) + .GetRequiredProject(projectId); var document = project.AddMetadataReference(NetFramework.mscorlib) .AddDocument("Document", SourceText.From("")); @@ -11236,7 +11375,7 @@ public void ExtractMethodCommandDisabledInSubmission() workspaceKind: WorkspaceKind.Interactive, composition: EditorTestCompositions.EditorFeaturesWpf); // Force initialization. - workspace.GetOpenDocumentIds().Select(id => workspace.GetTestDocument(id).GetTextView()).ToList(); + workspace.GetOpenDocumentIds().Select(id => workspace.GetTestDocument(id)!.GetTextView()).ToList(); var textView = workspace.Documents.Single().GetTextView(); @@ -11460,40 +11599,44 @@ private static int NewMethod(int arg) [WorkItem("https://github.com/dotnet/roslyn/issues/18347")] public async Task ExtractMethodFlowsToLocalFunction1(string usageSyntax) { - var code = $@"namespace ExtractMethodCrashRepro -{{ - public static class SomeClass - {{ - private static void Repro( int arg ) - {{ - [|arg = arg + 3;|] + var code = $$""" + namespace ExtractMethodCrashRepro + { + public static class SomeClass + { + private static void Repro( int arg ) + { + [|arg = arg + 3;|] - {usageSyntax} + {{usageSyntax}} - int LocalCapture() => arg; - }} - }} -}}"; - var expected = $@"namespace ExtractMethodCrashRepro -{{ - public static class SomeClass - {{ - private static void Repro( int arg ) - {{ - arg = NewMethod(arg); + int LocalCapture() => arg; + } + } + } + """; + var expected = $$""" + namespace ExtractMethodCrashRepro + { + public static class SomeClass + { + private static void Repro( int arg ) + { + arg = NewMethod(arg); - {usageSyntax} + {{usageSyntax}} - int LocalCapture() => arg; - }} + int LocalCapture() => arg; + } - private static int NewMethod(int arg) - {{ - arg = arg + 3; - return arg; - }} - }} -}}"; + private static int NewMethod(int arg) + { + arg = arg + 3; + return arg; + } + } + } + """; await TestExtractMethodAsync(code, expected); } @@ -11505,40 +11648,44 @@ private static int NewMethod(int arg) [WorkItem("https://github.com/dotnet/roslyn/issues/18347")] public async Task ExtractMethodFlowsToLocalFunction2(string usageSyntax) { - var code = $@"namespace ExtractMethodCrashRepro -{{ - public static class SomeClass - {{ - private static void Repro( int arg ) - {{ - int LocalCapture() => arg; + var code = $$""" + namespace ExtractMethodCrashRepro + { + public static class SomeClass + { + private static void Repro( int arg ) + { + int LocalCapture() => arg; - [|arg = arg + 3;|] + [|arg = arg + 3;|] - {usageSyntax} - }} - }} -}}"; - var expected = $@"namespace ExtractMethodCrashRepro -{{ - public static class SomeClass - {{ - private static void Repro( int arg ) - {{ - int LocalCapture() => arg; + {{usageSyntax}} + } + } + } + """; + var expected = $$""" + namespace ExtractMethodCrashRepro + { + public static class SomeClass + { + private static void Repro( int arg ) + { + int LocalCapture() => arg; - arg = NewMethod(arg); + arg = NewMethod(arg); - {usageSyntax} - }} + {{usageSyntax}} + } - private static int NewMethod(int arg) - {{ - arg = arg + 3; - return arg; - }} - }} -}}"; + private static int NewMethod(int arg) + { + arg = arg + 3; + return arg; + } + } + } + """; await TestExtractMethodAsync(code, expected); } @@ -11554,42 +11701,46 @@ private static int NewMethod(int arg) [WorkItem("https://github.com/dotnet/roslyn/issues/18347")] public async Task ExtractMethodFlowsToLocalFunctionWithUnassignedLocal(string usageSyntax) { - var code = $@"namespace ExtractMethodCrashRepro -{{ - public static class SomeClass - {{ - private static void Repro( int arg ) - {{ - int local; - int LocalCapture() => arg + local; + var code = $$""" + namespace ExtractMethodCrashRepro + { + public static class SomeClass + { + private static void Repro( int arg ) + { + int local; + int LocalCapture() => arg + local; - [|arg = arg + 3;|] + [|arg = arg + 3;|] - {usageSyntax} - }} - }} -}}"; - var expected = $@"namespace ExtractMethodCrashRepro -{{ - public static class SomeClass - {{ - private static void Repro( int arg ) - {{ - int local; - int LocalCapture() => arg + local; + {{usageSyntax}} + } + } + } + """; + var expected = $$""" + namespace ExtractMethodCrashRepro + { + public static class SomeClass + { + private static void Repro( int arg ) + { + int local; + int LocalCapture() => arg + local; - arg = NewMethod(arg); + arg = NewMethod(arg); - {usageSyntax} - }} + {{usageSyntax}} + } - private static int NewMethod(int arg) - {{ - arg = arg + 3; - return arg; - }} - }} -}}"; + private static int NewMethod(int arg) + { + arg = arg + 3; + return arg; + } + } + } + """; await TestExtractMethodAsync(code, expected); } @@ -12118,15 +12269,14 @@ public async Task TopLevelStatement_ValueInAssignment() """; var expected = """ bool local; + local = NewMethod(); static bool NewMethod() { return true; } - - local = NewMethod(); """; - await TestExtractMethodAsync(code, expected); + await TestExtractMethodAsync(code, expected, localFunction: true); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/44260")] @@ -12139,14 +12289,14 @@ public async Task TopLevelStatement_ArgumentInInvocation() System.Console.WriteLine([|"string"|]); """; var expected = """ - System.Console.WriteLine((string)NewMethod()); + System.Console.WriteLine(NewMethod()); static string NewMethod() { return "string"; } """; - await TestExtractMethodAsync(code, expected); + await TestExtractMethodAsync(code, expected, localFunction: true); } [Theory] @@ -12156,53 +12306,53 @@ static string NewMethod() [WorkItem("https://github.com/dotnet/roslyn/issues/4950")] public async Task ExtractMethodInvolvingUnsafeBlock(string keyword) { - var code = $@" -using System; + var code = $$""" + using System; -class Program {{ - static void Main(string[] args) - {{ - object value = args; + class Program { + static void Main(string[] args) + { + object value = args; - [| - IntPtr p; - {keyword} - {{ - object t = value; - p = IntPtr.Zero; - }} - |] + [| + IntPtr p; + {{keyword}} + { + object t = value; + p = IntPtr.Zero; + } + |] - Console.WriteLine(p); - }} -}} -"; - var expected = $@" -using System; + Console.WriteLine(p); + } + } + """; + var expected = $$""" + using System; -class Program {{ - static void Main(string[] args) - {{ - object value = args; + class Program { + static void Main(string[] args) + { + object value = args; - IntPtr p = NewMethod(value); + IntPtr p = NewMethod(value); - Console.WriteLine(p); - }} + Console.WriteLine(p); + } - private static IntPtr NewMethod(object value) - {{ - IntPtr p; - {keyword} - {{ - object t = value; - p = IntPtr.Zero; - }} + private static IntPtr NewMethod(object value) + { + IntPtr p; + {{keyword}} + { + object t = value; + p = IntPtr.Zero; + } - return p; - }} -}} -"; + return p; + } + } + """; await TestExtractMethodAsync(code, expected); } @@ -12363,4 +12513,328 @@ private static string GetS(int y) await TestExtractMethodAsync(code, expected); } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/73044")] + public async Task CapturedPrimaryConstructorParameter() + { + var code = """" + public class Test(int value) + { + public int M() + { + return [|value + 1|]; + } + } + """"; + var expected = """" + public class Test(int value) + { + public int M() + { + return NewMethod(); + } + + private int NewMethod() + { + return value + 1; + } + } + """"; + + await TestExtractMethodAsync(code, expected); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/39329")] + public async Task ExtractUsingLocalDeclaration1() + { + var code = """" + using System; + + public class Goo : IDisposable + { + void M2() { } + + void M() + { + [|using var g = new Goo(); + g.M2();|] + } + + public void Dispose() + { + } + } + """"; + var expected = """" + using System; + + public class Goo : IDisposable + { + void M2() { } + + void M() + { + NewMethod(); + } + + private static void NewMethod() + { + using var g = new Goo(); + g.M2(); + } + + public void Dispose() + { + } + } + """"; + + await TestExtractMethodAsync(code, expected); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/39329")] + public async Task ExtractUsingLocalDeclaration2() + { + var code = """" + using System; + + public class Goo : IDisposable + { + void M2() { } + + void M() + { + [|using var g = new Goo(); + g.M2();|] + g.M2(); + } + + public void Dispose() + { + } + } + """"; + var expected = """" + using System; + + public class Goo : IDisposable + { + void M2() { } + + void M() + { + using Goo g = NewMethod(); + g.M2(); + } + + private static Goo NewMethod() + { + var g = new Goo(); + g.M2(); + return g; + } + + public void Dispose() + { + } + } + """"; + + await TestExtractMethodAsync(code, expected); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/39329")] + public async Task ExtractUsingLocalDeclaration3() + { + var code = """" + using System; + + public class Goo + { + void M() + { + [|using var x1 = new System.IO.MemoryStream(); + using var x2 = new System.IO.MemoryStream(); + using var x3 = new System.IO.MemoryStream();|] + } + } + """"; + var expected = """" + using System; + + public class Goo + { + void M() + { + NewMethod(); + } + + private static void NewMethod() + { + using var x1 = new System.IO.MemoryStream(); + using var x2 = new System.IO.MemoryStream(); + using var x3 = new System.IO.MemoryStream(); + } + } + """"; + + await TestExtractMethodAsync(code, expected); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/39329")] + public async Task ExtractUsingLocalDeclaration4() + { + var code = """" + using System.Collections.Generic; + + class C + { + bool M(IEnumerable p) + { + [|using var x = p.GetEnumerator(); + return x.MoveNext();|] + } + } + """"; + var expected = """" + using System.Collections.Generic; + + class C + { + bool M(IEnumerable p) + { + return NewMethod(p); + } + + private static bool NewMethod(IEnumerable p) + { + using var x = p.GetEnumerator(); + return x.MoveNext(); + } + } + """"; + + await TestExtractMethodAsync(code, expected); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/18656")] + public async Task TestSelectionMidwayThroughTwoStatements() + { + var code = """" + class C + { + static void Main(string[] args) + { + var isAdditive = true; + var isSoftSelection = true; + var indexOfLastSelected = 0; + var index = 0; + var item = new Item(); + + if (isAddi[|tive) + { + if (!isSoftSelection) + { + item.IsSelected = !item.IsSelected; + } + } + else + { + item.IsSelected = true; + } + indexOfLast|]Selected = index; + } + } + + class Item + { + public bool IsSelected { get; set; } + } + """"; + var expected = """" + class C + { + static void Main(string[] args) + { + var isAdditive = true; + var isSoftSelection = true; + var indexOfLastSelected = 0; + var index = 0; + var item = new Item(); + indexOfLastSelected = NewMethod(isAdditive, isSoftSelection, index, item); + } + + private static int NewMethod(bool isAdditive, bool isSoftSelection, int index, Item item) + { + int indexOfLastSelected; + if (isAdditive) + { + if (!isSoftSelection) + { + item.IsSelected = !item.IsSelected; + } + } + else + { + item.IsSelected = true; + } + indexOfLastSelected = index; + return indexOfLastSelected; + } + } + + class Item + { + public bool IsSelected { get; set; } + } + """"; + + await TestExtractMethodAsync(code, expected); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/70024")] + public async Task TestAliasedType() + { + var code = """" + using System; + using Spec = System.Collections.Specialized; + + namespace ClassLibrary3 + { + public class T + { + public void Method() + { + var value = new Spec.ListDictionary(); + + [|Console.WriteLine(value);|] + } + } + } + """"; + var expected = """" + using System; + using Spec = System.Collections.Specialized; + + namespace ClassLibrary3 + { + public class T + { + public void Method() + { + var value = new Spec.ListDictionary(); + + NewMethod(value); + } + + private static void NewMethod(Spec.ListDictionary value) + { + Console.WriteLine(value); + } + } + } + """"; + + await TestExtractMethodAsync(code, expected); + } } diff --git a/src/EditorFeatures/CSharpTest/ExtractMethod/SelectionValidatorTests.cs b/src/EditorFeatures/CSharpTest/ExtractMethod/SelectionValidatorTests.cs index e5bc9a0ce7977..85ca23fcd4e39 100644 --- a/src/EditorFeatures/CSharpTest/ExtractMethod/SelectionValidatorTests.cs +++ b/src/EditorFeatures/CSharpTest/ExtractMethod/SelectionValidatorTests.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System.Threading.Tasks; using Microsoft.CodeAnalysis.Test.Utilities; using Microsoft.CodeAnalysis.Text; @@ -13,1263 +11,1433 @@ namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.ExtractMethod; [Trait(Traits.Feature, Traits.Features.ExtractMethod)] -public class SelectionValidatorTests : ExtractMethodBase +public sealed class SelectionValidatorTests : ExtractMethodBase { [Fact] public async Task SelectionTest1() { - var code = "{|b:using System;|}"; + var code = """ + {|b:using System;|} + """; await TestSelectionAsync(code, expectedFail: true); } [Fact] public async Task SelectionTest2() { - var code = @"{|b:namespace A|} -{ -}"; + var code = """ + {|b:namespace A|} + { + } + """; await TestSelectionAsync(code, expectedFail: true); } [Fact] public async Task SelectionTest3() { - var code = @"namespace {|b:A|} -{ -}"; + var code = """ + namespace {|b:A|} + { + } + """; await TestSelectionAsync(code, expectedFail: true); } [Fact] public async Task SelectionTest4() { - var code = @"{|b:class|} A -{ -}"; + var code = """ + {|b:class|} A + { + } + """; await TestSelectionAsync(code, expectedFail: true); } [Fact] public async Task SelectionTest5() { - var code = @"class {|b:A|} -{ -}"; + var code = """ + class {|b:A|} + { + } + """; await TestSelectionAsync(code, expectedFail: true); } [Fact] public async Task SelectionTest6() { - var code = @"class A : {|b:object|} -{ -}"; + var code = """ + class A : {|b:object|} + { + } + """; await TestSelectionAsync(code, expectedFail: true); } [Fact] public async Task SelectionTest7() { - var code = @"class A : object, {|b:IDisposable|} -{ -}"; + var code = """ + class A : object, {|b:IDisposable|} + { + } + """; await TestSelectionAsync(code, expectedFail: true); } [Fact] public async Task SelectionTest8() { - var code = @"class A<{|b:T|}> -{ -}"; + var code = """ + class A<{|b:T|}> + { + } + """; await TestSelectionAsync(code, expectedFail: true); } [Fact] public async Task SelectionTest9() { - var code = @"class A where {|b:T|} : class -{ -}"; + var code = """ + class A where {|b:T|} : class + { + } + """; await TestSelectionAsync(code, expectedFail: true); } [Fact] public async Task SelectionTest10() { - var code = @"class A where T : {|b:IDisposable|} -{ -}"; + var code = """ + class A where T : {|b:IDisposable|} + { + } + """; await TestSelectionAsync(code, expectedFail: true); } [Fact] public async Task SelectionTest11() { - var code = @"class A -{ - {|b:A|} Method() - { - } -}"; + var code = """ + class A + { + {|b:A|} Method() + { + } + } + """; await TestSelectionAsync(code, expectedFail: true); } [Fact] public async Task SelectionTest12() { - var code = @"class A -{ - A Method({|b:A|} a) - { - } -}"; + var code = """ + class A + { + A Method({|b:A|} a) + { + } + } + """; await TestSelectionAsync(code, expectedFail: true); } [Fact] public async Task SelectionTest13() { - var code = @"class A -{ - A Method(A {|b:a|}) - { - } -}"; + var code = """ + class A + { + A Method(A {|b:a|}) + { + } + } + """; await TestSelectionAsync(code, expectedFail: true); } [Fact] public async Task SelectionTest14() { - var code = @"class A -{ - [{|b:Goo|}] - A Method(A a) - { - } -}"; + var code = """ + class A + { + [{|b:Goo|}] + A Method(A a) + { + } + } + """; await TestSelectionAsync(code, expectedFail: true); } [Fact] public async Task SelectionTest15() { - var code = @"class A -{ - [Goo({|b:A|}=1)] - A Method(A a) - { - } -}"; + var code = """ + class A + { + [Goo({|b:A|}=1)] + A Method(A a) + { + } + } + """; await TestSelectionAsync(code, expectedFail: true); } [Fact] public async Task SelectionTest16() { - var code = @"class A -{ - [Goo(A={|b:1|})] - A Method(A a) - { - } -}"; + var code = """ + class A + { + [Goo(A={|b:1|})] + A Method(A a) + { + } + } + """; await TestSelectionAsync(code, expectedFail: true); } [Fact] public async Task SelectionTest17() { - var code = @"class A -{ - const int {|b:i|} = 1; -}"; + var code = """ + class A + { + const int {|b:i|} = 1; + } + """; await TestSelectionAsync(code, expectedFail: true); } [Fact] public async Task SelectionTest18() { - var code = @"class A -{ - const {|b:int|} i = 1; -}"; + var code = """ + class A + { + const {|b:int|} i = 1; + } + """; await TestSelectionAsync(code, expectedFail: true); } [Fact] public async Task SelectionTest19() { - var code = @"class A -{ - const int i = {|b:1|}; -}"; + var code = """ + class A + { + const int i = {|b:1|}; + } + """; await TestSelectionAsync(code, expectedFail: true); } [Fact] public async Task SelectionTest20() { - var code = @"class A -{ - const int i = {|r:{|b:1 + |}2|}; -}"; + var code = """ + class A + { + const int i = {|r:{|b:1 + |}2|}; + } + """; await TestSelectionAsync(code, expectedFail: true); } [Fact] public async Task SelectionTest21() { - var code = @"class A -{ - const int {|b:i = 1 + |}2; -}"; + var code = """ + class A + { + const int {|b:i = 1 + |}2; + } + """; await TestSelectionAsync(code, expectedFail: true); } [Fact] public async Task SelectionTest22() { - var code = @"class A -{ - void Method1() - { - {|b:int i = 1; - } - - void Method2() - { - int b = 2;|} - } -}"; + var code = """ + class A + { + void Method1() + { + {|b:int i = 1; + } + + void Method2() + { + int b = 2;|} + } + } + """; await TestSelectionAsync(code, expectedFail: true); } [Fact] public async Task SelectionTest23() { - var code = @"class A -{ - void Method1() - { - {|b:int i = 1; - }|} -}"; + var code = """ + class A + { + void Method1() + { + {|b:int i = 1; + }|} + } + """; await TestSelectionAsync(code, expectedFail: true); } [Fact] public async Task SelectionTest24() { - var code = @"class A -{ - void Method1() - { -#region A - {|b:int i = 1;|} -#endRegion - } -}"; + var code = """ + class A + { + void Method1() + { + #region A + {|b:int i = 1;|} + #endRegion + } + } + """; await TestSelectionAsync(code); } [Fact] public async Task SelectionTest25() { - var code = @"class A -{ - void Method1() - { -{|b:#region A - int i = 1;|} -#endRegion - } -}"; + var code = """ + class A + { + void Method1() + { + {|b:#region A + int i = 1;|} + #endRegion + } + } + """; await TestSelectionAsync(code, expectedFail: true); } [Fact] public async Task SelectionTest26() { - var code = @"class A -{ - void Method1() - { -#region A - {|b:int i = 1; -#endregion|} - } -}"; + var code = """ + class A + { + void Method1() + { + #region A + {|b:int i = 1; + #endregion|} + } + } + """; await TestSelectionAsync(code, expectedFail: true); } [Fact] public async Task SelectionTest27() { - var code = @"class A -{ - void Method1() - { -#region A -{|b:#endregion - int i = 1;|} - } -}"; + var code = """ + class A + { + void Method1() + { + #region A + {|b:#endregion + int i = 1;|} + } + } + """; await TestSelectionAsync(code, expectedFail: true); } [Fact] public async Task SelectionTest28() { - var code = @"class A -{ - void Method1() - { -#if true - {|b:int i = 1; -#endif|} - } -}"; + var code = """ + class A + { + void Method1() + { + #if true + {|b:int i = 1; + #endif|} + } + } + """; await TestSelectionAsync(code, expectedFail: true); } [Fact] public async Task SelectionTest29() { - var code = @"class A -{ - void Method1() - { -{|b:#if true - int i = 1;|} -#endif - } -}"; + var code = """ + class A + { + void Method1() + { + {|b:#if true + int i = 1;|} + #endif + } + } + """; await TestSelectionAsync(code, expectedFail: true); } [Fact] public async Task SelectionTest30() { - var code = @"class A -{ - void Method1() - { -#if true -{|b:#endif - int i = 1;|} - } -}"; + var code = """ + class A + { + void Method1() + { + #if true + {|b:#endif + int i = 1;|} + } + } + """; await TestSelectionAsync(code, expectedFail: true); } [Fact] public async Task SelectionTest31() { - var code = @"class A -{ - void Method1() - { -#if false -{|b:#else - int i = 1;|} -#endif - } -}"; + var code = """ + class A + { + void Method1() + { + #if false + {|b:#else + int i = 1;|} + #endif + } + } + """; await TestSelectionAsync(code, expectedFail: true); } [Fact] public async Task SelectionTest32() { - var code = @"class A -{ - void Method1() - { -#if false -{|b:#elsif true - int i = 1;|} -#endif - } -}"; + var code = """ + class A + { + void Method1() + { + #if false + {|b:#elsif true + int i = 1;|} + #endif + } + } + """; await TestSelectionAsync(code, expectedFail: true); } [Fact] public async Task SelectionTest33() { - var code = @"class A -{ - void Method1() - { -{|b:#if true - int i = 1; -#endif|} - } -}"; + var code = """ + class A + { + void Method1() + { + {|b:#if true + int i = 1; + #endif|} + } + } + """; await TestSelectionAsync(code); } [Fact] public async Task SelectionTest34() { - var code = @"class A -{ - void Method1() - { -{|b:#region - int i = 1; -#endregion|} - } -}"; + var code = """ + class A + { + void Method1() + { + {|b:#region + int i = 1; + #endregion|} + } + } + """; await TestSelectionAsync(code); } [Fact] public async Task SelectionTest35() { - var code = @"class A -{ - void Method1() - { - {|b:// test|} - } -}"; + var code = """ + class A + { + void Method1() + { + {|b:// test|} + } + } + """; await TestSelectionAsync(code, expectedFail: true); } [Fact] public async Task SelectionTest36() { - var code = @"class A -{ - IEnumerable Method1() - { - {|r:{|b:yield return 1;|}|} - } -}"; + var code = """ + class A + { + IEnumerable Method1() + { + {|r:{|b:yield return 1;|}|} + } + } + """; await TestSelectionAsync(code, expectedFail: true); } [Fact] public async Task SelectionTest37() { - var code = @"class A -{ - void Method1() - { - try - { - } - catch - { - {|b:throw;|} - } - } -}"; + var code = """ + class A + { + void Method1() + { + try + { + } + catch + { + {|b:throw;|} + } + } + } + """; await TestSelectionAsync(code, expectedFail: true); } [Fact] public async Task SelectionTest38() { - var code = @"class A -{ - void Method1() - { - try - { - } - catch - { - {|b:throw new Exception();|} - } - } -}"; + var code = """ + class A + { + void Method1() + { + try + { + } + catch + { + {|b:throw new Exception();|} + } + } + } + """; await TestSelectionAsync(code); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/540082")] public async Task SelectionTest39() { - var code = @"class A -{ - void Method1() - { - {|r:{|b:System|}.Console.WriteLine(1);|} - } -}"; + var code = """ + class A + { + void Method1() + { + {|r:{|b:System|}.Console.WriteLine(1);|} + } + } + """; await TestSelectionAsync(code); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/540082")] public async Task SelectionTest40() { - var code = @"class A -{ - void Method1() - { - {|r:{|b:System.Console|}.WriteLine(1);|} - } -}"; + var code = """ + class A + { + void Method1() + { + {|r:{|b:System.Console|}.WriteLine(1);|} + } + } + """; await TestSelectionAsync(code); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/540082")] public async Task SelectionTest41() { - var code = @"class A -{ - void Method1() - { - {|r:{|b:System.Console.WriteLine|}(1);|} - } -}"; + var code = """ + class A + { + void Method1() + { + {|r:{|b:System.Console.WriteLine|}(1);|} + } + } + """; await TestSelectionAsync(code); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/540082")] public async Task SelectionTest42() { - var code = @"class A -{ - void Method1() - { -{|r: System.{|b:Console|}.WriteLine(1);|} - } -}"; + var code = """ + class A + { + void Method1() + { + {|r: System.{|b:Console|}.WriteLine(1);|} + } + } + """; await TestSelectionAsync(code); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/540082")] public async Task SelectionTest43() { - var code = @"class A -{ - void Method1() - { -{|r: System.{|b:Console.WriteLine|}(1);|} - } -}"; + var code = """ + class A + { + void Method1() + { + {|r: System.{|b:Console.WriteLine|}(1);|} + } + } + """; await TestSelectionAsync(code); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/540082")] public async Task SelectionTest44() { - var code = @"class A -{ - void Method1() - { -{|r: System.Console.{|b:WriteLine|}(1);|} - } -}"; + var code = """ + class A + { + void Method1() + { + {|r: System.Console.{|b:WriteLine|}(1);|} + } + } + """; await TestSelectionAsync(code); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/539242")] public async Task SelectionTest45() { - var code = @"class A -{ - void Method1() - { - short[,] arr = {|r:new short[,] { {|b:{ 19, 19, 19 }|}, { 19, 19, 19 } }|}; - } -}"; + var code = """ + class A + { + void Method1() + { + short[,] arr = new short[,] { {|r:{|b:{ 19, 19, 19 }|}|}, { 19, 19, 19 } }; + } + } + """; await TestSelectionAsync(code); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/539242")] public async Task SelectionTest46() { - var code = @"class A -{ - void Method1() - { - short[,] arr = {|r:{ {|b:{ 19, 19, 19 }|}, { 19, 19, 19 } }|}; - } -}"; + var code = """ + class A + { + void Method1() + { + short[,] arr = { {|r:{|b:{ 19, 19, 19 }|}|}s, { 19, 19, 19 } }; + } + } + """; await TestSelectionAsync(code); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/540338")] public async Task SelectionTest47() { - var code = @"using System; -class C -{ - void M() - { - Action d = s => Console.Write(s); - {|b:d +=|} - } -} -"; + var code = """ + using System; + class C + { + void M() + { + Action d = s => Console.Write(s); + {|b:d +=|} + } + } + """; await TestSelectionAsync(code, expectedFail: true); } [Fact] public async Task SelectIfWithReturn() { - var code = @"class A -{ - public void Method1() - { - bool b = true; - {|b:if (b) - return;|} - return; - } -}"; + var code = """ + class A + { + public void Method1() + { + bool b = true; + {|b:if (b) + return;|} + return; + } + } + """; await TestSelectionAsync(code, expectedFail: true); } [Fact] public async Task SelectConstIfWithReturn() { - var code = @"class A -{ - public void Method1() - { - const bool b = true; - {|b:if (b) - return;|} - Console.WriteLine(); - } -}"; + var code = """ + class A + { + public void Method1() + { + const bool b = true; + {|b:if (b) + return;|} + Console.WriteLine(); + } + } + """; await TestSelectionAsync(code); } [Fact] public async Task SelectReturnButNotAllCodePathsContainAReturn() { - var code = @"class A -{ - public void Method1(bool b1, bool b2) - { - if (b1) - { - {|b:if (b2) - return; - Console.WriteLine();|} - } - Console.WriteLine(); - } -}"; + var code = """ + class A + { + public void Method1(bool b1, bool b2) + { + if (b1) + { + {|b:if (b2) + return; + Console.WriteLine();|} + } + Console.WriteLine(); + } + } + """; await TestSelectionAsync(code, expectedFail: true); } [Fact] public async Task SelectIfBranchWhereNotAllPathsReturn() { - var code = @"class A -{ - int Method8(int i) - { - {|b:if (i > 100) - { - return i++; - } - else if (i > 90) - { - return i--; - } - else - { - i++; - }|} - return i; - } -}"; + var code = """ + class A + { + int Method8(int i) + { + {|b:if (i > 100) + { + return i++; + } + else if (i > 90) + { + return i--; + } + else + { + i++; + }|} + return i; + } + } + """; await TestSelectionAsync(code, expectedFail: true); } [Fact] public async Task SelectCatchFilterClause() { - var code = @"class A -{ - int method() - { - try - { - Console.Write(5); - } - catch (Exception ex) if ({|b:ex.Message == ""goo""|}) - { - throw; - } - } -}"; + var code = """ + class A + { + int method() + { + try + { + Console.Write(5); + } + catch (Exception ex) if ({|b:ex.Message == "goo"|}) + { + throw; + } + } + } + """; await TestSelectionAsync(code); } [Fact] public async Task SelectCatchFilterClause2() { - var code = @"class A -{ - int method() - { - int i = 5; - try - { - Console.Write(5); - } - catch (Exception ex) if ({|b:i == 5|}) - { - Console.Write(5); - i = 0; - } - } -}"; + var code = """ + class A + { + int method() + { + int i = 5; + try + { + Console.Write(5); + } + catch (Exception ex) if ({|b:i == 5|}) + { + Console.Write(5); + i = 0; + } + } + } + """; await TestSelectionAsync(code); } [Fact] public async Task SelectWithinCatchFilterClause() { - var code = @"class A -{ - int method() - { - try - { - Console.Write(5); - } - catch (Exception ex) if ({|b:ex.Message|} == ""goo"") - { - throw; - } - } -}"; + var code = """ + class A + { + int method() + { + try + { + Console.Write(5); + } + catch (Exception ex) if ({|b:ex.Message|} == "goo") + { + throw; + } + } + } + """; await TestSelectionAsync(code); } [Fact] public async Task SelectWithinCatchFilterClause2() { - var code = @"class A -{ - int method() - { - try - { - Console.Write(5); - } - catch (Exception ex) if (ex.Message == {|b:""goo""|}) - { - throw; - } - } -}"; + var code = """ + class A + { + int method() + { + try + { + Console.Write(5); + } + catch (Exception ex) if (ex.Message == {|b:"goo"|}) + { + throw; + } + } + } + """; await TestSelectionAsync(code); } [Fact] public async Task SelectLValueOfPlusEqualsOperator() { - var code = @"class A -{ - int method() - { - int i = 0; - {|r:{|b:i|} += 1;|} - return i; - } -}"; + var code = """ + class A + { + int method() + { + int i = 0; + {|r:{|b:i|} += 1;|} + return i; + } + } + """; await TestSelectionAsync(code); } [Fact] public async Task SelectRValueOfPlusEqualsOperator() { - var code = @"class A -{ - int method() - { - int i = 0; - i += {|b:1|}; - return i; - } -}"; + var code = """ + class A + { + int method() + { + int i = 0; + i += {|b:1|}; + return i; + } + } + """; await TestSelectionAsync(code); } [Fact] public async Task SelectRValueOfPredecrementOperator() { - var code = @"class A -{ - string method(string s, int i) - { - string[] myvar = new string[i]; - myvar[0] = s; - myvar[{|r:--{|b:i|}|}] = s + i.ToString(); - return myvar[i]; - } -}"; + var code = """ + class A + { + string method(string s, int i) + { + string[] myvar = new string[i]; + myvar[0] = s; + myvar[{|r:--{|b:i|}|}] = s + i.ToString(); + return myvar[i]; + } + } + """; await TestSelectionAsync(code); } [Fact] public async Task SelectArrayWithDecrementIndex() { - var code = @"class A -{ - string method(string s, int i) - { - string[] myvar = new string[i]; - myvar[0] = s; - {|r:{|b:myvar[--i]|} = s + i.ToString();|} - return myvar[i]; - } -}"; + var code = """ + class A + { + string method(string s, int i) + { + string[] myvar = new string[i]; + myvar[0] = s; + {|r:{|b:myvar[--i]|} = s + i.ToString();|} + return myvar[i]; + } + } + """; await TestSelectionAsync(code); } [Fact] public async Task SelectCastOperator() { - var code = @"class A -{ - int method(string goo) - { - String bar = {|b:(String)goo|}; - return bar.Length; - } -}"; + var code = """ + class A + { + int method(string goo) + { + String bar = {|b:(String)goo|}; + return bar.Length; + } + } + """; await TestSelectionAsync(code); } [Fact] public async Task SelectLHSOfPostIncrementOperator() { - var code = @"class A -{ - int method(int i) - { - return {|r:{|b:i|}++|}; - } -}"; + var code = """ + class A + { + int method(int i) + { + return {|r:{|b:i|}++|}; + } + } + """; await TestSelectionAsync(code); } [Fact] public async Task SelectPostIncrementOperator() { - var code = @"class A -{ - int method(int i) - { - return {|r:i{|b:++|}|}; - } -}"; + var code = """ + class A + { + int method(int i) + { + return {|r:i{|b:++|}|}; + } + } + """; await TestSelectionAsync(code); } [Fact] public async Task SelectRHSOfPreIncrementOperator() { - var code = @"class A -{ - int method(int i) - { - return {|r:{|b:++|}i|}; - } -}"; + var code = """ + class A + { + int method(int i) + { + return {|r:{|b:++|}i|}; + } + } + """; await TestSelectionAsync(code); } [Fact] public async Task SelectPreIncrementOperator() { - var code = @"class A -{ - int method(int i) - { - return {|r:{|b:++|}i|}; - } -}"; + var code = """ + class A + { + int method(int i) + { + return {|r:{|b:++|}i|}; + } + } + """; await TestSelectionAsync(code); } [Fact] public async Task SelectPreDecrementOperator() { - var code = @"class A -{ - int method(int i) - { - return {|r:{|b:--|}i|}; - } -}"; + var code = """ + class A + { + int method(int i) + { + return {|r:{|b:--|}i|}; + } + } + """; await TestSelectionAsync(code); } [Fact] public async Task SelectLHSOfPostDecrementOperator() { - var code = @"class A -{ - int method(int i) - { - return {|r:{|b:i|}--|}; - } -}"; + var code = """ + class A + { + int method(int i) + { + return {|r:{|b:i|}--|}; + } + } + """; await TestSelectionAsync(code); } [Fact] public async Task SelectUnaryPlusOperator() { - var code = @"class A -{ - int method(int i) - { - int j = {|r:{|b:+|}i|}; - return j; - } -}"; + var code = """ + class A + { + int method(int i) + { + int j = {|r:{|b:+|}i|}; + return j; + } + } + """; await TestSelectionAsync(code); } [Fact] public async Task SelectUnaryMinusOperator() { - var code = @"class A -{ - int method(int i) - { - int j = {|r:{|b:-|}i|}; - return j; - } -}"; + var code = """ + class A + { + int method(int i) + { + int j = {|r:{|b:-|}i|}; + return j; + } + } + """; await TestSelectionAsync(code); } [Fact] public async Task SelectLogicalNegationOperator() { - var code = @"class A -{ - int method(int i) - { - int j = {|r:{|b:!|}i|}; - return j; - } -}"; + var code = """ + class A + { + int method(int i) + { + int j = {|r:{|b:!|}i|}; + return j; + } + } + """; await TestSelectionAsync(code); } [Fact] public async Task SelectBitwiseNegationOperator() { - var code = @"class A -{ - int method(int i) - { - int j = {|r:{|b:~|}i|}; - return j; - } -}"; + var code = """ + class A + { + int method(int i) + { + int j = {|r:{|b:~|}i|}; + return j; + } + } + """; await TestSelectionAsync(code); } [Fact] public async Task SelectCastOperator2() { - var code = @"class A -{ - int method(double i) - { - int j = {|r:{|b:(int)|}i|}; - return j; - } -}"; + var code = """ + class A + { + int method(double i) + { + int j = {|r:{|b:(int)|}i|}; + return j; + } + } + """; await TestSelectionAsync(code); } [Fact] public async Task SelectInvalidSubexpressionToExpand() { - var code = @"class A -{ - public int method(int a, int b, int c) - { - return {|r:a + {|b:b + c|}|}; - } -}"; + var code = """ + class A + { + public int method(int a, int b, int c) + { + return {|r:a + {|b:b + c|}|}; + } + } + """; await TestSelectionAsync(code); } [Fact] public async Task SelectValidSubexpressionAndHenceDoNotExpand() { - var code = @"class A -{ - public int method(int a, int b, int c) - { - return {|b:a + b|} + c; - } -}"; + var code = """ + class A + { + public int method(int a, int b, int c) + { + return {|b:a + b|} + c; + } + } + """; await TestSelectionAsync(code); } [Fact] public async Task SelectLHSOfMinusEqualsOperator() { - var code = @"class A -{ - public int method(int a, int b) - { - {|r:{|b:a|} -= b;|} - return a; - } -}"; + var code = """ + class A + { + public int method(int a, int b) + { + {|r:{|b:a|} -= b;|} + return a; + } + } + """; await TestSelectionAsync(code); } [Fact] public async Task SelectInnerBlockPartially() { - var code = @"using System; -using System.Collections; + var code = """ + using System; + using System.Collections; -class A -{ - void method() - { - ArrayList ar = null; - foreach (object var in ar) - { - {|r:{|b:System.Console.WriteLine(); - foreach (object var2 in ar) + class A { - System.Console.WriteLine();|} - }|} - } - } -}"; + void method() + { + ArrayList ar = null; + foreach (object var in ar) + { + {|r:{|b:System.Console.WriteLine(); + foreach (object var2 in ar) + { + System.Console.WriteLine();|} + }|} + } + } + } + """; await TestSelectionAsync(code); } [Fact] public async Task SelectInnerBlockWithoutBracesPartially() { - var code = @"using System; -using System.Collections; + var code = """ + using System; + using System.Collections; -class A -{ - void method() - { - while (true) - { - int i = 0; -{|r: if (i == 0) - Console.WriteLine(){|b:; - Console.WriteLine();|}|} - } - } -}"; + class A + { + void method() + { + while (true) + { + int i = 0; + {|r: if (i == 0) + Console.WriteLine(){|b:; + Console.WriteLine();|}|} + } + } + } + """; await TestSelectionAsync(code); } [Fact] public async Task SelectBeginningBrace() { - var code = @"using System; -using System.Collections; + var code = """ + using System; + using System.Collections; -class A -{ - void method() - { - if (true) {|r:{|b:{|} }|} - } -}"; + class A + { + void method() + { + if (true) {|r:{|b:{|} }|} + } + } + """; await TestSelectionAsync(code); } [Fact] public async Task SelectAcrossBlocks1() { - var code = @"using System; -using System.Collections; + var code = """ + using System; + using System.Collections; -class A -{ - void method() - { - if (true) - { -{|r: for (int i = 0; i < 100; i++) + class A { - {|b:System.Console.WriteLine(); + void method() + { + if (true) + { + {|r: for (int i = 0; i < 100; i++) + { + {|b:System.Console.WriteLine(); + } + System.Console.WriteLine();|}|} + } + } } - System.Console.WriteLine();|}|} - } - } -}"; + """; await TestSelectionAsync(code); } [Fact] public async Task SelectMethodParameters() { - var code = @"using System; -using System.Collections; + var code = """ + using System; + using System.Collections; -class A -{ - void method() - { - double x1 = 10; - double y1 = 20; - double z1 = 30; - double ret = {|r:sum({|b:ref x1, y1, z1|})|}; - } - double sum(ref double x, double y, double z) - { - x++; - return x + y + z; - } -}"; + class A + { + void method() + { + double x1 = 10; + double y1 = 20; + double z1 = 30; + double ret = {|r:sum({|b:ref x1, y1, z1|})|}; + } + double sum(ref double x, double y, double z) + { + x++; + return x + y + z; + } + } + """; await TestSelectionAsync(code); } [Fact] public async Task SelectChainedInvocations1() { - var code = @"using System; -using System.Collections; + var code = """ + using System; + using System.Collections; -class Test -{ - class B - { - public int c() - { - return 100; - } - } - class A - { - public B b = new B(); - } - - void method() - { - A a = new A(); - {|b:a.b|}.c(); - } -}"; + class Test + { + class B + { + public int c() + { + return 100; + } + } + class A + { + public B b = new B(); + } + + void method() + { + A a = new A(); + {|b:a.b|}.c(); + } + } + """; await TestSelectionAsync(code); } [Fact] public async Task SelectChainedInvocations2() { - var code = @"using System; -using System.Collections; + var code = """ + using System; + using System.Collections; -class Test -{ - class B - { - public int c() - { - return 100; - } - } - class A - { - public B b = new B(); - } - - void method() - { - A a = new A(); -{|r: a.{|b:b.c()|}|}; - } -}"; + class Test + { + class B + { + public int c() + { + return 100; + } + } + class A + { + public B b = new B(); + } + + void method() + { + A a = new A(); + {|r: a.{|b:b.c()|}|}; + } + } + """; await TestSelectionAsync(code); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/540474")] public async Task GotoStatement() { - var code = @"using System; -using System.Reflection.Emit; + var code = """ + using System; + using System.Reflection.Emit; -class Program -{ - public delegate R Del(T arg); - static void Main(string[] args) - { - Del del = {|r:(arg) => - { - goto {|b:Label|}; - Label: - return new ArgumentException(); - }|}; - } -}"; + class Program + { + public delegate R Del(T arg); + static void Main(string[] args) + { + Del del = {|r:(arg) => + { + goto {|b:Label|}; + Label: + return new ArgumentException(); + }|}; + } + } + """; await TestSelectionAsync(code); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/540481")] public async Task BugFix6750() { - var code = @"using System; + var code = """ + using System; -class Program -{ - int[] array = new int[{|b:1|}]; -}"; + class Program + { + int[] array = new int[{|b:1|}]; + } + """; await TestSelectionAsync(code); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/540481")] public async Task BugFix6750_1() { - var code = @"using System; + var code = """ + using System; -class Program -{ - int[] array = {|r:new int[{|b:1|}] { 1 }|}; -}"; + class Program + { + int[] array = new int[{|r:{|b:1|}|}] { 1 }; + } + """; await TestSelectionAsync(code); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/542201")] public async Task MalformedCode_NoOuterType() { - var code = @"x(a){ -{|b:for ();|} -} -"; + var code = """ + x(a){ + {|b:for ();|} + } + """; await TestSelectionAsync(code, expectedFail: true); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/542210")] public async Task NoQueryContinuation() { - var code = @"using System.Linq; - -class P -{ - static void Main() - { - var src = new int[] { 4, 5 }; - var q = {|r:from x in src - select x into y - {|b:select y|}|}; - } -}"; + var code = """ + using System.Linq; + + class P + { + static void Main() + { + var src = new int[] { 4, 5 }; + var q = {|r:from x in src + select x into y + {|b:select y|}|}; + } + } + """; await TestSelectionAsync(code); } @@ -1281,313 +1449,341 @@ public async Task DoNotCrash() [Fact, WorkItem(9931, "DevDiv_Projects/Roslyn")] public async Task ExtractMethodIdentifierAtEndOfInteractiveBuffer() { - var code = @"using System.Console; -WriteLine(); + var code = """ + using System.Console; + WriteLine(); -{|r:{|b:Diagnostic|}|}"; + {|r:{|b:Diagnostic|}|} + """; await TestSelectionAsync(code, expectedFail: true); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/543020")] public async Task MemberAccessStructAsExpression() { - var code = @"struct S -{ - public float X; - public float Y; - public float Z; - - void M() - { - if (3 < 3.4) - { - S s; - if (s.X < 3) + var code = """ + struct S { - s = GetS(); - {|r:{|b:s|}.Z = 10f;|} + public float X; + public float Y; + public float Z; + + void M() + { + if (3 < 3.4) + { + S s; + if (s.X < 3) + { + s = GetS(); + {|r:{|b:s|}|}.Z = 10f; + } + else + { + } + } + else + { + } + } + + private static S GetS() + { + return new S(); + } } - else - { - } - } - else - { - } - } - - private static S GetS() - { - return new S(); - } -} "; + """; await TestSelectionAsync(code); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/543140")] public async Task TypeOfExpression() { - var code = @"using System; -using System.Collections.Generic; -using System.Linq; + var code = """ + using System; + using System.Collections.Generic; + using System.Linq; -class Program -{ - static void Main(string[] args) - { - Console.WriteLine({|r:typeof({|b:Dictionary<,>|})|}.IsGenericTypeDefinition); - } -}"; + class Program + { + static void Main(string[] args) + { + Console.WriteLine({|r:typeof({|b:Dictionary<,>|})|}.IsGenericTypeDefinition); + } + } + """; await TestSelectionAsync(code); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/543186")] public async Task AnonymousTypeMember1() { - var code = @"using System; -class C { void M() { {|r:var x = new { {|b:String|} = true }; |}} } -"; + var code = """ + using System; + class C { void M() { {|r:var x = new { {|b:String|} = true };|} } } + """; await TestSelectionAsync(code); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/543186")] public async Task AnonymousTypeMember2() { - var code = @"using System; -class C { void M() { -var String = 1; -{|r:var x = new { {|b:String|} };|} -} } -"; + var code = """ + using System; + class C { void M() { + var String = 1; + var x = new { {|r:{|b:String|}|} }; + } } + """; await TestSelectionAsync(code); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/543186")] public async Task AnonymousTypeMember3() { - var code = @"using System; -class C { void M() { var x = new { String = {|b:true|} }; } } -"; + var code = """ + using System; + class C { void M() { var x = new { String = {|b:true|} }; } } + """; await TestSelectionAsync(code); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/543186")] public async Task AnonymousTypeMember4() { - var code = @"class Program -{ - static void Main(string[] args) - { - var contacts = {|r:new[] - { - new { - Name = ""ddd"", - PhoneNumbers = new[] { ""206"", ""425"" } - }, - new { - {|b:Name|} = ""sss"", - PhoneNumbers = new[] { ""206"" } + var code = """ + class Program + { + static void Main(string[] args) + { + var contacts = {|r:new[] + { + new { + Name = "ddd", + PhoneNumbers = new[] { "206", "425" } + }, + new { + {|b:Name|} = "sss", + PhoneNumbers = new[] { "206" } + } + }|}; + } } - }|}; - } -}"; + """; await TestSelectionAsync(code); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/543984")] public async Task AddressOfExpr1() { - var code = @" -class C -{ - unsafe void M() - { - int i = 5; - int* j = {|r:&{|b:i|}|}; - } -}"; + var code = """ + class C + { + unsafe void M() + { + int i = 5; + int* j = {|r:&{|b:i|}|}; + } + } + """; await TestSelectionAsync(code); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/543984")] public async Task AddressOfExpr2() { - var code = @" -class C -{ - unsafe void M() - { - int i = 5; - int* j = {|b:&i|}; - } -}"; + var code = """ + class C + { + unsafe void M() + { + int i = 5; + int* j = {|b:&i|}; + } + } + """; await TestSelectionAsync(code); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/544627")] public async Task BaseKeyword() { - var code = @"class C -{ - void Goo() - { - {|r:{|b:base|}.ToString();|} - } -} -"; + var code = """ + class C + { + void Goo() + { + {|r:{|b:base|}.ToString();|} + } + } + """; await TestSelectionAsync(code); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/545057")] public async Task RefvalueKeyword() { - var code = @"using System; - -class A -{ - static void Goo(__arglist) - { - var argIterator = new ArgIterator(__arglist); - var typedReference = argIterator.GetNextArg(); - Console.WriteLine(__reftype(typedReference)); - Console.WriteLine({|r:__refvalue(typedReference, {|b:Int32|})|}); - } -}"; + var code = """ + using System; + + class A + { + static void Goo(__arglist) + { + var argIterator = new ArgIterator(__arglist); + var typedReference = argIterator.GetNextArg(); + Console.WriteLine(__reftype(typedReference)); + Console.WriteLine({|r:__refvalue(typedReference, {|b:Int32|})|}); + } + } + """; await TestSelectionAsync(code); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/531286")] public async Task NoCrashOnThrowWithoutCatchClause() { - var code = @"public class Test -{ - delegate int D(); - static void Main() - { - try - { } - catch - { } - finally - { - {|b:((D)delegate { throw; return 0; })();|} - } - return 1; - } -}"; + var code = """ + public class Test + { + delegate int D(); + static void Main() + { + try + { } + catch + { } + finally + { + {|b:((D)delegate { throw; return 0; })();|} + } + return 1; + } + } + """; await TestSelectionAsync(code, expectedFail: true); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/751")] public async Task SimpleConditionalAccessExpressionSelectFirstExpression() { - var code = @"using System; -class Program -{ - static void Main(string[] args) - { - A a = new A(); - var l = {|r:{|b:a|}?.Length |}?? 0; - } -} -class A -{ - public int Length { get; internal set; } -}"; + var code = """ + using System; + class Program + { + static void Main(string[] args) + { + A a = new A(); + var l = {|r:{|b:a|}|}?.Length ?? 0; + } + } + class A + { + public int Length { get; internal set; } + } + """; await TestSelectionAsync(code); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/751")] public async Task SimpleConditionalAccessExpressionSelectSecondExpression() { - var code = @"using System; -class Program -{ - static void Main(string[] args) - { - A a = new A(); - var l = {|r:a?.{|b:Length|}|} ?? 0; - } -} -class A -{ - public int Length { get; internal set; } -}"; + var code = """ + using System; + class Program + { + static void Main(string[] args) + { + A a = new A(); + var l = {|r:a?.{|b:Length|}|} ?? 0; + } + } + class A + { + public int Length { get; internal set; } + } + """; await TestSelectionAsync(code); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/751")] public async Task NestedConditionalAccessExpressionWithMemberBindingExpression() { - var code = @"using System; - -class Program -{ - static void Main(string[] args) - { - A a = new A(); - var l = {|r:a?.{|b:Prop|}?.Length |}?? 0; - } -} -class A -{ - public B Prop { get; set; } -} -class B -{ - public int Length { get; set; } -}"; + var code = """ + using System; + + class Program + { + static void Main(string[] args) + { + A a = new A(); + var l = {|r:a?.{|b:Prop|}?.Length|} ?? 0; + } + } + class A + { + public B Prop { get; set; } + } + class B + { + public int Length { get; set; } + } + """; await TestSelectionAsync(code); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/751")] public async Task NestedConditionalAccessExpressionWithMemberBindingExpressionSelectSecondExpression() { - var code = @"using System; - -class Program -{ - static void Main(string[] args) - { - A a = new A(); - var l = {|r:a?.Prop?.{|b:Length|}|} ?? 0; - } -} -class A -{ - public B Prop { get; set; } -} -class B -{ - public int Length { get; set; } -}"; + var code = """ + using System; + + class Program + { + static void Main(string[] args) + { + A a = new A(); + var l = {|r:a?.Prop?.{|b:Length|}|} ?? 0; + } + } + class A + { + public B Prop { get; set; } + } + class B + { + public int Length { get; set; } + } + """; await TestSelectionAsync(code); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/751")] public async Task NestedConditionalAccessExpressionWithInvocationExpression() { - var code = @"using System; - -class Program -{ - static void Main(string[] args) - { - A a = new A(); - var l = {|r:a?.{|b:Method()|}?.Length |}?? 0; - } -} -class A -{ - public B Method() - { - return new B(); - } -} -class B -{ - public int Length { get; set; } -}"; + var code = """ + using System; + + class Program + { + static void Main(string[] args) + { + A a = new A(); + var l = {|r:a?.{|b:Method()|}?.Length|} ?? 0; + } + } + class A + { + public B Method() + { + return new B(); + } + } + class B + { + public int Length { get; set; } + } + """; await TestSelectionAsync(code); } diff --git a/src/EditorFeatures/CSharpTest/Formatting/CodeCleanupTests.TestFixers.cs b/src/EditorFeatures/CSharpTest/Formatting/CodeCleanupTests.TestFixers.cs index efe149122fe47..1c44694ed9fce 100644 --- a/src/EditorFeatures/CSharpTest/Formatting/CodeCleanupTests.TestFixers.cs +++ b/src/EditorFeatures/CSharpTest/Formatting/CodeCleanupTests.TestFixers.cs @@ -18,7 +18,7 @@ public partial class CodeCleanupTests { private abstract class TestThirdPartyCodeFix : CodeFixProvider { - public override ImmutableArray FixableDiagnosticIds { get; } = ImmutableArray.Create("HasDefaultCase"); + public override ImmutableArray FixableDiagnosticIds { get; } = ["HasDefaultCase"]; public override Task RegisterCodeFixesAsync(CodeFixContext context) { diff --git a/src/EditorFeatures/CSharpTest/Formatting/CodeCleanupTests.cs b/src/EditorFeatures/CSharpTest/Formatting/CodeCleanupTests.cs index fc5e10a37f257..3a71fabe43350 100644 --- a/src/EditorFeatures/CSharpTest/Formatting/CodeCleanupTests.cs +++ b/src/EditorFeatures/CSharpTest/Formatting/CodeCleanupTests.cs @@ -53,7 +53,6 @@ static void Main(string[] args) var expected = """ using System; - internal class Program { private static void Main(string[] args) @@ -84,7 +83,6 @@ static void Main(string[] args) var expected = """ using System; using System.Collections.Generic; - internal class Program { private static void Main(string[] args) @@ -122,7 +120,6 @@ static Task Main(string[] args) global using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; - internal class Program { private static Task Main(string[] args) diff --git a/src/EditorFeatures/CSharpTest/Formatting/FormattingEngineTests.cs b/src/EditorFeatures/CSharpTest/Formatting/FormattingEngineTests.cs index 84361e3511f51..e9e1feced8eb1 100644 --- a/src/EditorFeatures/CSharpTest/Formatting/FormattingEngineTests.cs +++ b/src/EditorFeatures/CSharpTest/Formatting/FormattingEngineTests.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using System; +using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Threading; using System.Threading.Tasks; @@ -24,10 +25,8 @@ namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Formatting; [Trait(Traits.Feature, Traits.Features.Formatting)] -public class FormattingEngineTests : CSharpFormattingEngineTestBase +public sealed class FormattingEngineTests(ITestOutputHelper output) : CSharpFormattingEngineTestBase(output) { - public FormattingEngineTests(ITestOutputHelper output) : base(output) { } - private static OptionsCollection SmartIndentButDoNotFormatWhileTyping() => new(LanguageNames.CSharp) { @@ -991,7 +990,7 @@ class Program { static void Main(string[] args) { - label1: int s = 0; + label1: int s = 0; } } """; @@ -2910,7 +2909,37 @@ interface I1 AssertFormatAfterTypeChar(code, expected); } - private static void AssertFormatAfterTypeChar(string code, string expected, OptionsCollection? globalOptions = null, ParseOptions? parseOptions = null) + [WpfFact, WorkItem("https://github.com/dotnet/roslyn/issues/13981")] + public void FormatLabeledStatementAfterColon() + { + var code = """ + class C + { + void M() + { + foo:$$ + } + } + """; + + var expected = """ + class C + { + void M() + { + foo: + } + } + """; + + AssertFormatAfterTypeChar(code, expected); + } + + private static void AssertFormatAfterTypeChar( + [StringSyntax(PredefinedEmbeddedLanguageNames.CSharpTest)] string code, + [StringSyntax(PredefinedEmbeddedLanguageNames.CSharpTest)] string expected, + OptionsCollection? globalOptions = null, + ParseOptions? parseOptions = null) { using var workspace = EditorTestWorkspace.CreateCSharp(code, parseOptions: parseOptions); diff --git a/src/EditorFeatures/CSharpTest/Formatting/Indentation/SmartIndenterTests.cs b/src/EditorFeatures/CSharpTest/Formatting/Indentation/SmartIndenterTests.cs index fcfe43cdb2966..d96f87951f5ae 100644 --- a/src/EditorFeatures/CSharpTest/Formatting/Indentation/SmartIndenterTests.cs +++ b/src/EditorFeatures/CSharpTest/Formatting/Indentation/SmartIndenterTests.cs @@ -3451,7 +3451,7 @@ private static void AssertSmartIndentInProjection( { var optionsSet = options != null ? new[] { options } - : new[] { TestOptions.Regular, TestOptions.Script }; + : [TestOptions.Regular, TestOptions.Script]; foreach (var option in optionsSet) { @@ -3507,7 +3507,7 @@ private void AssertSmartIndent( { var optionsSet = options != null ? new[] { options } - : new[] { TestOptions.Regular, TestOptions.Script }; + : [TestOptions.Regular, TestOptions.Script]; foreach (var option in optionsSet) { @@ -3536,7 +3536,7 @@ private void AssertSmartIndent( { var optionsSet = options != null ? new[] { options } - : new[] { TestOptions.Regular, TestOptions.Script }; + : [TestOptions.Regular, TestOptions.Script]; foreach (var option in optionsSet) { diff --git a/src/EditorFeatures/CSharpTest/Formatting/Indentation/SmartTokenFormatterFormatRangeTests.cs b/src/EditorFeatures/CSharpTest/Formatting/Indentation/SmartTokenFormatterFormatRangeTests.cs index f49409ae2fa51..37e6d3573e110 100644 --- a/src/EditorFeatures/CSharpTest/Formatting/Indentation/SmartTokenFormatterFormatRangeTests.cs +++ b/src/EditorFeatures/CSharpTest/Formatting/Indentation/SmartTokenFormatterFormatRangeTests.cs @@ -2467,35 +2467,41 @@ await AutoFormatOnColonAsync( SyntaxKind.ColonToken); } - [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/537804")] + [Fact] + [WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/537804")] + [WorkItem("https://github.com/dotnet/roslyn/issues/13981")] public async Task Colon_Label() { - var code = @"namespace ClassLibrary1 -{ - public class Class1 - { - void Test() - { - label :$$ - } - } -}"; + var code = """ + namespace ClassLibrary1 + { + public class Class1 + { + void Test() + { + label :$$ + } + } + } + """; - var expected = @"namespace ClassLibrary1 -{ - public class Class1 - { - void Test() - { - label : - } - } -}"; + var expected = """ + namespace ClassLibrary1 + { + public class Class1 + { + void Test() + { + label: + } + } + } + """; await AutoFormatOnColonAsync( code, expected, - SyntaxKind.None); + SyntaxKind.OpenBraceToken); } [WpfFact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/538793")] diff --git a/src/EditorFeatures/CSharpTest/GenerateConstructorFromMembers/GenerateConstructorFromMembersTests.cs b/src/EditorFeatures/CSharpTest/GenerateConstructors/GenerateConstructorsTests.cs similarity index 95% rename from src/EditorFeatures/CSharpTest/GenerateConstructorFromMembers/GenerateConstructorFromMembersTests.cs rename to src/EditorFeatures/CSharpTest/GenerateConstructors/GenerateConstructorsTests.cs index 128bc7615150e..6e9802b93932c 100644 --- a/src/EditorFeatures/CSharpTest/GenerateConstructorFromMembers/GenerateConstructorFromMembersTests.cs +++ b/src/EditorFeatures/CSharpTest/GenerateConstructors/GenerateConstructorsTests.cs @@ -7,7 +7,7 @@ using Microsoft.CodeAnalysis.CodeStyle; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.CodeStyle; -using Microsoft.CodeAnalysis.CSharp.GenerateConstructorFromMembers; +using Microsoft.CodeAnalysis.CSharp.GenerateConstructors; using Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.CodeRefactorings; using Microsoft.CodeAnalysis.Editor.UnitTests.Diagnostics.NamingStyles; using Microsoft.CodeAnalysis.PickMembers; @@ -15,13 +15,13 @@ using Roslyn.Test.Utilities; using Xunit; -namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.GenerateConstructorFromMembers; +namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.GenerateConstructors; [Trait(Traits.Feature, Traits.Features.CodeActionsGenerateConstructorFromMembers)] -public sealed class GenerateConstructorFromMembersTests : AbstractCSharpCodeActionTest +public sealed class GenerateConstructorsTests : AbstractCSharpCodeActionTest { protected override CodeRefactoringProvider CreateCodeRefactoringProvider(EditorTestWorkspace workspace, TestParameters parameters) - => new CSharpGenerateConstructorFromMembersCodeRefactoringProvider((IPickMembersService)parameters.fixProviderData); + => new CSharpGenerateConstructorsCodeRefactoringProvider((IPickMembersService)parameters.fixProviderData); private readonly NamingStylesTestOptionSets options = new(LanguageNames.CSharp); @@ -74,7 +74,7 @@ class Z public Z(int a{|Navigation:)|} => this.a = a; } """, -options: Option(CSharpCodeStyleOptions.PreferExpressionBodiedConstructors, CSharpCodeStyleOptions.WhenPossibleWithSilentEnforcement)); + options: Option(CSharpCodeStyleOptions.PreferExpressionBodiedConstructors, CSharpCodeStyleOptions.WhenPossibleWithSilentEnforcement)); } [Fact] @@ -99,7 +99,7 @@ class Z public Z(int a{|Navigation:)|} => this.a = a; } """, -options: Option(CSharpCodeStyleOptions.PreferExpressionBodiedConstructors, CSharpCodeStyleOptions.WhenOnSingleLineWithSilentEnforcement)); + options: Option(CSharpCodeStyleOptions.PreferExpressionBodiedConstructors, CSharpCodeStyleOptions.WhenOnSingleLineWithSilentEnforcement)); } [Fact] @@ -130,7 +130,7 @@ public Z(int a, int b{|Navigation:)|} } } """, -options: Option(CSharpCodeStyleOptions.PreferExpressionBodiedConstructors, CSharpCodeStyleOptions.WhenOnSingleLineWithSilentEnforcement)); + options: Option(CSharpCodeStyleOptions.PreferExpressionBodiedConstructors, CSharpCodeStyleOptions.WhenOnSingleLineWithSilentEnforcement)); } [Fact] @@ -974,7 +974,7 @@ public Program(int field{|Navigation:)|} } } """, -options: Option(CodeStyleOptions2.QualifyFieldAccess, CodeStyleOption2.TrueWithSuggestionEnforcement)); + options: Option(CodeStyleOptions2.QualifyFieldAccess, CodeStyleOption2.TrueWithSuggestionEnforcement)); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/13944")] @@ -1001,7 +1001,7 @@ protected Contribution(string title, int number{|Navigation:)|} public int Number { get; } } """, -options: Option(CodeStyleOptions2.QualifyFieldAccess, CodeStyleOption2.TrueWithSuggestionEnforcement)); + options: Option(CodeStyleOptions2.QualifyFieldAccess, CodeStyleOption2.TrueWithSuggestionEnforcement)); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/13944")] @@ -1015,7 +1015,7 @@ abstract class Contribution public int Number { get; }|] } """, -new TestParameters(options: Option(CodeStyleOptions2.QualifyFieldAccess, CodeStyleOption2.TrueWithSuggestionEnforcement))); + new TestParameters(options: Option(CodeStyleOptions2.QualifyFieldAccess, CodeStyleOption2.TrueWithSuggestionEnforcement))); } [Fact] @@ -1044,7 +1044,7 @@ public Z(int a{|Navigation:)|} } } """, -chosenSymbols: ["a"]); + chosenSymbols: ["a"]); } [Fact] @@ -1072,7 +1072,7 @@ public Z(int a{|Navigation:)|} } } """, -chosenSymbols: ["a"]); + chosenSymbols: ["a"]); } [Fact] @@ -1115,7 +1115,7 @@ public Z({|Navigation:)|} } } """, -chosenSymbols: []); + chosenSymbols: []); } [Fact] @@ -1147,7 +1147,7 @@ public Z(string b, int a{|Navigation:)|} } } """, -chosenSymbols: ["b", "a"]); + chosenSymbols: ["b", "a"]); } [Fact] @@ -1181,8 +1181,8 @@ public Z(int a, string b{|Navigation:)|} } } """, -chosenSymbols: ["a", "b"], -optionsCallback: options => options[0].Value = true); + chosenSymbols: ["a", "b"], + optionsCallback: options => options[0].Value = true); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/41428")] @@ -1221,8 +1221,8 @@ public Z(int a, string b, string? c{|Navigation:)|} } } """, -chosenSymbols: ["a", "b", "c"], -optionsCallback: options => options[0].Value = true); + chosenSymbols: ["a", "b", "c"], + optionsCallback: options => options[0].Value = true); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/41428")] @@ -1261,8 +1261,8 @@ public Z(int a, string b, T? c{|Navigation:)|} } } """, -chosenSymbols: ["a", "b", "c"], -optionsCallback: options => options[0].Value = true); + chosenSymbols: ["a", "b", "c"], + optionsCallback: options => options[0].Value = true); } [Fact] @@ -1301,9 +1301,9 @@ public Z(int a, string b{|Navigation:)|} } } """, -chosenSymbols: ["a", "b"], -optionsCallback: options => options[0].Value = true, -parameters: new TestParameters(options: + chosenSymbols: ["a", "b"], + optionsCallback: options => options[0].Value = true, + parameters: new TestParameters(options: Option(CSharpCodeStyleOptions.PreferThrowExpression, CodeStyleOption2.FalseWithSilentEnforcement))); } @@ -1338,10 +1338,10 @@ public Z(int a, int? b{|Navigation:)|} } } """, -chosenSymbols: ["a", "b"], -optionsCallback: options => options[0].Value = true, -parameters: new TestParameters(options: -Option(CSharpCodeStyleOptions.PreferThrowExpression, CodeStyleOption2.FalseWithSilentEnforcement))); + chosenSymbols: ["a", "b"], + optionsCallback: options => options[0].Value = true, + parameters: new TestParameters(options: + Option(CSharpCodeStyleOptions.PreferThrowExpression, CodeStyleOption2.FalseWithSilentEnforcement))); } [Fact] @@ -1380,11 +1380,11 @@ public Z(int a, string b{|Navigation:)|} } } """, -chosenSymbols: ["a", "b"], -optionsCallback: options => options[0].Value = true, -parameters: new TestParameters( -parseOptions: CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.CSharp6), -options: Option(CSharpCodeStyleOptions.PreferThrowExpression, CodeStyleOption2.FalseWithSilentEnforcement))); + chosenSymbols: ["a", "b"], + optionsCallback: options => options[0].Value = true, + parameters: new TestParameters( + parseOptions: CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.CSharp6), + options: Option(CSharpCodeStyleOptions.PreferThrowExpression, CodeStyleOption2.FalseWithSilentEnforcement))); } [Fact] @@ -1492,7 +1492,7 @@ protected C(int prop{|Navigation:)|} public int Prop { get; set; } } """, -options: Option(CodeStyleOptions2.QualifyFieldAccess, CodeStyleOption2.TrueWithSuggestionEnforcement)); + options: Option(CodeStyleOptions2.QualifyFieldAccess, CodeStyleOption2.TrueWithSuggestionEnforcement)); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/17643")] @@ -1517,7 +1517,7 @@ public Program(int f{|Navigation:)|} } } """, -chosenSymbols: null); + chosenSymbols: null); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/25690")] @@ -1544,7 +1544,7 @@ public Program(int p{|Navigation:)|} } } """, -chosenSymbols: null); + chosenSymbols: null); } [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsGenerateEqualsAndGetHashCode)] @@ -1572,7 +1572,7 @@ public Program(int p, int s{|Navigation:)|} } } """, -chosenSymbols: null); + chosenSymbols: null); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/33601")] diff --git a/src/EditorFeatures/CSharpTest/Intents/IntentTestsBase.cs b/src/EditorFeatures/CSharpTest/Intents/IntentTestsBase.cs index 45efedfb6e970..760b1ca4465a7 100644 --- a/src/EditorFeatures/CSharpTest/Intents/IntentTestsBase.cs +++ b/src/EditorFeatures/CSharpTest/Intents/IntentTestsBase.cs @@ -21,7 +21,7 @@ namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Intents; -public class IntentTestsBase +public abstract class IntentTestsBase { internal static async Task VerifyIntentMissingAsync( string intentName, diff --git a/src/EditorFeatures/CSharpTest/Interactive/NavigateTo/InteractiveNavigateToTests.cs b/src/EditorFeatures/CSharpTest/Interactive/NavigateTo/InteractiveNavigateToTests.cs index d0506df874268..17f71d674aeaa 100644 --- a/src/EditorFeatures/CSharpTest/Interactive/NavigateTo/InteractiveNavigateToTests.cs +++ b/src/EditorFeatures/CSharpTest/Interactive/NavigateTo/InteractiveNavigateToTests.cs @@ -586,11 +586,11 @@ public class Goo """, async w => { // Do one set of queries - Assert.Single((await _aggregator.GetItemsAsync("Goo")).Where(x => x.Kind != "Method")); + Assert.Single((await _aggregator.GetItemsAsync("Goo")), x => x.Kind != "Method"); _provider.StopSearch(); // Do the same query again, make sure nothing was left over - Assert.Single((await _aggregator.GetItemsAsync("Goo")).Where(x => x.Kind != "Method")); + Assert.Single((await _aggregator.GetItemsAsync("Goo")), x => x.Kind != "Method"); _provider.StopSearch(); // Dispose the provider diff --git a/src/EditorFeatures/CSharpTest/MoveToNamespace/MoveToNamespaceTests.cs b/src/EditorFeatures/CSharpTest/MoveToNamespace/MoveToNamespaceTests.cs index ea68e9a3618be..e51030176bce5 100644 --- a/src/EditorFeatures/CSharpTest/MoveToNamespace/MoveToNamespaceTests.cs +++ b/src/EditorFeatures/CSharpTest/MoveToNamespace/MoveToNamespaceTests.cs @@ -2,13 +2,10 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces; using Microsoft.CodeAnalysis.MoveToNamespace; using Microsoft.CodeAnalysis.Shared.Extensions; @@ -21,14 +18,13 @@ namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.MoveToNamespace; [UseExportProvider] [Trait(Traits.Feature, Traits.Features.MoveToNamespace)] -public class MoveToNamespaceTests : AbstractMoveToNamespaceTests +public sealed class MoveToNamespaceTests : AbstractMoveToNamespaceTests { private static readonly TestComposition s_compositionWithoutOptions = FeaturesTestCompositions.Features - .AddParts( - typeof(TestSymbolRenamedCodeActionOperationFactoryWorkspaceService)); + .AddParts(typeof(TestSymbolRenamedCodeActionOperationFactoryWorkspaceService)); - private static readonly TestComposition s_composition = s_compositionWithoutOptions.AddParts( - typeof(TestMoveToNamespaceOptionsService)); + private static readonly TestComposition s_composition = s_compositionWithoutOptions + .AddParts(typeof(TestMoveToNamespaceOptionsService)); protected override TestComposition GetComposition() => s_composition; @@ -36,12 +32,12 @@ public class MoveToNamespaceTests : AbstractMoveToNamespaceTests protected internal override string GetLanguage() => LanguageNames.CSharp; - public static IEnumerable SupportedKeywords => new[] - { - new[] { "class" }, - ["enum"], - ["interface"] - }; + public static IEnumerable SupportedKeywords + => [ + ["class"], + ["enum"], + ["interface"] + ]; [Fact] public Task MoveToNamespace_MoveItems_CaretAboveNamespace() @@ -56,7 +52,7 @@ class MyClass } } """, -expectedSuccess: false); + expectedSuccess: false); [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/59716")] public Task MoveToNamespace_MoveItems_CaretAboveNamespace_FileScopedNamespace() @@ -70,7 +66,7 @@ class MyClass { } """, -expectedSuccess: false); + expectedSuccess: false); [Fact] public Task MoveToNamespace_MoveItems_CaretAboveNamespace2() @@ -85,7 +81,7 @@ class MyClass } } """, -expectedSuccess: false); + expectedSuccess: false); [Fact] public Task MoveToNamespace_MoveItems_WeirdNamespace() @@ -98,7 +94,7 @@ class MyClass } } """, -expectedMarkup: """ + expectedMarkup: """ namespace {|Warning:A|} { class MyClass @@ -106,17 +102,17 @@ class MyClass } } """, -targetNamespace: "A", -expectedSymbolChanges: new Dictionary() -{ -{"A.B.C.MyClass", "A.MyClass" } -}); + targetNamespace: "A", + expectedSymbolChanges: new Dictionary() + { + {"A.B.C.MyClass", "A.MyClass" } + }); [Fact] public Task MoveToNamespace_MoveItems_CaretOnNamespaceName() => TestMoveToNamespaceAsync( """ - namespace A[||] + namespace A[||] { class MyClass { @@ -124,7 +120,7 @@ void Method() { } } } """, -expectedMarkup: """ + expectedMarkup: """ namespace {|Warning:B|} { class MyClass @@ -133,11 +129,11 @@ void Method() { } } } """, -targetNamespace: "B", -expectedSymbolChanges: new Dictionary() -{ -{"A.MyClass", "B.MyClass" } -}); + targetNamespace: "B", + expectedSymbolChanges: new Dictionary() + { + {"A.MyClass", "B.MyClass" } + }); [Fact] public Task MoveToNamespace_MoveItems_CaretOnNamespaceName2() @@ -151,7 +147,7 @@ void Method() { } } } """, -expectedMarkup: """ + expectedMarkup: """ namespace {|Warning:B|} { class MyClass @@ -160,113 +156,113 @@ void Method() { } } } """, -targetNamespace: "B", -expectedSymbolChanges: new Dictionary() -{ -{"A.B.C.MyClass", "B.MyClass" } -}); + targetNamespace: "B", + expectedSymbolChanges: new Dictionary() + { + {"A.B.C.MyClass", "B.MyClass" } + }); [Fact] public Task MoveToNamespace_MoveItems_CaretOnNamespaceKeyword() - => TestMoveToNamespaceAsync( - """ - namespace[||] A - { - class MyClass + => TestMoveToNamespaceAsync( + """ + namespace[||] A { - void Method() { } + class MyClass + { + void Method() { } + } } - } - """, -expectedMarkup: """ - namespace {|Warning:B|} - { - class MyClass + """, + expectedMarkup: """ + namespace {|Warning:B|} { - void Method() { } + class MyClass + { + void Method() { } + } } - } - """, -targetNamespace: "B", -expectedSymbolChanges: new Dictionary() -{ - {"A.MyClass", "B.MyClass"} -} -); + """, + targetNamespace: "B", + expectedSymbolChanges: new Dictionary() + { + {"A.MyClass", "B.MyClass"} + } + ); [Fact] public Task MoveToNamespace_MoveItems_CaretOnNamespaceKeyword2() - => TestMoveToNamespaceAsync( - """ - [||]namespace A - { - class MyClass + => TestMoveToNamespaceAsync( + """ + [||]namespace A { - void Method() { } + class MyClass + { + void Method() { } + } } - } - """, -expectedMarkup: """ - namespace {|Warning:B|} - { - class MyClass + """, + expectedMarkup: """ + namespace {|Warning:B|} { - void Method() { } + class MyClass + { + void Method() { } + } } - } - """, -targetNamespace: "B", -expectedSymbolChanges: new Dictionary() -{ - {"A.MyClass", "B.MyClass"} -}); + """, + targetNamespace: "B", + expectedSymbolChanges: new Dictionary() + { + {"A.MyClass", "B.MyClass"} + }); [Fact] public Task MoveToNamespace_MoveItems_CaretOnNamespaceBrace() - => TestMoveToNamespaceAsync( - """ - namespace A - [||]{ - class MyClass - { - void Method() { } + => TestMoveToNamespaceAsync( + """ + namespace A + [||]{ + class MyClass + { + void Method() { } + } } - } - """, -expectedSuccess: false); + """, + expectedSuccess: false); [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/59716")] public Task MoveToNamespace_MoveItems_CaretAfterFileScopedNamespaceSemicolon() - => TestMoveToNamespaceAsync( - """ - namespace A; [||] - - class MyClass - { - void Method() { } - } - """, -expectedSuccess: false); + => TestMoveToNamespaceAsync( + """ + namespace A; [||] - [Fact] - public Task MoveToNamespace_MoveItems_CaretOnNamespaceBrace2() - => TestMoveToNamespaceAsync( - """ - namespace A - {[||] class MyClass { void Method() { } } - } - """, -expectedSuccess: false); + """, + expectedSuccess: false); + + [Fact] + public Task MoveToNamespace_MoveItems_CaretOnNamespaceBrace2() + => TestMoveToNamespaceAsync( + """ + namespace A + {[||] + class MyClass + { + void Method() { } + } + } + """, + expectedSuccess: false); [Fact] public Task MoveToNamespace_MoveItems_MultipleDeclarations() => TestMoveToNamespaceAsync( """ - namespace A[||] + namespace A[||] { class MyClass { @@ -279,7 +275,7 @@ void Method() { } } } """, -expectedMarkup: """ + expectedMarkup: """ namespace {|Warning:B|} { class MyClass @@ -293,643 +289,669 @@ void Method() { } } } """, -targetNamespace: "B", -expectedSymbolChanges: new Dictionary() -{ -{"A.MyClass", "B.MyClass" }, -{"A.MyOtherClass", "B.MyOtherClass" } -}); + targetNamespace: "B", + expectedSymbolChanges: new Dictionary() + { + {"A.MyClass", "B.MyClass" }, + {"A.MyOtherClass", "B.MyOtherClass" } + }); [Fact] public Task MoveToNamespace_MoveItems_WithVariousSymbols() - => TestMoveToNamespaceAsync( - """ - namespace A[||] - { - public delegate void MyDelegate(); - - public enum MyEnum + => TestMoveToNamespaceAsync( + """ + namespace A[||] { - One, - Two, - Three - } + public delegate void MyDelegate(); - public struct MyStruct - { } + public enum MyEnum + { + One, + Two, + Three + } - public interface MyInterface - { } + public struct MyStruct + { } - class MyClass - { - void Method() { } - } + public interface MyInterface + { } - class MyOtherClass - { - void Method() { } - } - } - """, -expectedMarkup: """ - namespace {|Warning:B|} - { - public delegate void MyDelegate(); + class MyClass + { + void Method() { } + } - public enum MyEnum - { - One, - Two, - Three + class MyOtherClass + { + void Method() { } + } } + """, + expectedMarkup: """ + namespace {|Warning:B|} + { + public delegate void MyDelegate(); - public struct MyStruct - { } + public enum MyEnum + { + One, + Two, + Three + } - public interface MyInterface - { } + public struct MyStruct + { } - class MyClass - { - void Method() { } - } + public interface MyInterface + { } - class MyOtherClass - { - void Method() { } + class MyClass + { + void Method() { } + } + + class MyOtherClass + { + void Method() { } + } } - } - """, -targetNamespace: "B", -expectedSymbolChanges: new Dictionary() -{ -{"A.MyDelegate", "B.MyDelegate" }, -{"A.MyEnum", "B.MyEnum" }, -{"A.MyStruct", "B.MyStruct" }, -{"A.MyInterface", "B.MyInterface" }, -{"A.MyClass", "B.MyClass" }, -{"A.MyOtherClass", "B.MyOtherClass" } -}); + """, + targetNamespace: "B", + expectedSymbolChanges: new Dictionary() + { + {"A.MyDelegate", "B.MyDelegate" }, + {"A.MyEnum", "B.MyEnum" }, + {"A.MyStruct", "B.MyStruct" }, + {"A.MyInterface", "B.MyInterface" }, + {"A.MyClass", "B.MyClass" }, + {"A.MyOtherClass", "B.MyOtherClass" } + }); [Fact] public Task MoveToNamespace_MoveItems_NestedNamespace() - => TestMoveToNamespaceAsync( - """ - namespace A[||] - { - namespace C + => TestMoveToNamespaceAsync( + """ + namespace A[||] { - class MyClass + namespace C { - void Method() { } + class MyClass + { + void Method() { } + } } } - } - """, -expectedSuccess: false); + """, + expectedSuccess: false); [Fact] public Task MoveToNamespace_MoveItems_NestedNamespace2() - => TestMoveToNamespaceAsync( - """ - namespace A - { - namespace C[||] + => TestMoveToNamespaceAsync( + """ + namespace A { - class MyClass + namespace C[||] { - void Method() { } + class MyClass + { + void Method() { } + } } } - } - """, -expectedSuccess: false); + """, + expectedSuccess: false); - [Theory] - [MemberData(nameof(SupportedKeywords))] + [Theory, MemberData(nameof(SupportedKeywords))] public Task MoveToNamespace_MoveType_Nested(string typeKeyword) - => TestMoveToNamespaceAsync( -@$"namespace A -{{ - class MyClass - {{ - {typeKeyword} NestedType[||] - {{ - }} - }} -}}", -expectedSuccess: false); - - [Theory] - [MemberData(nameof(SupportedKeywords))] + => TestMoveToNamespaceAsync( + $$""" + namespace A + { + class MyClass + { + {{typeKeyword}} NestedType[||] + { + } + } + } + """, + expectedSuccess: false); + + [Theory, MemberData(nameof(SupportedKeywords))] public Task MoveToNamespace_MoveType_Single(string typeKeyword) - => TestMoveToNamespaceAsync( -@$"namespace A -{{ - {typeKeyword} MyType[||] - {{ - }} -}}", -expectedMarkup: @$"namespace {{|Warning:B|}} -{{ - {typeKeyword} MyType - {{ - }} -}}", -targetNamespace: "B", -expectedSymbolChanges: new Dictionary() -{ -{"A.MyType", "B.MyType" } -}); + => TestMoveToNamespaceAsync( + $$""" + namespace A + { + {{typeKeyword}} MyType[||] + { + } + } + """, + expectedMarkup: $$""" + namespace {|Warning:B|} + { + {{typeKeyword}} MyType + { + } + } + """, + targetNamespace: "B", + expectedSymbolChanges: new Dictionary() + { + {"A.MyType", "B.MyType" } + }); [Theory, WorkItem("https://github.com/dotnet/roslyn/issues/59716")] [MemberData(nameof(SupportedKeywords))] public Task MoveToNamespace_MoveType_Single_FileScopedNamespace(string typeKeyword) - => TestMoveToNamespaceAsync( -@$"namespace A; - -{typeKeyword} MyType[||] -{{ -}} -", -expectedMarkup: @$"namespace {{|Warning:B|}}; - -{typeKeyword} MyType -{{ -}} -", -targetNamespace: "B", -expectedSymbolChanges: new Dictionary() -{ -{"A.MyType", "B.MyType" } -}); + => TestMoveToNamespaceAsync( + $$""" + namespace A; - [Theory] - [MemberData(nameof(SupportedKeywords))] + {{typeKeyword}} MyType[||] + { + } + + """, + expectedMarkup: $$""" + namespace {|Warning:B|}; + + {{typeKeyword}} MyType + { + } + + """, + targetNamespace: "B", + expectedSymbolChanges: new Dictionary() + { + {"A.MyType", "B.MyType" } + }); + + [Theory, MemberData(nameof(SupportedKeywords))] public Task MoveToNamespace_MoveType_SingleTop(string typeKeyword) - => TestMoveToNamespaceAsync( -@$"namespace A -{{ - {typeKeyword} MyType[||] - {{ - }} - - {typeKeyword} MyType2 - {{ - }} -}}", -expectedMarkup: @$"namespace {{|Warning:B|}} -{{ - {typeKeyword} MyType - {{ - }} -}} - -namespace A -{{ - {typeKeyword} MyType2 - {{ - }} -}}", -targetNamespace: "B", -expectedSymbolChanges: new Dictionary() -{ -{"A.MyType", "B.MyType" } -}); + => TestMoveToNamespaceAsync( + $$""" + namespace A + { + {{typeKeyword}} MyType[||] + { + } + + {{typeKeyword}} MyType2 + { + } + } + """, + expectedMarkup: $$""" + namespace {|Warning:B|} + { + {{typeKeyword}} MyType + { + } + } + + namespace A + { + {{typeKeyword}} MyType2 + { + } + } + """, + targetNamespace: "B", + expectedSymbolChanges: new Dictionary() + { + {"A.MyType", "B.MyType" } + }); [Fact] public Task MoveToNamespace_MoveType_TopWithReference() - => TestMoveToNamespaceAsync( - """ - namespace A - { - class MyClass[||] : IMyClass + => TestMoveToNamespaceAsync( + """ + namespace A { + class MyClass[||] : IMyClass + { + } + + interface IMyClass + { + } } + """, + expectedMarkup: """ + using A; - interface IMyClass + namespace {|Warning:B|} { + class MyClass : IMyClass + { + } } - } - """, -expectedMarkup: """ - using A; - namespace {|Warning:B|} - { - class MyClass : IMyClass + namespace A { + interface IMyClass + { + } } - } + """, + targetNamespace: "B", + expectedSymbolChanges: new Dictionary() + { + {"A.MyClass", "B.MyClass" } + }); - namespace A - { - interface IMyClass + [Theory, MemberData(nameof(SupportedKeywords))] + public Task MoveToNamespace_MoveType_Bottom(string typeKeyword) + => TestMoveToNamespaceAsync( + $$""" + namespace A { + {{typeKeyword}} MyType + { + } + + {{typeKeyword}} MyType2[||] + { + } + } + """, + expectedMarkup: $$""" + namespace A + { + {{typeKeyword}} MyType + { + } } - } - """, -targetNamespace: "B", -expectedSymbolChanges: new Dictionary() -{ -{"A.MyClass", "B.MyClass" } -}); - [Theory] - [MemberData(nameof(SupportedKeywords))] - public Task MoveToNamespace_MoveType_Bottom(string typeKeyword) - => TestMoveToNamespaceAsync( -@$"namespace A -{{ - {typeKeyword} MyType - {{ - }} - - {typeKeyword} MyType2[||] - {{ - }} -}}", -expectedMarkup: @$"namespace A -{{ - {typeKeyword} MyType - {{ - }} -}} - -namespace {{|Warning:B|}} -{{ - {typeKeyword} MyType2 - {{ - }} -}}", -targetNamespace: "B", -expectedSymbolChanges: new Dictionary() -{ -{"A.MyType2", "B.MyType2" } -}); + namespace {|Warning:B|} + { + {{typeKeyword}} MyType2 + { + } + } + """, + targetNamespace: "B", + expectedSymbolChanges: new Dictionary() + { + {"A.MyType2", "B.MyType2" } + }); [Fact] public Task MoveToNamespace_MoveType_BottomReference() - => TestMoveToNamespaceAsync( - """ - namespace A - { - class MyClass : IMyClass + => TestMoveToNamespaceAsync( + """ + namespace A { + class MyClass : IMyClass + { + } + + interface IMyClass[||] + { + } } + """, + expectedMarkup: """ + using B; - interface IMyClass[||] + namespace A { + class MyClass : IMyClass + { + } } - } - """, -expectedMarkup: """ - using B; - namespace A - { - class MyClass : IMyClass + namespace {|Warning:B|} { + interface IMyClass + { + } } - } + """, + targetNamespace: "B", + expectedSymbolChanges: new Dictionary() + { + {"A.IMyClass", "B.IMyClass" } + }); - namespace {|Warning:B|} - { - interface IMyClass + [Theory, MemberData(nameof(SupportedKeywords))] + public Task MoveToNamespace_MoveType_Middle(string typeKeyword) + => TestMoveToNamespaceAsync( + $$""" + namespace A { + {{typeKeyword}} MyType + { + } + + {{typeKeyword}} MyType2[||] + { + } + + {{typeKeyword}} MyType3 + { + } + } + """, + expectedMarkup: $$""" + namespace A + { + {{typeKeyword}} MyType + { + } } - } - """, -targetNamespace: "B", -expectedSymbolChanges: new Dictionary() -{ -{"A.IMyClass", "B.IMyClass" } -}); - [Theory] - [MemberData(nameof(SupportedKeywords))] - public Task MoveToNamespace_MoveType_Middle(string typeKeyword) - => TestMoveToNamespaceAsync( -@$"namespace A -{{ - {typeKeyword} MyType - {{ - }} - - {typeKeyword} MyType2[||] - {{ - }} - - {typeKeyword} MyType3 - {{ - }} -}}", -expectedMarkup: @$"namespace A -{{ - {typeKeyword} MyType - {{ - }} -}} - -namespace {{|Warning:B|}} -{{ - {typeKeyword} MyType2 - {{ - }} -}} - -namespace A -{{ - {typeKeyword} MyType3 - {{ - }} -}}", -targetNamespace: "B", -expectedSymbolChanges: new Dictionary() -{ -{"A.MyType2", "B.MyType2" } -}); + namespace {|Warning:B|} + { + {{typeKeyword}} MyType2 + { + } + } - [Theory] - [MemberData(nameof(SupportedKeywords))] + namespace A + { + {{typeKeyword}} MyType3 + { + } + } + """, + targetNamespace: "B", + expectedSymbolChanges: new Dictionary() + { + {"A.MyType2", "B.MyType2" } + }); + + [Theory, MemberData(nameof(SupportedKeywords))] public Task MoveToNamespace_MoveType_Middle_CaretBeforeKeyword(string typeKeyword) - => TestMoveToNamespaceAsync( -@$"namespace A -{{ - {typeKeyword} MyType - {{ - }} - - [||]{typeKeyword} MyType2 - {{ - }} - - {typeKeyword} MyType3 - {{ - }} -}}", -expectedMarkup: @$"namespace A -{{ - {typeKeyword} MyType - {{ - }} -}} - -namespace {{|Warning:B|}} -{{ - {typeKeyword} MyType2 - {{ - }} -}} - -namespace A -{{ - {typeKeyword} MyType3 - {{ - }} -}}", -targetNamespace: "B", -expectedSymbolChanges: new Dictionary() -{ -{"A.MyType2", "B.MyType2" } -}); + => TestMoveToNamespaceAsync( + $$""" + namespace A + { + {{typeKeyword}} MyType + { + } - [Theory] - [MemberData(nameof(SupportedKeywords))] + [||]{{typeKeyword}} MyType2 + { + } + + {{typeKeyword}} MyType3 + { + } + } + """, + expectedMarkup: $$""" + namespace A + { + {{typeKeyword}} MyType + { + } + } + + namespace {|Warning:B|} + { + {{typeKeyword}} MyType2 + { + } + } + + namespace A + { + {{typeKeyword}} MyType3 + { + } + } + """, + targetNamespace: "B", + expectedSymbolChanges: new Dictionary() + { + {"A.MyType2", "B.MyType2" } + }); + + [Theory, MemberData(nameof(SupportedKeywords))] public Task MoveToNamespace_MoveType_Middle_CaretAfterTypeKeyword(string typeKeyword) - => TestMoveToNamespaceAsync( -@$"namespace A -{{ - {typeKeyword} MyType - {{ - }} - - {typeKeyword}[||] MyType2 - {{ - }} - - {typeKeyword} MyType3 - {{ - }} -}}", -expectedMarkup: @$"namespace A -{{ - {typeKeyword} MyType - {{ - }} -}} - -namespace {{|Warning:B|}} -{{ - {typeKeyword} MyType2 - {{ - }} -}} - -namespace A -{{ - {typeKeyword} MyType3 - {{ - }} -}}", -targetNamespace: "B", -expectedSymbolChanges: new Dictionary() -{ -{"A.MyType2", "B.MyType2" } -}); + => TestMoveToNamespaceAsync( + $$""" + namespace A + { + {{typeKeyword}} MyType + { + } - [Theory] - [MemberData(nameof(SupportedKeywords))] + {{typeKeyword}}[||] MyType2 + { + } + + {{typeKeyword}} MyType3 + { + } + } + """, + expectedMarkup: $$""" + namespace A + { + {{typeKeyword}} MyType + { + } + } + + namespace {|Warning:B|} + { + {{typeKeyword}} MyType2 + { + } + } + + namespace A + { + {{typeKeyword}} MyType3 + { + } + } + """, + targetNamespace: "B", + expectedSymbolChanges: new Dictionary() + { + {"A.MyType2", "B.MyType2" } + }); + + [Theory, MemberData(nameof(SupportedKeywords))] public Task MoveToNamespace_MoveType_Middle_CaretBeforeTypeName(string typeKeyword) - => TestMoveToNamespaceAsync( -@$"namespace A -{{ - {typeKeyword} MyType - {{ - }} - - {typeKeyword} [||]MyType2 - {{ - }} - - {typeKeyword} MyType3 - {{ - }} -}}", -expectedMarkup: @$"namespace A -{{ - {typeKeyword} MyType - {{ - }} -}} - -namespace {{|Warning:B|}} -{{ - {typeKeyword} MyType2 - {{ - }} -}} - -namespace A -{{ - {typeKeyword} MyType3 - {{ - }} -}}", -targetNamespace: "B", -expectedSymbolChanges: new Dictionary() -{ -{"A.MyType2", "B.MyType2" } -}); + => TestMoveToNamespaceAsync( + $$""" + namespace A + { + {{typeKeyword}} MyType + { + } - [Fact] - public Task MoveToNamespace_MoveType_CaretInMethod() - => TestMoveToNamespaceAsync( - """ - namespace A - { - class MyClass + {{typeKeyword}} [||]MyType2 + { + } + + {{typeKeyword}} MyType3 + { + } + } + """, + expectedMarkup: $$""" + namespace A { - public string [||]MyMethod + {{typeKeyword}} MyType { - return "; } } - } - """, -expectedSuccess: false); + namespace {|Warning:B|} + { + {{typeKeyword}} MyType2 + { + } + } - [Fact] - public Task MoveToNamespace_MoveType_MiddleReference() - => TestMoveToNamespaceAsync( - """ - namespace A - { - class MyClass : IMyClass + namespace A { + {{typeKeyword}} MyType3 + { + } } + """, + targetNamespace: "B", + expectedSymbolChanges: new Dictionary() + { + {"A.MyType2", "B.MyType2" } + }); - interface IMyClass[||] + [Fact] + public Task MoveToNamespace_MoveType_CaretInMethod() + => TestMoveToNamespaceAsync( + """ + namespace A { + class MyClass + { + public string [||]MyMethod + { + return "; + } + } + } + """, + expectedSuccess: false); - class MyClass3 : IMyClass + [Fact] + public Task MoveToNamespace_MoveType_MiddleReference() + => TestMoveToNamespaceAsync( + """ + namespace A { + class MyClass : IMyClass + { + } + + interface IMyClass[||] + { + } + + class MyClass3 : IMyClass + { + } } - } - """, -expectedMarkup: """ - using B; + """, + expectedMarkup: """ + using B; - namespace A - { - class MyClass : IMyClass + namespace A { + class MyClass : IMyClass + { + } } - } - namespace {|Warning:B|} - { - interface IMyClass + namespace {|Warning:B|} { + interface IMyClass + { + } } - } - namespace A - { - class MyClass3 : IMyClass + namespace A { + class MyClass3 : IMyClass + { + } } - } - """, -targetNamespace: "B", -expectedSymbolChanges: new Dictionary() -{ -{"A.IMyClass", "B.IMyClass" } -}); + """, + targetNamespace: "B", + expectedSymbolChanges: new Dictionary() + { + {"A.IMyClass", "B.IMyClass" } + }); [Fact] public Task MoveToNamespace_MoveType_MiddleReference2() - => TestMoveToNamespaceAsync( - """ - namespace A - { - class MyClass : IMyClass + => TestMoveToNamespaceAsync( + """ + namespace A { - } + class MyClass : IMyClass + { + } + + interface IMyClass + { + } - interface IMyClass - { - } + class [||]MyClass3 : IMyClass + { + } - class [||]MyClass3 : IMyClass - { + class MyClass4 + { + } } + """, + expectedMarkup: """ + using A; - class MyClass4 + namespace A { - } - } - """, -expectedMarkup: """ - using A; + class MyClass : IMyClass + { + } - namespace A - { - class MyClass : IMyClass - { + interface IMyClass + { + } } - interface IMyClass + namespace {|Warning:B|} { + class MyClass3 : IMyClass + { + } } - } - namespace {|Warning:B|} - { - class MyClass3 : IMyClass + namespace A { + class MyClass4 + { + } } - } - - namespace A - { - class MyClass4 + """, + targetNamespace: "B", + expectedSymbolChanges: new Dictionary() { - } - } - """, -targetNamespace: "B", -expectedSymbolChanges: new Dictionary() -{ -{"A.MyClass3", "B.MyClass3" } -}); + {"A.MyClass3", "B.MyClass3" } + }); [Fact] public Task MoveToNamespace_MoveType_NestedInNamespace() - => TestMoveToNamespaceAsync( - """ - namespace A - { - class MyClass + => TestMoveToNamespaceAsync( + """ + namespace A { - } + class MyClass + { + } - namespace B - { - interface [||]IMyClass + namespace B { + interface [||]IMyClass + { + } } - } - class MyClass2 : B.IMyClass - { + class MyClass2 : B.IMyClass + { + } } - } - """, -expectedSuccess: false); + """, + expectedSuccess: false); [Fact] public Task MoveToNamespace_MoveType_Cancelled() @@ -973,174 +995,174 @@ class MyClass2 : B.IMyClass [Fact] public Task MoveToNamespace_MoveType_MiddleReference_ComplexName() - => TestMoveToNamespaceAsync( - """ - namespace A.B.C - { - class MyClass : IMyClass + => TestMoveToNamespaceAsync( + """ + namespace A.B.C { - } + class MyClass : IMyClass + { + } - interface IMyClass - { - } + interface IMyClass + { + } - class [||]MyClass3 : IMyClass - { - } + class [||]MyClass3 : IMyClass + { + } - class MyClass4 - { + class MyClass4 + { + } } - } - """, -expectedMarkup: """ - using A.B.C; + """, + expectedMarkup: """ + using A.B.C; - namespace A.B.C - { - class MyClass : IMyClass + namespace A.B.C { - } + class MyClass : IMyClass + { + } - interface IMyClass - { + interface IMyClass + { + } } - } - namespace {|Warning:My.New.Namespace|} - { - class MyClass3 : IMyClass + namespace {|Warning:My.New.Namespace|} { + class MyClass3 : IMyClass + { + } } - } - namespace A.B.C - { - class MyClass4 + namespace A.B.C { + class MyClass4 + { + } } - } - """, -targetNamespace: "My.New.Namespace", -expectedSymbolChanges: new Dictionary() -{ -{"A.B.C.MyClass3", "My.New.Namespace.MyClass3" } -}); + """, + targetNamespace: "My.New.Namespace", + expectedSymbolChanges: new Dictionary() + { + {"A.B.C.MyClass3", "My.New.Namespace.MyClass3" } + }); [Fact] public Task MoveToNamespace_MoveType_MiddleReference_ComplexName2() - => TestMoveToNamespaceAsync( - """ - namespace A - { - class MyClass : IMyClass + => TestMoveToNamespaceAsync( + """ + namespace A { - } + class MyClass : IMyClass + { + } - interface IMyClass - { - } + interface IMyClass + { + } - class [||]MyClass3 : IMyClass - { - } + class [||]MyClass3 : IMyClass + { + } - class MyClass4 - { - } - } - """, -expectedMarkup: """ - using A; - - namespace A - { - class MyClass : IMyClass - { + class MyClass4 + { + } } + """, + expectedMarkup: """ + using A; - interface IMyClass + namespace A { + class MyClass : IMyClass + { + } + + interface IMyClass + { + } } - } - namespace {|Warning:My.New.Namespace|} - { - class MyClass3 : IMyClass + namespace {|Warning:My.New.Namespace|} { + class MyClass3 : IMyClass + { + } } - } - namespace A - { - class MyClass4 + namespace A { + class MyClass4 + { + } } - } - """, -targetNamespace: "My.New.Namespace", -expectedSymbolChanges: new Dictionary() -{ -{"A.MyClass3", "My.New.Namespace.MyClass3" } -}); + """, + targetNamespace: "My.New.Namespace", + expectedSymbolChanges: new Dictionary() + { + {"A.MyClass3", "My.New.Namespace.MyClass3" } + }); [Fact] public Task MoveToNamespace_MoveType_MiddleReference_ComplexName3() - => TestMoveToNamespaceAsync( - """ - namespace A.B.C - { - class MyClass : IMyClass + => TestMoveToNamespaceAsync( + """ + namespace A.B.C { - } + class MyClass : IMyClass + { + } - interface IMyClass - { - } + interface IMyClass + { + } - class [||]MyClass3 : IMyClass - { - } + class [||]MyClass3 : IMyClass + { + } - class MyClass4 - { - } - } - """, -expectedMarkup: """ - using A.B.C; - - namespace A.B.C - { - class MyClass : IMyClass - { + class MyClass4 + { + } } + """, + expectedMarkup: """ + using A.B.C; - interface IMyClass + namespace A.B.C { + class MyClass : IMyClass + { + } + + interface IMyClass + { + } } - } - namespace {|Warning:B|} - { - class MyClass3 : IMyClass + namespace {|Warning:B|} { + class MyClass3 : IMyClass + { + } } - } - namespace A.B.C - { - class MyClass4 + namespace A.B.C { + class MyClass4 + { + } } - } - """, -targetNamespace: "B", -expectedSymbolChanges: new Dictionary() -{ -{"A.B.C.MyClass3", "B.MyClass3" } -}); + """, + targetNamespace: "B", + expectedSymbolChanges: new Dictionary() + { + {"A.B.C.MyClass3", "B.MyClass3" } + }); [Fact] public Task MoveToNamespace_Analysis_MoveItems_ComplexNamespace() @@ -1157,42 +1179,42 @@ class MyClass [Fact] public Task MoveToNamespace_Analysis_MoveType_ComplexNamespace() - => TestMoveToNamespaceAnalysisAsync( - """ - namespace A.Complex.Namespace - { - class [||]MyClass - { - } - } - """, -expectedNamespaceName: "A.Complex.Namespace"); + => TestMoveToNamespaceAnalysisAsync( + """ + namespace A.Complex.Namespace + { + class [||]MyClass + { + } + } + """, + expectedNamespaceName: "A.Complex.Namespace"); [Fact] public Task MoveToNamespace_Analysis_MoveItems_WeirdNamespace() - => TestMoveToNamespaceAnalysisAsync( - """ - namespace A [||]. B . C - { - class MyClass - { - } - } - """, -expectedNamespaceName: "A . B . C"); + => TestMoveToNamespaceAnalysisAsync( + """ + namespace A [||]. B . C + { + class MyClass + { + } + } + """, + expectedNamespaceName: "A . B . C"); [Fact] public Task MoveToNamespace_Analysis_MoveType_WeirdNamespace() - => TestMoveToNamespaceAnalysisAsync( - """ - namespace A . B . C - { - class MyClass[||] - { - } - } - """, -expectedNamespaceName: "A . B . C"); + => TestMoveToNamespaceAnalysisAsync( + """ + namespace A . B . C + { + class MyClass[||] + { + } + } + """, + expectedNamespaceName: "A . B . C"); [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/34736")] public Task MoveToNamespace_MoveType_Usings() @@ -1215,7 +1237,7 @@ class C2 } } """, -expectedMarkup: """ + expectedMarkup: """ namespace One { using Three; @@ -1233,11 +1255,11 @@ class C2 } } """, -targetNamespace: "Three", -expectedSymbolChanges: new Dictionary() -{ -{"Two.C2", "Three.C2" } -}); + targetNamespace: "Three", + expectedSymbolChanges: new Dictionary() + { + {"Two.C2", "Three.C2" } + }); [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/35577")] public async Task MoveToNamespace_WithoutOptionsService() @@ -1267,21 +1289,25 @@ void Method() { } [Theory, WorkItem("https://devdiv.visualstudio.com/DevDiv/_workitems/edit/980758")] [MemberData(nameof(SupportedKeywords))] public Task MoveToNamespace_MoveOnlyTypeInGlobalNamespace(string typeKeyword) - => TestMoveToNamespaceAsync( -@$"{typeKeyword} MyType[||] -{{ -}}", -expectedMarkup: @$"namespace {{|Warning:A|}} -{{ - {typeKeyword} MyType - {{ - }} -}}", -targetNamespace: "A", -expectedSymbolChanges: new Dictionary() -{ -{"MyType", "A.MyType" } -}); + => TestMoveToNamespaceAsync( + $$""" + {{typeKeyword}} MyType[||] + { + } + """, + expectedMarkup: $$""" + namespace {|Warning:A|} + { + {{typeKeyword}} MyType + { + } + } + """, + targetNamespace: "A", + expectedSymbolChanges: new Dictionary() + { + {"MyType", "A.MyType" } + }); [Theory, WorkItem("https://devdiv.visualstudio.com/DevDiv/_workitems/edit/980758")] [MemberData(nameof(SupportedKeywords))] @@ -1290,33 +1316,39 @@ public async Task MoveToNamespace_MoveOnlyTypeToGlobalNamespace(string typeKeywo // We will not get "" as target namespace in VS, but the refactoring should be able // to handle it w/o crashing. await TestMoveToNamespaceAsync( -@$"namespace A -{{ - {typeKeyword} MyType[||] - {{ - }} -}}", -expectedMarkup: @$"namespace A -{{ - {typeKeyword} MyType - {{ - }} -}}", - targetNamespace: ""); + $$""" + namespace A + { + {{typeKeyword}} MyType[||] + { + } + } + """, + expectedMarkup: $$""" + namespace A + { + {{typeKeyword}} MyType + { + } + } + """, + targetNamespace: ""); } [Theory, WorkItem("https://devdiv.visualstudio.com/DevDiv/_workitems/edit/980758")] [MemberData(nameof(SupportedKeywords))] public Task MoveToNamespace_MoveOneTypeInGlobalNamespace(string typeKeyword) => TestMoveToNamespaceAsync( -@$"{typeKeyword} MyType1[||] -{{ -}} + $$""" + {{typeKeyword}} MyType1[||] + { + } -{typeKeyword} MyType2 -{{ -}}", -expectedSuccess: false); + {{typeKeyword}} MyType2 + { + } + """, + expectedSuccess: false); [Fact, WorkItem("https://devdiv.visualstudio.com/DevDiv/_workitems/edit/980758")] public Task MoveToNamespace_PartialTypesInNamesapce_SelectType() @@ -1333,7 +1365,7 @@ partial class MyClass } } """, -expectedSuccess: false); + expectedSuccess: false); [Fact, WorkItem("https://devdiv.visualstudio.com/DevDiv/_workitems/edit/980758")] public Task MoveToNamespace_PartialTypesInNamesapce_SelectNamespace() @@ -1350,7 +1382,7 @@ partial class MyClass } } """, -expectedSuccess: false); + expectedSuccess: false); [Fact, WorkItem("https://devdiv.visualstudio.com/DevDiv/_workitems/edit/980758")] public Task MoveToNamespace_PartialTypesInGlobalNamesapce() @@ -1363,7 +1395,7 @@ partial class MyClass { } """, -expectedSuccess: false); + expectedSuccess: false); [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/39234")] public async Task TestMultiTargetingProject() @@ -1411,8 +1443,8 @@ public class Class2 // Set the target namespace to "B" var testDocument = workspace.Projects.Single(p => p.Name == "Proj1").Documents.Single(); - var document = workspace.CurrentSolution.GetDocument(testDocument.Id); - var movenamespaceService = document.GetLanguageService(); + var document = workspace.CurrentSolution.GetRequiredDocument(testDocument.Id); + var movenamespaceService = document.GetRequiredLanguageService(); var moveToNamespaceOptions = new MoveToNamespaceOptionsResult("B"); ((TestMoveToNamespaceOptionsService)movenamespaceService.OptionsService).SetOptions(moveToNamespaceOptions); @@ -1423,10 +1455,10 @@ public class Class2 // Make sure both linked documents are changed. foreach (var id in workspace.Documents.Select(d => d.Id)) { - var changedDocument = result.Item2.GetDocument(id); - var changedRoot = await changedDocument.GetSyntaxRootAsync(); + var changedDocument = result.Item2.GetRequiredDocument(id); + var changedRoot = await changedDocument.GetRequiredSyntaxRootAsync(CancellationToken.None); var actualText = changedRoot.ToFullString(); - Assert.Equal(expected, actualText); + AssertEx.Equal(expected, actualText); } } @@ -1442,7 +1474,7 @@ namespace System } } """, -expectedMarkup: """ + expectedMarkup: """ namespace {|Warning:Test|} { [||]class A @@ -1451,9 +1483,53 @@ namespace {|Warning:Test|} } } """, -targetNamespace: "Test", -expectedSymbolChanges: new Dictionary() -{ -{"System.A", "Test.A" } -}); + targetNamespace: "Test", + expectedSymbolChanges: new Dictionary() + { + {"System.A", "Test.A" } + }); + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/54889")] + public Task MoveToNamespace_MoveType_NoFormat() + => TestMoveToNamespaceAsync( + $$""" + namespace A + { + class MyType[||] + { + public const string ShortName = ""; + public const string VeryLongName = ""; + } + + struct MyType2 + { + public const string ShortName = ""; + public const string VeryLongName = ""; + } + } + """, + expectedMarkup: $$""" + namespace {|Warning:B|} + { + class MyType + { + public const string ShortName = ""; + public const string VeryLongName = ""; + } + } + + namespace A + { + struct MyType2 + { + public const string ShortName = ""; + public const string VeryLongName = ""; + } + } + """, + targetNamespace: "B", + expectedSymbolChanges: new Dictionary() + { + {"A.MyType", "B.MyType" } + }); } diff --git a/src/EditorFeatures/CSharpTest/NavigateTo/NavigateToTests.cs b/src/EditorFeatures/CSharpTest/NavigateTo/NavigateToTests.cs index cae098cf81b3e..09a8a2137eedb 100644 --- a/src/EditorFeatures/CSharpTest/NavigateTo/NavigateToTests.cs +++ b/src/EditorFeatures/CSharpTest/NavigateTo/NavigateToTests.cs @@ -978,11 +978,11 @@ public class Goo """, async w => { // Do one set of queries - Assert.Single((await _aggregator.GetItemsAsync("Goo")).Where(x => x.Kind != "Method")); + Assert.Single((await _aggregator.GetItemsAsync("Goo")), x => x.Kind != "Method"); _provider.StopSearch(); // Do the same query again, make sure nothing was left over - Assert.Single((await _aggregator.GetItemsAsync("Goo")).Where(x => x.Kind != "Method")); + Assert.Single((await _aggregator.GetItemsAsync("Goo")), x => x.Kind != "Method"); _provider.StopSearch(); // Dispose the provider diff --git a/src/EditorFeatures/CSharpTest/PdbSourceDocument/AbstractPdbSourceDocumentTests.cs b/src/EditorFeatures/CSharpTest/PdbSourceDocument/AbstractPdbSourceDocumentTests.cs index 678b8b0fd99a4..151b4737bdb03 100644 --- a/src/EditorFeatures/CSharpTest/PdbSourceDocument/AbstractPdbSourceDocumentTests.cs +++ b/src/EditorFeatures/CSharpTest/PdbSourceDocument/AbstractPdbSourceDocumentTests.cs @@ -242,7 +242,7 @@ protected static TestComposition GetTestComposition() // to be available. return EditorTestCompositions.EditorFeatures - .WithExcludedPartTypes(ImmutableHashSet.Create(typeof(IMetadataAsSourceFileProvider))) + .WithExcludedPartTypes([typeof(IMetadataAsSourceFileProvider)]) .AddParts(typeof(PdbSourceDocumentMetadataAsSourceFileProvider), typeof(NullResultMetadataAsSourceFileProvider)); } diff --git a/src/EditorFeatures/CSharpTest/PdbSourceDocument/PdbSourceDocumentLoaderServiceTests.cs b/src/EditorFeatures/CSharpTest/PdbSourceDocument/PdbSourceDocumentLoaderServiceTests.cs index 929e99379f4ec..d4efd62b990da 100644 --- a/src/EditorFeatures/CSharpTest/PdbSourceDocument/PdbSourceDocumentLoaderServiceTests.cs +++ b/src/EditorFeatures/CSharpTest/PdbSourceDocument/PdbSourceDocumentLoaderServiceTests.cs @@ -45,7 +45,7 @@ await RunTestAsync(async path => using var hash = SHA256.Create(); var fileHash = hash.ComputeHash(File.ReadAllBytes(sourceFilePath)); - var sourceDocument = new SourceDocument("goo.cs", Text.SourceHashAlgorithms.Default, fileHash.ToImmutableArray(), null, "https://sourcelink"); + var sourceDocument = new SourceDocument("goo.cs", Text.SourceHashAlgorithms.Default, [.. fileHash], null, "https://sourcelink"); var result = await service.LoadSourceDocumentAsync(path, sourceDocument, Encoding.UTF8, new TelemetryMessage(CancellationToken.None), useExtendedTimeout: false, CancellationToken.None); Assert.NotNull(result); diff --git a/src/EditorFeatures/CSharpTest/PdbSourceDocument/PdbSourceDocumentTests.cs b/src/EditorFeatures/CSharpTest/PdbSourceDocument/PdbSourceDocumentTests.cs index 14c90546f64c3..b074133b9c1ce 100644 --- a/src/EditorFeatures/CSharpTest/PdbSourceDocument/PdbSourceDocumentTests.cs +++ b/src/EditorFeatures/CSharpTest/PdbSourceDocument/PdbSourceDocumentTests.cs @@ -663,7 +663,7 @@ await RunTestAsync(async path => var (project, symbol) = await CompileAndFindSymbolAsync(path, Location.OnDisk, Location.OnDisk, metadataSource, c => c.GetMember("C.E")); // Now make the PDB a zero byte file - File.WriteAllBytes(GetPdbPath(path), new byte[0]); + File.WriteAllBytes(GetPdbPath(path), []); await GenerateFileAndVerifyAsync(project, symbol, Location.OnDisk, source, expectedSpan, expectNullResult: true); }); diff --git a/src/EditorFeatures/CSharpTest/QuickInfo/DiagnosticAnalyzerQuickInfoSourceTests.cs b/src/EditorFeatures/CSharpTest/QuickInfo/DiagnosticAnalyzerQuickInfoSourceTests.cs index 983b7fa7327c6..79f3517c2eead 100644 --- a/src/EditorFeatures/CSharpTest/QuickInfo/DiagnosticAnalyzerQuickInfoSourceTests.cs +++ b/src/EditorFeatures/CSharpTest/QuickInfo/DiagnosticAnalyzerQuickInfoSourceTests.cs @@ -25,7 +25,7 @@ namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.QuickInfo; [UseExportProvider] [Trait(Traits.Feature, Traits.Features.QuickInfo)] -public class DiagnosticAnalyzerQuickInfoSourceTests +public sealed class DiagnosticAnalyzerQuickInfoSourceTests { [WpfFact, WorkItem("https://github.com/dotnet/roslyn/issues/46604")] public async Task ErrorTitleIsShownOnDisablePragma() @@ -127,7 +127,7 @@ public class C private int _i; } } - """, GetFormattedIDEAnalyzerTitle(51, nameof(AnalyzersResources.Remove_unused_private_members)), ImmutableArray.Empty); + """, GetFormattedIDEAnalyzerTitle(51, nameof(AnalyzersResources.Remove_unused_private_members)), []); } [WorkItem("https://github.com/dotnet/roslyn/issues/46604")] @@ -156,26 +156,26 @@ public async Task QuickInfoSuppressMessageAttributeUseCases(string suppressMessa ? GetFormattedIDEAnalyzerTitle(51, nameof(AnalyzersResources.Remove_unused_private_members)) : null; await TestAsync( -@$" -using System.Diagnostics.CodeAnalysis; -using SM = System.Diagnostics.CodeAnalysis.SuppressMessageAttribute; -namespace T -{{ - public static class DiagnosticIds - {{ - public const string IDE0051 = ""IDE0051""; - }} + $$""" + using System.Diagnostics.CodeAnalysis; + using SM = System.Diagnostics.CodeAnalysis.SuppressMessageAttribute; + namespace T + { + public static class DiagnosticIds + { + public const string IDE0051 = "IDE0051"; + } - {suppressMessageAttribute} - public class C - {{ - private int _i; - }} -}} -", description, ImmutableArray.Empty); + {{suppressMessageAttribute}} + public class C + { + private int _i; + } + } + """, description, []); } - protected static async Task AssertContentIsAsync(EditorTestWorkspace workspace, Document document, int position, string expectedDescription, + private static async Task AssertContentIsAsync(EditorTestWorkspace workspace, Document document, int position, string expectedDescription, ImmutableArray relatedSpans) { var info = await GetQuickinfo(workspace, document, position); @@ -183,7 +183,7 @@ protected static async Task AssertContentIsAsync(EditorTestWorkspace workspace, Assert.NotNull(description); Assert.Equal(expectedDescription, description.Text); Assert.Collection(relatedSpans, - info.RelatedSpans.Select(actualSpan => new Action(expectedSpan => Assert.Equal(expectedSpan, actualSpan))).ToArray()); + [.. info.RelatedSpans.Select(actualSpan => new Action(expectedSpan => Assert.Equal(expectedSpan, actualSpan)))]); } private static async Task GetQuickinfo(EditorTestWorkspace workspace, Document document, int position) @@ -194,22 +194,20 @@ private static async Task GetQuickinfo(EditorTestWorkspace worksp return info; } - protected static async Task AssertNoContentAsync(EditorTestWorkspace workspace, Document document, int position) + private static async Task AssertNoContentAsync(EditorTestWorkspace workspace, Document document, int position) { var info = await GetQuickinfo(workspace, document, position); Assert.Null(info); } - protected static async Task TestAsync( + private static async Task TestAsync( string code, string expectedDescription, ImmutableArray relatedSpans, CSharpParseOptions parseOptions = null) { using var workspace = EditorTestWorkspace.CreateCSharp(code, parseOptions); - var analyzerReference = new AnalyzerImageReference(ImmutableArray.Create( - new CSharpCompilerDiagnosticAnalyzer(), - new CSharpRemoveUnusedMembersDiagnosticAnalyzer())); + var analyzerReference = new AnalyzerImageReference([new CSharpCompilerDiagnosticAnalyzer(), new CSharpRemoveUnusedMembersDiagnosticAnalyzer()]); workspace.TryApplyChanges(workspace.CurrentSolution.WithAnalyzerReferences([analyzerReference])); var testDocument = workspace.Documents.Single(); @@ -237,16 +235,16 @@ private static string GetFormattedIDEAnalyzerTitle(int ideDiagnosticId, string n return $"IDE{ideDiagnosticId:0000}: {localizable}"; } - protected static Task TestInClassAsync(string code, string expectedDescription, params TextSpan[] relatedSpans) + private static Task TestInClassAsync(string code, string expectedDescription, params TextSpan[] relatedSpans) => TestAsync( $$""" class C { {{code}} } - """, expectedDescription, relatedSpans.ToImmutableArray()); + """, expectedDescription, [.. relatedSpans]); - protected static Task TestInMethodAsync(string code, string expectedDescription, params TextSpan[] relatedSpans) + private static Task TestInMethodAsync(string code, string expectedDescription, params TextSpan[] relatedSpans) => TestInClassAsync( $$""" void M() diff --git a/src/EditorFeatures/CSharpTest/QuickInfo/SemanticQuickInfoSourceTests.cs b/src/EditorFeatures/CSharpTest/QuickInfo/SemanticQuickInfoSourceTests.cs index e6fc8b85e3e7e..f4c7b4efab924 100644 --- a/src/EditorFeatures/CSharpTest/QuickInfo/SemanticQuickInfoSourceTests.cs +++ b/src/EditorFeatures/CSharpTest/QuickInfo/SemanticQuickInfoSourceTests.cs @@ -6240,7 +6240,7 @@ void goo() """; - await VerifyWithReferenceWorkerAsync(markup, new[] { MainDescription($"({FeaturesResources.field}) int C.x"), Usage("") }); + await VerifyWithReferenceWorkerAsync(markup, [MainDescription($"({FeaturesResources.field}) int C.x"), Usage("")]); } [Fact] @@ -6276,7 +6276,7 @@ void goo() {FeaturesResources.You_can_use_the_navigation_bar_to_switch_contexts} """, expectsWarningGlyph: true); - await VerifyWithReferenceWorkerAsync(markup, new[] { expectedDescription }); + await VerifyWithReferenceWorkerAsync(markup, [expectedDescription]); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/37097")] @@ -6312,7 +6312,7 @@ void goo() {FeaturesResources.You_can_use_the_navigation_bar_to_switch_contexts} """, expectsWarningGlyph: true); - await VerifyWithReferenceWorkerAsync(markup, new[] { expectedDescription }); + await VerifyWithReferenceWorkerAsync(markup, [expectedDescription]); } [Fact] @@ -6354,7 +6354,7 @@ void goo() """, expectsWarningGlyph: true); - await VerifyWithReferenceWorkerAsync(markup, new[] { expectedDescription }); + await VerifyWithReferenceWorkerAsync(markup, [expectedDescription]); } [Fact] @@ -6395,7 +6395,7 @@ void goo() {FeaturesResources.You_can_use_the_navigation_bar_to_switch_contexts} """, expectsWarningGlyph: true); - await VerifyWithReferenceWorkerAsync(markup, new[] { expectedDescription }); + await VerifyWithReferenceWorkerAsync(markup, [expectedDescription]); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/962353")] @@ -6450,7 +6450,7 @@ void M() """; - await VerifyWithReferenceWorkerAsync(markup, new[] { MainDescription($"({FeaturesResources.local_variable}) int x"), Usage("") }); + await VerifyWithReferenceWorkerAsync(markup, [MainDescription($"({FeaturesResources.local_variable}) int x"), Usage("")]); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1020944")] @@ -6480,13 +6480,13 @@ void M() """; - await VerifyWithReferenceWorkerAsync(markup, new[] { MainDescription($"({FeaturesResources.local_variable}) int x"), Usage($""" + await VerifyWithReferenceWorkerAsync(markup, [MainDescription($"({FeaturesResources.local_variable}) int x"), Usage($""" {string.Format(FeaturesResources._0_1, "Proj1", FeaturesResources.Available)} {string.Format(FeaturesResources._0_1, "Proj2", FeaturesResources.Not_Available)} {FeaturesResources.You_can_use_the_navigation_bar_to_switch_contexts} - """, expectsWarningGlyph: true) }); + """, expectsWarningGlyph: true)]); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1020944")] @@ -6512,7 +6512,7 @@ void M() """; - await VerifyWithReferenceWorkerAsync(markup, new[] { MainDescription($"({FeaturesResources.label}) LABEL"), Usage("") }); + await VerifyWithReferenceWorkerAsync(markup, [MainDescription($"({FeaturesResources.label}) LABEL"), Usage("")]); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1020944")] @@ -6539,7 +6539,7 @@ void M() """; - await VerifyWithReferenceWorkerAsync(markup, new[] { MainDescription($"({FeaturesResources.range_variable}) int y"), Usage("") }); + await VerifyWithReferenceWorkerAsync(markup, [MainDescription($"({FeaturesResources.range_variable}) int y"), Usage("")]); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1019766")] @@ -8368,7 +8368,7 @@ await TestWithOptionsAsync(TestOptions.Regular8, Documentation("A generic method T."), item => Assert.Equal( item.Sections.First(section => section.Kind == QuickInfoSectionKinds.DocumentationComments).TaggedParts.Select(p => p.Tag).ToArray(), - new[] { "Text", "Space", "TypeParameter", "Text" })); + ["Text", "Space", "TypeParameter", "Text"])); } [Fact] @@ -10144,8 +10144,8 @@ public async Task TestAnonymousType() """; var description = $"string 'a.@string {{ get; }}"; - await VerifyWithMscorlib45Async(markup, new[] - { + await VerifyWithMscorlib45Async(markup, + [ MainDescription(description), AnonymousTypes( $$""" @@ -10153,7 +10153,7 @@ await VerifyWithMscorlib45Async(markup, new[] {{FeaturesResources.Types_colon}} 'a {{FeaturesResources.is_}} new { string @string } """) - }); + ]); } [Theory, CombinatorialData] diff --git a/src/EditorFeatures/CSharpTest/SignatureHelp/AttributeSignatureHelpProviderTests.cs b/src/EditorFeatures/CSharpTest/SignatureHelp/AttributeSignatureHelpProviderTests.cs index 9e6969a7ce52f..bcdde03575248 100644 --- a/src/EditorFeatures/CSharpTest/SignatureHelp/AttributeSignatureHelpProviderTests.cs +++ b/src/EditorFeatures/CSharpTest/SignatureHelp/AttributeSignatureHelpProviderTests.cs @@ -335,7 +335,7 @@ class D var expectedOrderedItems = new List { - new SignatureHelpTestItem($"SomethingAttribute({CSharpFeaturesResources.Properties}: [goo = int])", string.Empty, string.Empty, currentParameterIndex: 0) + new SignatureHelpTestItem($"SomethingAttribute({FeaturesResources.Properties}: [goo = int])", string.Empty, string.Empty, currentParameterIndex: 0) }; await TestAsync(markup, expectedOrderedItems, usePreviousCharAsTrigger: false); @@ -432,7 +432,7 @@ class D var expectedOrderedItems = new List { - new SignatureHelpTestItem($"SomethingAttribute({CSharpFeaturesResources.Properties}: [goo = int])", string.Empty, string.Empty, currentParameterIndex: 0) + new SignatureHelpTestItem($"SomethingAttribute({FeaturesResources.Properties}: [goo = int])", string.Empty, string.Empty, currentParameterIndex: 0) }; // TODO: Bug 12319: Enable tests for script when this is fixed. @@ -580,7 +580,7 @@ class C var expectedOrderedItems = new List { - new SignatureHelpTestItem($"DerivedAttribute({CSharpFeaturesResources.Properties}: [Name = string])", string.Empty, string.Empty, currentParameterIndex: 0) + new SignatureHelpTestItem($"DerivedAttribute({FeaturesResources.Properties}: [Name = string])", string.Empty, string.Empty, currentParameterIndex: 0) }; await TestAsync(markup, expectedOrderedItems, usePreviousCharAsTrigger: false); @@ -612,7 +612,7 @@ class D var expectedOrderedItems = new List { - new SignatureHelpTestItem($"SomethingAttribute([int goo = 0], [string bar = null], {CSharpFeaturesResources.Properties}: [fieldbar = string], [fieldfoo = int])", string.Empty, "GooParameter", currentParameterIndex: 0) + new SignatureHelpTestItem($"SomethingAttribute([int goo = 0], [string bar = null], {FeaturesResources.Properties}: [fieldbar = string], [fieldfoo = int])", string.Empty, "GooParameter", currentParameterIndex: 0) }; // TODO: Bug 12319: Enable tests for script when this is fixed. @@ -641,7 +641,7 @@ class D var expectedOrderedItems = new List { - new SignatureHelpTestItem($"SomethingAttribute([int goo = 0], [string bar = null], {CSharpFeaturesResources.Properties}: [fieldbar = string], [fieldfoo = int])", string.Empty, "BarParameter", currentParameterIndex: 1) + new SignatureHelpTestItem($"SomethingAttribute([int goo = 0], [string bar = null], {FeaturesResources.Properties}: [fieldbar = string], [fieldfoo = int])", string.Empty, "BarParameter", currentParameterIndex: 1) }; // TODO: Bug 12319: Enable tests for script when this is fixed. @@ -670,7 +670,7 @@ class D var expectedOrderedItems = new List { - new SignatureHelpTestItem($"SomethingAttribute([int goo = 0], [string bar = null], {CSharpFeaturesResources.Properties}: [fieldbar = string], [fieldfoo = int])", string.Empty, string.Empty, currentParameterIndex: 2) + new SignatureHelpTestItem($"SomethingAttribute([int goo = 0], [string bar = null], {FeaturesResources.Properties}: [fieldbar = string], [fieldfoo = int])", string.Empty, string.Empty, currentParameterIndex: 2) }; // TODO: Bug 12319: Enable tests for script when this is fixed. @@ -697,7 +697,7 @@ class D var expectedOrderedItems = new List { - new SignatureHelpTestItem($"SomethingAttribute([int goo = 0], {CSharpFeaturesResources.Properties}: [goo = int])", string.Empty, "GooParameter", currentParameterIndex: 0) + new SignatureHelpTestItem($"SomethingAttribute([int goo = 0], {FeaturesResources.Properties}: [goo = int])", string.Empty, "GooParameter", currentParameterIndex: 0) }; // TODO: Bug 12319: Enable tests for script when this is fixed. @@ -724,7 +724,7 @@ class D var expectedOrderedItems = new List { - new SignatureHelpTestItem($"SomethingAttribute([int goo = 0], {CSharpFeaturesResources.Properties}: [goo = int])", string.Empty, string.Empty, currentParameterIndex: 1) + new SignatureHelpTestItem($"SomethingAttribute([int goo = 0], {FeaturesResources.Properties}: [goo = int])", string.Empty, string.Empty, currentParameterIndex: 1) }; // TODO: Bug 12319: Enable tests for script when this is fixed. diff --git a/src/EditorFeatures/CSharpTest/StringCopyPaste/StringCopyPasteCommandHandlerTests.cs b/src/EditorFeatures/CSharpTest/StringCopyPaste/StringCopyPasteCommandHandlerTests.cs index ffc75f5374580..faec3d3367b79 100644 --- a/src/EditorFeatures/CSharpTest/StringCopyPaste/StringCopyPasteCommandHandlerTests.cs +++ b/src/EditorFeatures/CSharpTest/StringCopyPaste/StringCopyPasteCommandHandlerTests.cs @@ -123,7 +123,7 @@ public void TestCopyPaste(string expectedMarkup, string? pasteText, bool pasteTe { // we were given text to directly place on the clipboard without needing to do a copy. Contract.ThrowIfNull(pasteText); - var json = new StringCopyPasteData(ImmutableArray.Create(StringCopyPasteContent.ForText(pasteText))).ToJson(); + var json = new StringCopyPasteData([StringCopyPasteContent.ForText(pasteText)]).ToJson(); Contract.ThrowIfNull(json); service!.TrySetClipboardData(StringCopyPasteCommandHandler.KeyAndVersion, json); } diff --git a/src/EditorFeatures/CSharpTest/SymbolKey/SymbolKeyMetadataVsSourceTests.cs b/src/EditorFeatures/CSharpTest/SymbolKey/SymbolKeyMetadataVsSourceTests.cs index c7c42b2a38239..b53ab6555d20a 100644 --- a/src/EditorFeatures/CSharpTest/SymbolKey/SymbolKeyMetadataVsSourceTests.cs +++ b/src/EditorFeatures/CSharpTest/SymbolKey/SymbolKeyMetadataVsSourceTests.cs @@ -150,7 +150,7 @@ static void EH(AN.S s) { } // --------------------------- // Source symbols var originalSymbols = GetSourceSymbols(comp1, SymbolCategory.NonTypeMember | SymbolCategory.Parameter).ToList(); - originalSymbols = originalSymbols.Where(s => !s.IsAccessor() && s.Kind != SymbolKind.Parameter).OrderBy(s => s.Name).Select(s => s).ToList(); + originalSymbols = [.. originalSymbols.Where(s => !s.IsAccessor() && s.Kind != SymbolKind.Parameter).OrderBy(s => s.Name).Select(s => s)]; Assert.Equal(8, originalSymbols.Count); // --------------------------- diff --git a/src/EditorFeatures/CSharpTest/TextStructureNavigation/TextStructureNavigatorTests.cs b/src/EditorFeatures/CSharpTest/TextStructureNavigation/TextStructureNavigatorTests.cs index 317fcf9c14b28..89159b427b39f 100644 --- a/src/EditorFeatures/CSharpTest/TextStructureNavigation/TextStructureNavigatorTests.cs +++ b/src/EditorFeatures/CSharpTest/TextStructureNavigation/TextStructureNavigatorTests.cs @@ -18,7 +18,7 @@ namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.TextStructureNavigation [UseExportProvider] [Trait(Traits.Feature, Traits.Features.TextStructureNavigator)] -public class TextStructureNavigatorTests : AbstractTextStructureNavigatorTests +public sealed class TextStructureNavigatorTests : AbstractTextStructureNavigatorTests { protected override string ContentType => ContentTypeNames.CSharpContentType; @@ -28,27 +28,27 @@ protected override EditorTestWorkspace CreateWorkspace(string code) [Fact] public void Empty() { - AssertExtent("$${|Insignificant:|}"); + AssertExtent("""$${|Insignificant:|}"""); } [WpfFact] public void Whitespace() { AssertExtent( - "$${|Insignificant: |}"); + """$${|Insignificant: |}"""); AssertExtent( - "{|Insignificant: $$ |}"); + """{|Insignificant: $$ |}"""); AssertExtent( - "{|Insignificant: $$|}"); + """{|Insignificant: $$|}"""); } [WpfFact] public void EndOfFile() { AssertExtent( - "using System{|Significant:;|}$$"); + """using System{|Significant:;|}$$"""); } [Fact] @@ -72,249 +72,229 @@ class Class1 { public void SingleLineComment() { AssertExtent( - "$${|Significant:// Comment |}"); + """$${|Significant:// Comment |}"""); // It is important that this returns just the comment banner. Returning the whole comment // means Ctrl+Right before the slash will cause it to jump across the entire comment AssertExtent( - "{|Significant:/$$/|} Comment "); + """{|Significant:/$$/|} Comment """); AssertExtent( - "// {|Significant:Co$$mment|} "); + """// {|Significant:Co$$mment|} """); AssertExtent( - "// {|Significant:($$)|} test"); + """// {|Significant:($$)|} test"""); } [WpfFact] public void MultiLineComment() { AssertExtent( - @"{|Significant:$$/* Comment */|}"); + """{|Significant:$$/* Comment */|}"""); // It is important that this returns just the comment banner. Returning the whole comment // means Ctrl+Right before the slash will cause it to jump across the entire comment AssertExtent( - @"{|Significant:/$$*|} Comment */"); + """{|Significant:/$$*|} Comment */"""); AssertExtent( - @"/* {|Significant:Co$$mment|} */"); + """/* {|Significant:Co$$mment|} */"""); AssertExtent( - @"/* {|Significant:($$)|} test */"); + """/* {|Significant:($$)|} test */"""); AssertExtent( - @"/* () test {|Significant:$$*/|}"); + """/* () test {|Significant:$$*/|}"""); // It is important that this returns just the comment banner. Returning the whole comment // means Ctrl+Left after the slash will cause it to jump across the entire comment AssertExtent( - @"/* () test {|Significant:*$$/|}"); + """/* () test {|Significant:*$$/|}"""); AssertExtent( - @"/* () test {|Significant:*/|}$$"); + """/* () test {|Significant:*/|}$$"""); } [WpfFact] public void Keyword() { AssertExtent( - @"public {|Significant:$$class|} Class1"); + """public {|Significant:$$class|} Class1"""); AssertExtent( - @"public {|Significant:c$$lass|} Class1"); + """public {|Significant:c$$lass|} Class1"""); AssertExtent( - @"public {|Significant:cl$$ass|} Class1"); + """public {|Significant:cl$$ass|} Class1"""); AssertExtent( - @"public {|Significant:cla$$ss|} Class1"); + """public {|Significant:cla$$ss|} Class1"""); AssertExtent( - @"public {|Significant:clas$$s|} Class1"); + """public {|Significant:clas$$s|} Class1"""); } [WpfFact] public void Identifier() { AssertExtent( - @"public class {|Significant:$$SomeClass|} : IDisposable"); + """public class {|Significant:$$SomeClass|} : IDisposable"""); AssertExtent( - @"public class {|Significant:S$$omeClass|} : IDisposable"); + """public class {|Significant:S$$omeClass|} : IDisposable"""); AssertExtent( - @"public class {|Significant:So$$meClass|} : IDisposable"); + """public class {|Significant:So$$meClass|} : IDisposable"""); AssertExtent( - @"public class {|Significant:Som$$eClass|} : IDisposable"); + """public class {|Significant:Som$$eClass|} : IDisposable"""); AssertExtent( - @"public class {|Significant:Some$$Class|} : IDisposable"); + """public class {|Significant:Some$$Class|} : IDisposable"""); AssertExtent( - @"public class {|Significant:SomeC$$lass|} : IDisposable"); + """public class {|Significant:SomeC$$lass|} : IDisposable"""); AssertExtent( - @"public class {|Significant:SomeCl$$ass|} : IDisposable"); + """public class {|Significant:SomeCl$$ass|} : IDisposable"""); AssertExtent( - @"public class {|Significant:SomeCla$$ss|} : IDisposable"); + """public class {|Significant:SomeCla$$ss|} : IDisposable"""); AssertExtent( - @"public class {|Significant:SomeClas$$s|} : IDisposable"); + """public class {|Significant:SomeClas$$s|} : IDisposable"""); } [WpfFact] public void EscapedIdentifier() { AssertExtent( - @"public enum {|Significant:$$@interface|} : int"); + """public enum {|Significant:$$@interface|} : int"""); AssertExtent( - @"public enum {|Significant:@$$interface|} : int"); + """public enum {|Significant:@$$interface|} : int"""); AssertExtent( - @"public enum {|Significant:@i$$nterface|} : int"); + """public enum {|Significant:@i$$nterface|} : int"""); AssertExtent( - @"public enum {|Significant:@in$$terface|} : int"); + """public enum {|Significant:@in$$terface|} : int"""); AssertExtent( - @"public enum {|Significant:@int$$erface|} : int"); + """public enum {|Significant:@int$$erface|} : int"""); AssertExtent( - @"public enum {|Significant:@inte$$rface|} : int"); + """public enum {|Significant:@inte$$rface|} : int"""); AssertExtent( - @"public enum {|Significant:@inter$$face|} : int"); + """public enum {|Significant:@inter$$face|} : int"""); AssertExtent( - @"public enum {|Significant:@interf$$ace|} : int"); + """public enum {|Significant:@interf$$ace|} : int"""); AssertExtent( - @"public enum {|Significant:@interfa$$ce|} : int"); + """public enum {|Significant:@interfa$$ce|} : int"""); AssertExtent( - @"public enum {|Significant:@interfac$$e|} : int"); + """public enum {|Significant:@interfac$$e|} : int"""); } [WpfFact] public void Number() { AssertExtent( - @"class Test { private double num = -{|Significant:$$1.234678e10|}; }"); + """class Test { private double num = -{|Significant:$$1.234678e10|}; }"""); AssertExtent( - @"class Test { private double num = -{|Significant:1$$.234678e10|}; }"); + """class Test { private double num = -{|Significant:1$$.234678e10|}; }"""); AssertExtent( - @"class Test { private double num = -{|Significant:1.$$234678e10|}; }"); + """class Test { private double num = -{|Significant:1.$$234678e10|}; }"""); AssertExtent( - @"class Test { private double num = -{|Significant:1.2$$34678e10|}; }"); + """class Test { private double num = -{|Significant:1.2$$34678e10|}; }"""); AssertExtent( - @"class Test { private double num = -{|Significant:1.23$$4678e10|}; }"); + """class Test { private double num = -{|Significant:1.23$$4678e10|}; }"""); AssertExtent( - @"class Test { private double num = -{|Significant:1.234$$678e10|}; }"); + """class Test { private double num = -{|Significant:1.234$$678e10|}; }"""); AssertExtent( - @"class Test { private double num = -{|Significant:1.2346$$78e10|}; }"); + """class Test { private double num = -{|Significant:1.2346$$78e10|}; }"""); AssertExtent( - @"class Test { private double num = -{|Significant:1.23467$$8e10|}; }"); + """class Test { private double num = -{|Significant:1.23467$$8e10|}; }"""); AssertExtent( - @"class Test { private double num = -{|Significant:1.234678$$e10|}; }"); + """class Test { private double num = -{|Significant:1.234678$$e10|}; }"""); AssertExtent( - @"class Test { private double num = -{|Significant:1.234678e$$10|}; }"); + """class Test { private double num = -{|Significant:1.234678e$$10|}; }"""); AssertExtent( - @"class Test { private double num = -{|Significant:1.234678e1$$0|}; }"); + """class Test { private double num = -{|Significant:1.234678e1$$0|}; }"""); } - [WpfFact] - public void String() + [WpfTheory] + [InlineData("""class Test { private string s1 = {|Significant:$$"|} () test "; }""")] + [InlineData("""class Test { private string s1 = "{|Insignificant:$$ |}() test "; }""")] + [InlineData("""class Test { private string s1 = " {|Significant:$$()|} test "; }""")] + [InlineData("""class Test { private string s1 = " () test{|Insignificant:$$ |}"; }""")] + [InlineData("""class Test { private string s1 = " () test {|Significant:$$"|}; }""")] + [InlineData("""class Test { private string s1 = " () test "{|Significant:$$;|} }""")] + public void String(string content) { - AssertExtent( - @"class Test { private string s1 = {|Significant:$$""|} () test ""; }"); - - AssertExtent( - @"class Test { private string s1 = ""{|Insignificant:$$ |}() test ""; }"); - - AssertExtent( - @"class Test { private string s1 = "" {|Significant:$$()|} test ""; }"); - - AssertExtent( - @"class Test { private string s1 = "" () test{|Insignificant:$$ |}""; }"); - - AssertExtent( - @"class Test { private string s1 = "" () test {|Significant:$$""|}; }"); - - AssertExtent( - @"class Test { private string s1 = "" () test ""{|Significant:$$;|} }"); + AssertExtent(content); } - [WpfFact] - public void Utf8String() + [WpfTheory] + [InlineData("""class Test { private string s1 = {|Significant:$$"|} () test "u8; }""")] + [InlineData("""class Test { private string s1 = "{|Insignificant:$$ |}() test "u8; }""")] + [InlineData("""class Test { private string s1 = " {|Significant:$$()|} test "u8; }""")] + [InlineData("""class Test { private string s1 = " () test{|Insignificant:$$ |}"u8; }""")] + [InlineData("""class Test { private string s1 = " () test {|Significant:$$"u8|}; }""")] + [InlineData("""class Test { private string s1 = " () test "u8{|Significant:$$;|} }""")] + public void Utf8String(string content) { - AssertExtent( - @"class Test { private string s1 = {|Significant:$$""|} () test ""u8; }"); - - AssertExtent( - @"class Test { private string s1 = ""{|Insignificant:$$ |}() test ""u8; }"); - - AssertExtent( - @"class Test { private string s1 = "" {|Significant:$$()|} test ""u8; }"); - - AssertExtent( - @"class Test { private string s1 = "" () test{|Insignificant:$$ |}""u8; }"); - - AssertExtent( - @"class Test { private string s1 = "" () test {|Significant:$$""u8|}; }"); - - AssertExtent( - @"class Test { private string s1 = "" () test ""u8{|Significant:$$;|} }"); + AssertExtent(content); } [WpfFact] public void InterpolatedString1() { AssertExtent( - @"class Test { string x = ""hello""; string s = {|Significant:$$$""|} { x } hello""; }"); + """class Test { string x = "hello"; string s = {|Significant:$$$"|} { x } hello"; }"""); AssertExtent( - @"class Test { string x = ""hello""; string s = $""{|Insignificant:$$ |}{ x } hello""; }"); + """class Test { string x = "hello"; string s = $"{|Insignificant:$$ |}{ x } hello"; }"""); AssertExtent( - @"class Test { string x = ""hello""; string s = $"" {|Significant:$${|} x } hello""; }"); + """class Test { string x = "hello"; string s = $" {|Significant:$${|} x } hello"; }"""); AssertExtent( - @"class Test { string x = ""hello""; string s = $"" {{|Insignificant:$$ |}x } hello""; }"); + """class Test { string x = "hello"; string s = $" {{|Insignificant:$$ |}x } hello"; }"""); AssertExtent( - @"class Test { string x = ""hello""; string s = $"" { {|Significant:$$x|} } hello""; }"); + """class Test { string x = "hello"; string s = $" { {|Significant:$$x|} } hello"; }"""); AssertExtent( - @"class Test { string x = ""hello""; string s = $"" { x{|Insignificant:$$ |}} hello""; }"); + """class Test { string x = "hello"; string s = $" { x{|Insignificant:$$ |}} hello"; }"""); AssertExtent( - @"class Test { string x = ""hello""; string s = $"" { x {|Significant:$$}|} hello""; }"); + """class Test { string x = "hello"; string s = $" { x {|Significant:$$}|} hello"; }"""); AssertExtent( - @"class Test { string x = ""hello""; string s = $"" { x }{|Insignificant:$$ |}hello""; }"); + """class Test { string x = "hello"; string s = $" { x }{|Insignificant:$$ |}hello"; }"""); AssertExtent( - @"class Test { string x = ""hello""; string s = $"" { x } {|Significant:$$hello|}""; }"); + """class Test { string x = "hello"; string s = $" { x } {|Significant:$$hello|}"; }"""); AssertExtent( - @"class Test { string x = ""hello""; string s = $"" { x } hello{|Significant:$$""|}; }"); + """class Test { string x = "hello"; string s = $" { x } hello{|Significant:$$"|}; }"""); } - [WpfFact, WorkItem("https://github.com/dotnet/roslyn/issues/59581")] + [WpfFact, WorkItem("""https://github.com/dotnet/roslyn/issues/59581""")] public void TestRawStringContent() { AssertExtent( @@ -372,115 +352,110 @@ public void TestRawStringContent() """"); } - [WpfFact, WorkItem("https://github.com/dotnet/roslyn/issues/59581")] - public void TestRawStringDelimeter1() + [WpfTheory, WorkItem("""https://github.com/dotnet/roslyn/issues/59581""")] + [InlineData( + """" + string s = {|Significant:$$"""|} + Hello + World! + :) + """; + """")] + [InlineData( + """" + string s = {|Significant:"$$""|} + Hello + World! + :) + """; + """")] + [InlineData( + """" + string s = {|Significant:""$$"|} + Hello + World! + :) + """; + """")] + public void TestRawStringDelimiter1(string content) { - AssertExtent( - """" - string s = {|Significant:$$"""|} - Hello - World! - :) - """; - """"); - - AssertExtent( - """" - string s = {|Significant:"$$""|} - Hello - World! - :) - """; - """"); - - AssertExtent( - """" - string s = {|Significant:""$$"|} - Hello - World! - :) - """; - """"); + AssertExtent(content); } - [WpfFact, WorkItem("https://github.com/dotnet/roslyn/issues/59581")] - public void TestRawStringDelimeter2() + [WpfTheory, WorkItem("""https://github.com/dotnet/roslyn/issues/59581""")] + [InlineData( + """" + string s = """ + Hello + World! + :) + {|Significant:$$"""|}; + """")] + [InlineData( + """" + string s = """ + Hello + World! + :) + {|Significant:"$$""|}; + """")] + [InlineData( + """" + string s = """ + Hello + World! + :) + {|Significant:""$$"|}; + """")] + public void TestRawStringDelimiter2(string content) { - AssertExtent( - """" - string s = """ - Hello - World! - :) - {|Significant:$$"""|}; - """"); - - AssertExtent( - """" - string s = """ - Hello - World! - :) - {|Significant:"$$""|}; - """"); - - AssertExtent( - """" - string s = """ - Hello - World! - :) - {|Significant:""$$"|}; - """"); + AssertExtent(content); } - [WpfFact] - public void TestUtf8RawStringDelimeter() + [WpfTheory] + [InlineData( + """" + string s = """ + Hello + World! + :) + {|Significant:$$"""u8|}; + """")] + [InlineData( + """" + string s = """ + Hello + World! + :) + {|Significant:"$$""u8|}; + """")] + [InlineData( + """" + string s = """ + Hello + World! + :) + {|Significant:""$$"u8|}; + """")] + [InlineData( + """" + string s = """ + Hello + World! + :) + {|Significant:"""$$u8|}; + """")] + [InlineData( + """" + string s = """ + Hello + World! + :) + {|Significant:"""u$$8|}; + """")] + public void TestUtf8RawStringDelimiter(string content) { - AssertExtent( - """" - string s = """ - Hello - World! - :) - {|Significant:$$"""u8|}; - """"); - - AssertExtent( - """" - string s = """ - Hello - World! - :) - {|Significant:"$$""u8|}; - """"); - - AssertExtent( - """" - string s = """ - Hello - World! - :) - {|Significant:""$$"u8|}; - """"); - - AssertExtent( -"""" -string s = """ - Hello - World! - :) - {|Significant:"""$$u8|}; -""""); - - AssertExtent( -"""" -string s = """ - Hello - World! - :) - {|Significant:"""u$$8|}; -""""); + AssertExtent(content); } private static void TestNavigator( @@ -522,15 +497,15 @@ public void GetSpanOfEnclosingTest() { // First operation returns span of 'Class1' TestNavigator( -@"class Class1 { }", (n, s) => n.GetSpanOfEnclosing(s), 10, 0, 6, 6); + """class Class1 { }""", (n, s) => n.GetSpanOfEnclosing(s), 10, 0, 6, 6); // Second operation returns span of 'class Class1 { }' TestNavigator( -@"class Class1 { }", (n, s) => n.GetSpanOfEnclosing(s), 6, 6, 0, 16); + """class Class1 { }""", (n, s) => n.GetSpanOfEnclosing(s), 6, 6, 0, 16); // Last operation does nothing TestNavigator( -@"class Class1 { }", (n, s) => n.GetSpanOfEnclosing(s), 0, 16, 0, 16); + """class Class1 { }""", (n, s) => n.GetSpanOfEnclosing(s), 0, 16, 0, 16); } [WpfFact] @@ -570,6 +545,20 @@ public void GetSpanOfPreviousSiblingTest() { // Go from '{' to 'Class1' TestNavigator( -@"class Class1 { }", (n, s) => n.GetSpanOfPreviousSibling(s), 13, 1, 6, 6); + """class Class1 { }""", (n, s) => n.GetSpanOfPreviousSibling(s), 13, 1, 6, 6); + } + + [WpfTheory] + [InlineData("""Console.WriteLine("{|Significant:$$=============|}");""")] + [InlineData("""Console.WriteLine("{|Significant:=$$============|}");""")] + [InlineData("""Console.WriteLine("{|Significant:$$=============|}"u8);""")] + [InlineData("""Console.WriteLine("{|Significant:=$$============|}"u8);""")] + [InlineData(""""Console.WriteLine("""{|Significant:$$=============|}""");"""")] + [InlineData(""""Console.WriteLine("""{|Significant:=$$============|}""");"""")] + [InlineData(""""Console.WriteLine("""{|Significant:$$=============|}"""u8);"""")] + [InlineData(""""Console.WriteLine("""{|Significant:=$$============|}"""u8);"""")] + public void TestClampStringLiteral(string content) + { + AssertExtent(content); } } diff --git a/src/EditorFeatures/CSharpTest2/Recommendations/AbstractKeywordRecommenderTests.cs b/src/EditorFeatures/CSharpTest2/Recommendations/AbstractKeywordRecommenderTests.cs index 023bdb25ac4cc..cf2736a2be179 100644 --- a/src/EditorFeatures/CSharpTest2/Recommendations/AbstractKeywordRecommenderTests.cs +++ b/src/EditorFeatures/CSharpTest2/Recommendations/AbstractKeywordRecommenderTests.cs @@ -30,9 +30,9 @@ class C { } } [Fact] - public async Task TestAfterGlobalStatement_Interactive() + public async Task TestAfterGlobalStatement() { - await VerifyKeywordAsync(SourceCodeKind.Script, + await VerifyKeywordAsync( """ System.Console.WriteLine(); $$ diff --git a/src/EditorFeatures/CSharpTest2/Recommendations/CharKeywordRecommenderTests.cs b/src/EditorFeatures/CSharpTest2/Recommendations/CharKeywordRecommenderTests.cs index f219d8ccc36c6..828bcdaa9fd06 100644 --- a/src/EditorFeatures/CSharpTest2/Recommendations/CharKeywordRecommenderTests.cs +++ b/src/EditorFeatures/CSharpTest2/Recommendations/CharKeywordRecommenderTests.cs @@ -29,9 +29,9 @@ class C { } } [Fact, Trait(Traits.Feature, Traits.Features.KeywordRecommending)] - public async Task TestAfterGlobalStatement_Interactive() + public async Task TestAfterGlobalStatement() { - await VerifyKeywordAsync(SourceCodeKind.Script, + await VerifyKeywordAsync( """ System.Console.WriteLine(); $$ diff --git a/src/EditorFeatures/CSharpTest2/Recommendations/CheckedKeywordRecommenderTests.cs b/src/EditorFeatures/CSharpTest2/Recommendations/CheckedKeywordRecommenderTests.cs index 7d88d4a26e39f..30c5953f5ccc6 100644 --- a/src/EditorFeatures/CSharpTest2/Recommendations/CheckedKeywordRecommenderTests.cs +++ b/src/EditorFeatures/CSharpTest2/Recommendations/CheckedKeywordRecommenderTests.cs @@ -30,9 +30,9 @@ class C { } } [Fact] - public async Task TestAfterGlobalStatement_Interactive() + public async Task TestAfterGlobalStatement() { - await VerifyKeywordAsync(SourceCodeKind.Script, + await VerifyKeywordAsync( """ System.Console.WriteLine(); $$ diff --git a/src/EditorFeatures/CSharpTest2/Recommendations/ClassKeywordRecommenderTests.cs b/src/EditorFeatures/CSharpTest2/Recommendations/ClassKeywordRecommenderTests.cs index 1a26be8cdb965..f58aa3947595c 100644 --- a/src/EditorFeatures/CSharpTest2/Recommendations/ClassKeywordRecommenderTests.cs +++ b/src/EditorFeatures/CSharpTest2/Recommendations/ClassKeywordRecommenderTests.cs @@ -30,9 +30,9 @@ class C { } } [Fact] - public async Task TestAfterGlobalStatement_Interactive() + public async Task TestAfterGlobalStatement() { - await VerifyKeywordAsync(SourceCodeKind.Script, + await VerifyKeywordAsync( """ System.Console.WriteLine(); $$ diff --git a/src/EditorFeatures/CSharpTest2/Recommendations/DecimalKeywordRecommenderTests.cs b/src/EditorFeatures/CSharpTest2/Recommendations/DecimalKeywordRecommenderTests.cs index bf5adab380851..fc4ed190203ec 100644 --- a/src/EditorFeatures/CSharpTest2/Recommendations/DecimalKeywordRecommenderTests.cs +++ b/src/EditorFeatures/CSharpTest2/Recommendations/DecimalKeywordRecommenderTests.cs @@ -30,9 +30,9 @@ class C { } } [Fact] - public async Task TestAfterGlobalStatement_Interactive() + public async Task TestAfterGlobalStatement() { - await VerifyKeywordAsync(SourceCodeKind.Script, + await VerifyKeywordAsync( """ System.Console.WriteLine(); $$ diff --git a/src/EditorFeatures/CSharpTest2/Recommendations/DefaultKeywordRecommenderTests.cs b/src/EditorFeatures/CSharpTest2/Recommendations/DefaultKeywordRecommenderTests.cs index edfe87f8ed9fb..ca126f704f9f5 100644 --- a/src/EditorFeatures/CSharpTest2/Recommendations/DefaultKeywordRecommenderTests.cs +++ b/src/EditorFeatures/CSharpTest2/Recommendations/DefaultKeywordRecommenderTests.cs @@ -30,9 +30,9 @@ class C { } } [Fact] - public async Task TestAfterGlobalStatement_Interactive() + public async Task TestAfterGlobalStatement() { - await VerifyKeywordAsync(SourceCodeKind.Script, + await VerifyKeywordAsync( """ System.Console.WriteLine(); $$ diff --git a/src/EditorFeatures/CSharpTest2/Recommendations/DelegateKeywordRecommenderTests.cs b/src/EditorFeatures/CSharpTest2/Recommendations/DelegateKeywordRecommenderTests.cs index 336b240de4c54..c5dd8fa1b50d0 100644 --- a/src/EditorFeatures/CSharpTest2/Recommendations/DelegateKeywordRecommenderTests.cs +++ b/src/EditorFeatures/CSharpTest2/Recommendations/DelegateKeywordRecommenderTests.cs @@ -30,9 +30,9 @@ class C { } } [Fact] - public async Task TestAfterGlobalStatement_Interactive() + public async Task TestAfterGlobalStatement() { - await VerifyKeywordAsync(SourceCodeKind.Script, + await VerifyKeywordAsync( """ System.Console.WriteLine(); $$ diff --git a/src/EditorFeatures/CSharpTest2/Recommendations/DoKeywordRecommenderTests.cs b/src/EditorFeatures/CSharpTest2/Recommendations/DoKeywordRecommenderTests.cs index 7ebf189e44bf2..19abcee0c702f 100644 --- a/src/EditorFeatures/CSharpTest2/Recommendations/DoKeywordRecommenderTests.cs +++ b/src/EditorFeatures/CSharpTest2/Recommendations/DoKeywordRecommenderTests.cs @@ -29,9 +29,9 @@ class C { } } [Fact] - public async Task TestAfterGlobalStatement_Interactive() + public async Task TestAfterGlobalStatement() { - await VerifyKeywordAsync(SourceCodeKind.Script, + await VerifyKeywordAsync( """ System.Console.WriteLine(); $$ diff --git a/src/EditorFeatures/CSharpTest2/Recommendations/DoubleKeywordRecommenderTests.cs b/src/EditorFeatures/CSharpTest2/Recommendations/DoubleKeywordRecommenderTests.cs index 8ae45592d382a..2283d0e9fc4ce 100644 --- a/src/EditorFeatures/CSharpTest2/Recommendations/DoubleKeywordRecommenderTests.cs +++ b/src/EditorFeatures/CSharpTest2/Recommendations/DoubleKeywordRecommenderTests.cs @@ -30,9 +30,9 @@ class C { } } [Fact] - public async Task TestAfterGlobalStatement_Interactive() + public async Task TestAfterGlobalStatement() { - await VerifyKeywordAsync(SourceCodeKind.Script, + await VerifyKeywordAsync( """ System.Console.WriteLine(); $$ diff --git a/src/EditorFeatures/CSharpTest2/Recommendations/DynamicKeywordRecommenderTests.cs b/src/EditorFeatures/CSharpTest2/Recommendations/DynamicKeywordRecommenderTests.cs index a0d71b4a02f43..585d0ab2710fc 100644 --- a/src/EditorFeatures/CSharpTest2/Recommendations/DynamicKeywordRecommenderTests.cs +++ b/src/EditorFeatures/CSharpTest2/Recommendations/DynamicKeywordRecommenderTests.cs @@ -41,9 +41,9 @@ class C { } } [Fact] - public async Task TestAfterGlobalStatement_Interactive() + public async Task TestAfterGlobalStatement() { - await VerifyKeywordAsync(SourceCodeKind.Script, + await VerifyKeywordAsync( """ System.Console.WriteLine(); $$ diff --git a/src/EditorFeatures/CSharpTest2/Recommendations/EnumKeywordRecommenderTests.cs b/src/EditorFeatures/CSharpTest2/Recommendations/EnumKeywordRecommenderTests.cs index 2dc2cead9fa68..7b325f7c6d165 100644 --- a/src/EditorFeatures/CSharpTest2/Recommendations/EnumKeywordRecommenderTests.cs +++ b/src/EditorFeatures/CSharpTest2/Recommendations/EnumKeywordRecommenderTests.cs @@ -29,9 +29,9 @@ class C { } } [Fact] - public async Task TestAfterGlobalStatement_Interactive() + public async Task TestAfterGlobalStatement() { - await VerifyKeywordAsync(SourceCodeKind.Script, + await VerifyKeywordAsync( """ System.Console.WriteLine(); $$ diff --git a/src/EditorFeatures/CSharpTest2/Recommendations/FalseKeywordRecommenderTests.cs b/src/EditorFeatures/CSharpTest2/Recommendations/FalseKeywordRecommenderTests.cs index 2476597a47ade..3819c02a497c1 100644 --- a/src/EditorFeatures/CSharpTest2/Recommendations/FalseKeywordRecommenderTests.cs +++ b/src/EditorFeatures/CSharpTest2/Recommendations/FalseKeywordRecommenderTests.cs @@ -30,9 +30,9 @@ class C { } } [Fact] - public async Task TestAfterGlobalStatement_Interactive() + public async Task TestAfterGlobalStatement() { - await VerifyKeywordAsync(SourceCodeKind.Script, + await VerifyKeywordAsync( """ System.Console.WriteLine(); $$ diff --git a/src/EditorFeatures/CSharpTest2/Recommendations/FloatKeywordRecommenderTests.cs b/src/EditorFeatures/CSharpTest2/Recommendations/FloatKeywordRecommenderTests.cs index f96a90030538d..958a92bfc8de6 100644 --- a/src/EditorFeatures/CSharpTest2/Recommendations/FloatKeywordRecommenderTests.cs +++ b/src/EditorFeatures/CSharpTest2/Recommendations/FloatKeywordRecommenderTests.cs @@ -30,9 +30,9 @@ class C { } } [Fact] - public async Task TestAfterGlobalStatement_Interactive() + public async Task TestAfterGlobalStatement() { - await VerifyKeywordAsync(SourceCodeKind.Script, + await VerifyKeywordAsync( """ System.Console.WriteLine(); $$ diff --git a/src/EditorFeatures/CSharpTest2/Recommendations/ForEachKeywordRecommenderTests.cs b/src/EditorFeatures/CSharpTest2/Recommendations/ForEachKeywordRecommenderTests.cs index 59abfab56cf94..abf1606e11c56 100644 --- a/src/EditorFeatures/CSharpTest2/Recommendations/ForEachKeywordRecommenderTests.cs +++ b/src/EditorFeatures/CSharpTest2/Recommendations/ForEachKeywordRecommenderTests.cs @@ -36,9 +36,9 @@ class C { } } [Fact] - public async Task TestAfterGlobalStatement_Interactive() + public async Task TestAfterGlobalStatement() { - await VerifyKeywordAsync(SourceCodeKind.Script, + await VerifyKeywordAsync( """ System.Console.WriteLine(); $$ diff --git a/src/EditorFeatures/CSharpTest2/Recommendations/ForKeywordRecommenderTests.cs b/src/EditorFeatures/CSharpTest2/Recommendations/ForKeywordRecommenderTests.cs index aff8c4dbfd0d7..98b81a03e0cce 100644 --- a/src/EditorFeatures/CSharpTest2/Recommendations/ForKeywordRecommenderTests.cs +++ b/src/EditorFeatures/CSharpTest2/Recommendations/ForKeywordRecommenderTests.cs @@ -29,9 +29,9 @@ class C { } } [Fact] - public async Task TestAfterGlobalStatement_Interactive() + public async Task TestAfterGlobalStatement() { - await VerifyKeywordAsync(SourceCodeKind.Script, + await VerifyKeywordAsync( """ System.Console.WriteLine(); $$ diff --git a/src/EditorFeatures/CSharpTest2/Recommendations/FromKeywordRecommenderTests.cs b/src/EditorFeatures/CSharpTest2/Recommendations/FromKeywordRecommenderTests.cs index 7d645977af57a..33ecc4499c51a 100644 --- a/src/EditorFeatures/CSharpTest2/Recommendations/FromKeywordRecommenderTests.cs +++ b/src/EditorFeatures/CSharpTest2/Recommendations/FromKeywordRecommenderTests.cs @@ -30,9 +30,9 @@ class C { } } [Fact] - public async Task TestAfterGlobalStatement_Interactive() + public async Task TestAfterGlobalStatement() { - await VerifyKeywordAsync(SourceCodeKind.Script, + await VerifyKeywordAsync( """ System.Console.WriteLine(); $$ diff --git a/src/EditorFeatures/CSharpTest2/Recommendations/GotoKeywordRecommenderTests.cs b/src/EditorFeatures/CSharpTest2/Recommendations/GotoKeywordRecommenderTests.cs index f33464dea0e74..e6623203061c6 100644 --- a/src/EditorFeatures/CSharpTest2/Recommendations/GotoKeywordRecommenderTests.cs +++ b/src/EditorFeatures/CSharpTest2/Recommendations/GotoKeywordRecommenderTests.cs @@ -29,9 +29,9 @@ class C { } } [Fact] - public async Task TestAfterGlobalStatement_Interactive() + public async Task TestAfterGlobalStatement() { - await VerifyKeywordAsync(SourceCodeKind.Script, + await VerifyKeywordAsync( """ System.Console.WriteLine(); $$ diff --git a/src/EditorFeatures/CSharpTest2/Recommendations/IfKeywordRecommenderTests.cs b/src/EditorFeatures/CSharpTest2/Recommendations/IfKeywordRecommenderTests.cs index d8ba60bea0f1b..1d28be82fd594 100644 --- a/src/EditorFeatures/CSharpTest2/Recommendations/IfKeywordRecommenderTests.cs +++ b/src/EditorFeatures/CSharpTest2/Recommendations/IfKeywordRecommenderTests.cs @@ -29,9 +29,9 @@ class C { } } [Fact] - public async Task TestAfterGlobalStatement_Interactive() + public async Task TestAfterGlobalStatement() { - await VerifyKeywordAsync(SourceCodeKind.Script, + await VerifyKeywordAsync( """ System.Console.WriteLine(); $$ diff --git a/src/EditorFeatures/CSharpTest2/Recommendations/IntKeywordRecommenderTests.cs b/src/EditorFeatures/CSharpTest2/Recommendations/IntKeywordRecommenderTests.cs index 5953f5f323d16..b4ae9655b78bc 100644 --- a/src/EditorFeatures/CSharpTest2/Recommendations/IntKeywordRecommenderTests.cs +++ b/src/EditorFeatures/CSharpTest2/Recommendations/IntKeywordRecommenderTests.cs @@ -30,9 +30,9 @@ class C { } } [Fact] - public async Task TestAfterGlobalStatement_Interactive() + public async Task TestAfterGlobalStatement() { - await VerifyKeywordAsync(SourceCodeKind.Script, + await VerifyKeywordAsync( """ System.Console.WriteLine(); $$ diff --git a/src/EditorFeatures/CSharpTest2/Recommendations/InterfaceKeywordRecommenderTests.cs b/src/EditorFeatures/CSharpTest2/Recommendations/InterfaceKeywordRecommenderTests.cs index af3f49fd078cb..18dfcc00466d7 100644 --- a/src/EditorFeatures/CSharpTest2/Recommendations/InterfaceKeywordRecommenderTests.cs +++ b/src/EditorFeatures/CSharpTest2/Recommendations/InterfaceKeywordRecommenderTests.cs @@ -29,9 +29,9 @@ class C { } } [Fact] - public async Task TestAfterGlobalStatement_Interactive() + public async Task TestAfterGlobalStatement() { - await VerifyKeywordAsync(SourceCodeKind.Script, + await VerifyKeywordAsync( """ System.Console.WriteLine(); $$ diff --git a/src/EditorFeatures/CSharpTest2/Recommendations/InternalKeywordRecommenderTests.cs b/src/EditorFeatures/CSharpTest2/Recommendations/InternalKeywordRecommenderTests.cs index e607d891910a7..dadf68e402dbc 100644 --- a/src/EditorFeatures/CSharpTest2/Recommendations/InternalKeywordRecommenderTests.cs +++ b/src/EditorFeatures/CSharpTest2/Recommendations/InternalKeywordRecommenderTests.cs @@ -29,9 +29,9 @@ class C { } } [Fact] - public async Task TestAfterGlobalStatement_Interactive() + public async Task TestAfterGlobalStatement() { - await VerifyKeywordAsync(SourceCodeKind.Script, + await VerifyKeywordAsync( """ System.Console.WriteLine(); $$ diff --git a/src/EditorFeatures/CSharpTest2/Recommendations/LockKeywordRecommenderTests.cs b/src/EditorFeatures/CSharpTest2/Recommendations/LockKeywordRecommenderTests.cs index 1542e5d740398..ad58d464dc11b 100644 --- a/src/EditorFeatures/CSharpTest2/Recommendations/LockKeywordRecommenderTests.cs +++ b/src/EditorFeatures/CSharpTest2/Recommendations/LockKeywordRecommenderTests.cs @@ -29,9 +29,9 @@ class C { } } [Fact] - public async Task TestAfterGlobalStatement_Interactive() + public async Task TestAfterGlobalStatement() { - await VerifyKeywordAsync(SourceCodeKind.Script, + await VerifyKeywordAsync( """ System.Console.WriteLine(); $$ diff --git a/src/EditorFeatures/CSharpTest2/Recommendations/LongKeywordRecommenderTests.cs b/src/EditorFeatures/CSharpTest2/Recommendations/LongKeywordRecommenderTests.cs index 972bebcf8074b..4aef97388870c 100644 --- a/src/EditorFeatures/CSharpTest2/Recommendations/LongKeywordRecommenderTests.cs +++ b/src/EditorFeatures/CSharpTest2/Recommendations/LongKeywordRecommenderTests.cs @@ -30,9 +30,9 @@ class C { } } [Fact] - public async Task TestAfterGlobalStatement_Interactive() + public async Task TestAfterGlobalStatement() { - await VerifyKeywordAsync(SourceCodeKind.Script, + await VerifyKeywordAsync( """ System.Console.WriteLine(); $$ diff --git a/src/EditorFeatures/CSharpTest2/Recommendations/NameOfKeywordRecommenderTests.cs b/src/EditorFeatures/CSharpTest2/Recommendations/NameOfKeywordRecommenderTests.cs index 66f6ca242029d..638d670e72466 100644 --- a/src/EditorFeatures/CSharpTest2/Recommendations/NameOfKeywordRecommenderTests.cs +++ b/src/EditorFeatures/CSharpTest2/Recommendations/NameOfKeywordRecommenderTests.cs @@ -34,9 +34,9 @@ class C { } } [Fact] - public async Task TestAfterGlobalStatement_Interactive() + public async Task TestAfterGlobalStatement() { - await VerifyKeywordAsync(SourceCodeKind.Script, + await VerifyKeywordAsync( """ System.Console.WriteLine(); $$ diff --git a/src/EditorFeatures/CSharpTest2/Recommendations/NullKeywordRecommenderTests.cs b/src/EditorFeatures/CSharpTest2/Recommendations/NullKeywordRecommenderTests.cs index 1d673d246d0e2..1aeb19e97f721 100644 --- a/src/EditorFeatures/CSharpTest2/Recommendations/NullKeywordRecommenderTests.cs +++ b/src/EditorFeatures/CSharpTest2/Recommendations/NullKeywordRecommenderTests.cs @@ -30,9 +30,9 @@ class C { } } [Fact] - public async Task TestAfterGlobalStatement_Interactive() + public async Task TestAfterGlobalStatement() { - await VerifyKeywordAsync(SourceCodeKind.Script, + await VerifyKeywordAsync( """ System.Console.WriteLine(); $$ diff --git a/src/EditorFeatures/CSharpTest2/Recommendations/ObjectKeywordRecommenderTests.cs b/src/EditorFeatures/CSharpTest2/Recommendations/ObjectKeywordRecommenderTests.cs index ee2f3032d5040..0fc8d684ea2e1 100644 --- a/src/EditorFeatures/CSharpTest2/Recommendations/ObjectKeywordRecommenderTests.cs +++ b/src/EditorFeatures/CSharpTest2/Recommendations/ObjectKeywordRecommenderTests.cs @@ -30,9 +30,9 @@ class C { } } [Fact] - public async Task TestAfterGlobalStatement_Interactive() + public async Task TestAfterGlobalStatement() { - await VerifyKeywordAsync(SourceCodeKind.Script, + await VerifyKeywordAsync( """ System.Console.WriteLine(); $$ diff --git a/src/EditorFeatures/CSharpTest2/Recommendations/PartialKeywordRecommenderTests.cs b/src/EditorFeatures/CSharpTest2/Recommendations/PartialKeywordRecommenderTests.cs index ea7ee7f806365..0a1423072176a 100644 --- a/src/EditorFeatures/CSharpTest2/Recommendations/PartialKeywordRecommenderTests.cs +++ b/src/EditorFeatures/CSharpTest2/Recommendations/PartialKeywordRecommenderTests.cs @@ -30,9 +30,9 @@ class C { } } [Fact] - public async Task TestAfterGlobalStatement_Interactive() + public async Task TestAfterGlobalStatement() { - await VerifyKeywordAsync(SourceCodeKind.Script, + await VerifyKeywordAsync( """ System.Console.WriteLine(); $$ diff --git a/src/EditorFeatures/CSharpTest2/Recommendations/PublicKeywordRecommenderTests.cs b/src/EditorFeatures/CSharpTest2/Recommendations/PublicKeywordRecommenderTests.cs index 653433795b4ba..56ffbb2a5df3b 100644 --- a/src/EditorFeatures/CSharpTest2/Recommendations/PublicKeywordRecommenderTests.cs +++ b/src/EditorFeatures/CSharpTest2/Recommendations/PublicKeywordRecommenderTests.cs @@ -30,9 +30,9 @@ class C { } } [Fact] - public async Task TestAfterGlobalStatement_Interactive() + public async Task TestAfterGlobalStatement() { - await VerifyKeywordAsync(SourceCodeKind.Script, + await VerifyKeywordAsync( """ System.Console.WriteLine(); $$ diff --git a/src/EditorFeatures/CSharpTest2/Recommendations/RecordKeywordRecommenderTests.cs b/src/EditorFeatures/CSharpTest2/Recommendations/RecordKeywordRecommenderTests.cs index 5c5bb66f8685e..02ac3ea83a9dc 100644 --- a/src/EditorFeatures/CSharpTest2/Recommendations/RecordKeywordRecommenderTests.cs +++ b/src/EditorFeatures/CSharpTest2/Recommendations/RecordKeywordRecommenderTests.cs @@ -31,9 +31,9 @@ class C { } } [Fact] - public async Task TestAfterGlobalStatement_Interactive() + public async Task TestAfterGlobalStatement() { - await VerifyKeywordAsync(SourceCodeKind.Script, + await VerifyKeywordAsync( """ System.Console.WriteLine(); $$ diff --git a/src/EditorFeatures/CSharpTest2/Recommendations/SByteKeywordRecommenderTests.cs b/src/EditorFeatures/CSharpTest2/Recommendations/SByteKeywordRecommenderTests.cs index f60d247c61c61..f47b1315ef06b 100644 --- a/src/EditorFeatures/CSharpTest2/Recommendations/SByteKeywordRecommenderTests.cs +++ b/src/EditorFeatures/CSharpTest2/Recommendations/SByteKeywordRecommenderTests.cs @@ -30,9 +30,9 @@ class C { } } [Fact] - public async Task TestAfterGlobalStatement_Interactive() + public async Task TestAfterGlobalStatement() { - await VerifyKeywordAsync(SourceCodeKind.Script, + await VerifyKeywordAsync( """ System.Console.WriteLine(); $$ diff --git a/src/EditorFeatures/CSharpTest2/Recommendations/ScopedKeywordRecommenderTests.cs b/src/EditorFeatures/CSharpTest2/Recommendations/ScopedKeywordRecommenderTests.cs index 86ff7a3598521..2263319cbc2aa 100644 --- a/src/EditorFeatures/CSharpTest2/Recommendations/ScopedKeywordRecommenderTests.cs +++ b/src/EditorFeatures/CSharpTest2/Recommendations/ScopedKeywordRecommenderTests.cs @@ -38,9 +38,9 @@ class C { } } [Fact] - public async Task TestAfterGlobalStatement_Interactive() + public async Task TestAfterGlobalStatement() { - await VerifyKeywordAsync(SourceCodeKind.Script, + await VerifyKeywordAsync( """ System.Console.WriteLine(); $$ diff --git a/src/EditorFeatures/CSharpTest2/Recommendations/SealedKeywordRecommenderTests.cs b/src/EditorFeatures/CSharpTest2/Recommendations/SealedKeywordRecommenderTests.cs index 641033c2e02fa..6011e8077e3ea 100644 --- a/src/EditorFeatures/CSharpTest2/Recommendations/SealedKeywordRecommenderTests.cs +++ b/src/EditorFeatures/CSharpTest2/Recommendations/SealedKeywordRecommenderTests.cs @@ -30,9 +30,9 @@ class C { } } [Fact] - public async Task TestAfterGlobalStatement_Interactive() + public async Task TestAfterGlobalStatement() { - await VerifyKeywordAsync(SourceCodeKind.Script, + await VerifyKeywordAsync( """ System.Console.WriteLine(); $$ diff --git a/src/EditorFeatures/CSharpTest2/Recommendations/ShortKeywordRecommenderTests.cs b/src/EditorFeatures/CSharpTest2/Recommendations/ShortKeywordRecommenderTests.cs index a70b8579e3749..2e261c1aa6aa9 100644 --- a/src/EditorFeatures/CSharpTest2/Recommendations/ShortKeywordRecommenderTests.cs +++ b/src/EditorFeatures/CSharpTest2/Recommendations/ShortKeywordRecommenderTests.cs @@ -30,9 +30,9 @@ class C { } } [Fact] - public async Task TestAfterGlobalStatement_Interactive() + public async Task TestAfterGlobalStatement() { - await VerifyKeywordAsync(SourceCodeKind.Script, + await VerifyKeywordAsync( """ System.Console.WriteLine(); $$ diff --git a/src/EditorFeatures/CSharpTest2/Recommendations/SizeOfKeywordRecommenderTests.cs b/src/EditorFeatures/CSharpTest2/Recommendations/SizeOfKeywordRecommenderTests.cs index 525c57ed927ac..dbeed7fa7b190 100644 --- a/src/EditorFeatures/CSharpTest2/Recommendations/SizeOfKeywordRecommenderTests.cs +++ b/src/EditorFeatures/CSharpTest2/Recommendations/SizeOfKeywordRecommenderTests.cs @@ -30,9 +30,9 @@ class C { } } [Fact] - public async Task TestAfterGlobalStatement_Interactive() + public async Task TestAfterGlobalStatement() { - await VerifyKeywordAsync(SourceCodeKind.Script, + await VerifyKeywordAsync( """ System.Console.WriteLine(); $$ diff --git a/src/EditorFeatures/CSharpTest2/Recommendations/StackAllocKeywordRecommenderTests.cs b/src/EditorFeatures/CSharpTest2/Recommendations/StackAllocKeywordRecommenderTests.cs index 1189869d09da2..9c0d1ffa31489 100644 --- a/src/EditorFeatures/CSharpTest2/Recommendations/StackAllocKeywordRecommenderTests.cs +++ b/src/EditorFeatures/CSharpTest2/Recommendations/StackAllocKeywordRecommenderTests.cs @@ -30,9 +30,9 @@ class C { } } [Fact] - public async Task TestAfterGlobalStatement_Interactive() + public async Task TestAfterGlobalStatement() { - await VerifyKeywordAsync(SourceCodeKind.Script, + await VerifyKeywordAsync( """ System.Console.WriteLine(); $$ diff --git a/src/EditorFeatures/CSharpTest2/Recommendations/StaticKeywordRecommenderTests.cs b/src/EditorFeatures/CSharpTest2/Recommendations/StaticKeywordRecommenderTests.cs index 44c3182d827bc..e46bbf87812e6 100644 --- a/src/EditorFeatures/CSharpTest2/Recommendations/StaticKeywordRecommenderTests.cs +++ b/src/EditorFeatures/CSharpTest2/Recommendations/StaticKeywordRecommenderTests.cs @@ -30,9 +30,9 @@ class C { } } [Fact] - public async Task TestAfterGlobalStatement_Interactive() + public async Task TestAfterGlobalStatement() { - await VerifyKeywordAsync(SourceCodeKind.Script, + await VerifyKeywordAsync( """ System.Console.WriteLine(); $$ diff --git a/src/EditorFeatures/CSharpTest2/Recommendations/StringKeywordRecommenderTests.cs b/src/EditorFeatures/CSharpTest2/Recommendations/StringKeywordRecommenderTests.cs index a21d3c48f06a5..1b6fa709c8dd9 100644 --- a/src/EditorFeatures/CSharpTest2/Recommendations/StringKeywordRecommenderTests.cs +++ b/src/EditorFeatures/CSharpTest2/Recommendations/StringKeywordRecommenderTests.cs @@ -30,9 +30,9 @@ class C { } } [Fact] - public async Task TestAfterGlobalStatement_Interactive() + public async Task TestAfterGlobalStatement() { - await VerifyKeywordAsync(SourceCodeKind.Script, + await VerifyKeywordAsync( """ System.Console.WriteLine(); $$ diff --git a/src/EditorFeatures/CSharpTest2/Recommendations/StructKeywordRecommenderTests.cs b/src/EditorFeatures/CSharpTest2/Recommendations/StructKeywordRecommenderTests.cs index e36194620d1fb..01f496fac662d 100644 --- a/src/EditorFeatures/CSharpTest2/Recommendations/StructKeywordRecommenderTests.cs +++ b/src/EditorFeatures/CSharpTest2/Recommendations/StructKeywordRecommenderTests.cs @@ -30,9 +30,9 @@ class C { } } [Fact] - public async Task TestAfterGlobalStatement_Interactive() + public async Task TestAfterGlobalStatement() { - await VerifyKeywordAsync(SourceCodeKind.Script, + await VerifyKeywordAsync( """ System.Console.WriteLine(); $$ diff --git a/src/EditorFeatures/CSharpTest2/Recommendations/SwitchKeywordRecommenderTests.cs b/src/EditorFeatures/CSharpTest2/Recommendations/SwitchKeywordRecommenderTests.cs index 7e8ff1665c1cd..48a6f52ef57aa 100644 --- a/src/EditorFeatures/CSharpTest2/Recommendations/SwitchKeywordRecommenderTests.cs +++ b/src/EditorFeatures/CSharpTest2/Recommendations/SwitchKeywordRecommenderTests.cs @@ -30,9 +30,9 @@ class C { } } [Fact] - public async Task TestAfterGlobalStatement_Interactive() + public async Task TestAfterGlobalStatement() { - await VerifyKeywordAsync(SourceCodeKind.Script, + await VerifyKeywordAsync( """ System.Console.WriteLine(); $$ diff --git a/src/EditorFeatures/CSharpTest2/Recommendations/ThrowKeywordRecommenderTests.cs b/src/EditorFeatures/CSharpTest2/Recommendations/ThrowKeywordRecommenderTests.cs index e84ac3af0ceec..f252f4b744697 100644 --- a/src/EditorFeatures/CSharpTest2/Recommendations/ThrowKeywordRecommenderTests.cs +++ b/src/EditorFeatures/CSharpTest2/Recommendations/ThrowKeywordRecommenderTests.cs @@ -30,9 +30,9 @@ class C { } } [Fact] - public async Task TestAfterGlobalStatement_Interactive() + public async Task TestAfterGlobalStatement() { - await VerifyKeywordAsync(SourceCodeKind.Script, + await VerifyKeywordAsync( """ System.Console.WriteLine(); $$ diff --git a/src/EditorFeatures/CSharpTest2/Recommendations/TrueKeywordRecommenderTests.cs b/src/EditorFeatures/CSharpTest2/Recommendations/TrueKeywordRecommenderTests.cs index 158afca6cb2ac..cca5cbeded4fa 100644 --- a/src/EditorFeatures/CSharpTest2/Recommendations/TrueKeywordRecommenderTests.cs +++ b/src/EditorFeatures/CSharpTest2/Recommendations/TrueKeywordRecommenderTests.cs @@ -30,9 +30,9 @@ class C { } } [Fact] - public async Task TestAfterGlobalStatement_Interactive() + public async Task TestAfterGlobalStatement() { - await VerifyKeywordAsync(SourceCodeKind.Script, + await VerifyKeywordAsync( """ System.Console.WriteLine(); $$ diff --git a/src/EditorFeatures/CSharpTest2/Recommendations/TryKeywordRecommenderTests.cs b/src/EditorFeatures/CSharpTest2/Recommendations/TryKeywordRecommenderTests.cs index 495ecc2910bb4..e8baa2642456b 100644 --- a/src/EditorFeatures/CSharpTest2/Recommendations/TryKeywordRecommenderTests.cs +++ b/src/EditorFeatures/CSharpTest2/Recommendations/TryKeywordRecommenderTests.cs @@ -29,9 +29,9 @@ class C { } } [Fact] - public async Task TestAfterGlobalStatement_Interactive() + public async Task TestAfterGlobalStatement() { - await VerifyKeywordAsync(SourceCodeKind.Script, + await VerifyKeywordAsync( """ System.Console.WriteLine(); $$ diff --git a/src/EditorFeatures/CSharpTest2/Recommendations/TypeOfKeywordRecommenderTests.cs b/src/EditorFeatures/CSharpTest2/Recommendations/TypeOfKeywordRecommenderTests.cs index c76c4d1fcc6d4..b6e81469cf031 100644 --- a/src/EditorFeatures/CSharpTest2/Recommendations/TypeOfKeywordRecommenderTests.cs +++ b/src/EditorFeatures/CSharpTest2/Recommendations/TypeOfKeywordRecommenderTests.cs @@ -34,9 +34,9 @@ class C { } } [Fact] - public async Task TestAfterGlobalStatement_Interactive() + public async Task TestAfterGlobalStatement() { - await VerifyKeywordAsync(SourceCodeKind.Script, + await VerifyKeywordAsync( """ System.Console.WriteLine(); $$ diff --git a/src/EditorFeatures/CSharpTest2/Recommendations/UIntKeywordRecommenderTests.cs b/src/EditorFeatures/CSharpTest2/Recommendations/UIntKeywordRecommenderTests.cs index 80f8e5be00749..382b988c5dfcc 100644 --- a/src/EditorFeatures/CSharpTest2/Recommendations/UIntKeywordRecommenderTests.cs +++ b/src/EditorFeatures/CSharpTest2/Recommendations/UIntKeywordRecommenderTests.cs @@ -30,9 +30,9 @@ class C { } } [Fact] - public async Task TestAfterGlobalStatement_Interactive() + public async Task TestAfterGlobalStatement() { - await VerifyKeywordAsync(SourceCodeKind.Script, + await VerifyKeywordAsync( """ System.Console.WriteLine(); $$ diff --git a/src/EditorFeatures/CSharpTest2/Recommendations/ULongKeywordRecommenderTests.cs b/src/EditorFeatures/CSharpTest2/Recommendations/ULongKeywordRecommenderTests.cs index 5f8c6dd3259bb..78a7092812e0c 100644 --- a/src/EditorFeatures/CSharpTest2/Recommendations/ULongKeywordRecommenderTests.cs +++ b/src/EditorFeatures/CSharpTest2/Recommendations/ULongKeywordRecommenderTests.cs @@ -30,9 +30,9 @@ class C { } } [Fact] - public async Task TestAfterGlobalStatement_Interactive() + public async Task TestAfterGlobalStatement() { - await VerifyKeywordAsync(SourceCodeKind.Script, + await VerifyKeywordAsync( """ System.Console.WriteLine(); $$ diff --git a/src/EditorFeatures/CSharpTest2/Recommendations/UShortKeywordRecommenderTests.cs b/src/EditorFeatures/CSharpTest2/Recommendations/UShortKeywordRecommenderTests.cs index 7f0f1d21d213b..c93001d03ff98 100644 --- a/src/EditorFeatures/CSharpTest2/Recommendations/UShortKeywordRecommenderTests.cs +++ b/src/EditorFeatures/CSharpTest2/Recommendations/UShortKeywordRecommenderTests.cs @@ -30,9 +30,9 @@ class C { } } [Fact] - public async Task TestAfterGlobalStatement_Interactive() + public async Task TestAfterGlobalStatement() { - await VerifyKeywordAsync(SourceCodeKind.Script, + await VerifyKeywordAsync( """ System.Console.WriteLine(); $$ diff --git a/src/EditorFeatures/CSharpTest2/Recommendations/UncheckedKeywordRecommenderTests.cs b/src/EditorFeatures/CSharpTest2/Recommendations/UncheckedKeywordRecommenderTests.cs index 077273e2c561b..83b624cda5953 100644 --- a/src/EditorFeatures/CSharpTest2/Recommendations/UncheckedKeywordRecommenderTests.cs +++ b/src/EditorFeatures/CSharpTest2/Recommendations/UncheckedKeywordRecommenderTests.cs @@ -30,9 +30,9 @@ class C { } } [Fact] - public async Task TestAfterGlobalStatement_Interactive() + public async Task TestAfterGlobalStatement() { - await VerifyKeywordAsync(SourceCodeKind.Script, + await VerifyKeywordAsync( """ System.Console.WriteLine(); $$ diff --git a/src/EditorFeatures/CSharpTest2/Recommendations/UnsafeKeywordRecommenderTests.cs b/src/EditorFeatures/CSharpTest2/Recommendations/UnsafeKeywordRecommenderTests.cs index fea89fd3f7ce3..a3e485c72a616 100644 --- a/src/EditorFeatures/CSharpTest2/Recommendations/UnsafeKeywordRecommenderTests.cs +++ b/src/EditorFeatures/CSharpTest2/Recommendations/UnsafeKeywordRecommenderTests.cs @@ -30,9 +30,9 @@ class C { } } [Fact] - public async Task TestAfterGlobalStatement_Interactive() + public async Task TestAfterGlobalStatement() { - await VerifyKeywordAsync(SourceCodeKind.Script, + await VerifyKeywordAsync( """ System.Console.WriteLine(); $$ diff --git a/src/EditorFeatures/CSharpTest2/Recommendations/UsingKeywordRecommenderTests.cs b/src/EditorFeatures/CSharpTest2/Recommendations/UsingKeywordRecommenderTests.cs index 628430a10dd25..c0ef8cd6b2186 100644 --- a/src/EditorFeatures/CSharpTest2/Recommendations/UsingKeywordRecommenderTests.cs +++ b/src/EditorFeatures/CSharpTest2/Recommendations/UsingKeywordRecommenderTests.cs @@ -36,9 +36,9 @@ class C { } } [Fact] - public async Task TestAfterGlobalStatement_Interactive() + public async Task TestAfterGlobalStatement() { - await VerifyKeywordAsync(SourceCodeKind.Script, + await VerifyKeywordAsync( """ System.Console.WriteLine(); $$ diff --git a/src/EditorFeatures/CSharpTest2/Recommendations/VarKeywordRecommenderTests.cs b/src/EditorFeatures/CSharpTest2/Recommendations/VarKeywordRecommenderTests.cs index 2b24e9b2651b9..253f5fe3e52ab 100644 --- a/src/EditorFeatures/CSharpTest2/Recommendations/VarKeywordRecommenderTests.cs +++ b/src/EditorFeatures/CSharpTest2/Recommendations/VarKeywordRecommenderTests.cs @@ -41,9 +41,9 @@ class C { } } [Fact] - public async Task TestAfterGlobalStatement_Interactive() + public async Task TestAfterGlobalStatement() { - await VerifyKeywordAsync(SourceCodeKind.Script, + await VerifyKeywordAsync( """ System.Console.WriteLine(); $$ diff --git a/src/EditorFeatures/CSharpTest2/Recommendations/VoidKeywordRecommenderTests.cs b/src/EditorFeatures/CSharpTest2/Recommendations/VoidKeywordRecommenderTests.cs index 9fbb3a1effe27..7f79f1cfd613d 100644 --- a/src/EditorFeatures/CSharpTest2/Recommendations/VoidKeywordRecommenderTests.cs +++ b/src/EditorFeatures/CSharpTest2/Recommendations/VoidKeywordRecommenderTests.cs @@ -30,9 +30,9 @@ class C { } } [Fact] - public async Task TestAfterGlobalStatement_Interactive() + public async Task TestAfterGlobalStatement() { - await VerifyKeywordAsync(SourceCodeKind.Script, + await VerifyKeywordAsync( """ System.Console.WriteLine(); $$ diff --git a/src/EditorFeatures/CSharpTest2/Recommendations/WhileKeywordRecommenderTests.cs b/src/EditorFeatures/CSharpTest2/Recommendations/WhileKeywordRecommenderTests.cs index 7ab47cc0e5c00..a882d7c9976d6 100644 --- a/src/EditorFeatures/CSharpTest2/Recommendations/WhileKeywordRecommenderTests.cs +++ b/src/EditorFeatures/CSharpTest2/Recommendations/WhileKeywordRecommenderTests.cs @@ -29,9 +29,9 @@ class C { } } [Fact] - public async Task TestAfterGlobalStatement_Interactive() + public async Task TestAfterGlobalStatement() { - await VerifyKeywordAsync(SourceCodeKind.Script, + await VerifyKeywordAsync( """ System.Console.WriteLine(); $$ diff --git a/src/EditorFeatures/Core.Wpf/BackgroundWorkIndicator/BackgroundWorkIndicatorContext.cs b/src/EditorFeatures/Core.Wpf/BackgroundWorkIndicator/BackgroundWorkIndicatorContext.cs index 3e0d7dd893555..037808e696ec0 100644 --- a/src/EditorFeatures/Core.Wpf/BackgroundWorkIndicator/BackgroundWorkIndicatorContext.cs +++ b/src/EditorFeatures/Core.Wpf/BackgroundWorkIndicator/BackgroundWorkIndicatorContext.cs @@ -63,7 +63,7 @@ private enum UIUpdateRequest /// Set of scopes we have. We always start with one (the one created by the initial call to create the work /// indicator). However, the client of the background indicator can add more. /// - private ImmutableArray _scopes = ImmutableArray.Empty; + private ImmutableArray _scopes = []; /// /// If we've been dismissed or not. Once dismissed, we will close the tool-tip showing information. This diff --git a/src/EditorFeatures/Core.Wpf/InlineHints/CachedAdornmentTagSpan.cs b/src/EditorFeatures/Core.Wpf/InlineHints/CachedAdornmentTagSpan.cs new file mode 100644 index 0000000000000..4f6f0a0efc4c6 --- /dev/null +++ b/src/EditorFeatures/Core.Wpf/InlineHints/CachedAdornmentTagSpan.cs @@ -0,0 +1,32 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Microsoft.VisualStudio.Text.Editor; +using Microsoft.VisualStudio.Text.Formatting; +using Microsoft.VisualStudio.Text.Tagging; + +namespace Microsoft.CodeAnalysis.Editor.InlineHints; + +internal partial class InlineHintsTaggerProvider +{ + /// + /// The computed adornment tag for an inline hint, along with information needed to determine if it can be reused. + /// This is created and cached on on demand + /// so that we only create adornment tags once and reuse as long as possible. + /// + /// Whether or not the adornment tag was classified. If the option for this changes, this + /// cached tag should not be reused. + /// The text formatting used to create the hint. If this format no longer matches the current + /// formatting, this should not be reused. + /// The actual adornment tag to render. + private sealed class CachedAdornmentTagSpan( + bool classified, + TextFormattingRunProperties format, + TagSpan adornmentTagSpan) + { + public bool Classified { get; } = classified; + public TextFormattingRunProperties Format { get; } = format; + public TagSpan AdornmentTagSpan { get; } = adornmentTagSpan; + } +} diff --git a/src/EditorFeatures/Core.Wpf/InlineHints/InlineHintsTagger.cs b/src/EditorFeatures/Core.Wpf/InlineHints/InlineHintsTagger.cs index ed2bb08bd6060..c7fad83f466a5 100644 --- a/src/EditorFeatures/Core.Wpf/InlineHints/InlineHintsTagger.cs +++ b/src/EditorFeatures/Core.Wpf/InlineHints/InlineHintsTagger.cs @@ -3,10 +3,15 @@ // See the LICENSE file in the project root for more information. using System; -using System.Collections.Generic; +using Microsoft.CodeAnalysis.Collections; using Microsoft.CodeAnalysis.Editor.Shared.Extensions; +using Microsoft.CodeAnalysis.Editor.Tagging; using Microsoft.CodeAnalysis.ErrorReporting; +using Microsoft.CodeAnalysis.Options; +using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Text; +using Microsoft.CodeAnalysis.Text.Shared.Extensions; +using Microsoft.CodeAnalysis.Utilities; using Microsoft.VisualStudio.Text; using Microsoft.VisualStudio.Text.Classification; using Microsoft.VisualStudio.Text.Editor; @@ -14,26 +19,18 @@ using Microsoft.VisualStudio.Text.Tagging; using Roslyn.Utilities; -namespace Microsoft.CodeAnalysis.Editor.InlineHints +namespace Microsoft.CodeAnalysis.Editor.InlineHints; + +internal partial class InlineHintsTaggerProvider { /// - /// The purpose of this tagger is to convert the to the to the , which actually creates the UIElement. It reacts to tags changing and updates the /// adornments accordingly. /// - internal sealed class InlineHintsTagger : ITagger, IDisposable + private sealed class InlineHintsTagger : EfficientTagger { - private readonly ITagAggregator _tagAggregator; - - /// - /// stores the parameter hint tags in a global location - /// - private readonly List<(IMappingTagSpan mappingTagSpan, TagSpan? tagSpan)> _cache = []; - - /// - /// Stores the snapshot associated with the cached tags in - /// - private ITextSnapshot? _cacheSnapshot; + private readonly EfficientTagger> _underlyingTagger; private readonly IClassificationFormatMap _formatMap; @@ -45,77 +42,59 @@ internal sealed class InlineHintsTagger : ITagger, IDispo private readonly InlineHintsTaggerProvider _taggerProvider; - private readonly ITextBuffer _buffer; private readonly IWpfTextView _textView; - - public event EventHandler? TagsChanged; + private readonly ITextBuffer _subjectBuffer; public InlineHintsTagger( InlineHintsTaggerProvider taggerProvider, IWpfTextView textView, - ITextBuffer buffer, - ITagAggregator tagAggregator) + ITextBuffer subjectBuffer, + EfficientTagger> tagger) { _taggerProvider = taggerProvider; _textView = textView; - _buffer = buffer; + _subjectBuffer = subjectBuffer; + + // When the underlying tagger produced new data tags, inform any clients of us that we have new adornment tags. + _underlyingTagger = tagger; + _underlyingTagger.TagsChanged += OnTagsChanged; - _tagAggregator = tagAggregator; _formatMap = taggerProvider.ClassificationFormatMapService.GetClassificationFormatMap(textView); _hintClassification = taggerProvider.ClassificationTypeRegistryService.GetClassificationType(InlineHintsTag.TagId); + _formatMap.ClassificationFormatMappingChanged += this.OnClassificationFormatMappingChanged; - _tagAggregator.BatchedTagsChanged += TagAggregator_BatchedTagsChanged; + _taggerProvider.GlobalOptionService.AddOptionChangedHandler(this, OnGlobalOptionChanged); } - /// - /// Goes through all the spans in which tags have changed and - /// invokes a TagsChanged event. Using the BatchedTagsChangedEvent since it is raised - /// on the same thread that created the tag aggregator, unlike TagsChanged. - /// - private void TagAggregator_BatchedTagsChanged(object sender, BatchedTagsChangedEventArgs e) + public override void Dispose() { - _taggerProvider.ThreadingContext.ThrowIfNotOnUIThread(); - InvalidateCache(); - - var tagsChanged = TagsChanged; - if (tagsChanged is null) - { - return; - } - - var mappingSpans = e.Spans; - foreach (var item in mappingSpans) - { - var spans = item.GetSpans(_buffer); - foreach (var span in spans) - { - if (tagsChanged != null) - { - tagsChanged.Invoke(this, new SnapshotSpanEventArgs(span)); - } - } - } + _formatMap.ClassificationFormatMappingChanged -= OnClassificationFormatMappingChanged; + _taggerProvider.GlobalOptionService.RemoveOptionChangedHandler(this, OnGlobalOptionChanged); + _underlyingTagger.TagsChanged -= OnTagsChanged; + _underlyingTagger.Dispose(); } private void OnClassificationFormatMappingChanged(object sender, EventArgs e) { _taggerProvider.ThreadingContext.ThrowIfNotOnUIThread(); + + // When classifications change we need to rebuild the inline tags with updated Font and Color information. + if (_format != null) { _format = null; - InvalidateCache(); - - // When classifications change we need to rebuild the inline tags with updated Font and Color information. - var tags = GetTags(new NormalizedSnapshotSpanCollection(_textView.TextViewLines.FormattedSpan)); - - foreach (var tag in tags) - { - TagsChanged?.Invoke(this, new SnapshotSpanEventArgs(tag.Span)); - } + OnTagsChanged(this, new SnapshotSpanEventArgs(_subjectBuffer.CurrentSnapshot.GetFullSpan())); } } + private void OnGlobalOptionChanged(object sender, object target, OptionChangedEventArgs e) + { + // Reclassify everything. + if (e.HasOption(option => option.Equals(InlineHintsViewOptionsStorage.ColorHints))) + OnTagsChanged(this, new SnapshotSpanEventArgs(_subjectBuffer.CurrentSnapshot.GetFullSpan())); + } + private TextFormattingRunProperties Format { get @@ -126,74 +105,39 @@ private TextFormattingRunProperties Format } } - private void InvalidateCache() - { - _taggerProvider.ThreadingContext.ThrowIfNotOnUIThread(); - _cacheSnapshot = null; - _cache.Clear(); - } - - IEnumerable> ITagger.GetTags(NormalizedSnapshotSpanCollection spans) - => GetTags(spans); - - public IReadOnlyList> GetTags(NormalizedSnapshotSpanCollection spans) + public override void AddTags( + NormalizedSnapshotSpanCollection spans, + SegmentedList> adornmentTagSpans) { try { if (spans.Count == 0) - return []; + return; + // If the snapshot has changed, we can't use any of the cached data, as it is associated with the + // original snapshot they were created against. var snapshot = spans[0].Snapshot; - if (snapshot != _cacheSnapshot) - { - // Calculate UI elements - _cache.Clear(); - _cacheSnapshot = snapshot; - - // Calling into the InlineParameterNameHintsDataTaggerProvider which only responds with the current - // active view and disregards and requests for tags not in that view - var fullSpan = new SnapshotSpan(snapshot, 0, snapshot.Length); - var tags = _tagAggregator.GetTags(new NormalizedSnapshotSpanCollection(fullSpan)); - foreach (var tag in tags) - { - // Gets the associated span from the snapshot span and creates the IntraTextAdornmentTag from the data - // tags. Only dealing with the dataTagSpans if the count is 1 because we do not see a multi-buffer case - // occurring - var dataTagSpans = tag.Span.GetSpans(snapshot); - if (dataTagSpans.Count == 1) - { - _cache.Add((tag, tagSpan: null)); - } - } - } var document = snapshot.GetOpenDocumentInCurrentContextWithChanges(); - var classify = document != null && _taggerProvider.EditorOptionsService.GlobalOptions.GetOption(InlineHintsViewOptionsStorage.ColorHints, document.Project.Language); + if (document is null) + return; + + var colorHints = _taggerProvider.EditorOptionsService.GlobalOptions.GetOption(InlineHintsViewOptionsStorage.ColorHints, document.Project.Language); + + using var _1 = SegmentedListPool.GetPooledList>>(out var dataTagSpans); + _underlyingTagger.AddTags(spans, dataTagSpans); + + // Presize so we can add the elements below without continually resizing. + adornmentTagSpans.Capacity += dataTagSpans.Count; + + using var _2 = PooledHashSet.GetInstance(out var seenPositions); - var selectedSpans = new List>(); - for (var i = 0; i < _cache.Count; i++) + var format = this.Format; + foreach (var dataTagSpan in dataTagSpans) { - var tagSpans = _cache[i].mappingTagSpan.Span.GetSpans(snapshot); - if (tagSpans.Count == 1) - { - var tagSpan = tagSpans[0]; - if (spans.IntersectsWith(tagSpan)) - { - if (_cache[i].tagSpan is not { } hintTagSpan) - { - var hintUITag = InlineHintsTag.Create( - _cache[i].mappingTagSpan.Tag.Hint, Format, _textView, tagSpan, _taggerProvider, _formatMap, classify); - - hintTagSpan = new TagSpan(tagSpan, hintUITag); - _cache[i] = (_cache[i].mappingTagSpan, hintTagSpan); - } - - selectedSpans.Add(hintTagSpan); - } - } + if (seenPositions.Add(dataTagSpan.Span.Start)) + adornmentTagSpans.Add(GetOrCreateAdornmentTagsSpan(dataTagSpan, colorHints, format)); } - - return selectedSpans; } catch (Exception e) when (FatalError.ReportAndPropagateUnlessCanceled(e, ErrorSeverity.General)) { @@ -201,11 +145,20 @@ public IReadOnlyList> GetTags(NormalizedSnapshotS } } - public void Dispose() + private TagSpan GetOrCreateAdornmentTagsSpan( + TagSpan> dataTagSpan, bool classify, TextFormattingRunProperties format) { - _tagAggregator.BatchedTagsChanged -= TagAggregator_BatchedTagsChanged; - _tagAggregator.Dispose(); - _formatMap.ClassificationFormatMappingChanged -= OnClassificationFormatMappingChanged; + // If we've never computed the adornment info, or options have changed, then compute and cache the new information. + var cachedTagInformation = dataTagSpan.Tag.AdditionalData; + if (cachedTagInformation is null || cachedTagInformation.Classified != classify || cachedTagInformation.Format != format) + { + var adornmentSpan = dataTagSpan.Span; + cachedTagInformation = new(classify, format, new TagSpan(adornmentSpan, InlineHintsTag.Create( + dataTagSpan.Tag.Hint, format, _textView, adornmentSpan, _taggerProvider, _formatMap, classify))); + dataTagSpan.Tag.AdditionalData = cachedTagInformation; + } + + return cachedTagInformation.AdornmentTagSpan; } } } diff --git a/src/EditorFeatures/Core.Wpf/InlineHints/InlineHintsTaggerProvider.cs b/src/EditorFeatures/Core.Wpf/InlineHints/InlineHintsTaggerProvider.cs index db59432deb50e..3d668d60618c2 100644 --- a/src/EditorFeatures/Core.Wpf/InlineHints/InlineHintsTaggerProvider.cs +++ b/src/EditorFeatures/Core.Wpf/InlineHints/InlineHintsTaggerProvider.cs @@ -7,6 +7,7 @@ using Microsoft.CodeAnalysis.Editor.Host; using Microsoft.CodeAnalysis.Editor.Shared.Extensions; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; +using Microsoft.CodeAnalysis.Editor.Tagging; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Shared.TestHooks; @@ -27,55 +28,60 @@ namespace Microsoft.CodeAnalysis.Editor.InlineHints [ContentType(ContentTypeNames.RoslynContentType)] [TagType(typeof(IntraTextAdornmentTag))] [Name(nameof(InlineHintsTaggerProvider))] - internal class InlineHintsTaggerProvider : IViewTaggerProvider + [method: ImportingConstructor] + [method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] + internal sealed partial class InlineHintsTaggerProvider( + IGlobalOptionService globalOptionService, + IClassificationFormatMapService classificationFormatMapService, + IClassificationTypeRegistryService classificationTypeRegistryService, + IThreadingContext threadingContext, + IUIThreadOperationExecutor operationExecutor, + IAsynchronousOperationListenerProvider listenerProvider, + IToolTipService toolTipService, + ClassificationTypeMap typeMap, + Lazy streamingFindUsagesPresenter, + EditorOptionsService editorOptionsService, + TaggerHost taggerHost, + [Import(AllowDefault = true)] IInlineHintKeyProcessor inlineHintKeyProcessor) : IViewTaggerProvider { - private readonly IViewTagAggregatorFactoryService _viewTagAggregatorFactoryService; - public readonly IClassificationFormatMapService ClassificationFormatMapService; - public readonly IClassificationTypeRegistryService ClassificationTypeRegistryService; - public readonly IThreadingContext ThreadingContext; - public readonly IUIThreadOperationExecutor OperationExecutor; - public readonly IAsynchronousOperationListener AsynchronousOperationListener; - public readonly IToolTipService ToolTipService; - public readonly ClassificationTypeMap TypeMap; - public readonly Lazy StreamingFindUsagesPresenter; - public readonly EditorOptionsService EditorOptionsService; + public readonly IGlobalOptionService GlobalOptionService = globalOptionService; + public readonly IClassificationFormatMapService ClassificationFormatMapService = classificationFormatMapService; + public readonly IClassificationTypeRegistryService ClassificationTypeRegistryService = classificationTypeRegistryService; + public readonly IThreadingContext ThreadingContext = threadingContext; + public readonly IUIThreadOperationExecutor OperationExecutor = operationExecutor; + public readonly IAsynchronousOperationListener AsynchronousOperationListener = listenerProvider.GetListener(FeatureAttribute.InlineHints); + public readonly IToolTipService ToolTipService = toolTipService; + public readonly ClassificationTypeMap TypeMap = typeMap; + public readonly Lazy StreamingFindUsagesPresenter = streamingFindUsagesPresenter; + public readonly EditorOptionsService EditorOptionsService = editorOptionsService; - [ImportingConstructor] - [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - public InlineHintsTaggerProvider( - IViewTagAggregatorFactoryService viewTagAggregatorFactoryService, - IClassificationFormatMapService classificationFormatMapService, - IClassificationTypeRegistryService classificationTypeRegistryService, - IThreadingContext threadingContext, - IUIThreadOperationExecutor operationExecutor, - IAsynchronousOperationListenerProvider listenerProvider, - IToolTipService toolTipService, - ClassificationTypeMap typeMap, - Lazy streamingFindUsagesPresenter, - EditorOptionsService editorOptionsService) + /// + /// Underlying data tagger that produces the raw data tags. We defer to it to own the actual low level tagger. + /// That tagger is responsible for listening to events (like scrolling/editing the buffer) and emitting events when the tags change. We then forward those events along to any + /// client of us. When that client then asks us for our adornment tags, we call into the underlying tagger for + /// its data tags. Then, on demand, we convert and cache those data tags into adornment tags and pass on the + /// results. + /// + private readonly InlineHintsDataTaggerProvider _dataTaggerProvider = new(taggerHost, inlineHintKeyProcessor); + + public ITagger? CreateTagger(ITextView textView, ITextBuffer subjectBuffer) where T : ITag { - _viewTagAggregatorFactoryService = viewTagAggregatorFactoryService; - ClassificationFormatMapService = classificationFormatMapService; - ClassificationTypeRegistryService = classificationTypeRegistryService; - ThreadingContext = threadingContext; - OperationExecutor = operationExecutor; - ToolTipService = toolTipService; - StreamingFindUsagesPresenter = streamingFindUsagesPresenter; - TypeMap = typeMap; - EditorOptionsService = editorOptionsService; + if (textView.IsNotSurfaceBufferOfTextView(subjectBuffer)) + return null; - AsynchronousOperationListener = listenerProvider.GetListener(FeatureAttribute.InlineHints); - } + if (textView is not IWpfTextView wpfTextView) + return null; - public ITagger? CreateTagger(ITextView textView, ITextBuffer buffer) where T : ITag - { - if (textView.IsNotSurfaceBufferOfTextView(buffer)) + var tagger = new InlineHintsTagger( + this, wpfTextView, subjectBuffer, _dataTaggerProvider.CreateTagger(textView, subjectBuffer)); + if (tagger is not ITagger typedTagger) { + tagger.Dispose(); return null; } - var tagAggregator = _viewTagAggregatorFactoryService.CreateTagAggregator(textView); - return new InlineHintsTagger(this, (IWpfTextView)textView, buffer, tagAggregator) as ITagger; + return typedTagger; } } } diff --git a/src/EditorFeatures/Core.Wpf/InlineHints/InlineHintsViewOptionsStorage.cs b/src/EditorFeatures/Core.Wpf/InlineHints/InlineHintsViewOptionsStorage.cs index c4188e0c17927..b7df8d2ad50b7 100644 --- a/src/EditorFeatures/Core.Wpf/InlineHints/InlineHintsViewOptionsStorage.cs +++ b/src/EditorFeatures/Core.Wpf/InlineHints/InlineHintsViewOptionsStorage.cs @@ -4,14 +4,13 @@ using Microsoft.CodeAnalysis.Options; -namespace Microsoft.CodeAnalysis.Editor.InlineHints +namespace Microsoft.CodeAnalysis.Editor.InlineHints; + +internal sealed class InlineHintsViewOptionsStorage { - internal sealed class InlineHintsViewOptionsStorage - { - public static readonly Option2 DisplayAllHintsWhilePressingAltF1 = new( - "dotnet_display_inline_hints_while_pressing_alt_f1", defaultValue: true); + public static readonly Option2 DisplayAllHintsWhilePressingAltF1 = new( + "dotnet_display_inline_hints_while_pressing_alt_f1", defaultValue: true); - public static readonly PerLanguageOption2 ColorHints = new( - "dotnet_colorize_inline_hints", defaultValue: true); - } + public static readonly PerLanguageOption2 ColorHints = new( + "dotnet_colorize_inline_hints", defaultValue: true); } 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 65752cc5d5b70..4704d981f8722 100644 --- a/src/EditorFeatures/Core.Wpf/InlineRename/UI/Dashboard/RenameDashboard.xaml.cs +++ b/src/EditorFeatures/Core.Wpf/InlineRename/UI/Dashboard/RenameDashboard.xaml.cs @@ -87,10 +87,10 @@ public RenameDashboard( } ResolvableConflictBorder.StrokeThickness = RenameFixupTagDefinition.StrokeThickness; - ResolvableConflictBorder.StrokeDashArray = new DoubleCollection(RenameFixupTagDefinition.StrokeDashArray); + ResolvableConflictBorder.StrokeDashArray = [.. RenameFixupTagDefinition.StrokeDashArray]; UnresolvableConflictBorder.StrokeThickness = RenameConflictTagDefinition.StrokeThickness; - UnresolvableConflictBorder.StrokeDashArray = new DoubleCollection(RenameConflictTagDefinition.StrokeDashArray); + UnresolvableConflictBorder.StrokeDashArray = [.. RenameConflictTagDefinition.StrokeDashArray]; this.Focus(); textView.Caret.IsHidden = false; diff --git a/src/EditorFeatures/Core.Wpf/InlineRename/UI/SmartRename/SmartRenameViewModel.cs b/src/EditorFeatures/Core.Wpf/InlineRename/UI/SmartRename/SmartRenameViewModel.cs index fbb4afed7d98e..337c4373f3a2b 100644 --- a/src/EditorFeatures/Core.Wpf/InlineRename/UI/SmartRename/SmartRenameViewModel.cs +++ b/src/EditorFeatures/Core.Wpf/InlineRename/UI/SmartRename/SmartRenameViewModel.cs @@ -21,6 +21,7 @@ using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.TestHooks; +using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.InlineRename.UI.SmartRename; @@ -33,10 +34,26 @@ internal sealed partial class SmartRenameViewModel : INotifyPropertyChanged, IDi private readonly IGlobalOptionService _globalOptionService; private readonly IThreadingContext _threadingContext; private readonly IAsynchronousOperationListener _asyncListener; - private CancellationTokenSource? _cancellationTokenSource; + + /// + /// Cancellation token source for . + /// Each call uses a new instance. Mutliple calls are allowed only if previous call failed or was canceled. + /// The request is canceled on UI thread through one of the following user interactions: + /// 1. when user types in the text box. + /// 2. when user toggles the automatic suggestions. + /// 3. when the dialog is closed. + /// + private CancellationTokenSource _cancellationTokenSource = new(); private bool _isDisposed; private TimeSpan AutomaticFetchDelay => _smartRenameSession.AutomaticFetchDelay; - private Task _getSuggestionsTask = Task.CompletedTask; + private TimeSpan _semanticContextDelay; + private bool _semanticContextError; + private bool _semanticContextUsed; + + /// + /// Backing field for . + /// + private bool _isInProgress = false; public event PropertyChangedEventHandler? PropertyChanged; @@ -48,7 +65,26 @@ internal sealed partial class SmartRenameViewModel : INotifyPropertyChanged, IDi public bool HasSuggestions => _smartRenameSession.HasSuggestions; - public bool IsInProgress => _smartRenameSession.IsInProgress; + /// + /// Indicates whether a request to get suggestions is in progress. + /// The request to get suggestions is comprised of initial short delay, + /// and call to . + /// When true, the UI shows the progress bar, and prevents from making parallel request. + /// + public bool IsInProgress + { + get + { + _threadingContext.ThrowIfNotOnUIThread(); + return _isInProgress; + } + set + { + _threadingContext.ThrowIfNotOnUIThread(); + _isInProgress = value; + NotifyPropertyChanged(nameof(IsInProgress)); + } + } public string StatusMessage => _smartRenameSession.StatusMessage; @@ -146,60 +182,80 @@ public SmartRenameViewModel( private void FetchSuggestions(bool isAutomaticOnInitialization) { _threadingContext.ThrowIfNotOnUIThread(); - if (this.SuggestedNames.Count > 0 || _isDisposed) + if (this.SuggestedNames.Count > 0 || _isDisposed || this.IsInProgress) { // Don't get suggestions again return; } - if (_getSuggestionsTask.Status is TaskStatus.RanToCompletion or TaskStatus.Faulted or TaskStatus.Canceled) - { - var listenerToken = _asyncListener.BeginAsyncOperation(nameof(_smartRenameSession.GetSuggestionsAsync)); - _cancellationTokenSource?.Dispose(); - _cancellationTokenSource = new CancellationTokenSource(); - _getSuggestionsTask = GetSuggestionsTaskAsync(isAutomaticOnInitialization, _cancellationTokenSource.Token).CompletesAsyncOperation(listenerToken); - } + var listenerToken = _asyncListener.BeginAsyncOperation(nameof(_smartRenameSession.GetSuggestionsAsync)); + _cancellationTokenSource.Cancel(); + _cancellationTokenSource = new CancellationTokenSource(); + GetSuggestionsTaskAsync(isAutomaticOnInitialization, _cancellationTokenSource.Token).CompletesAsyncOperation(listenerToken); } + /// + /// The request for rename suggestions. It's made of three parts: + /// 1. Short delay of duration . + /// 2. Get definition and references if is set. + /// 3. Call to . + /// private async Task GetSuggestionsTaskAsync(bool isAutomaticOnInitialization, CancellationToken cancellationToken) { - if (isAutomaticOnInitialization) - { - await Task.Delay(_smartRenameSession.AutomaticFetchDelay, cancellationToken) - .ConfigureAwait(false); - } - - if (cancellationToken.IsCancellationRequested || _isDisposed) - { - return; - } + RoslynDebug.Assert(!this.IsInProgress); + this.IsInProgress = true; + await _threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); - if (IsUsingSemanticContext) + try { - var document = this.BaseViewModel.Session.TriggerDocument; - var smartRenameContext = ImmutableDictionary>.Empty; - try + if (isAutomaticOnInitialization) { - var editorRenameService = document.GetRequiredLanguageService(); - var renameLocations = await this.BaseViewModel.Session.AllRenameLocationsTask.JoinAsync(cancellationToken) + await Task.Delay(_smartRenameSession.AutomaticFetchDelay, cancellationToken) .ConfigureAwait(false); - var context = await editorRenameService.GetRenameContextAsync(this.BaseViewModel.Session.RenameInfo, renameLocations, cancellationToken) + } + + if (cancellationToken.IsCancellationRequested || _isDisposed) + { + return; + } + + if (IsUsingSemanticContext) + { + var stopwatch = SharedStopwatch.StartNew(); + _semanticContextUsed = true; + var document = this.BaseViewModel.Session.TriggerDocument; + var smartRenameContext = ImmutableDictionary>.Empty; + try + { + var editorRenameService = document.GetRequiredLanguageService(); + var renameLocations = await this.BaseViewModel.Session.AllRenameLocationsTask.JoinAsync(cancellationToken) + .ConfigureAwait(false); + var context = await editorRenameService.GetRenameContextAsync(this.BaseViewModel.Session.RenameInfo, renameLocations, cancellationToken) + .ConfigureAwait(false); + smartRenameContext = ImmutableDictionary.CreateRange>( + context + .Select(n => new KeyValuePair>(n.Key, n.Value))); + _semanticContextDelay = stopwatch.Elapsed; + } + catch (Exception e) when (FatalError.ReportAndCatch(e, ErrorSeverity.Diagnostic)) + { + _semanticContextError = true; + // use empty smartRenameContext + } + _ = await _smartRenameSession.GetSuggestionsAsync(smartRenameContext, cancellationToken) .ConfigureAwait(false); - smartRenameContext = ImmutableDictionary.CreateRange>( - context - .Select(n => new KeyValuePair>(n.Key, n.Value))); } - catch (Exception e) when (FatalError.ReportAndCatch(e, ErrorSeverity.Diagnostic)) + else { - // use empty smartRenameContext + _ = await _smartRenameSession.GetSuggestionsAsync(cancellationToken) + .ConfigureAwait(false); } - _ = await _smartRenameSession.GetSuggestionsAsync(smartRenameContext, cancellationToken) - .ConfigureAwait(false); } - else + finally { - _ = await _smartRenameSession.GetSuggestionsAsync(cancellationToken) - .ConfigureAwait(false); + // cancellationToken might be already canceled. Fallback to the disposal token. + await _threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(_threadingContext.DisposalToken); + this.IsInProgress = false; } } @@ -255,7 +311,7 @@ private async Task SessionPropertyChangedAsync(object sender, PropertyChangedEve public void Cancel() { - _cancellationTokenSource?.Cancel(); + _cancellationTokenSource.Cancel(); // It's needed by editor-side telemetry. _smartRenameSession.OnCancel(); PostTelemetry(isCommit: false); @@ -270,21 +326,22 @@ public void Commit(string finalIdentifierName) public void Dispose() { + _threadingContext.ThrowIfNotOnUIThread(); _isDisposed = true; _smartRenameSession.PropertyChanged -= SessionPropertyChanged; BaseViewModel.PropertyChanged -= BaseViewModelPropertyChanged; _smartRenameSession.Dispose(); - _cancellationTokenSource?.Cancel(); - _cancellationTokenSource?.Dispose(); + _cancellationTokenSource.Cancel(); } /// /// When smart rename operates in explicit mode, this method gets the suggestions. - /// When smart rename operates in automatic mode, this method toggles the automatic suggestions, - /// and gets the suggestions if it was just enabled. + /// When smart rename operates in automatic mode, this method toggles the automatic suggestions: + /// gets the suggestions if it was just enabled, and cancels the ongoing request if it was just disabled. /// public void ToggleOrTriggerSuggestions() { + _threadingContext.ThrowIfNotOnUIThread(); if (this.SupportsAutomaticSuggestions) { this.IsAutomaticSuggestionsEnabled = !this.IsAutomaticSuggestionsEnabled; @@ -292,6 +349,10 @@ public void ToggleOrTriggerSuggestions() { this.FetchSuggestions(isAutomaticOnInitialization: false); } + else + { + _cancellationTokenSource.Cancel(); + } NotifyPropertyChanged(nameof(IsSuggestionsPanelExpanded)); NotifyPropertyChanged(nameof(IsAutomaticSuggestionsEnabled)); // Use existing "CollapseSuggestionsPanel" option (true if user does not wish to get suggestions automatically) to honor user's choice. @@ -308,9 +369,11 @@ private void NotifyPropertyChanged([CallerMemberName] string? name = null) private void BaseViewModelPropertyChanged(object sender, PropertyChangedEventArgs e) { + _threadingContext.ThrowIfNotOnUIThread(); if (e.PropertyName == nameof(BaseViewModel.IdentifierText)) { - _cancellationTokenSource?.Cancel(); + // User is typing the new identifier name, cancel the ongoing request to get suggestions. + _cancellationTokenSource.Cancel(); } } } diff --git a/src/EditorFeatures/Core.Wpf/InlineRename/UI/SmartRename/SmartRenameViewModel_Telemetry.cs b/src/EditorFeatures/Core.Wpf/InlineRename/UI/SmartRename/SmartRenameViewModel_Telemetry.cs index 572060b76a5e0..b89cd75bcfe6e 100644 --- a/src/EditorFeatures/Core.Wpf/InlineRename/UI/SmartRename/SmartRenameViewModel_Telemetry.cs +++ b/src/EditorFeatures/Core.Wpf/InlineRename/UI/SmartRename/SmartRenameViewModel_Telemetry.cs @@ -52,6 +52,10 @@ private void PostTelemetry(bool isCommit) m[nameof(SuggestionsPanelTelemetry.CollapseSuggestionsPanelWhenRenameStarts)] = _suggestionsPanelTelemetry.CollapseSuggestionsPanelWhenRenameStarts; m["CollapseSuggestionsPanelWhenRenameEnds"] = _globalOptionService.GetOption(InlineRenameUIOptionsStorage.CollapseSuggestionsPanel); m["smartRenameSessionInProgress"] = _smartRenameSession.IsInProgress; + m["smartRenameCorrelationId"] = _smartRenameSession.CorrelationId; + m["smartRenameSemanticContextUsed"] = _semanticContextUsed; + m["smartRenameSemanticContextDelay"] = _semanticContextDelay.TotalMilliseconds; + m["smartRenameSemanticContextError"] = _semanticContextError; })); } else @@ -63,6 +67,10 @@ private void PostTelemetry(bool isCommit) m["UseDropDown"] = true; m[nameof(SuggestionsDropdownTelemetry.DropdownButtonClickTimes)] = _suggestionsDropdownTelemetry.DropdownButtonClickTimes; m["smartRenameSessionInProgress"] = _smartRenameSession.IsInProgress; + m["smartRenameCorrelationId"] = _smartRenameSession.CorrelationId; + m["smartRenameSemanticContextUsed"] = _semanticContextUsed; + m["smartRenameSemanticContextDelay"] = _semanticContextDelay.TotalMilliseconds; + m["smartRenameSemanticContextError"] = _semanticContextError; })); } } diff --git a/src/EditorFeatures/Core.Wpf/Interactive/InertClassifierProvider.InertClassifier.cs b/src/EditorFeatures/Core.Wpf/Interactive/InertClassifierProvider.InertClassifier.cs index 1ea753ded59d3..aaf4739b14c9a 100644 --- a/src/EditorFeatures/Core.Wpf/Interactive/InertClassifierProvider.InertClassifier.cs +++ b/src/EditorFeatures/Core.Wpf/Interactive/InertClassifierProvider.InertClassifier.cs @@ -31,7 +31,7 @@ public IList GetClassificationSpans(SnapshotSpan span) // that intersect the requested span if we do. if (_textBuffer.Properties.TryGetProperty>(s_classificationsKey, out var classifications)) { - return classifications.Where(c => c.Span.IntersectsWith(span)).ToList(); + return [.. classifications.Where(c => c.Span.IntersectsWith(span))]; } return []; diff --git a/src/EditorFeatures/Core.Wpf/Interactive/InteractiveEvaluator.cs b/src/EditorFeatures/Core.Wpf/Interactive/InteractiveEvaluator.cs index 452e3a2849679..bf3b243d0be11 100644 --- a/src/EditorFeatures/Core.Wpf/Interactive/InteractiveEvaluator.cs +++ b/src/EditorFeatures/Core.Wpf/Interactive/InteractiveEvaluator.cs @@ -14,7 +14,6 @@ using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.ErrorReporting; using Microsoft.CodeAnalysis.Host; -using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Shared.TestHooks; using Microsoft.VisualStudio.InteractiveWindow; using Microsoft.VisualStudio.InteractiveWindow.Commands; @@ -70,7 +69,6 @@ internal CSharpInteractiveEvaluator( IInteractiveWindowCommandsFactory commandsFactory, ImmutableArray commands, ITextDocumentFactoryService textDocumentFactoryService, - EditorOptionsService editorOptionsService, InteractiveEvaluatorLanguageInfoProvider languageInfo, string initialWorkingDirectory) { @@ -87,10 +85,8 @@ internal CSharpInteractiveEvaluator( _session = new InteractiveSession( _workspace, - threadingContext, listener, textDocumentFactoryService, - editorOptionsService, languageInfo, initialWorkingDirectory); diff --git a/src/EditorFeatures/Core.Wpf/Interactive/InteractiveWindowResetCommand.cs b/src/EditorFeatures/Core.Wpf/Interactive/InteractiveWindowResetCommand.cs index db725791fe4e8..92d1836eedae4 100644 --- a/src/EditorFeatures/Core.Wpf/Interactive/InteractiveWindowResetCommand.cs +++ b/src/EditorFeatures/Core.Wpf/Interactive/InteractiveWindowResetCommand.cs @@ -120,7 +120,7 @@ internal static bool TryParseArguments(string arguments, out bool initialize, ou var noConfigSpecified = false; - foreach (var argument in arguments.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries)) + foreach (var argument in arguments.Split([' '], StringSplitOptions.RemoveEmptyEntries)) { switch (argument.ToLowerInvariant()) { diff --git a/src/EditorFeatures/Core.Wpf/Interactive/ResetInteractive.cs b/src/EditorFeatures/Core.Wpf/Interactive/ResetInteractive.cs index 44f9efd6558fd..fffb86eb37059 100644 --- a/src/EditorFeatures/Core.Wpf/Interactive/ResetInteractive.cs +++ b/src/EditorFeatures/Core.Wpf/Interactive/ResetInteractive.cs @@ -41,36 +41,35 @@ internal ResetInteractive(EditorOptionsService editorOptionsService, Func - { - context.Dispose(); - ExecutionCompleted?.Invoke(this, new EventArgs()); - }, - TaskScheduler.FromCurrentSynchronizationContext()); + try + { + // Now, we're going to do a bunch of async operations. So create a wait + // indicator so the user knows something is happening, and also so they cancel. + var uiThreadOperationExecutor = GetUIThreadOperationExecutor(); + using var context = uiThreadOperationExecutor.BeginExecute(title, EditorFeaturesWpfResources.Building_Project, allowCancellation: true, showProgress: false); + + // We want to come back onto the calling context to dismiss the wait indicator and to notify about + // execution completion. + await ResetInteractiveAsync( + interactiveWindow, + references, + referenceSearchPaths, + sourceSearchPaths, + projectNamespaces, + projectDirectory, + platform, + context).ConfigureAwait(true); + } + finally + { + // Once we're done resetting focus the REPL window. + ExecutionCompleted?.Invoke(this, new EventArgs()); + } } - - return Task.CompletedTask; } private async Task ResetInteractiveAsync( diff --git a/src/EditorFeatures/Core.Wpf/Lightup/ISmartRenameSessionWrapper.cs b/src/EditorFeatures/Core.Wpf/Lightup/ISmartRenameSessionWrapper.cs index 9ee6e53ca2168..45efb9baff566 100644 --- a/src/EditorFeatures/Core.Wpf/Lightup/ISmartRenameSessionWrapper.cs +++ b/src/EditorFeatures/Core.Wpf/Lightup/ISmartRenameSessionWrapper.cs @@ -29,6 +29,7 @@ namespace Microsoft.CodeAnalysis.EditorFeatures.Lightup; private static readonly Func s_statusMessageAccessor; private static readonly Func s_statusMessageVisibilityAccessor; private static readonly Func> s_suggestedNamesAccessor; + private static readonly Func s_correlationIdAccessor; private static readonly Func? s_renameContextImmutableListCreateBuilderAccessor; private static readonly Action? s_renameContextImmutableListBuilderAddAccessor; private static readonly Func? s_renameContextImmutableListBuilderToArrayAccessor; @@ -52,6 +53,7 @@ static ISmartRenameSessionWrapper() s_statusMessageAccessor = LightupHelpers.CreatePropertyAccessor(s_wrappedType, nameof(StatusMessage), ""); s_statusMessageVisibilityAccessor = LightupHelpers.CreatePropertyAccessor(s_wrappedType, nameof(StatusMessageVisibility), false); s_suggestedNamesAccessor = LightupHelpers.CreatePropertyAccessor>(s_wrappedType, nameof(SuggestedNames), []); + s_correlationIdAccessor = LightupHelpers.CreatePropertyAccessor(s_wrappedType, nameof(CorrelationId), Guid.Empty); if (s_wrappedRenameContextType is not null) { @@ -93,6 +95,7 @@ private ISmartRenameSessionWrapper(object instance) public string StatusMessage => s_statusMessageAccessor(_instance); public bool StatusMessageVisibility => s_statusMessageVisibilityAccessor(_instance); public IReadOnlyList SuggestedNames => s_suggestedNamesAccessor(_instance); + public Guid CorrelationId => s_correlationIdAccessor(_instance); public event PropertyChangedEventHandler PropertyChanged { diff --git a/src/EditorFeatures/Core.Wpf/LineSeparators/LineSeparatorTaggerProvider.cs b/src/EditorFeatures/Core.Wpf/LineSeparators/LineSeparatorTaggerProvider.cs index 6ed1085f9f6fc..bdd44f4c75d68 100644 --- a/src/EditorFeatures/Core.Wpf/LineSeparators/LineSeparatorTaggerProvider.cs +++ b/src/EditorFeatures/Core.Wpf/LineSeparators/LineSeparatorTaggerProvider.cs @@ -38,7 +38,7 @@ internal sealed partial class LineSeparatorTaggerProvider : AsynchronousTaggerPr { private readonly IEditorFormatMap _editorFormatMap; - protected sealed override ImmutableArray Options { get; } = ImmutableArray.Empty; + protected sealed override ImmutableArray Options { get; } = []; private readonly object _lineSeparatorTagGate = new(); private LineSeparatorTag _lineSeparatorTag; diff --git a/src/EditorFeatures/Core.Wpf/Peek/PeekableItemFactory.cs b/src/EditorFeatures/Core.Wpf/Peek/PeekableItemFactory.cs index a81d9ab3434de..d3b86ff56a40a 100644 --- a/src/EditorFeatures/Core.Wpf/Peek/PeekableItemFactory.cs +++ b/src/EditorFeatures/Core.Wpf/Peek/PeekableItemFactory.cs @@ -60,10 +60,10 @@ public async Task> GetPeekableItemsAsync( throw new ArgumentNullException(nameof(peekResultFactory)); var solution = project.Solution; - symbol = await SymbolFinder.FindSourceDefinitionAsync(symbol, solution, cancellationToken).ConfigureAwait(false) ?? symbol; - symbol = await GoToDefinitionFeatureHelpers.TryGetPreferredSymbolAsync(solution, symbol, cancellationToken).ConfigureAwait(false); + symbol = SymbolFinder.FindSourceDefinition(symbol, solution, cancellationToken) ?? symbol; + symbol = GoToDefinitionFeatureHelpers.TryGetPreferredSymbol(solution, symbol, cancellationToken); if (symbol is null) - return ImmutableArray.Empty; + return []; // if we mapped the symbol, then get the new project it is contained in. var originatingProject = solution.GetProject(symbol.ContainingAssembly, cancellationToken); diff --git a/src/EditorFeatures/Core.Wpf/QuickInfo/OnTheFlyDocsView.xaml.cs b/src/EditorFeatures/Core.Wpf/QuickInfo/OnTheFlyDocsView.xaml.cs index 6a8bc27d8b5db..f2ab905041903 100644 --- a/src/EditorFeatures/Core.Wpf/QuickInfo/OnTheFlyDocsView.xaml.cs +++ b/src/EditorFeatures/Core.Wpf/QuickInfo/OnTheFlyDocsView.xaml.cs @@ -76,21 +76,19 @@ public OnTheFlyDocsView(ITextView textView, IViewElementFactoryService viewEleme OnDemandLinkContent = ToUIElement( new ContainerElement( ContainerElementStyle.Wrapped, - new object[] - { + [ sparkle, onDemandLinkText, - })); + ])); LoadingContent = ToUIElement( new ContainerElement( ContainerElementStyle.Stacked, - new object[] - { + [ new ClassifiedTextElement(new ClassifiedTextRun( ClassificationTypeDefinitions.ReducedEmphasisText, EditorFeaturesResources.Copilot_thinking)), new SmoothProgressBar { IsIndeterminate = true, Height = 2, Margin = new Thickness { Top = 2 } }, - })); + ])); // Ensure the loading content stretches so that the progress bar // takes the entire width of the quick info tooltip. @@ -102,18 +100,16 @@ public OnTheFlyDocsView(ITextView textView, IViewElementFactoryService viewEleme ResultsContent = ToUIElement( new ContainerElement( ContainerElementStyle.Stacked, - new object[] - { + [ new ContainerElement( ContainerElementStyle.Wrapped, - new object[] - { + [ sparkle, ClassifiedTextElement.CreatePlainText(EditorFeaturesResources.Copilot), - }), + ]), new ThematicBreakElement(), _responseControl, - })); + ])); ResultsRequested += (_, _) => PopulateAIDocumentationElements(_cancellationTokenSource.Token); _asyncQuickInfoSession.StateChanged += (_, _) => OnQuickInfoSessionChanged(); diff --git a/src/EditorFeatures/Core.Wpf/SignatureHelp/Controller.Session.cs b/src/EditorFeatures/Core.Wpf/SignatureHelp/Controller.Session.cs index 5afb115c9bf50..2536450973e52 100644 --- a/src/EditorFeatures/Core.Wpf/SignatureHelp/Controller.Session.cs +++ b/src/EditorFeatures/Core.Wpf/SignatureHelp/Controller.Session.cs @@ -15,7 +15,7 @@ internal partial class Controller internal partial class Session : Session { public Session(Controller controller, ISignatureHelpPresenterSession presenterSession) - : base(controller, new ModelComputation(controller.ThreadingContext, controller, TaskScheduler.Default), presenterSession) + : base(controller, new ModelComputation(controller.ThreadingContext, controller), presenterSession) { this.PresenterSession.ItemSelected += OnPresenterSessionItemSelected; } diff --git a/src/EditorFeatures/Core.Wpf/SignatureHelp/Controller.Session_ComputeModel.cs b/src/EditorFeatures/Core.Wpf/SignatureHelp/Controller.Session_ComputeModel.cs index 6ba12a299a638..2b913940c08ef 100644 --- a/src/EditorFeatures/Core.Wpf/SignatureHelp/Controller.Session_ComputeModel.cs +++ b/src/EditorFeatures/Core.Wpf/SignatureHelp/Controller.Session_ComputeModel.cs @@ -13,10 +13,10 @@ using Microsoft.CodeAnalysis.ErrorReporting; using Microsoft.CodeAnalysis.Internal.Log; using Microsoft.CodeAnalysis.LanguageService; -using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.SignatureHelp; using Microsoft.VisualStudio.Text; +using Microsoft.VisualStudio.Threading; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Editor.Implementation.IntelliSense.SignatureHelp @@ -37,9 +37,8 @@ public void ComputeModel( // If we've already computed a model, then just use that. Otherwise, actually // compute a new model and send that along. Computation.ChainTaskAndNotifyControllerWhenFinished( - (model, cancellationToken) => ComputeModelInBackgroundAsync( - model, providers, caretPosition, disconnectedBufferGraph, - triggerInfo, cancellationToken)); + (currentModel, cancellationToken) => ComputeModelInBackgroundAsync( + currentModel, providers, caretPosition, disconnectedBufferGraph, triggerInfo, cancellationToken)); } private async Task ComputeModelInBackgroundAsync( diff --git a/src/EditorFeatures/Core.Wpf/SignatureHelp/Controller.Session_SetModelSelectedItem.cs b/src/EditorFeatures/Core.Wpf/SignatureHelp/Controller.Session_SetModelSelectedItem.cs index 534980d3ab7c3..026e40169bcb8 100644 --- a/src/EditorFeatures/Core.Wpf/SignatureHelp/Controller.Session_SetModelSelectedItem.cs +++ b/src/EditorFeatures/Core.Wpf/SignatureHelp/Controller.Session_SetModelSelectedItem.cs @@ -2,11 +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. -#nullable disable - using System; +using System.Threading.Tasks; using Microsoft.CodeAnalysis.Editor.Shared.Extensions; using Microsoft.CodeAnalysis.SignatureHelp; +using Microsoft.VisualStudio.Threading; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Editor.Implementation.IntelliSense.SignatureHelp @@ -20,20 +20,17 @@ private void SetModelExplicitlySelectedItem(Func selec this.Computation.ThreadingContext.ThrowIfNotOnUIThread(); Computation.ChainTaskAndNotifyControllerWhenFinished( - model => SetModelExplicitlySelectedItemInBackground(model, selector), + (model, cancellationToken) => Task.FromResult(SetModelExplicitlySelectedItemInBackground(model, selector)), updateController: false); } - private Model SetModelExplicitlySelectedItemInBackground( - Model model, + private Model? SetModelExplicitlySelectedItemInBackground( + Model? model, Func selector) { this.Computation.ThreadingContext.ThrowIfNotOnBackgroundThread(); - if (model == null) - { return null; - } var selectedItem = selector(model); Contract.ThrowIfFalse(model.Items.Contains(selectedItem)); diff --git a/src/EditorFeatures/Core.Wpf/SignatureHelp/Controller.cs b/src/EditorFeatures/Core.Wpf/SignatureHelp/Controller.cs index c47daf7d94ede..71935aee1646b 100644 --- a/src/EditorFeatures/Core.Wpf/SignatureHelp/Controller.cs +++ b/src/EditorFeatures/Core.Wpf/SignatureHelp/Controller.cs @@ -66,7 +66,7 @@ internal Controller( IAsyncCompletionBroker completionBroker) : base(globalOptions, threadingContext, textView, subjectBuffer, presenter, asyncListener, documentProvider, "SignatureHelp") { - _providers = providers.ToImmutableArray(); + _providers = [.. providers]; _completionBroker = completionBroker; } @@ -131,8 +131,8 @@ private ImmutableArray GetProviders() var document = snapshot.GetOpenDocumentInCurrentContextWithChanges(); if (document != null) { - _providers = document.Project.Solution.Services.SelectMatchingExtensionValues( - _allProviders, this.SubjectBuffer.ContentType).ToImmutableArray(); + _providers = [.. document.Project.Solution.Services.SelectMatchingExtensionValues( + _allProviders, this.SubjectBuffer.ContentType)]; _lastSeenContentType = currentContentType; } } diff --git a/src/EditorFeatures/Core.Wpf/SignatureHelp/Controller_NavigationKeys.cs b/src/EditorFeatures/Core.Wpf/SignatureHelp/Controller_NavigationKeys.cs deleted file mode 100644 index d2730efa02baf..0000000000000 --- a/src/EditorFeatures/Core.Wpf/SignatureHelp/Controller_NavigationKeys.cs +++ /dev/null @@ -1,67 +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. - -#nullable disable - -using System; -using Microsoft.CodeAnalysis.Editor.Shared.Extensions; - -namespace Microsoft.CodeAnalysis.Editor.Implementation.IntelliSense.SignatureHelp -{ - internal partial class Controller - { - internal bool TryHandleUpKey() - { - this.ThreadingContext.ThrowIfNotOnUIThread(); - return ChangeSelection(() => sessionOpt.PresenterSession.SelectPreviousItem()); - } - - internal bool TryHandleDownKey() - { - this.ThreadingContext.ThrowIfNotOnUIThread(); - return ChangeSelection(() => sessionOpt.PresenterSession.SelectNextItem()); - } - - private bool ChangeSelection(Action computationAction) - { - this.ThreadingContext.ThrowIfNotOnUIThread(); - - if (!IsSessionActive) - { - // No computation running, so just let the editor handle this. - return false; - } - - // If we haven't started our editor session yet, just abort. - // The user hasn't seen a SigHelp presentation yet, so they're - // probably not trying to change the currently visible overload. - if (!sessionOpt.PresenterSession.EditorSessionIsActive) - { - DismissSessionIfActive(); - return false; - } - - // If we've finished computing the items then use the navigation commands to change the - // selected item. Otherwise, the user was just typing and is now moving through the - // file. In this case stop everything we're doing. - var model = sessionOpt.InitialUnfilteredModel != null ? WaitForController() : null; - - // Check if completion is still active. Then update the computation appropriately. - // - // Also, if we only computed one item, then the user doesn't want to select anything - // else. Just stop and let the editor handle the nav character. - if (model != null && model.Items.Count > 1) - { - computationAction(); - return true; - } - else - { - // Dismiss ourselves and actually allow the editor to navigate. - DismissSessionIfActive(); - return false; - } - } - } -} diff --git a/src/EditorFeatures/Core.Wpf/SignatureHelp/SignatureHelpAfterCompletionCommandHandler.cs b/src/EditorFeatures/Core.Wpf/SignatureHelp/SignatureHelpAfterCompletionCommandHandler.cs deleted file mode 100644 index c999a5dbe5519..0000000000000 --- a/src/EditorFeatures/Core.Wpf/SignatureHelp/SignatureHelpAfterCompletionCommandHandler.cs +++ /dev/null @@ -1,101 +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. - -#nullable disable - -using System; -using System.ComponentModel.Composition; -using Microsoft.CodeAnalysis.Editor.Implementation.IntelliSense.SignatureHelp; -using Microsoft.CodeAnalysis.Editor.Shared.Utilities; -using Microsoft.CodeAnalysis.Host.Mef; -using Microsoft.CodeAnalysis.Options; -using Microsoft.VisualStudio.Commanding; -using Microsoft.VisualStudio.Language.Intellisense.AsyncCompletion; -using Microsoft.VisualStudio.Text.Editor.Commanding.Commands; -using Microsoft.VisualStudio.Utilities; - -namespace Microsoft.CodeAnalysis.Editor.CommandHandlers -{ - /// - /// There are two forms of intellisense that may be active at the same time. Completion and - /// SigHelp. Completion precedes SigHelp in - /// because it wants to make sure - /// it's operating on a buffer *after* Completion has changed it. i.e. if "WriteL(" is typed, - /// sig help wants to allow completion to complete that to "WriteLine(" before it tried to - /// proffer sig help. If we were to reverse things, then we'd get a bogus situation where sig - /// help would see "WriteL(" would have nothing to offer and would return. - /// - /// However, despite wanting sighelp to receive typechar first and then defer it to completion, - /// we want completion to receive other events first (like escape, and navigation keys). We - /// consider completion to have higher priority for those commands. In order to accomplish that, - /// we introduced the current command handler. This command handler then delegates escape, up and - /// down to those command handlers. - /// It is called after . - /// - [Export] - [Export(typeof(ICommandHandler))] - [ContentType(ContentTypeNames.RoslynContentType)] - [Name(PredefinedCommandHandlerNames.SignatureHelpAfterCompletion)] - [Order(After = PredefinedCompletionNames.CompletionCommandHandler)] - // Ensure roslyn comes after LSP to allow them to provide results. - // https://github.com/dotnet/roslyn/issues/42338 - [Order(After = "LSP SignatureHelpCommandHandler")] - internal class SignatureHelpAfterCompletionCommandHandler : - AbstractSignatureHelpCommandHandler, - IChainedCommandHandler, - IChainedCommandHandler, - IChainedCommandHandler - { - public string DisplayName => EditorFeaturesResources.Signature_Help; - - [ImportingConstructor] - [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - public SignatureHelpAfterCompletionCommandHandler( - IThreadingContext threadingContext, - SignatureHelpControllerProvider controllerProvider, - IGlobalOptionService globalOptions) - : base(threadingContext, controllerProvider, globalOptions) - { - } - - public CommandState GetCommandState(EscapeKeyCommandArgs args, Func nextHandler) - => nextHandler(); - - public CommandState GetCommandState(UpKeyCommandArgs args, Func nextHandler) - => nextHandler(); - - public CommandState GetCommandState(DownKeyCommandArgs args, Func nextHandler) - => nextHandler(); - - public void ExecuteCommand(EscapeKeyCommandArgs args, Action nextHandler, CommandExecutionContext context) - { - if (TryGetController(args, out var controller) && controller.TryHandleEscapeKey()) - { - return; - } - - nextHandler(); - } - - public void ExecuteCommand(UpKeyCommandArgs args, Action nextHandler, CommandExecutionContext context) - { - if (TryGetController(args, out var controller) && controller.TryHandleUpKey()) - { - return; - } - - nextHandler(); - } - - public void ExecuteCommand(DownKeyCommandArgs args, Action nextHandler, CommandExecutionContext context) - { - if (TryGetController(args, out var controller) && controller.TryHandleDownKey()) - { - return; - } - - nextHandler(); - } - } -} diff --git a/src/EditorFeatures/Core.Wpf/SignatureHelp/SignatureHelpBeforeCompletionCommandHandler.cs b/src/EditorFeatures/Core.Wpf/SignatureHelp/SignatureHelpBeforeCompletionCommandHandler.cs index 59688bdaa08f8..301980e672a3d 100644 --- a/src/EditorFeatures/Core.Wpf/SignatureHelp/SignatureHelpBeforeCompletionCommandHandler.cs +++ b/src/EditorFeatures/Core.Wpf/SignatureHelp/SignatureHelpBeforeCompletionCommandHandler.cs @@ -20,19 +20,11 @@ namespace Microsoft.CodeAnalysis.Editor.CommandHandlers { /// - /// There are two forms of intellisense that may be active at the same time. Completion and - /// SigHelp. Completion precedes SigHelp in the command handler because it wants to make sure - /// it's operating on a buffer *after* Completion has changed it. i.e. if "WriteL(" is typed, - /// sig help wants to allow completion to complete that to "WriteLine(" before it tried to - /// proffer sig help. If we were to reverse things, then we'd get a bogus situation where sig - /// help would see "WriteL(" would have nothing to offer and would return. - /// - /// However, despite wanting sighelp to receive typechar first and then defer it to completion, - /// we want completion to receive other events first (like escape, and navigation keys). We - /// consider completion to have higher priority for those commands. In order to accomplish that, - /// we introduced - /// This command handler then delegates escape, up and down to those command handlers. - /// It is called before . + /// There are two forms of intellisense that may be active at the same time. Completion and SigHelp. Completion + /// precedes SigHelp in the command handler because it wants to make sure it's operating on a buffer *after* + /// Completion has changed it. i.e. if "WriteL(" is typed, sig help wants to allow completion to complete that to + /// "WriteLine(" before it tried to proffer sig help. If we were to reverse things, then we'd get a bogus situation + /// where sig help would see "WriteL(" would have nothing to offer and would return. /// [Export] [Export(typeof(ICommandHandler))] diff --git a/src/EditorFeatures/Core.Wpf/Structure/StructureTaggerProvider.cs b/src/EditorFeatures/Core.Wpf/Structure/StructureTaggerProvider.cs index 5d4b545ccb3ed..052ce63ef992f 100644 --- a/src/EditorFeatures/Core.Wpf/Structure/StructureTaggerProvider.cs +++ b/src/EditorFeatures/Core.Wpf/Structure/StructureTaggerProvider.cs @@ -18,48 +18,47 @@ using Microsoft.VisualStudio.Utilities; using StructureTag = Microsoft.CodeAnalysis.Editor.Implementation.Structure.StructureTag; -namespace Microsoft.CodeAnalysis.Editor.Structure -{ - [Export(typeof(ITaggerProvider))] - [Export(typeof(AbstractStructureTaggerProvider))] - [TagType(typeof(IStructureTag))] - [ContentType(ContentTypeNames.RoslynContentType)] - [method: ImportingConstructor] - [method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - internal sealed class StructureTaggerProvider( - TaggerHost taggerHost, - EditorOptionsService editorOptionsService, - IProjectionBufferFactoryService projectionBufferFactoryService, - ITextEditorFactoryService textEditorFactoryService) : AbstractStructureTaggerProvider(taggerHost, editorOptionsService, projectionBufferFactoryService) - { - private readonly ITextEditorFactoryService _textEditorFactoryService = textEditorFactoryService; +namespace Microsoft.CodeAnalysis.Editor.Structure; - internal override object? GetCollapsedHintForm(StructureTag structureTag) - { - return new ViewHostingControl(CreateElisionBufferView, () => CreateElisionBufferForTagTooltip(structureTag)); - } +[Export(typeof(ITaggerProvider))] +[Export(typeof(AbstractStructureTaggerProvider))] +[TagType(typeof(IStructureTag))] +[ContentType(ContentTypeNames.RoslynContentType)] +[method: ImportingConstructor] +[method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] +internal sealed class StructureTaggerProvider( + TaggerHost taggerHost, + EditorOptionsService editorOptionsService, + IProjectionBufferFactoryService projectionBufferFactoryService, + ITextEditorFactoryService textEditorFactoryService) : AbstractStructureTaggerProvider(taggerHost, editorOptionsService, projectionBufferFactoryService) +{ + private readonly ITextEditorFactoryService _textEditorFactoryService = textEditorFactoryService; - private IWpfTextView CreateElisionBufferView(ITextBuffer finalBuffer) - => CreateShrunkenTextView(ThreadingContext, _textEditorFactoryService, finalBuffer); + internal override object? GetCollapsedHintForm(StructureTag structureTag) + { + return new ViewHostingControl(CreateElisionBufferView, () => CreateElisionBufferForTagTooltip(structureTag)); + } - private static IWpfTextView CreateShrunkenTextView( - IThreadingContext threadingContext, - ITextEditorFactoryService textEditorFactoryService, - ITextBuffer finalBuffer) - { - var roles = textEditorFactoryService.CreateTextViewRoleSet(OutliningRegionTextViewRole); - var view = textEditorFactoryService.CreateTextView(finalBuffer, roles); + private IWpfTextView CreateElisionBufferView(ITextBuffer finalBuffer) + => CreateShrunkenTextView(ThreadingContext, _textEditorFactoryService, finalBuffer); - view.Background = Brushes.Transparent; + private static IWpfTextView CreateShrunkenTextView( + IThreadingContext threadingContext, + ITextEditorFactoryService textEditorFactoryService, + ITextBuffer finalBuffer) + { + var roles = textEditorFactoryService.CreateTextViewRoleSet(OutliningRegionTextViewRole); + var view = textEditorFactoryService.CreateTextView(finalBuffer, roles); - view.SizeToFit(threadingContext); + view.Background = Brushes.Transparent; - // Zoom out a bit to shrink the text. - view.ZoomLevel *= 0.75; + view.SizeToFit(threadingContext); - return view; - } + // Zoom out a bit to shrink the text. + view.ZoomLevel *= 0.75; - private const string OutliningRegionTextViewRole = nameof(OutliningRegionTextViewRole); + return view; } + + private const string OutliningRegionTextViewRole = nameof(OutliningRegionTextViewRole); } diff --git a/src/EditorFeatures/Core.Wpf/Suggestions/FixAll/FixMultipleOccurrencesService.cs b/src/EditorFeatures/Core.Wpf/Suggestions/FixAll/FixMultipleOccurrencesService.cs index 5268050b4926c..3d38af13ce9ad 100644 --- a/src/EditorFeatures/Core.Wpf/Suggestions/FixAll/FixMultipleOccurrencesService.cs +++ b/src/EditorFeatures/Core.Wpf/Suggestions/FixAll/FixMultipleOccurrencesService.cs @@ -8,85 +8,77 @@ using System.Collections.Immutable; using System.Composition; using System.Threading; -using Microsoft.CodeAnalysis.CodeActions; +using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeFixes; using Microsoft.CodeAnalysis.Extensions; using Microsoft.CodeAnalysis.Host.Mef; -using Microsoft.CodeAnalysis.Shared.TestHooks; -using Roslyn.Utilities; -namespace Microsoft.CodeAnalysis.Editor.Implementation.Suggestions +namespace Microsoft.CodeAnalysis.Editor.Implementation.Suggestions; + +/// +/// Service to compute and apply code fixes. +/// +[ExportWorkspaceService(typeof(IFixMultipleOccurrencesService), ServiceLayer.Host), Shared] +[method: ImportingConstructor] +[method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] +internal sealed class FixMultipleOccurrencesService() : IFixMultipleOccurrencesService { - /// - /// Service to compute and apply code fixes. - /// - [ExportWorkspaceService(typeof(IFixMultipleOccurrencesService), ServiceLayer.Host), Shared] - internal sealed class FixMultipleOccurrencesService : IFixMultipleOccurrencesService + public Task GetFixAsync( + ImmutableDictionary> diagnosticsToFix, + Workspace workspace, + CodeFixProvider fixProvider, + FixAllProvider fixAllProvider, + string equivalenceKey, + string waitDialogTitle, + string waitDialogMessage, + IProgress progress, + CancellationToken cancellationToken) { - [ImportingConstructor] - [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - public FixMultipleOccurrencesService(IAsynchronousOperationListenerProvider listenerProvider) - { - listenerProvider.GetListener(FeatureAttribute.LightBulb); - } + var fixMultipleState = FixAllState.Create( + fixAllProvider, diagnosticsToFix, fixProvider, equivalenceKey); - public Solution GetFix( - ImmutableDictionary> diagnosticsToFix, - Workspace workspace, - CodeFixProvider fixProvider, - FixAllProvider fixAllProvider, - string equivalenceKey, - string waitDialogTitle, - string waitDialogMessage, - IProgress progress, - CancellationToken cancellationToken) - { - var fixMultipleState = FixAllState.Create( - fixAllProvider, diagnosticsToFix, fixProvider, equivalenceKey); + return GetFixedSolutionAsync( + fixMultipleState, workspace, waitDialogTitle, waitDialogMessage, progress, cancellationToken); + } - return GetFixedSolution( - fixMultipleState, workspace, waitDialogTitle, waitDialogMessage, progress, cancellationToken); - } + public Task GetFixAsync( + ImmutableDictionary> diagnosticsToFix, + Workspace workspace, + CodeFixProvider fixProvider, + FixAllProvider fixAllProvider, + string equivalenceKey, + string waitDialogTitle, + string waitDialogMessage, + IProgress progress, + CancellationToken cancellationToken) + { + var fixMultipleState = FixAllState.Create( + fixAllProvider, diagnosticsToFix, fixProvider, equivalenceKey); - public Solution GetFix( - ImmutableDictionary> diagnosticsToFix, - Workspace workspace, - CodeFixProvider fixProvider, - FixAllProvider fixAllProvider, - string equivalenceKey, - string waitDialogTitle, - string waitDialogMessage, - IProgress progress, - CancellationToken cancellationToken) - { - var fixMultipleState = FixAllState.Create( - fixAllProvider, diagnosticsToFix, fixProvider, equivalenceKey); + return GetFixedSolutionAsync( + fixMultipleState, workspace, waitDialogTitle, waitDialogMessage, progress, cancellationToken); + } - return GetFixedSolution( - fixMultipleState, workspace, waitDialogTitle, waitDialogMessage, progress, cancellationToken); - } + private static async Task GetFixedSolutionAsync( + FixAllState fixAllState, + Workspace workspace, + string title, + string waitDialogMessage, + IProgress progress, + CancellationToken cancellationToken) + { + var fixMultipleCodeAction = new FixMultipleCodeAction( + fixAllState, title, waitDialogMessage); - private static Solution GetFixedSolution( - FixAllState fixAllState, - Workspace workspace, - string title, - string waitDialogMessage, - IProgress progress, - CancellationToken cancellationToken) + Solution newSolution = null; + var extensionManager = workspace.Services.GetService(); + await extensionManager.PerformActionAsync(fixAllState.FixAllProvider, async () => { - var fixMultipleCodeAction = new FixMultipleCodeAction( - fixAllState, title, waitDialogMessage); - - Solution newSolution = null; - var extensionManager = workspace.Services.GetService(); - extensionManager.PerformAction(fixAllState.FixAllProvider, () => - { - // We don't need to post process changes here as the inner code action created for Fix multiple code fix already executes. - newSolution = fixMultipleCodeAction.GetChangedSolutionInternalAsync( - fixAllState.Solution, progress, postProcessChanges: false, cancellationToken).WaitAndGetResult(cancellationToken); - }); + // We don't need to post process changes here as the inner code action created for Fix multiple code fix already executes. + newSolution = await fixMultipleCodeAction.GetChangedSolutionInternalAsync( + fixAllState.Solution, progress, postProcessChanges: false, cancellationToken).ConfigureAwait(false); + }).ConfigureAwait(false); - return newSolution; - } + return newSolution; } } diff --git a/src/EditorFeatures/Core.Wpf/Suggestions/PreviewChanges/PreviewChangesCodeAction.cs b/src/EditorFeatures/Core.Wpf/Suggestions/PreviewChanges/PreviewChangesCodeAction.cs index 41611712f3c5f..14cbd6ff5e2f6 100644 --- a/src/EditorFeatures/Core.Wpf/Suggestions/PreviewChanges/PreviewChangesCodeAction.cs +++ b/src/EditorFeatures/Core.Wpf/Suggestions/PreviewChanges/PreviewChangesCodeAction.cs @@ -37,13 +37,13 @@ private protected override async Task> GetOp var previewDialogService = _workspace.Services.GetService(); if (previewDialogService == null) { - return ImmutableArray.Empty; + return []; } var previewResult = await _getPreviewResultAsync(cancellationToken).ConfigureAwait(true); if (previewResult?.ChangeSummary is not { } changeSummary) { - return ImmutableArray.Empty; + return []; } var changedSolution = previewDialogService.PreviewChanges( @@ -59,7 +59,7 @@ private protected override async Task> GetOp if (changedSolution == null) { // User pressed the cancel button. - return ImmutableArray.Empty; + return []; } cancellationToken.ThrowIfCancellationRequested(); diff --git a/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionWithNestedFlavors.cs b/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionWithNestedFlavors.cs index ec52af6c88e4c..cb486d50fcc43 100644 --- a/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionWithNestedFlavors.cs +++ b/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionWithNestedFlavors.cs @@ -81,7 +81,7 @@ public sealed override async Task> GetActionSets // check if Copilot service is available using a relatively cheap, but async method call. _nestedFlavors = await extensionManager.PerformFunctionAsync( Provider, CreateAllFlavorsAsync, - defaultValue: ImmutableArray.Empty, cancellationToken).ConfigureAwait(false); + defaultValue: [], cancellationToken).ConfigureAwait(false); } Contract.ThrowIfTrue(_nestedFlavors.IsDefault); diff --git a/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActions/SuggestedAction.cs b/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActions/SuggestedAction.cs index 81de54979ae38..462e1ba04e101 100644 --- a/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActions/SuggestedAction.cs +++ b/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActions/SuggestedAction.cs @@ -178,7 +178,7 @@ await EditHandler.ApplyAsync( Workspace, OriginalSolution, document, - operations.ToImmutableArray(), + [.. operations], CodeAction.Title, progressTracker, cancellationToken).ConfigureAwait(false); diff --git a/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSourceProvider.cs b/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSourceProvider.cs index 9ebd4cdd26913..49b3fe24307b5 100644 --- a/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSourceProvider.cs +++ b/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSourceProvider.cs @@ -80,7 +80,7 @@ public SuggestedActionsSourceProvider( UIThreadOperationExecutor = uiThreadOperationExecutor; OperationListener = listenerProvider.GetListener(FeatureAttribute.LightBulb); - ImageIdServices = ExtensionOrderer.Order(imageIdServices).ToImmutableArray(); + ImageIdServices = [.. ExtensionOrderer.Order(imageIdServices)]; } public ISuggestedActionsSource? CreateSuggestedActionsSource(ITextView textView, ITextBuffer textBuffer) diff --git a/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSource_Async.cs b/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSource_Async.cs index 135caef587b35..206c7f08f8f81 100644 --- a/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSource_Async.cs +++ b/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSource_Async.cs @@ -235,7 +235,7 @@ async Task> GetCodeFixesAsync() !supportsFeatureService.SupportsCodeFixes(target.SubjectBuffer) || !requestedActionCategories.Contains(PredefinedSuggestedActionCategoryNames.CodeFix)) { - return ImmutableArray.Empty; + return []; } return await UnifiedSuggestedActionsSource.GetFilterAndOrderCodeFixesAsync( @@ -251,20 +251,20 @@ async Task> GetRefactoringsAsync() { // this is here to fail test and see why it is failed. Trace.WriteLine("given range is not current"); - return ImmutableArray.Empty; + return []; } if (!this.GlobalOptions.GetOption(EditorComponentOnOffOptions.CodeRefactorings) || owner._codeRefactoringService == null || !supportsFeatureService.SupportsRefactorings(subjectBuffer)) { - return ImmutableArray.Empty; + return []; } // 'CodeActionRequestPriority.Lowest' is reserved for suppression/configuration code fixes. // No code refactoring should have this request priority. if (priorityProvider.Priority == CodeActionRequestPriority.Lowest) - return ImmutableArray.Empty; + return []; // If we are computing refactorings outside the 'Refactoring' context, i.e. for example, from the lightbulb under a squiggle or selection, // then we want to filter out refactorings outside the selection span. diff --git a/src/EditorFeatures/Core/AutomaticCompletion/BraceCompletionSessionProvider.BraceCompletionSession.cs b/src/EditorFeatures/Core/AutomaticCompletion/BraceCompletionSessionProvider.BraceCompletionSession.cs index 3d9c496a7b667..ae11d57312352 100644 --- a/src/EditorFeatures/Core/AutomaticCompletion/BraceCompletionSessionProvider.BraceCompletionSession.cs +++ b/src/EditorFeatures/Core/AutomaticCompletion/BraceCompletionSessionProvider.BraceCompletionSession.cs @@ -7,6 +7,7 @@ using System; using System.Diagnostics; using System.Threading; +using System.Threading.Tasks; using Microsoft.CodeAnalysis.BraceCompletion; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Editor.Shared.Extensions; @@ -31,52 +32,46 @@ internal partial class BraceCompletionSessionProvider // fortunately, editor provides another extension point where we have more control over brace completion but we do not // want to re-implement logics base session provider already provides. so I ported editor's default session and // modified it little bit so that we can use it as base class. - private class BraceCompletionSession : IBraceCompletionSession + private class BraceCompletionSession( + ITextView textView, + ITextBuffer subjectBuffer, + SnapshotPoint openingPoint, + char openingBrace, + char closingBrace, + ITextUndoHistory undoHistory, + IEditorOperationsFactoryService editorOperationsFactoryService, + EditorOptionsService editorOptionsService, + IBraceCompletionService service, + IThreadingContext threadingContext) : IBraceCompletionSession { - public char OpeningBrace { get; } - public char ClosingBrace { get; } + private readonly ITextUndoHistory _undoHistory = undoHistory; + private readonly IEditorOperations _editorOperations = editorOperationsFactoryService.GetEditorOperations(textView); + private readonly EditorOptionsService _editorOptionsService = editorOptionsService; + private readonly IBraceCompletionService _service = service; + private readonly IThreadingContext _threadingContext = threadingContext; + + public char OpeningBrace { get; } = openingBrace; + public char ClosingBrace { get; } = closingBrace; + public ITrackingPoint OpeningPoint { get; private set; } - public ITrackingPoint ClosingPoint { get; private set; } - public ITextBuffer SubjectBuffer { get; } - public ITextView TextView { get; } - - private readonly ITextUndoHistory _undoHistory; - private readonly IEditorOperations _editorOperations; - private readonly EditorOptionsService _editorOptionsService; - private readonly IBraceCompletionService _service; - private readonly IThreadingContext _threadingContext; - - public BraceCompletionSession( - ITextView textView, ITextBuffer subjectBuffer, - SnapshotPoint openingPoint, char openingBrace, char closingBrace, ITextUndoHistory undoHistory, - IEditorOperationsFactoryService editorOperationsFactoryService, - EditorOptionsService editorOptionsService, IBraceCompletionService service, IThreadingContext threadingContext) - { - TextView = textView; - SubjectBuffer = subjectBuffer; - OpeningBrace = openingBrace; - ClosingBrace = closingBrace; - ClosingPoint = SubjectBuffer.CurrentSnapshot.CreateTrackingPoint(openingPoint.Position, PointTrackingMode.Positive); - _undoHistory = undoHistory; - _editorOperations = editorOperationsFactoryService.GetEditorOperations(textView); - _editorOptionsService = editorOptionsService; - _service = service; - _threadingContext = threadingContext; - } + public ITrackingPoint ClosingPoint { get; private set; } = subjectBuffer.CurrentSnapshot.CreateTrackingPoint(openingPoint.Position, PointTrackingMode.Positive); + + public ITextBuffer SubjectBuffer { get; } = subjectBuffer; + public ITextView TextView { get; } = textView; #region IBraceCompletionSession Methods public void Start() { _threadingContext.ThrowIfNotOnUIThread(); + // Brace completion is not cancellable. - if (!this.TryStart(CancellationToken.None)) - { + var success = _threadingContext.JoinableTaskFactory.Run(() => TryStartAsync(CancellationToken.None)); + if (!success) EndSession(); - } } - private bool TryStart(CancellationToken cancellationToken) + private async Task TryStartAsync(CancellationToken cancellationToken) { _threadingContext.ThrowIfNotOnUIThread(); var closingSnapshotPoint = ClosingPoint.GetPoint(SubjectBuffer.CurrentSnapshot); @@ -101,18 +96,15 @@ private bool TryStart(CancellationToken cancellationToken) var document = SubjectBuffer.CurrentSnapshot.GetOpenDocumentInCurrentContextWithChanges(); if (document == null) - { return false; - } var parsedDocument = ParsedDocument.CreateSynchronously(document, cancellationToken); var context = GetBraceCompletionContext(parsedDocument, document.Project.GetFallbackAnalyzerOptions()); // Note: completes synchronously unless Semantic Model is needed to determine the result: - if (!_service.HasBraceCompletionAsync(context, document, cancellationToken).WaitAndGetResult(cancellationToken)) - { + var hasBraceCompletions = await _service.HasBraceCompletionAsync(context, document, cancellationToken).ConfigureAwait(true); + if (!hasBraceCompletions) return false; - } var braceResult = _service.GetBraceCompletion(context); diff --git a/src/EditorFeatures/Core/ChangeSignature/AbstractChangeSignatureCommandHandler.cs b/src/EditorFeatures/Core/ChangeSignature/AbstractChangeSignatureCommandHandler.cs index 3123472b90d4a..8c81a0fe321df 100644 --- a/src/EditorFeatures/Core/ChangeSignature/AbstractChangeSignatureCommandHandler.cs +++ b/src/EditorFeatures/Core/ChangeSignature/AbstractChangeSignatureCommandHandler.cs @@ -3,31 +3,26 @@ // See the LICENSE file in the project root for more information. using System.Diagnostics.CodeAnalysis; +using System.Threading.Tasks; using Microsoft.CodeAnalysis.Editor.Host; using Microsoft.CodeAnalysis.Editor.Shared.Extensions; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.Editor.Undo; using Microsoft.CodeAnalysis.Notification; -using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.VisualStudio.Commanding; using Microsoft.VisualStudio.Text; using Microsoft.VisualStudio.Text.Editor; using Microsoft.VisualStudio.Text.Editor.Commanding.Commands; using Microsoft.VisualStudio.Utilities; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.ChangeSignature; -internal abstract class AbstractChangeSignatureCommandHandler : ICommandHandler, - ICommandHandler +internal abstract class AbstractChangeSignatureCommandHandler(IThreadingContext threadingContext) + : ICommandHandler, + ICommandHandler { - private readonly IThreadingContext _threadingContext; - - protected AbstractChangeSignatureCommandHandler(IThreadingContext threadingContext) - { - _threadingContext = threadingContext; - } + private readonly IThreadingContext _threadingContext = threadingContext; public string DisplayName => EditorFeaturesResources.Change_Signature; @@ -55,49 +50,48 @@ private bool ExecuteCommand(ITextView textView, ITextBuffer subjectBuffer, Comma { using (context.OperationContext.AddScope(allowCancellation: true, FeaturesResources.Change_signature)) { - if (!IsAvailable(subjectBuffer, out var workspace)) - { - return false; - } + return _threadingContext.JoinableTaskFactory.Run(() => ExecuteCommandAsync(textView, subjectBuffer, context)); + } + } - var caretPoint = textView.GetCaretPoint(subjectBuffer); - if (!caretPoint.HasValue) - { - return false; - } + private static async Task ExecuteCommandAsync(ITextView textView, ITextBuffer subjectBuffer, CommandExecutionContext context) + { + if (!IsAvailable(subjectBuffer, out var workspace)) + return false; - var document = subjectBuffer.CurrentSnapshot.GetFullyLoadedOpenDocumentInCurrentContextWithChanges( - context.OperationContext, _threadingContext); - if (document == null) - { - return false; - } + var caretPoint = textView.GetCaretPoint(subjectBuffer); + if (!caretPoint.HasValue) + return false; - var changeSignatureService = document.GetRequiredLanguageService(); + var document = await subjectBuffer.CurrentSnapshot.GetFullyLoadedOpenDocumentInCurrentContextWithChangesAsync(context.OperationContext).ConfigureAwait(true); + if (document == null) + return false; - var cancellationToken = context.OperationContext.UserCancellationToken; + var changeSignatureService = document.GetRequiredLanguageService(); - // TODO: Make asynchronous and avoid expensive semantic operations on UI thread: - // https://github.com/dotnet/roslyn/issues/62135 + var cancellationToken = context.OperationContext.UserCancellationToken; - // Async operation to determine the change signature - var changeSignatureContext = changeSignatureService.GetChangeSignatureContextAsync( - document, - caretPoint.Value.Position, - restrictToDeclarations: false, - cancellationToken).WaitAndGetResult(context.OperationContext.UserCancellationToken); + // TODO: Make asynchronous and avoid expensive semantic operations on UI thread: + // https://github.com/dotnet/roslyn/issues/62135 - // UI thread bound operation to show the change signature dialog. - var changeSignatureOptions = AbstractChangeSignatureService.GetChangeSignatureOptions(changeSignatureContext); + // Async operation to determine the change signature + var changeSignatureContext = await changeSignatureService.GetChangeSignatureContextAsync( + document, + caretPoint.Value.Position, + restrictToDeclarations: false, + cancellationToken).ConfigureAwait(true); - // Async operation to compute the new solution created from the specified options. - var result = changeSignatureService.ChangeSignatureWithContextAsync(changeSignatureContext, changeSignatureOptions, cancellationToken).WaitAndGetResult(cancellationToken); + // UI thread bound operation to show the change signature dialog. + var changeSignatureOptions = AbstractChangeSignatureService.GetChangeSignatureOptions(changeSignatureContext); - // UI thread bound operation to show preview changes dialog / show error message, then apply the solution changes (if applicable). - HandleResult(result, document.Project.Solution, workspace, context); + // Async operation to compute the new solution created from the specified options. + var result = await changeSignatureService.ChangeSignatureWithContextAsync( + changeSignatureContext, changeSignatureOptions, cancellationToken).ConfigureAwait(true); - return true; - } + // UI thread bound operation to show preview changes dialog / show error message, then apply the solution changes (if applicable). + HandleResult(result, document.Project.Solution, workspace, context); + + return true; } private static void HandleResult(ChangeSignatureResult result, Solution oldSolution, Workspace workspace, CommandExecutionContext context) diff --git a/src/EditorFeatures/Core/CommentSelection/CommentSelectionResult.cs b/src/EditorFeatures/Core/CommentSelection/CommentSelectionResult.cs index f08e300202a96..db211738e78f5 100644 --- a/src/EditorFeatures/Core/CommentSelection/CommentSelectionResult.cs +++ b/src/EditorFeatures/Core/CommentSelection/CommentSelectionResult.cs @@ -15,11 +15,11 @@ internal readonly struct CommentSelectionResult(IEnumerable textChan /// /// Text changes to make for this operation. /// - public ImmutableArray TextChanges { get; } = textChanges.ToImmutableArray(); + public ImmutableArray TextChanges { get; } = [.. textChanges]; /// /// Tracking spans used to format and set the output selection after edits. /// - public ImmutableArray TrackingSpans { get; } = trackingSpans.ToImmutableArray(); + public ImmutableArray TrackingSpans { get; } = [.. trackingSpans]; /// /// The type of text changes being made. /// This is known beforehand in some cases (comment selection) diff --git a/src/EditorFeatures/Core/DocumentationComments/AbstractDocumentationCommentCommandHandler.cs b/src/EditorFeatures/Core/DocumentationComments/AbstractDocumentationCommentCommandHandler.cs index 04db5a505e483..f5e72cd324736 100644 --- a/src/EditorFeatures/Core/DocumentationComments/AbstractDocumentationCommentCommandHandler.cs +++ b/src/EditorFeatures/Core/DocumentationComments/AbstractDocumentationCommentCommandHandler.cs @@ -50,10 +50,7 @@ protected AbstractDocumentationCommentCommandHandler( protected abstract string ExteriorTriviaText { get; } - private char TriggerCharacter - { - get { return ExteriorTriviaText[^1]; } - } + private char TriggerCharacter => ExteriorTriviaText[^1]; public string DisplayName => EditorFeaturesResources.Documentation_Comment; @@ -81,15 +78,11 @@ private bool CompleteComment( { var caretPosition = textView.GetCaretPoint(subjectBuffer) ?? -1; if (caretPosition < 0) - { return false; - } var document = subjectBuffer.CurrentSnapshot.GetOpenDocumentInCurrentContextWithChanges(); if (document == null) - { return false; - } var service = document.GetRequiredLanguageService(); var parsedDocument = ParsedDocument.CreateSynchronously(document, cancellationToken); @@ -120,15 +113,11 @@ public void ExecuteCommand(TypeCharCommandArgs args, Action nextHandler, Command nextHandler(); if (args.TypedChar != TriggerCharacter) - { return; - } // Don't execute in cloud environment, as we let LSP handle that if (args.SubjectBuffer.IsInLspEditorContext()) - { return; - } CompleteComment(args.SubjectBuffer, args.TextView, InsertOnCharacterTyped, CancellationToken.None); } @@ -138,6 +127,8 @@ public CommandState GetCommandState(ReturnKeyCommandArgs args) public bool ExecuteCommand(ReturnKeyCommandArgs args, CommandExecutionContext context) { + var cancellationToken = context.OperationContext.UserCancellationToken; + // Don't execute in cloud environment, as we let LSP handle that if (args.SubjectBuffer.IsInLspEditorContext()) { @@ -169,7 +160,7 @@ public bool ExecuteCommand(ReturnKeyCommandArgs args, CommandExecutionContext co return false; } - if (!CurrentLineStartsWithExteriorTrivia(args.SubjectBuffer, originalPosition, context.OperationContext.UserCancellationToken)) + if (!CurrentLineStartsWithExteriorTrivia(args.SubjectBuffer, originalPosition, cancellationToken)) { return false; } diff --git a/src/EditorFeatures/Core/Editor/EditorLayerExtensionManager.cs b/src/EditorFeatures/Core/Editor/EditorLayerExtensionManager.cs index 30bb2617011eb..8ad860c76ae22 100644 --- a/src/EditorFeatures/Core/Editor/EditorLayerExtensionManager.cs +++ b/src/EditorFeatures/Core/Editor/EditorLayerExtensionManager.cs @@ -31,7 +31,7 @@ namespace Microsoft.CodeAnalysis.Editor; internal sealed class EditorLayerExtensionManager( [ImportMany] IEnumerable errorHandlers) : IWorkspaceServiceFactory { - private readonly ImmutableArray _errorHandlers = errorHandlers.ToImmutableArray(); + private readonly ImmutableArray _errorHandlers = [.. errorHandlers]; public IWorkspaceService CreateService(HostWorkspaceServices workspaceServices) { diff --git a/src/EditorFeatures/Core/Editor/TextBufferAssociatedViewService.cs b/src/EditorFeatures/Core/Editor/TextBufferAssociatedViewService.cs index 80165a5c981f7..fb1a32b9644f7 100644 --- a/src/EditorFeatures/Core/Editor/TextBufferAssociatedViewService.cs +++ b/src/EditorFeatures/Core/Editor/TextBufferAssociatedViewService.cs @@ -100,7 +100,7 @@ private static IList GetTextViews(ITextBuffer textBuffer) return []; } - return set.ToList(); + return [.. set]; } } diff --git a/src/EditorFeatures/Core/EditorConfigSettings/Data/NamingStyleSetting.cs b/src/EditorFeatures/Core/EditorConfigSettings/Data/NamingStyleSetting.cs index 15b1edbd97a14..e51df2279d80e 100644 --- a/src/EditorFeatures/Core/EditorConfigSettings/Data/NamingStyleSetting.cs +++ b/src/EditorFeatures/Core/EditorConfigSettings/Data/NamingStyleSetting.cs @@ -52,7 +52,7 @@ internal static NamingStyleSetting FromParseResult(NamingStyleOption namingStyle internal SymbolSpecification? Type { get; set; } public string StyleName => Style.Name; - public string[] AllStyles => _allStyles.Select(style => style.Name).ToArray(); + public string[] AllStyles => [.. _allStyles.Select(style => style.Name)]; public string TypeName => Type?.Name ?? string.Empty; public ReportDiagnostic Severity { get; private set; } public SettingLocation? Location { get; protected set; } diff --git a/src/EditorFeatures/Core/EditorFeaturesResources.resx b/src/EditorFeatures/Core/EditorFeaturesResources.resx index c5acfd2bc2bb9..0d2ddf466abbc 100644 --- a/src/EditorFeatures/Core/EditorFeaturesResources.resx +++ b/src/EditorFeatures/Core/EditorFeaturesResources.resx @@ -303,9 +303,6 @@ Rename operation was not properly completed. Some file might not have been updated. - - Rename '{0}' to '{1}' - Preview Warning diff --git a/src/EditorFeatures/Core/EndConstructGeneration/IEndConstructGenerationService.cs b/src/EditorFeatures/Core/EndConstructGeneration/IEndConstructGenerationService.cs index 99e2571f7ace6..0014088bc5f3d 100644 --- a/src/EditorFeatures/Core/EndConstructGeneration/IEndConstructGenerationService.cs +++ b/src/EditorFeatures/Core/EndConstructGeneration/IEndConstructGenerationService.cs @@ -2,9 +2,8 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System.Threading; +using System.Threading.Tasks; using Microsoft.CodeAnalysis.Host; using Microsoft.VisualStudio.Text; using Microsoft.VisualStudio.Text.Editor; @@ -13,5 +12,5 @@ namespace Microsoft.CodeAnalysis.Editor.Implementation.EndConstructGeneration; internal interface IEndConstructGenerationService : ILanguageService { - bool TryDo(ITextView textView, ITextBuffer subjectBuffer, char typedChar, CancellationToken cancellationToken); + Task TryDoAsync(ITextView textView, ITextBuffer subjectBuffer, char typedChar, CancellationToken cancellationToken); } diff --git a/src/EditorFeatures/Core/Extensibility/NavigationBar/NavigationBarProjectItem.cs b/src/EditorFeatures/Core/Extensibility/NavigationBar/NavigationBarProjectItem.cs index 9d741f28f74e0..83659cf4529d9 100644 --- a/src/EditorFeatures/Core/Extensibility/NavigationBar/NavigationBarProjectItem.cs +++ b/src/EditorFeatures/Core/Extensibility/NavigationBar/NavigationBarProjectItem.cs @@ -14,8 +14,8 @@ internal sealed class NavigationBarProjectItem( Workspace workspace, DocumentId documentId, string language) : NavigationBarItem(textVersion: null, text, glyph, - spans: ImmutableArray.Empty, - childItems: ImmutableArray.Empty, + spans: [], + childItems: [], indent: 0, bolded: false, grayed: false), IEquatable { public Workspace Workspace { get; } = workspace; diff --git a/src/EditorFeatures/Core/ExternalAccess/UnitTesting/UnitTestingReferencesService.cs b/src/EditorFeatures/Core/ExternalAccess/UnitTesting/UnitTestingReferencesService.cs index 23fc4f16d43fd..48a5af7b6ef01 100644 --- a/src/EditorFeatures/Core/ExternalAccess/UnitTesting/UnitTestingReferencesService.cs +++ b/src/EditorFeatures/Core/ExternalAccess/UnitTesting/UnitTestingReferencesService.cs @@ -19,7 +19,7 @@ namespace Microsoft.CodeAnalysis.UnitTesting.ExternalAccess; internal class UnitTestingReferencesService { private static readonly IEnumerable<(string MethodFullyQualifedName, string MethodFilePath, string MethodOutputFilePath)> Empty = - Enumerable.Empty<(string MethodFullyQualifedName, string MethodFilePath, string MethodOutputFilePath)>(); + []; internal static async Task> GetCallerMethodsAsync( IAsyncCodeLensDataPointProvider provider, diff --git a/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/Api/IVSTypeScriptFindUsagesContext.cs b/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/Api/IVSTypeScriptFindUsagesContext.cs index c189e29d28f5d..86b847e0f24aa 100644 --- a/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/Api/IVSTypeScriptFindUsagesContext.cs +++ b/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/Api/IVSTypeScriptFindUsagesContext.cs @@ -53,7 +53,7 @@ private sealed class ExternalDefinitionItem(VSTypeScriptDefinitionItemNavigator : DefinitionItem( tags, displayParts, - ImmutableArray.Empty, + [], sourceSpans: default, metadataLocations: [], classifiedSpans: default, diff --git a/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/Api/VSTypeScriptDebugDataTipInfoWrapper.cs b/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/Api/VSTypeScriptDebugDataTipInfoWrapper.cs index f1b4c228b9337..a32191949dff1 100644 --- a/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/Api/VSTypeScriptDebugDataTipInfoWrapper.cs +++ b/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/Api/VSTypeScriptDebugDataTipInfoWrapper.cs @@ -9,9 +9,9 @@ namespace Microsoft.CodeAnalysis.ExternalAccess.VSTypeScript.Api; internal readonly struct VSTypeScriptDebugDataTipInfoWrapper(TextSpan span, string text) { - internal readonly DebugDataTipInfo UnderlyingObject = new DebugDataTipInfo(span, text); + internal readonly DebugDataTipInfo UnderlyingObject = new(span, text); public readonly TextSpan Span => UnderlyingObject.Span; - public readonly string Text => UnderlyingObject.Text; + public readonly string Text => UnderlyingObject.Text!; public bool IsDefault => UnderlyingObject.IsDefault; } diff --git a/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/VSTypeScriptLanguageDebugInfoService.cs b/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/VSTypeScriptLanguageDebugInfoService.cs index 51c59c3d372f0..1f173eb45bf85 100644 --- a/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/VSTypeScriptLanguageDebugInfoService.cs +++ b/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/VSTypeScriptLanguageDebugInfoService.cs @@ -12,15 +12,15 @@ namespace Microsoft.CodeAnalysis.ExternalAccess.VSTypeScript; -[Shared] -[ExportLanguageService(typeof(ILanguageDebugInfoService), InternalLanguageNames.TypeScript)] +[ExportLanguageService(typeof(ILanguageDebugInfoService), InternalLanguageNames.TypeScript), Shared] [method: ImportingConstructor] [method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] -internal sealed class VSTypeScriptLanguageDebugInfoService(IVSTypeScriptLanguageDebugInfoServiceImplementation implementation) : ILanguageDebugInfoService +internal sealed class VSTypeScriptLanguageDebugInfoService(IVSTypeScriptLanguageDebugInfoServiceImplementation implementation) + : ILanguageDebugInfoService { private readonly IVSTypeScriptLanguageDebugInfoServiceImplementation _implementation = implementation; - public async Task GetDataTipInfoAsync(Document document, int position, CancellationToken cancellationToken) + public async Task GetDataTipInfoAsync(Document document, int position, bool includeKind, CancellationToken cancellationToken) => (await _implementation.GetDataTipInfoAsync(document, position, cancellationToken).ConfigureAwait(false)).UnderlyingObject; public async Task GetLocationInfoAsync(Document document, int position, CancellationToken cancellationToken) diff --git a/src/EditorFeatures/Core/ExtractMethod/ExtractMethodCommandHandler.cs b/src/EditorFeatures/Core/ExtractMethod/ExtractMethodCommandHandler.cs index 4c5351e60b5c7..b60702640bde8 100644 --- a/src/EditorFeatures/Core/ExtractMethod/ExtractMethodCommandHandler.cs +++ b/src/EditorFeatures/Core/ExtractMethod/ExtractMethodCommandHandler.cs @@ -14,7 +14,6 @@ using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Notification; -using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Shared.TestHooks; using Microsoft.CodeAnalysis.Text; using Microsoft.CodeAnalysis.Text.Shared.Extensions; @@ -39,7 +38,6 @@ internal sealed class ExtractMethodCommandHandler : ICommandHandler(); + + // Note: we do not want to cancel on 'focus lost'. That's because extract-method may show the user a + // notification dialog about proceeding or not. We don't want the act of showing them a dialog about proceeding + // to then cause the whole operation to then fail. using var indicatorContext = indicatorFactory.Create( - view, span, EditorFeaturesResources.Applying_Extract_Method_refactoring, cancelOnEdit: true, cancelOnFocusLost: true); + view, span, EditorFeaturesResources.Applying_Extract_Method_refactoring, cancelOnEdit: true, cancelOnFocusLost: false); using var asyncToken = _asyncListener.BeginAsyncOperation(nameof(ExecuteCommand)); await ExecuteWorkerAsync(view, textBuffer, span.Span.ToTextSpan(), indicatorContext).ConfigureAwait(false); @@ -140,12 +140,35 @@ private async Task ExecuteWorkerAsync( return; var options = await document.GetExtractMethodGenerationOptionsAsync(cancellationToken).ConfigureAwait(false); - var result = await ExtractMethodService.ExtractMethodAsync( - document, span, localFunction: false, options, cancellationToken).ConfigureAwait(false); + + var result = await ExtractMethodService.ExtractMethodAsync(document, span, localFunction: false, options, cancellationToken).ConfigureAwait(false); + + if (!Succeeded(result)) + { + // Extract method didn't succeed. Or succeeded, but had some reasons to notify the user about. See if + // extracting a local function would be better.. + + var localFunctionResult = await ExtractMethodService.ExtractMethodAsync(document, span, localFunction: true, options, cancellationToken).ConfigureAwait(false); + if (Succeeded(localFunctionResult)) + { + // Extract local function completely succeeded. Use that instead. + result = localFunctionResult; + } + else if (!result.Succeeded && localFunctionResult.Succeeded) + { + // Extract method entirely failed. But extract local function was able to proceed, albeit with reasons + // to notify the user about. Continue one with extract local function instead. + result = localFunctionResult; + } + else + { + // Extract local function was just as bad as extract method. Just report the extract method issues below. + } + } + Contract.ThrowIfNull(result); - result = await NotifyUserIfNecessaryAsync( - document, result, cancellationToken).ConfigureAwait(false); + result = await NotifyUserIfNecessaryAsync(document, result, cancellationToken).ConfigureAwait(false); if (result is null) return; @@ -185,11 +208,14 @@ private void ApplyChange_OnUIThread( undoTransaction.Complete(); } + private static bool Succeeded(ExtractMethodResult result) + => result is { Succeeded: true, Reasons.Length: 0 }; + private async Task NotifyUserIfNecessaryAsync( Document document, ExtractMethodResult result, CancellationToken cancellationToken) { // If we succeeded without any problems, just proceed without notifying the user. - if (result is { Succeeded: true, Reasons.Length: 0 }) + if (Succeeded(result)) return result; // We have some sort of issue. See what the user wants to do. If we have no way to inform the user bail diff --git a/src/EditorFeatures/Core/Formatting/FormatCommandHandler.Paste.cs b/src/EditorFeatures/Core/Formatting/FormatCommandHandler.Paste.cs index bf46b4736017e..27969da4257d1 100644 --- a/src/EditorFeatures/Core/Formatting/FormatCommandHandler.Paste.cs +++ b/src/EditorFeatures/Core/Formatting/FormatCommandHandler.Paste.cs @@ -3,7 +3,7 @@ // See the LICENSE file in the project root for more information. using System; -using System.Threading; +using System.Threading.Tasks; using Microsoft.CodeAnalysis.Editor.Shared.Extensions; using Microsoft.CodeAnalysis.Formatting.Rules; using Microsoft.CodeAnalysis.Shared.Extensions; @@ -11,7 +11,6 @@ using Microsoft.VisualStudio.Commanding; using Microsoft.VisualStudio.Text; using Microsoft.VisualStudio.Text.Editor.Commanding.Commands; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Formatting; @@ -29,13 +28,11 @@ public void ExecuteCommand(PasteCommandArgs args, Action nextHandler, CommandExe var cancellationToken = context.OperationContext.UserCancellationToken; if (cancellationToken.IsCancellationRequested) - { return; - } try { - ExecuteCommandWorker(args, caretPosition, cancellationToken); + _threadingContext.JoinableTaskFactory.Run(() => ExecuteCommandWorkerAsync()); } catch (OperationCanceledException) { @@ -43,45 +40,47 @@ public void ExecuteCommand(PasteCommandArgs args, Action nextHandler, CommandExe // is requested instead of throwing. Otherwise, we could end up in an invalid state due to already // calling nextHandler(). } - } - private void ExecuteCommandWorker(PasteCommandArgs args, SnapshotPoint? caretPosition, CancellationToken cancellationToken) - { - if (!caretPosition.HasValue) - return; + return; - var subjectBuffer = args.SubjectBuffer; - if (!subjectBuffer.TryGetWorkspace(out var workspace) || - !workspace.CanApplyChange(ApplyChangesKind.ChangeDocument)) + async Task ExecuteCommandWorkerAsync() { - return; + if (!caretPosition.HasValue) + return; + + var subjectBuffer = args.SubjectBuffer; + if (!subjectBuffer.TryGetWorkspace(out var workspace) || + !workspace.CanApplyChange(ApplyChangesKind.ChangeDocument)) + { + return; + } + + var document = subjectBuffer.CurrentSnapshot.GetOpenDocumentInCurrentContextWithChanges(); + if (document == null) + return; + + if (!_globalOptions.GetOption(FormattingOptionsStorage.FormatOnPaste, document.Project.Language)) + return; + + var solution = document.Project.Solution; + var services = solution.Services; + var formattingRuleService = services.GetService(); + if (formattingRuleService != null && formattingRuleService.ShouldNotFormatOrCommitOnPaste(document.Id)) + return; + + var formattingService = document.GetLanguageService(); + if (formattingService == null || !formattingService.SupportsFormatOnPaste) + return; + + var trackingSpan = caretPosition.Value.Snapshot.CreateTrackingSpan(caretPosition.Value.Position, 0, SpanTrackingMode.EdgeInclusive); + var span = trackingSpan.GetSpan(subjectBuffer.CurrentSnapshot).Span.ToTextSpan(); + + // Note: C# always completes synchronously, TypeScript is async + var changes = await formattingService.GetFormattingChangesOnPasteAsync(document, subjectBuffer, span, cancellationToken).ConfigureAwait(true); + if (changes.IsEmpty) + return; + + subjectBuffer.ApplyChanges(changes); } - - var document = subjectBuffer.CurrentSnapshot.GetOpenDocumentInCurrentContextWithChanges(); - if (document == null) - return; - - if (!_globalOptions.GetOption(FormattingOptionsStorage.FormatOnPaste, document.Project.Language)) - return; - - var solution = document.Project.Solution; - var services = solution.Services; - var formattingRuleService = services.GetService(); - if (formattingRuleService != null && formattingRuleService.ShouldNotFormatOrCommitOnPaste(document.Id)) - return; - - var formattingService = document.GetLanguageService(); - if (formattingService == null || !formattingService.SupportsFormatOnPaste) - return; - - var trackingSpan = caretPosition.Value.Snapshot.CreateTrackingSpan(caretPosition.Value.Position, 0, SpanTrackingMode.EdgeInclusive); - var span = trackingSpan.GetSpan(subjectBuffer.CurrentSnapshot).Span.ToTextSpan(); - - // Note: C# always completes synchronously, TypeScript is async - var changes = formattingService.GetFormattingChangesOnPasteAsync(document, subjectBuffer, span, cancellationToken).WaitAndGetResult(cancellationToken); - if (changes.IsEmpty) - return; - - subjectBuffer.ApplyChanges(changes); } } diff --git a/src/EditorFeatures/Core/Formatting/FormatCommandHandler.cs b/src/EditorFeatures/Core/Formatting/FormatCommandHandler.cs index 35c6a77571b57..77b4e7623910c 100644 --- a/src/EditorFeatures/Core/Formatting/FormatCommandHandler.cs +++ b/src/EditorFeatures/Core/Formatting/FormatCommandHandler.cs @@ -7,9 +7,11 @@ using System.Collections.Immutable; using System.ComponentModel.Composition; using System.Threading; +using System.Threading.Tasks; using Microsoft.CodeAnalysis.Editor; using Microsoft.CodeAnalysis.Editor.Shared.Extensions; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; +using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.Formatting.Rules; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Internal.Log; @@ -37,7 +39,8 @@ namespace Microsoft.CodeAnalysis.Formatting; [Order(Before = PredefinedCompletionNames.CompletionCommandHandler)] [method: ImportingConstructor] [method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] -internal partial class FormatCommandHandler( +internal sealed partial class FormatCommandHandler( + IThreadingContext threadingContext, ITextUndoHistoryRegistry undoHistoryRegistry, IEditorOperationsFactoryService editorOperationsFactoryService, IGlobalOptionService globalOptions) : @@ -47,6 +50,7 @@ internal partial class FormatCommandHandler( IChainedCommandHandler, IChainedCommandHandler { + private readonly IThreadingContext _threadingContext = threadingContext; private readonly ITextUndoHistoryRegistry _undoHistoryRegistry = undoHistoryRegistry; private readonly IEditorOperationsFactoryService _editorOperationsFactoryService = editorOperationsFactoryService; private readonly IGlobalOptionService _globalOptions = globalOptions; @@ -55,33 +59,39 @@ internal partial class FormatCommandHandler( private void Format(ITextView textView, ITextBuffer textBuffer, Document document, TextSpan? selectionOpt, CancellationToken cancellationToken) { - var formattingService = document.GetRequiredLanguageService(); - using (Logger.LogBlock(FunctionId.CommandHandler_FormatCommand, KeyValueLogMessage.Create(LogType.UserAction, m => m["Span"] = selectionOpt?.Length ?? -1), cancellationToken)) using (var transaction = CreateEditTransaction(textView, EditorFeaturesResources.Formatting)) { - // Note: C# always completes synchronously, TypeScript is async - var changes = formattingService.GetFormattingChangesAsync(document, textBuffer, selectionOpt, cancellationToken).WaitAndGetResult(cancellationToken); - if (changes.IsEmpty) - { - return; - } + _threadingContext.JoinableTaskFactory.Run(() => FormatAsync( + textBuffer, document, selectionOpt, cancellationToken)); - if (selectionOpt.HasValue) - { - var ruleFactory = document.Project.Solution.Services.GetRequiredService(); - changes = ruleFactory.FilterFormattedChanges(document.Id, selectionOpt.Value, changes).ToImmutableArray(); - } + transaction.Complete(); + } + } + + private static async Task FormatAsync( + ITextBuffer textBuffer, Document document, TextSpan? selectionOpt, CancellationToken cancellationToken) + { + var formattingService = document.GetRequiredLanguageService(); + + // Note: C# always completes synchronously, TypeScript is async + var changes = await formattingService.GetFormattingChangesAsync( + document, textBuffer, selectionOpt, cancellationToken).ConfigureAwait(true); + if (changes.IsEmpty) + return; + + if (selectionOpt.HasValue) + { + var ruleFactory = document.Project.Solution.Services.GetRequiredService(); + changes = [.. ruleFactory.FilterFormattedChanges(document.Id, selectionOpt.Value, changes)]; + } - if (!changes.IsEmpty) + if (!changes.IsEmpty) + { + using (Logger.LogBlock(FunctionId.Formatting_ApplyResultToBuffer, cancellationToken)) { - using (Logger.LogBlock(FunctionId.Formatting_ApplyResultToBuffer, cancellationToken)) - { - textBuffer.ApplyChanges(changes); - } + textBuffer.ApplyChanges(changes); } - - transaction.Complete(); } } @@ -102,7 +112,7 @@ public void ExecuteReturnOrTypeCommand(EditorCommandArgs args, Action nextHandle try { - ExecuteReturnOrTypeCommandWorker(args, cancellationToken); + _threadingContext.JoinableTaskFactory.Run(() => ExecuteReturnOrTypeCommandWorkerAsync(args, cancellationToken)); } catch (OperationCanceledException) { @@ -112,32 +122,24 @@ public void ExecuteReturnOrTypeCommand(EditorCommandArgs args, Action nextHandle } } - private void ExecuteReturnOrTypeCommandWorker(EditorCommandArgs args, CancellationToken cancellationToken) + private async Task ExecuteReturnOrTypeCommandWorkerAsync(EditorCommandArgs args, CancellationToken cancellationToken) { var textView = args.TextView; var subjectBuffer = args.SubjectBuffer; if (!CanExecuteCommand(subjectBuffer)) - { return; - } var caretPosition = textView.GetCaretPoint(args.SubjectBuffer); if (!caretPosition.HasValue) - { return; - } var document = subjectBuffer.CurrentSnapshot.GetOpenDocumentInCurrentContextWithChanges(); if (document == null) - { return; - } var service = document.GetLanguageService(); if (service == null) - { return; - } IList? textChanges; @@ -145,12 +147,11 @@ private void ExecuteReturnOrTypeCommandWorker(EditorCommandArgs args, Cancellati if (args is ReturnKeyCommandArgs) { if (!service.SupportsFormatOnReturn) - { return; - } // Note: C# always completes synchronously, TypeScript is async - textChanges = service.GetFormattingChangesOnReturnAsync(document, caretPosition.Value, cancellationToken).WaitAndGetResult(cancellationToken); + textChanges = await service.GetFormattingChangesOnReturnAsync( + document, caretPosition.Value, cancellationToken).ConfigureAwait(true); } else if (args is TypeCharCommandArgs typeCharArgs) { @@ -160,8 +161,8 @@ private void ExecuteReturnOrTypeCommandWorker(EditorCommandArgs args, Cancellati } // Note: C# always completes synchronously, TypeScript is async - textChanges = service.GetFormattingChangesAsync( - document, typeCharArgs.SubjectBuffer, typeCharArgs.TypedChar, caretPosition.Value, cancellationToken).WaitAndGetResult(cancellationToken); + textChanges = await service.GetFormattingChangesAsync( + document, typeCharArgs.SubjectBuffer, typeCharArgs.TypedChar, caretPosition.Value, cancellationToken).ConfigureAwait(true); } else { @@ -169,9 +170,7 @@ private void ExecuteReturnOrTypeCommandWorker(EditorCommandArgs args, Cancellati } if (textChanges == null || textChanges.Count == 0) - { return; - } using (var transaction = CreateEditTransaction(textView, EditorFeaturesResources.Automatic_Formatting)) { @@ -183,18 +182,14 @@ private void ExecuteReturnOrTypeCommandWorker(EditorCommandArgs args, Cancellati // get new caret position after formatting var newCaretPositionMarker = args.TextView.GetCaretPoint(args.SubjectBuffer); if (!newCaretPositionMarker.HasValue) - { return; - } var snapshotAfterFormatting = subjectBuffer.CurrentSnapshot; var oldCaretPosition = caretPosition.Value.TranslateTo(snapshotAfterFormatting, PointTrackingMode.Negative); var newCaretPosition = newCaretPositionMarker.Value.TranslateTo(snapshotAfterFormatting, PointTrackingMode.Negative); if (oldCaretPosition.Position == newCaretPosition.Position) - { return; - } // caret has moved to wrong position, move it back to correct position args.TextView.TryMoveCaretToAndEnsureVisible(oldCaretPosition); diff --git a/src/EditorFeatures/Core/InlineHints/InlineHintDataTag.cs b/src/EditorFeatures/Core/InlineHints/InlineHintDataTag.cs index 8607f14677567..d9505b71205e3 100644 --- a/src/EditorFeatures/Core/InlineHints/InlineHintDataTag.cs +++ b/src/EditorFeatures/Core/InlineHints/InlineHintDataTag.cs @@ -16,9 +16,12 @@ namespace Microsoft.CodeAnalysis.Editor.InlineHints; /// The simple tag that only holds information regarding the associated parameter name /// for the argument /// -internal sealed class InlineHintDataTag(InlineHintsDataTaggerProvider provider, ITextSnapshot snapshot, InlineHint hint) : ITag, IEquatable +internal sealed class InlineHintDataTag( + InlineHintsDataTaggerProvider provider, ITextSnapshot snapshot, InlineHint hint) + : ITag, IEquatable> + where TAdditionalInformation : class { - private readonly InlineHintsDataTaggerProvider _provider = provider; + private readonly InlineHintsDataTaggerProvider _provider = provider; /// /// The snapshot this tag was created against. @@ -27,15 +30,21 @@ internal sealed class InlineHintDataTag(InlineHintsDataTaggerProvider provider, public readonly InlineHint Hint = hint; + /// + /// Additional data that can be attached to the tag. For example, the view tagger uses this to attach the adornment + /// tag information so it can be created and cached on demand. + /// + public TAdditionalInformation? AdditionalData; + // Intentionally throwing, we have never supported this facility, and there is no contract around placing // these tags in sets or maps. public override int GetHashCode() => throw new NotImplementedException(); public override bool Equals(object? obj) - => obj is InlineHintDataTag tag && Equals(tag); + => obj is InlineHintDataTag tag && Equals(tag); - public bool Equals(InlineHintDataTag? other) + public bool Equals(InlineHintDataTag? other) { if (other is null) return false; diff --git a/src/EditorFeatures/Core/InlineHints/InlineHintKeyProcessorEventSource.cs b/src/EditorFeatures/Core/InlineHints/InlineHintKeyProcessorEventSource.cs index d14a599f3c6b3..f832a457ac39b 100644 --- a/src/EditorFeatures/Core/InlineHints/InlineHintKeyProcessorEventSource.cs +++ b/src/EditorFeatures/Core/InlineHints/InlineHintKeyProcessorEventSource.cs @@ -6,7 +6,7 @@ namespace Microsoft.CodeAnalysis.Editor.InlineHints; -internal partial class InlineHintsDataTaggerProvider +internal partial class InlineHintsDataTaggerProvider { private sealed class InlineHintKeyProcessorEventSource(IInlineHintKeyProcessor? inlineHintKeyProcessor) : AbstractTaggerEventSource { diff --git a/src/EditorFeatures/Core/InlineHints/InlineHintsDataTaggerProvider.cs b/src/EditorFeatures/Core/InlineHints/InlineHintsDataTaggerProvider.cs index 43cdbfe4190bf..b104436e84086 100644 --- a/src/EditorFeatures/Core/InlineHints/InlineHintsDataTaggerProvider.cs +++ b/src/EditorFeatures/Core/InlineHints/InlineHintsDataTaggerProvider.cs @@ -2,15 +2,12 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System; -using System.ComponentModel.Composition; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Editor.Shared.Extensions; using Microsoft.CodeAnalysis.Editor.Shared.Tagging; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.Editor.Tagging; -using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.InlineHints; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.TestHooks; @@ -18,23 +15,17 @@ using Microsoft.VisualStudio.Text; using Microsoft.VisualStudio.Text.Editor; using Microsoft.VisualStudio.Text.Tagging; -using VSUtilities = Microsoft.VisualStudio.Utilities; namespace Microsoft.CodeAnalysis.Editor.InlineHints; /// /// The TaggerProvider that calls upon the service in order to locate the spans and names /// -[Export(typeof(IViewTaggerProvider))] -[VSUtilities.ContentType(ContentTypeNames.RoslynContentType)] -[TagType(typeof(InlineHintDataTag))] -[VSUtilities.Name(nameof(InlineHintsDataTaggerProvider))] -[method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] -[method: ImportingConstructor] -internal sealed partial class InlineHintsDataTaggerProvider( +internal sealed partial class InlineHintsDataTaggerProvider( TaggerHost taggerHost, - [Import(AllowDefault = true)] IInlineHintKeyProcessor inlineHintKeyProcessor) - : AsynchronousViewportTaggerProvider(taggerHost, FeatureAttribute.InlineHints) + IInlineHintKeyProcessor inlineHintKeyProcessor) + : AsynchronousViewportTaggerProvider>(taggerHost, FeatureAttribute.InlineHints) + where TAdditionalInformation : class { private readonly IInlineHintKeyProcessor _inlineHintKeyProcessor = inlineHintKeyProcessor; @@ -73,7 +64,7 @@ protected override ITaggerEventSource CreateEventSource(ITextView textView, ITex } protected override async Task ProduceTagsAsync( - TaggerContext context, + TaggerContext> context, DocumentSnapshotSpan spanToTag, CancellationToken cancellationToken) { @@ -105,12 +96,12 @@ protected override async Task ProduceTagsAsync( if (hint.DisplayParts.Sum(p => p.ToString().Length) == 0) continue; - context.AddTag(new TagSpan( + context.AddTag(new TagSpan>( hint.Span.ToSnapshotSpan(snapshotSpan.Snapshot), - new InlineHintDataTag(this, snapshotSpan.Snapshot, hint))); + new(this, snapshotSpan.Snapshot, hint))); } } - protected override bool TagEquals(InlineHintDataTag tag1, InlineHintDataTag tag2) + protected override bool TagEquals(InlineHintDataTag tag1, InlineHintDataTag tag2) => tag1.Equals(tag2); } diff --git a/src/EditorFeatures/Core/InlineRename/InlineRenameSession.OpenTextBufferManager.cs b/src/EditorFeatures/Core/InlineRename/InlineRenameSession.OpenTextBufferManager.cs index 01c02a309551b..cce8d677fc3f5 100644 --- a/src/EditorFeatures/Core/InlineRename/InlineRenameSession.OpenTextBufferManager.cs +++ b/src/EditorFeatures/Core/InlineRename/InlineRenameSession.OpenTextBufferManager.cs @@ -312,7 +312,7 @@ internal void DisconnectAndRollbackEdits(bool documentIsClosed) } } - internal void ApplyConflictResolutionEdits(IInlineRenameReplacementInfo conflictResolution, LinkedFileMergeSessionResult mergeResult, IEnumerable documents, CancellationToken cancellationToken) + internal async Task ApplyConflictResolutionEditsAsync(IInlineRenameReplacementInfo conflictResolution, LinkedFileMergeSessionResult mergeResult, IEnumerable documents, CancellationToken cancellationToken) { _session._threadingContext.ThrowIfNotOnUIThread(); @@ -330,7 +330,8 @@ internal void ApplyConflictResolutionEdits(IInlineRenameReplacementInfo conflict var newDocument = mergeResult.MergedSolution.GetDocument(documents.First().Id); var originalDocument = _baseDocuments.Single(d => d.Id == newDocument.Id); - var changes = GetTextChangesFromTextDifferencingServiceAsync(originalDocument, newDocument, cancellationToken).WaitAndGetResult(cancellationToken); + var changes = await GetTextChangesFromTextDifferencingServiceAsync( + originalDocument, newDocument, cancellationToken).ConfigureAwait(true); // TODO: why does the following line stop responding when uncommented? // newDocument.GetTextChangesAsync(this.baseDocuments.Single(d => d.Id == newDocument.Id), cancellationToken).WaitAndGetResult(cancellationToken).Reverse(); @@ -436,18 +437,19 @@ internal void ApplyConflictResolutionEdits(IInlineRenameReplacementInfo conflict foreach (var document in documents) { - var relevantReplacements = conflictResolution.GetReplacements(document.Id).Where(r => GetRenameSpanKind(r.Kind) != RenameSpanKind.None); + var relevantReplacements = conflictResolution + .GetReplacements(document.Id) + .Where(r => GetRenameSpanKind(r.Kind) != RenameSpanKind.None) + .ToImmutableArray(); if (!relevantReplacements.Any()) - { continue; - } var mergedReplacements = linkedDocumentsMightConflict - ? GetMergedReplacementInfos( + ? await GetMergedReplacementInfosAsync( relevantReplacements, conflictResolution.NewSolution.GetDocument(document.Id), mergeResult.MergedSolution.GetDocument(document.Id), - cancellationToken) + cancellationToken).ConfigureAwait(true) : relevantReplacements; // Show merge conflicts comments as unresolvable conflicts, and do not @@ -578,8 +580,8 @@ private static async Task> GetTextChangesFromTextDiffere } } - private IEnumerable GetMergedReplacementInfos( - IEnumerable relevantReplacements, + private async Task> GetMergedReplacementInfosAsync( + ImmutableArray relevantReplacements, Document preMergeDocument, Document postMergeDocument, CancellationToken cancellationToken) @@ -606,6 +608,7 @@ private IEnumerable GetMergedReplacementInfos( preMergeDocumentTextString = preMergeDocument.GetTextSynchronously(cancellationToken).ToString(); } + var result = new FixedSizeArrayBuilder(relevantReplacements.Length); foreach (var replacement in relevantReplacements) { var buffer = snapshotSpanToClone.HasValue ? _textBufferCloneService.CloneWithUnknownContentType(snapshotSpanToClone.Value) : _textBufferFactoryService.CreateTextBuffer(preMergeDocumentTextString, contentType); @@ -613,16 +616,19 @@ private IEnumerable GetMergedReplacementInfos( using (var edit = _subjectBuffer.CreateEdit(EditOptions.None, null, s_calculateMergedSpansEditTag)) { - foreach (var change in textDiffService.GetTextChangesAsync(preMergeDocument, postMergeDocument, cancellationToken).WaitAndGetResult(cancellationToken)) - { + var textChanges = await textDiffService.GetTextChangesAsync( + preMergeDocument, postMergeDocument, cancellationToken).ConfigureAwait(true); + foreach (var change in textChanges) buffer.Replace(change.Span.ToSpan(), change.NewText); - } edit.ApplyAndLogExceptions(); } - yield return new InlineRenameReplacement(replacement.Kind, replacement.OriginalSpan, trackingSpan.GetSpan(buffer.CurrentSnapshot).Span.ToTextSpan()); + result.Add(new InlineRenameReplacement( + replacement.Kind, replacement.OriginalSpan, trackingSpan.GetSpan(buffer.CurrentSnapshot).Span.ToTextSpan())); } + + return result.MoveToImmutable(); } private static RenameSpanKind GetRenameSpanKind(InlineRenameReplacementKind kind) diff --git a/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs b/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs index 4ea243f8f2c37..28562337002f0 100644 --- a/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs +++ b/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs @@ -574,9 +574,9 @@ private void QueueApplyReplacements() // Switch to a background thread for expensive work await TaskScheduler.Default; - var computedMergeResult = await ComputeMergeResultAsync(replacementInfo, cancellationToken); - await _threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(alwaysYield: true, cancellationToken); - ApplyReplacements(computedMergeResult.replacementInfo, computedMergeResult.mergeResult, cancellationToken); + var computedMergeResult = await ComputeMergeResultAsync(replacementInfo, cancellationToken).ConfigureAwait(false); + await ApplyReplacementsAsync( + computedMergeResult.replacementInfo, computedMergeResult.mergeResult, cancellationToken).ConfigureAwait(true); }); replacementOperation.Task.CompletesAsyncOperation(asyncToken); } @@ -584,14 +584,14 @@ private void QueueApplyReplacements() private async Task<(IInlineRenameReplacementInfo replacementInfo, LinkedFileMergeSessionResult mergeResult)> ComputeMergeResultAsync(IInlineRenameReplacementInfo replacementInfo, CancellationToken cancellationToken) { var diffMergingSession = new LinkedFileDiffMergingSession(_baseSolution, replacementInfo.NewSolution, replacementInfo.NewSolution.GetChanges(_baseSolution)); - var mergeResult = await diffMergingSession.MergeDiffsAsync(mergeConflictHandler: null, cancellationToken: cancellationToken).ConfigureAwait(false); + var mergeResult = await diffMergingSession.MergeDiffsAsync(cancellationToken).ConfigureAwait(false); return (replacementInfo, mergeResult); } - private void ApplyReplacements(IInlineRenameReplacementInfo replacementInfo, LinkedFileMergeSessionResult mergeResult, CancellationToken cancellationToken) + private async Task ApplyReplacementsAsync( + IInlineRenameReplacementInfo replacementInfo, LinkedFileMergeSessionResult mergeResult, CancellationToken cancellationToken) { - _threadingContext.ThrowIfNotOnUIThread(); - cancellationToken.ThrowIfCancellationRequested(); + await _threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); RaiseReplacementsComputed(replacementInfo); @@ -602,7 +602,8 @@ private void ApplyReplacements(IInlineRenameReplacementInfo replacementInfo, Lin if (documents.Any()) { var textBufferManager = _openTextBuffers[textBuffer]; - textBufferManager.ApplyConflictResolutionEdits(replacementInfo, mergeResult, documents, cancellationToken); + await textBufferManager.ApplyConflictResolutionEditsAsync( + replacementInfo, mergeResult, documents, cancellationToken).ConfigureAwait(true); } } diff --git a/src/EditorFeatures/Core/IntelliSense/AbstractController.cs b/src/EditorFeatures/Core/IntelliSense/AbstractController.cs index f240f64e55d4a..b4265f3b01c70 100644 --- a/src/EditorFeatures/Core/IntelliSense/AbstractController.cs +++ b/src/EditorFeatures/Core/IntelliSense/AbstractController.cs @@ -12,6 +12,7 @@ using Microsoft.VisualStudio.Text.Editor; using Roslyn.Utilities; using Microsoft.CodeAnalysis.Editor.Shared.Extensions; +using System.Threading.Tasks; namespace Microsoft.CodeAnalysis.Editor.Implementation.IntelliSense; @@ -77,11 +78,11 @@ private void OnTextViewClosed(object sender, EventArgs e) this.TextView.TextBuffer.PostChanged -= this.OnTextViewBufferPostChanged; } - public TModel WaitForController() + public Task WaitForModelComputation_ForTestingPurposesOnlyAsync() { this.ThreadingContext.ThrowIfNotOnUIThread(); VerifySessionIsActive(); - return sessionOpt.WaitForController(); + return sessionOpt.WaitForModelComputation_ForTestingPurposesOnlyAsync(); } void IController.OnModelUpdated(TModel result, bool updateController) @@ -136,26 +137,4 @@ public void StopModelComputation() sessionOpt = null; localSession.Stop(); } - - public bool TryHandleEscapeKey() - { - this.ThreadingContext.ThrowIfNotOnUIThread(); - - // Escape simply dismissed a session if it's up. Otherwise let the next thing in the - // chain handle us. - if (!IsSessionActive) - { - return false; - } - - // If we haven't even computed a model yet, then also send this command to anyone - // listening. It's unlikely that the command was intended for us (as we wouldn't - // have even shown ui yet. - var handledCommand = sessionOpt.InitialUnfilteredModel != null; - - // In the presence of an escape, we always stop what we're doing. - this.StopModelComputation(); - - return handledCommand; - } } diff --git a/src/EditorFeatures/Core/IntelliSense/AsyncCompletion/ItemManager.CompletionListUpdater.cs b/src/EditorFeatures/Core/IntelliSense/AsyncCompletion/ItemManager.CompletionListUpdater.cs index 17a56e095c14d..2760f7f65fae4 100644 --- a/src/EditorFeatures/Core/IntelliSense/AsyncCompletion/ItemManager.CompletionListUpdater.cs +++ b/src/EditorFeatures/Core/IntelliSense/AsyncCompletion/ItemManager.CompletionListUpdater.cs @@ -648,7 +648,7 @@ static Span GetOffsetSpan(TextSpan span, RoslynCompletionItem item) // model (and all the previously filtered items), but switch over to soft // selection. return new FilteredCompletionModel( - items: ImmutableArray.Empty, selectedItemIndex, + items: [], selectedItemIndex, filters: _snapshotData.SelectedFilters, selectionHint: UpdateSelectionHint.SoftSelected, centerSelection: true, uniqueItem: null); } diff --git a/src/EditorFeatures/Core/IntelliSense/ISession.cs b/src/EditorFeatures/Core/IntelliSense/ISession.cs index d68a14cdc820e..e1b777b77937c 100644 --- a/src/EditorFeatures/Core/IntelliSense/ISession.cs +++ b/src/EditorFeatures/Core/IntelliSense/ISession.cs @@ -4,6 +4,8 @@ #nullable disable +using System.Threading.Tasks; + namespace Microsoft.CodeAnalysis.Editor.Implementation.IntelliSense; internal interface ISession @@ -12,5 +14,5 @@ internal interface ISession void Stop(); - TModel WaitForController(); + Task WaitForModelComputation_ForTestingPurposesOnlyAsync(); } diff --git a/src/EditorFeatures/Core/IntelliSense/ModelComputation.cs b/src/EditorFeatures/Core/IntelliSense/ModelComputation.cs index d5a48fdabb9cd..0e6b5e87d57e8 100644 --- a/src/EditorFeatures/Core/IntelliSense/ModelComputation.cs +++ b/src/EditorFeatures/Core/IntelliSense/ModelComputation.cs @@ -11,11 +11,12 @@ using Microsoft.CodeAnalysis.Editor.Shared.Extensions; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.Shared.TestHooks; +using Microsoft.VisualStudio.Threading; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Editor.Implementation.IntelliSense; -internal class ModelComputation where TModel : class +internal sealed class ModelComputation where TModel : class { #region Fields that can be accessed from either thread @@ -32,16 +33,6 @@ internal class ModelComputation where TModel : class #region Fields that can only be accessed from the foreground thread private readonly IController _controller; - private readonly TaskScheduler __taskScheduler; - - private TaskScheduler _taskScheduler - { - get - { - ThreadingContext.ThrowIfNotOnUIThread(); - return __taskScheduler; - } - } private readonly CancellationTokenSource _stopTokenSource; @@ -57,12 +48,10 @@ private TaskScheduler _taskScheduler public ModelComputation( IThreadingContext threadingContext, - IController controller, - TaskScheduler computationTaskScheduler) + IController controller) { ThreadingContext = threadingContext; _controller = controller; - __taskScheduler = computationTaskScheduler; _stopTokenSource = new CancellationTokenSource(); _stopCancellationToken = _stopTokenSource.Token; @@ -92,23 +81,10 @@ public Task ModelTask } } - public TModel WaitForController() - { - ThreadingContext.ThrowIfNotOnUIThread(); - - var model = ModelTask.WaitAndGetResult(CancellationToken.None); - if (!_notifyControllerTask.IsCompleted) - { - OnModelUpdated(model, updateController: true); - - // Reset lastTask so controller.OnModelUpdated is only called once - _lastTask = Task.FromResult(model); - } - - return model; - } + public Task WaitForModelComputation_ForTestingPurposesOnlyAsync() + => ModelTask; - public virtual void Stop() + public void Stop() { ThreadingContext.ThrowIfNotOnUIThread(); @@ -119,13 +95,6 @@ public virtual void Stop() _notifyControllerTask = _lastTask = SpecializedTasks.Null(); } - public void ChainTaskAndNotifyControllerWhenFinished( - Func transformModel, - bool updateController = true) - { - ChainTaskAndNotifyControllerWhenFinished((m, c) => Task.FromResult(transformModel(m)), updateController); - } - public void ChainTaskAndNotifyControllerWhenFinished( Func> transformModelAsync, bool updateController = true) @@ -140,9 +109,8 @@ public void ChainTaskAndNotifyControllerWhenFinished( var asyncToken = _controller.BeginAsyncOperation(); // Create the task that will actually run the transformation step. - var nextTask = _lastTask.SafeContinueWithFromAsync( - t => transformModelAsync(t.Result, _stopCancellationToken), - _stopCancellationToken, TaskContinuationOptions.OnlyOnRanToCompletion, _taskScheduler); + var nextTask = TransformModelAsync(_lastTask);// transformModelAsync(_lastTask, _stopCancellationToken); + nextTask.ReportNonFatalErrorAsync(); // The next task is now the last task in the chain. _lastTask = nextTask; @@ -174,6 +142,14 @@ public void ChainTaskAndNotifyControllerWhenFinished( // When we've notified the controller of our result, we consider the async operation // to be completed. _notifyControllerTask.CompletesAsyncOperation(asyncToken); + + async Task TransformModelAsync(Task lastTask) + { + // Ensure we're on the BG before doing any model transformation work. + await TaskScheduler.Default; + var model = await lastTask.ConfigureAwait(false); + return await transformModelAsync(model, _stopCancellationToken).ConfigureAwait(false); + } } private void OnModelUpdated(TModel result, bool updateController) diff --git a/src/EditorFeatures/Core/IntelliSense/Session.cs b/src/EditorFeatures/Core/IntelliSense/Session.cs index 9c63ae8f13eb1..e3c7a1bdb52df 100644 --- a/src/EditorFeatures/Core/IntelliSense/Session.cs +++ b/src/EditorFeatures/Core/IntelliSense/Session.cs @@ -5,6 +5,7 @@ #nullable disable using System; +using System.Threading.Tasks; using Microsoft.CodeAnalysis.Editor.Shared.Extensions; using Roslyn.Utilities; @@ -52,9 +53,9 @@ public virtual void Stop() this.PresenterSession.Dismiss(); } - public TModel WaitForController() + public Task WaitForModelComputation_ForTestingPurposesOnlyAsync() { Computation.ThreadingContext.ThrowIfNotOnUIThread(); - return Computation.WaitForController(); + return Computation.WaitForModelComputation_ForTestingPurposesOnlyAsync(); } } diff --git a/src/EditorFeatures/Core/Intents/RenameIntentProvider.cs b/src/EditorFeatures/Core/Intents/RenameIntentProvider.cs index eaa6f97ed2dd7..04c4895e01e1e 100644 --- a/src/EditorFeatures/Core/Intents/RenameIntentProvider.cs +++ b/src/EditorFeatures/Core/Intents/RenameIntentProvider.cs @@ -54,6 +54,6 @@ public async Task> ComputeIntentAsync( var renameLocationSet = await renameInfo.FindRenameLocationsAsync(options, cancellationToken).ConfigureAwait(false); var renameReplacementInfo = await renameLocationSet.GetReplacementsAsync(renameIntentData.NewName, options, cancellationToken).ConfigureAwait(false); - return [new IntentProcessorResult(renameReplacementInfo.NewSolution, renameReplacementInfo.DocumentIds.ToImmutableArray(), EditorFeaturesResources.Rename, WellKnownIntents.Rename)]; + return [new IntentProcessorResult(renameReplacementInfo.NewSolution, [.. renameReplacementInfo.DocumentIds], EditorFeaturesResources.Rename, WellKnownIntents.Rename)]; } } diff --git a/src/EditorFeatures/Core/Interactive/InteractiveSession.cs b/src/EditorFeatures/Core/Interactive/InteractiveSession.cs index cede11519dbfa..8b4ee5b63197d 100644 --- a/src/EditorFeatures/Core/Interactive/InteractiveSession.cs +++ b/src/EditorFeatures/Core/Interactive/InteractiveSession.cs @@ -13,10 +13,8 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.ErrorReporting; using Microsoft.CodeAnalysis.Host; -using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Scripting.Hosting; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.TestHooks; @@ -27,17 +25,16 @@ namespace Microsoft.CodeAnalysis.Interactive; using InteractiveHost::Microsoft.CodeAnalysis.Interactive; +using Microsoft.CodeAnalysis.Collections; using RelativePathResolver = Scripting::Microsoft.CodeAnalysis.RelativePathResolver; internal sealed class InteractiveSession : IDisposable { public InteractiveHost Host { get; } - private readonly IThreadingContext _threadingContext; private readonly InteractiveEvaluatorLanguageInfoProvider _languageInfo; private readonly InteractiveWorkspace _workspace; private readonly ITextDocumentFactoryService _textDocumentFactoryService; - private readonly EditorOptionsService _editorOptionsService; private readonly CancellationTokenSource _shutdownCancellationSource; @@ -54,7 +51,7 @@ internal sealed class InteractiveSession : IDisposable // At the same time a code submission might be in progress. // If we left these operations run in parallel we might get into a state // inconsistent with the state of the host. - private readonly TaskQueue _taskQueue; + private readonly AsyncBatchingWorkQueue> _workQueue; private ProjectId? _lastSuccessfulSubmissionProjectId; private ProjectId? _currentSubmissionProjectId; @@ -76,21 +73,21 @@ internal sealed class InteractiveSession : IDisposable public InteractiveSession( InteractiveWorkspace workspace, - IThreadingContext threadingContext, IAsynchronousOperationListener listener, ITextDocumentFactoryService documentFactory, - EditorOptionsService editorOptionsService, InteractiveEvaluatorLanguageInfoProvider languageInfo, string initialWorkingDirectory) { _workspace = workspace; - _threadingContext = threadingContext; _languageInfo = languageInfo; _textDocumentFactoryService = documentFactory; - _editorOptionsService = editorOptionsService; - _taskQueue = new TaskQueue(listener, TaskScheduler.Default); _shutdownCancellationSource = new CancellationTokenSource(); + _workQueue = new( + TimeSpan.Zero, + ProcessWorkQueueAsync, + listener, + _shutdownCancellationSource.Token); // The following settings will apply when the REPL starts without .rsp file. // They are discarded once the REPL is reset. @@ -112,6 +109,21 @@ public void Dispose() Host.Dispose(); } + private async ValueTask ProcessWorkQueueAsync(ImmutableSegmentedList> list, CancellationToken cancellationToken) + { + foreach (var taskCreator in list) + { + cancellationToken.ThrowIfCancellationRequested(); + + // Kick off the task to run. This also ensures that if the taskCreator func throws synchronously, that we + // appropriately handle reporting it in ReportNonFatalErrorAsync. Also, ensure we always process the next + // piece of work, even if the current work fails. + var task = Task.Run(taskCreator, cancellationToken); + _ = task.ReportNonFatalErrorAsync(); + await task.NoThrowAwaitableInternal(captureContext: false); + } + } + /// /// Invoked by when a new process initialization completes. /// @@ -119,7 +131,7 @@ private void ProcessInitialized(InteractiveHostPlatformInfo platformInfo, Intera { Contract.ThrowIfFalse(result.InitializationResult != null); - _ = _taskQueue.ScheduleTask(nameof(ProcessInitialized), () => + _workQueue.AddWork(() => { _workspace.ResetSolution(); @@ -140,7 +152,8 @@ private void ProcessInitialized(InteractiveHostPlatformInfo platformInfo, Intera } _pendingBuffers.Clear(); - }, _shutdownCancellationSource.Token); + return Task.CompletedTask; + }); } /// @@ -148,10 +161,12 @@ private void ProcessInitialized(InteractiveHostPlatformInfo platformInfo, Intera /// internal void AddSubmissionProject(ITextBuffer submissionBuffer) { - _taskQueue.ScheduleTask( - nameof(AddSubmissionProject), - () => AddSubmissionProjectNoLock(submissionBuffer, _languageInfo.LanguageName), - _shutdownCancellationSource.Token); + _workQueue.AddWork( + () => + { + AddSubmissionProjectNoLock(submissionBuffer, _languageInfo.LanguageName); + return Task.CompletedTask; + }); } private void AddSubmissionProjectNoLock(ITextBuffer submissionBuffer, string languageName) @@ -316,9 +331,10 @@ private Project CreateSubmissionProjectNoLock(Solution solution, ProjectId newSu /// Called once a code snippet is submitted. /// Followed by creation of a new language buffer and call to . /// - internal Task ExecuteCodeAsync(string text) + internal async Task ExecuteCodeAsync(string text) { - return _taskQueue.ScheduleTask(nameof(ExecuteCodeAsync), async () => + var returnValue = false; + _workQueue.AddWork(async () => { var result = await Host.ExecuteAsync(text).ConfigureAwait(false); if (result.Success) @@ -329,8 +345,11 @@ internal Task ExecuteCodeAsync(string text) UpdatePathsNoLock(result); } - return result.Success; - }, _shutdownCancellationSource.Token); + returnValue = result.Success; + }); + + await _workQueue.WaitUntilCurrentBatchCompletesAsync().ConfigureAwait(false); + return returnValue; } internal async Task ResetAsync(InteractiveHostOptions options) @@ -377,11 +396,13 @@ private static SourceReferenceResolver CreateSourceReferenceResolver(ImmutableAr public Task SetPathsAsync(ImmutableArray referenceSearchPaths, ImmutableArray sourceSearchPaths, string workingDirectory) { - return _taskQueue.ScheduleTask(nameof(ExecuteCodeAsync), async () => + _workQueue.AddWork(async () => { var result = await Host.SetPathsAsync(referenceSearchPaths, sourceSearchPaths, workingDirectory).ConfigureAwait(false); UpdatePathsNoLock(result); - }, _shutdownCancellationSource.Token); + }); + + return _workQueue.WaitUntilCurrentBatchCompletesAsync(); } private void UpdatePathsNoLock(RemoteExecutionResult result) diff --git a/src/EditorFeatures/Core/LanguageServer/AlwaysActivateInProcLanguageClient.cs b/src/EditorFeatures/Core/LanguageServer/AlwaysActivateInProcLanguageClient.cs index 8bd7fe294313c..6dc96f3d27c60 100644 --- a/src/EditorFeatures/Core/LanguageServer/AlwaysActivateInProcLanguageClient.cs +++ b/src/EditorFeatures/Core/LanguageServer/AlwaysActivateInProcLanguageClient.cs @@ -67,6 +67,7 @@ public override ServerCapabilities GetCapabilities(ClientCapabilities clientCapa serverCapabilities.ProjectContextProvider = true; serverCapabilities.BreakableRangeProvider = true; + serverCapabilities.DataTipRangeProvider = true; serverCapabilities.SupportsDiagnosticRequests = true; @@ -82,11 +83,10 @@ public override ServerCapabilities GetCapabilities(ClientCapabilities clientCapa serverCapabilities.DiagnosticProvider = serverCapabilities.DiagnosticProvider with { SupportsMultipleContextsDiagnostics = true, - DiagnosticKinds = diagnosticSourceNames.Select(n => new VSInternalDiagnosticKind(n)).ToArray(), - BuildOnlyDiagnosticIds = _buildOnlyDiagnostics + DiagnosticKinds = [.. diagnosticSourceNames.Select(n => new VSInternalDiagnosticKind(n))], + BuildOnlyDiagnosticIds = [.. _buildOnlyDiagnostics .SelectMany(lazy => lazy.Metadata.BuildOnlyDiagnostics) - .Distinct() - .ToArray(), + .Distinct()], }; // This capability is always enabled as we provide cntrl+Q VS search only via LSP in ever scenario. diff --git a/src/EditorFeatures/Core/Navigation/AbstractDefinitionLocationService.cs b/src/EditorFeatures/Core/Navigation/AbstractDefinitionLocationService.cs index ed6ff3af80e9b..ef6a5fba60c5b 100644 --- a/src/EditorFeatures/Core/Navigation/AbstractDefinitionLocationService.cs +++ b/src/EditorFeatures/Core/Navigation/AbstractDefinitionLocationService.cs @@ -50,14 +50,17 @@ internal abstract partial class AbstractDefinitionLocationService( async ValueTask GetDefinitionLocationWorkerAsync(Document document) { - return await GetControlFlowTargetLocationAsync(document).ConfigureAwait(false) ?? - await GetSymbolLocationAsync(document).ConfigureAwait(false); + // We don't need nullable information to compute the symbol. So avoid expensive work computing this. + var semanticModel = await document.GetRequiredNullableDisabledSemanticModelAsync(cancellationToken).ConfigureAwait(false); + return await GetControlFlowTargetLocationAsync(document, semanticModel).ConfigureAwait(false) ?? + await GetSymbolLocationAsync(document, semanticModel).ConfigureAwait(false); } - async ValueTask GetControlFlowTargetLocationAsync(Document document) + async ValueTask GetControlFlowTargetLocationAsync( + Document document, SemanticModel semanticModel) { var (controlFlowTarget, controlFlowSpan) = await symbolService.GetTargetIfControlFlowAsync( - document, position, cancellationToken).ConfigureAwait(false); + document, semanticModel, position, cancellationToken).ConfigureAwait(false); if (controlFlowTarget == null) return null; @@ -66,11 +69,12 @@ internal abstract partial class AbstractDefinitionLocationService( return location is null ? null : new DefinitionLocation(location, new DocumentSpan(document, controlFlowSpan)); } - async ValueTask GetSymbolLocationAsync(Document document) + async ValueTask GetSymbolLocationAsync( + Document document, SemanticModel semanticModel) { // Try to compute the referenced symbol and attempt to go to definition for the symbol. var (symbol, project, span) = await symbolService.GetSymbolProjectAndBoundSpanAsync( - document, position, cancellationToken).ConfigureAwait(false); + document, semanticModel, position, cancellationToken).ConfigureAwait(false); if (symbol is null) return null; @@ -126,15 +130,12 @@ async ValueTask> GetInterceptorDefinitionsAsync( { var solution = project.Solution; - var sourceLocations = symbol.Locations.WhereAsArray(loc => loc.IsInSource); - if (sourceLocations.Length != 1) + if (symbol.DeclaringSyntaxReferences is not [{ SyntaxTree: { } definitionTree, Span: var definitionSpan }]) return null; - var definitionLocation = sourceLocations[0]; - if (!definitionLocation.SourceSpan.IntersectsWith(position)) + if (!definitionSpan.IntersectsWith(position)) return null; - var definitionTree = definitionLocation.SourceTree; var definitionDocument = solution.GetDocument(definitionTree); if (definitionDocument != originalDocument) return null; @@ -142,7 +143,8 @@ async ValueTask> GetInterceptorDefinitionsAsync( // Ok, we were already on the definition. Look for better symbols we could show results for instead. This can be // expanded with other mappings in the future if appropriate. return await TryGetExplicitInterfaceLocationAsync().ConfigureAwait(false) ?? - await TryGetInterceptedLocationAsync().ConfigureAwait(false); + await TryGetInterceptedLocationAsync().ConfigureAwait(false) ?? + await TryGetOtherPartOfPartialAsync().ConfigureAwait(false); async ValueTask TryGetExplicitInterfaceLocationAsync() { @@ -251,6 +253,24 @@ async ValueTask> GetInterceptorDefinitionsAsync( }); } } + async ValueTask TryGetOtherPartOfPartialAsync() + { + ISymbol? otherPart = symbol is IMethodSymbol method ? method.PartialDefinitionPart ?? method.PartialImplementationPart : null; + otherPart ??= symbol is IPropertySymbol property ? property.PartialDefinitionPart ?? property.PartialImplementationPart : null; + + if (otherPart is null || Equals(symbol, otherPart)) + return null; + + if (otherPart.Locations is not [{ SourceTree: { } sourceTree, SourceSpan: var span }]) + return null; + + var document = solution.GetDocument(sourceTree); + if (document is null) + return null; + + var documentSpan = new DocumentSpan(document, span); + return await documentSpan.GetNavigableLocationAsync(cancellationToken).ConfigureAwait(false); + } } private static async Task IsThirdPartyNavigationAllowedAsync( diff --git a/src/EditorFeatures/Core/Organizing/OrganizeDocumentCommandHandler.cs b/src/EditorFeatures/Core/Organizing/OrganizeDocumentCommandHandler.cs index e884b3129b9c7..c7e05e1cbb2a6 100644 --- a/src/EditorFeatures/Core/Organizing/OrganizeDocumentCommandHandler.cs +++ b/src/EditorFeatures/Core/Organizing/OrganizeDocumentCommandHandler.cs @@ -35,7 +35,7 @@ namespace Microsoft.CodeAnalysis.Editor.Implementation.Organizing; [Name(PredefinedCommandHandlerNames.OrganizeDocument)] [method: ImportingConstructor] [SuppressMessage("RoslynDiagnosticsReliability", "RS0033:Importing constructor should be [Obsolete]", Justification = "Used in test code: https://github.com/dotnet/roslyn/issues/42814")] -internal class OrganizeDocumentCommandHandler( +internal sealed class OrganizeDocumentCommandHandler( IThreadingContext threadingContext, IAsynchronousOperationListenerProvider listenerProvider) : ICommandHandler, @@ -125,7 +125,7 @@ private async Task ExecuteAsync( if (!subjectBuffer.TryGetWorkspace(out var workspace)) return; - var snapshotSpan = textView.GetTextElementSpan(caretPoint.Value); + var snapshotSpan = textView.GetTextElementSpan(textView.Caret.Position.BufferPosition); var indicatorFactory = workspace.Services.GetRequiredService(); using var backgroundWorkContext = indicatorFactory.Create( @@ -139,7 +139,7 @@ private async Task ExecuteAsync( await TaskScheduler.Default; - var currentDocument = await getCurrentDocumentAsync(snapshotSpan.Snapshot, backgroundWorkContext).ConfigureAwait(false); + var currentDocument = await getCurrentDocumentAsync(caretPoint.Value.Snapshot, backgroundWorkContext).ConfigureAwait(false); if (currentDocument is null) return; diff --git a/src/EditorFeatures/Core/Preview/SolutionPreviewResult.cs b/src/EditorFeatures/Core/Preview/SolutionPreviewResult.cs index ebb88186ebc74..8e2fc6d81bd38 100644 --- a/src/EditorFeatures/Core/Preview/SolutionPreviewResult.cs +++ b/src/EditorFeatures/Core/Preview/SolutionPreviewResult.cs @@ -101,7 +101,7 @@ public SolutionPreviewResult(IThreadingContext threadingContext, SolutionPreview return new SolutionPreviewResult( result1._threadingContext, - result1._previews.Concat(result2._previews).ToList(), + [.. result1._previews, .. result2._previews], result1.ChangeSummary ?? result2.ChangeSummary); } } diff --git a/src/EditorFeatures/Core/RenameTracking/RenameTrackingCodeRefactoringProvider.cs b/src/EditorFeatures/Core/RenameTracking/RenameTrackingCodeRefactoringProvider.cs index c7b084bf7667e..32784ce769f62 100644 --- a/src/EditorFeatures/Core/RenameTracking/RenameTrackingCodeRefactoringProvider.cs +++ b/src/EditorFeatures/Core/RenameTracking/RenameTrackingCodeRefactoringProvider.cs @@ -34,10 +34,10 @@ public RenameTrackingCodeRefactoringProvider( public override Task ComputeRefactoringsAsync(CodeRefactoringContext context) { - var (document, span, cancellationToken) = context; + var (document, span, _) = context; var (action, renameSpan) = RenameTrackingTaggerProvider.TryGetCodeAction( - document, span, _refactorNotifyServices, _undoHistoryRegistry, cancellationToken); + document, span, _refactorNotifyServices, _undoHistoryRegistry); if (action != null) context.RegisterRefactoring(action, renameSpan); diff --git a/src/EditorFeatures/Core/RenameTracking/RenameTrackingTaggerProvider.RenameTrackingCodeAction.cs b/src/EditorFeatures/Core/RenameTracking/RenameTrackingTaggerProvider.RenameTrackingCodeAction.cs index f43e0a530435c..1c191ca0692e4 100644 --- a/src/EditorFeatures/Core/RenameTracking/RenameTrackingTaggerProvider.RenameTrackingCodeAction.cs +++ b/src/EditorFeatures/Core/RenameTracking/RenameTrackingTaggerProvider.RenameTrackingCodeAction.cs @@ -59,13 +59,8 @@ protected override Task> ComputeOperationsAs IProgress progress, CancellationToken cancellationToken) { // Invoked directly without previewing. - if (_renameTrackingCommitter == null) - { - if (!TryInitializeRenameTrackingCommitter(cancellationToken)) - { - return SpecializedTasks.EmptyImmutableArray(); - } - } + if (_renameTrackingCommitter == null && !TryInitializeRenameTrackingCommitter()) + return SpecializedTasks.EmptyImmutableArray(); var committerOperation = new RenameTrackingCommitterOperation(_renameTrackingCommitter, _threadingContext); return Task.FromResult(ImmutableArray.Create(committerOperation)); @@ -74,7 +69,7 @@ protected override Task> ComputeOperationsAs protected override async Task> ComputePreviewOperationsAsync(CancellationToken cancellationToken) { if (!_globalOptions.GetOption(RenameTrackingOptionsStorage.RenameTrackingPreview, _document.Project.Language) || - !TryInitializeRenameTrackingCommitter(cancellationToken)) + !TryInitializeRenameTrackingCommitter()) { return await SpecializedTasks.EmptyEnumerable().ConfigureAwait(false); } @@ -84,14 +79,14 @@ protected override async Task> ComputePreviewOp return [new ApplyChangesOperation(solutionSet.RenamedSolution)]; } - private bool TryInitializeRenameTrackingCommitter(CancellationToken cancellationToken) + private bool TryInitializeRenameTrackingCommitter() { if (_document.TryGetText(out var text)) { var textBuffer = text.Container.GetTextBuffer(); if (textBuffer.Properties.TryGetProperty(typeof(StateMachine), out StateMachine stateMachine)) { - if (!stateMachine.CanInvokeRename(out _, cancellationToken: cancellationToken)) + if (!stateMachine.CanInvokeRename(out _)) { // The rename tracking could be dismissed while a codefix is still cached // in the lightbulb. If this happens, do not perform the rename requested @@ -103,7 +98,7 @@ private bool TryInitializeRenameTrackingCommitter(CancellationToken cancellation var snapshotSpan = stateMachine.TrackingSession.TrackingSpan.GetSpan(stateMachine.Buffer.CurrentSnapshot); var newName = snapshotSpan.GetText(); - var displayText = string.Format(EditorFeaturesResources.Rename_0_to_1, stateMachine.TrackingSession.OriginalName, newName); + var displayText = string.Format(WorkspacesResources.Rename_0_to_1, stateMachine.TrackingSession.OriginalName, newName); _renameTrackingCommitter = new RenameTrackingCommitter(stateMachine, snapshotSpan, _refactorNotifyServices, _undoHistoryRegistry, displayText); return true; } diff --git a/src/EditorFeatures/Core/RenameTracking/RenameTrackingTaggerProvider.StateMachine.cs b/src/EditorFeatures/Core/RenameTracking/RenameTrackingTaggerProvider.StateMachine.cs index af17f723ee661..33e6adf031c9b 100644 --- a/src/EditorFeatures/Core/RenameTracking/RenameTrackingTaggerProvider.StateMachine.cs +++ b/src/EditorFeatures/Core/RenameTracking/RenameTrackingTaggerProvider.StateMachine.cs @@ -129,7 +129,7 @@ private void Buffer_Changed(object sender, TextContentChangedEventArgs e) public void UpdateTrackingSessionIfRenamable() { ThreadingContext.ThrowIfNotOnUIThread(); - if (this.TrackingSession.IsDefinitelyRenamableIdentifier()) + if (this.TrackingSession.IsDefinitelyRenamableIdentifierFastCheck()) { this.TrackingSession.CheckNewIdentifier(this, Buffer.CurrentSnapshot); TrackingSessionUpdated(); @@ -214,7 +214,7 @@ public bool ClearTrackingSession() previousTrackingSession.Cancel(); // If there may have been a tag showing, then actually clear the tags. - if (previousTrackingSession.IsDefinitelyRenamableIdentifier()) + if (previousTrackingSession.IsDefinitelyRenamableIdentifierFastCheck()) { TrackingSessionCleared(previousTrackingSession.TrackingSpan); } @@ -229,7 +229,7 @@ public bool ClearVisibleTrackingSession() { ThreadingContext.ThrowIfNotOnUIThread(); - if (this.TrackingSession != null && this.TrackingSession.IsDefinitelyRenamableIdentifier()) + if (this.TrackingSession != null && this.TrackingSession.IsDefinitelyRenamableIdentifierFastCheck()) { var document = Buffer.CurrentSnapshot.GetOpenDocumentInCurrentContextWithChanges(); if (document != null) @@ -271,7 +271,7 @@ internal int StoreCurrentTrackingSessionAndGenerateId() public bool CanInvokeRename( [NotNullWhen(true)] out TrackingSession trackingSession, - bool isSmartTagCheck = false, bool waitForResult = false, CancellationToken cancellationToken = default) + bool isSmartTagCheck = false) { // This needs to be able to run on a background thread for the diagnostic. @@ -280,14 +280,15 @@ public bool CanInvokeRename( return false; return TryGetSyntaxFactsService(out var syntaxFactsService) && TryGetLanguageHeuristicsService(out var languageHeuristicsService) && - trackingSession.CanInvokeRename(syntaxFactsService, languageHeuristicsService, isSmartTagCheck, waitForResult, cancellationToken); + trackingSession.CanInvokeRename(syntaxFactsService, languageHeuristicsService, isSmartTagCheck); } internal (CodeAction action, TextSpan renameSpan) TryGetCodeAction( - Document document, SourceText text, TextSpan userSpan, + Document document, + SourceText text, + TextSpan userSpan, IEnumerable refactorNotifyServices, - ITextUndoHistoryRegistry undoHistoryRegistry, - CancellationToken cancellationToken) + ITextUndoHistoryRegistry undoHistoryRegistry) { try { @@ -299,7 +300,7 @@ public bool CanInvokeRename( // engine will know that the document changed and not display the lightbulb anyway. if (Buffer.AsTextContainer().CurrentText == text && - CanInvokeRename(out var trackingSession, waitForResult: true, cancellationToken: cancellationToken)) + CanInvokeRename(out var trackingSession)) { var snapshotSpan = trackingSession.TrackingSpan.GetSpan(Buffer.CurrentSnapshot); @@ -307,7 +308,7 @@ public bool CanInvokeRename( if (text.AreOnSameLine(userSpan.Start, snapshotSpan.Start)) { var title = string.Format( - EditorFeaturesResources.Rename_0_to_1, + WorkspacesResources.Rename_0_to_1, trackingSession.OriginalName, snapshotSpan.GetText()); @@ -318,7 +319,7 @@ public bool CanInvokeRename( return default; } - catch (Exception e) when (FatalError.ReportAndPropagateUnlessCanceled(e, cancellationToken)) + catch (Exception e) when (FatalError.ReportAndPropagateUnlessCanceled(e)) { throw ExceptionUtilities.Unreachable(); } diff --git a/src/EditorFeatures/Core/RenameTracking/RenameTrackingTaggerProvider.TrackingSession.cs b/src/EditorFeatures/Core/RenameTracking/RenameTrackingTaggerProvider.TrackingSession.cs index 3ec77331b758d..59c60ae160e19 100644 --- a/src/EditorFeatures/Core/RenameTracking/RenameTrackingTaggerProvider.TrackingSession.cs +++ b/src/EditorFeatures/Core/RenameTracking/RenameTrackingTaggerProvider.TrackingSession.cs @@ -18,6 +18,7 @@ using Microsoft.CodeAnalysis.Shared.TestHooks; using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.Text; +using Microsoft.VisualStudio.Threading; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Editor.Implementation.RenameTracking; @@ -69,27 +70,11 @@ public TrackingSession( // tagging. OriginalName = snapshotSpan.GetText(); - _isRenamableIdentifierTask = Task.Factory.SafeStartNewFromAsync( - () => DetermineIfRenamableIdentifierAsync(snapshotSpan, initialCheck: true), - _cancellationToken, - TaskScheduler.Default); + _isRenamableIdentifierTask = DetermineIfRenamableIdentifierAsync(snapshotSpan, initialCheck: true); + _isRenamableIdentifierTask.ReportNonFatalErrorAsync(); - var asyncToken = _asyncListener.BeginAsyncOperation(GetType().Name + ".UpdateTrackingSessionAfterIsRenamableIdentifierTask"); - - _isRenamableIdentifierTask.SafeContinueWithFromAsync( - async t => - { - await _threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(alwaysYield: true, _cancellationToken).NoThrowAwaitable(); - - // Avoid throwing an exception in this common case - if (_cancellationToken.IsCancellationRequested) - return; - - stateMachine.UpdateTrackingSessionIfRenamable(); - }, - _cancellationToken, - TaskContinuationOptions.OnlyOnRanToCompletion | TaskContinuationOptions.ExecuteSynchronously, - TaskScheduler.Default).CompletesAsyncOperation(asyncToken); + SwitchToMainThreadAfterAndUpdateSessionTrackerAsync(_isRenamableIdentifierTask).CompletesAsyncOperation( + _asyncListener.BeginAsyncOperation(GetType().Name + ".UpdateTrackingSessionAfterIsRenamableIdentifierTask")); QueueUpdateToStateMachine(stateMachine, _isRenamableIdentifierTask); } @@ -102,51 +87,68 @@ public TrackingSession( _isRenamableIdentifierTask = s_notRenamableTask; } + + return; + + async Task SwitchToMainThreadAfterAndUpdateSessionTrackerAsync(Task isRenamableIdentifierTask) + { + // Use CA(true) so we can stay on the UI thread if already there. + await isRenamableIdentifierTask.ConfigureAwait(true); + + // Avoid throwing an exception in this common case + await _threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(alwaysYield: true, _cancellationToken).NoThrowAwaitable(); + if (_cancellationToken.IsCancellationRequested) + return; + + stateMachine.UpdateTrackingSessionIfRenamable(); + } } private void QueueUpdateToStateMachine(StateMachine stateMachine, Task task) { - var asyncToken = _asyncListener.BeginAsyncOperation($"{GetType().Name}.{nameof(QueueUpdateToStateMachine)}"); - - task.SafeContinueWithFromAsync(async t => - { - await _threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(alwaysYield: true, _cancellationToken).NoThrowAwaitable(); - - // Avoid throwing an exception in this common case - if (_cancellationToken.IsCancellationRequested) - return; - - if (_isRenamableIdentifierTask.Result != TriggerIdentifierKind.NotRenamable) - { - stateMachine.OnTrackingSessionUpdated(this); - } - }, - _cancellationToken, - TaskContinuationOptions.OnlyOnRanToCompletion | TaskContinuationOptions.ExecuteSynchronously, - TaskScheduler.Default).CompletesAsyncOperation(asyncToken); + QueueUpdateToStateMachineAsync().CompletesAsyncOperation( + _asyncListener.BeginAsyncOperation($"{GetType().Name}.{nameof(QueueUpdateToStateMachine)}")); + + async Task QueueUpdateToStateMachineAsync() + { + // Use CA(true) so we can stay on the UI thread if already there. + await task.ConfigureAwait(true); + + // Avoid throwing an exception in this common case + await _threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(alwaysYield: true, _cancellationToken).NoThrowAwaitable(); + if (_cancellationToken.IsCancellationRequested) + return; + + if (await _isRenamableIdentifierTask.ConfigureAwait(true) != TriggerIdentifierKind.NotRenamable) + stateMachine.OnTrackingSessionUpdated(this); + } } internal void CheckNewIdentifier(StateMachine stateMachine, ITextSnapshot snapshot) { _threadingContext.ThrowIfNotOnUIThread(); - _newIdentifierBindsTask = _isRenamableIdentifierTask.SafeContinueWithFromAsync( - async t => t.Result != TriggerIdentifierKind.NotRenamable && - TriggerIdentifierKind.RenamableReference == - await DetermineIfRenamableIdentifierAsync( - TrackingSpan.GetSpan(snapshot), - initialCheck: false).ConfigureAwait(false), - _cancellationToken, - TaskContinuationOptions.OnlyOnRanToCompletion, - TaskScheduler.Default); + _newIdentifierBindsTask = DetermineIfNewIdentifierBindsAsync(_isRenamableIdentifierTask); + _newIdentifierBindsTask.ReportNonFatalErrorAsync(); QueueUpdateToStateMachine(stateMachine, _newIdentifierBindsTask); + + async Task DetermineIfNewIdentifierBindsAsync(Task isRenamableIdentifierTask) + { + // Ensure we do this work on a BG thread. + await TaskScheduler.Default; + var isRenamableIdentifier = await isRenamableIdentifierTask.ConfigureAwait(false); + return isRenamableIdentifier != TriggerIdentifierKind.NotRenamable && + TriggerIdentifierKind.RenamableReference == await DetermineIfRenamableIdentifierAsync( + TrackingSpan.GetSpan(snapshot), + initialCheck: false).ConfigureAwait(false); + } } - internal bool IsDefinitelyRenamableIdentifier() + internal bool IsDefinitelyRenamableIdentifierFastCheck() { // This needs to be able to run on a background thread for the CodeFix - return IsRenamableIdentifier(_isRenamableIdentifierTask, waitForResult: false, cancellationToken: CancellationToken.None); + return IsRenamableIdentifierFastCheck(_isRenamableIdentifierTask, out _); } public void Cancel() @@ -157,7 +159,9 @@ public void Cancel() private async Task DetermineIfRenamableIdentifierAsync(SnapshotSpan snapshotSpan, bool initialCheck) { - _threadingContext.ThrowIfNotOnBackgroundThread(); + // Ensure we do this work on the background. + await TaskScheduler.Default; + var document = snapshotSpan.Snapshot.GetOpenDocumentInCurrentContextWithChanges(); if (document != null) { @@ -193,7 +197,7 @@ private async Task DetermineIfRenamableIdentifierAsync(Sn // This is a reference from a nameof expression. Allow the rename but set the RenameOverloads option ForceRenameOverloads = true; - return await DetermineIfRenamableSymbolsAsync(renameSymbolInfo.Symbols, document).ConfigureAwait(false); + return DetermineIfRenamableSymbols(renameSymbolInfo.Symbols, document); } else { @@ -204,7 +208,7 @@ private async Task DetermineIfRenamableIdentifierAsync(Sn return TriggerIdentifierKind.NotRenamable; } - return await DetermineIfRenamableSymbolAsync(renameSymbolInfo.Symbols.Single(), document, token).ConfigureAwait(false); + return DetermineIfRenamableSymbol(renameSymbolInfo.Symbols.Single(), document, token); } } } @@ -212,12 +216,12 @@ private async Task DetermineIfRenamableIdentifierAsync(Sn return TriggerIdentifierKind.NotRenamable; } - private async Task DetermineIfRenamableSymbolsAsync(IEnumerable symbols, Document document) + private TriggerIdentifierKind DetermineIfRenamableSymbols(IEnumerable symbols, Document document) { foreach (var symbol in symbols) { // Get the source symbol if possible - var sourceSymbol = await SymbolFinder.FindSourceDefinitionAsync(symbol, document.Project.Solution, _cancellationToken).ConfigureAwait(false) ?? symbol; + var sourceSymbol = SymbolFinder.FindSourceDefinition(symbol, document.Project.Solution, _cancellationToken) ?? symbol; if (!sourceSymbol.IsFromSource()) { @@ -228,10 +232,10 @@ private async Task DetermineIfRenamableSymbolsAsync(IEnum return TriggerIdentifierKind.RenamableReference; } - private async Task DetermineIfRenamableSymbolAsync(ISymbol symbol, Document document, SyntaxToken token) + private TriggerIdentifierKind DetermineIfRenamableSymbol(ISymbol symbol, Document document, SyntaxToken token) { // Get the source symbol if possible - var sourceSymbol = await SymbolFinder.FindSourceDefinitionAsync(symbol, document.Project.Solution, _cancellationToken).ConfigureAwait(false) ?? symbol; + var sourceSymbol = SymbolFinder.FindSourceDefinition(symbol, document.Project.Solution, _cancellationToken) ?? symbol; if (sourceSymbol.Kind == SymbolKind.Field && ((IFieldSymbol)sourceSymbol).ContainingType.IsTupleType && @@ -255,13 +259,11 @@ private async Task DetermineIfRenamableSymbolAsync(ISymbo internal bool CanInvokeRename( ISyntaxFactsService syntaxFactsService, IRenameTrackingLanguageHeuristicsService languageHeuristicsService, - bool isSmartTagCheck, - bool waitForResult, - CancellationToken cancellationToken) + bool isSmartTagCheck) { - if (IsRenamableIdentifier(_isRenamableIdentifierTask, waitForResult, cancellationToken)) + if (IsRenamableIdentifierFastCheck(_isRenamableIdentifierTask, out var triggerIdentifierKind)) { - var isRenamingDeclaration = _isRenamableIdentifierTask.Result == TriggerIdentifierKind.RenamableDeclaration; + var isRenamingDeclaration = triggerIdentifierKind == TriggerIdentifierKind.RenamableDeclaration; var newName = TrackingSpan.GetText(TrackingSpan.TextBuffer.CurrentSnapshot); var comparison = isRenamingDeclaration || syntaxFactsService.IsCaseSensitive ? StringComparison.Ordinal : StringComparison.OrdinalIgnoreCase; diff --git a/src/EditorFeatures/Core/RenameTracking/RenameTrackingTaggerProvider.cs b/src/EditorFeatures/Core/RenameTracking/RenameTrackingTaggerProvider.cs index 6115767293f35..de3b3ce56c86e 100644 --- a/src/EditorFeatures/Core/RenameTracking/RenameTrackingTaggerProvider.cs +++ b/src/EditorFeatures/Core/RenameTracking/RenameTrackingTaggerProvider.cs @@ -16,6 +16,7 @@ using Microsoft.CodeAnalysis.ErrorReporting; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Shared.TestHooks; +using Microsoft.CodeAnalysis.SQLite.Interop; using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.Text; using Microsoft.VisualStudio.Text.Editor; @@ -103,9 +104,8 @@ internal static bool ResetRenameTrackingStateWorker(Workspace workspace, Documen public static (CodeAction action, TextSpan renameSpan) TryGetCodeAction( Document document, TextSpan textSpan, - IEnumerable refactorNotifyServices, - ITextUndoHistoryRegistry undoHistoryRegistry, - CancellationToken cancellationToken) + IEnumerable refactorNotifyServices, + ITextUndoHistoryRegistry undoHistoryRegistry) { try { @@ -113,53 +113,35 @@ public static (CodeAction action, TextSpan renameSpan) TryGetCodeAction( { var textBuffer = text.Container.TryGetTextBuffer(); if (textBuffer != null && - textBuffer.Properties.TryGetProperty(typeof(StateMachine), out StateMachine stateMachine) && - stateMachine.CanInvokeRename(out _, cancellationToken: cancellationToken)) + textBuffer.Properties.TryGetProperty(typeof(StateMachine), out StateMachine stateMachine)) { return stateMachine.TryGetCodeAction( - document, text, textSpan, refactorNotifyServices, undoHistoryRegistry, cancellationToken); + document, text, textSpan, refactorNotifyServices, undoHistoryRegistry); } } return default; } - catch (Exception e) when (FatalError.ReportAndPropagateUnlessCanceled(e, cancellationToken, ErrorSeverity.General)) + catch (Exception e) when (FatalError.ReportAndPropagateUnlessCanceled(e, ErrorSeverity.General)) { throw ExceptionUtilities.Unreachable(); } } - internal static bool IsRenamableIdentifier(Task isRenamableIdentifierTask, bool waitForResult, CancellationToken cancellationToken) + internal static bool IsRenamableIdentifierFastCheck( + Task isRenamableIdentifierTask, out TriggerIdentifierKind identifierKind) { - if (isRenamableIdentifierTask.Status == TaskStatus.RanToCompletion && isRenamableIdentifierTask.Result != TriggerIdentifierKind.NotRenamable) + if (isRenamableIdentifierTask.Status == TaskStatus.RanToCompletion) { - return true; - } - else if (isRenamableIdentifierTask.Status == TaskStatus.Canceled) - { - return false; - } - else if (waitForResult) - { - return WaitForIsRenamableIdentifier(isRenamableIdentifierTask, cancellationToken); - } - else - { - return false; + var kind = isRenamableIdentifierTask.Result; + if (kind != TriggerIdentifierKind.NotRenamable) + { + identifierKind = kind; + return true; + } } - } - internal static bool WaitForIsRenamableIdentifier(Task isRenamableIdentifierTask, CancellationToken cancellationToken) - { - try - { - return isRenamableIdentifierTask.WaitAndGetResult_CanCallOnBackground(cancellationToken) != TriggerIdentifierKind.NotRenamable; - } - catch (OperationCanceledException e) when (e.CancellationToken != cancellationToken || cancellationToken == CancellationToken.None) - { - // We passed in a different cancellationToken, so if there's a race and - // isRenamableIdentifierTask was cancelled, we'll get a OperationCanceledException - return false; - } + identifierKind = default; + return false; } } diff --git a/src/EditorFeatures/Core/Shared/Extensions/HostWorkspaceServicesExtensions.cs b/src/EditorFeatures/Core/Shared/Extensions/HostWorkspaceServicesExtensions.cs index 149349319e8b3..fc097a4d4d938 100644 --- a/src/EditorFeatures/Core/Shared/Extensions/HostWorkspaceServicesExtensions.cs +++ b/src/EditorFeatures/Core/Shared/Extensions/HostWorkspaceServicesExtensions.cs @@ -92,8 +92,7 @@ internal static IList SelectMatchingExtensionValues( if (items == null) return []; - return items.Where(lazy => LanguageMatches(lazy.Metadata.Language, contentType, workspaceServices)). - Select(lazy => lazy.Value).ToList(); + return [.. items.Where(lazy => LanguageMatches(lazy.Metadata.Language, contentType, workspaceServices)).Select(lazy => lazy.Value)]; } private static bool LanguageMatches( diff --git a/src/EditorFeatures/Core/Shared/Extensions/MefExtensions.cs b/src/EditorFeatures/Core/Shared/Extensions/MefExtensions.cs index 3847d66bb4136..31c9e46e5b9a3 100644 --- a/src/EditorFeatures/Core/Shared/Extensions/MefExtensions.cs +++ b/src/EditorFeatures/Core/Shared/Extensions/MefExtensions.cs @@ -36,7 +36,7 @@ public static IList> SelectMatchingExtensions contentTypes) where TMetadata : IContentTypeMetadata { - return extensions.Where(h => contentTypes.Any(d => d.MatchesAny(h.Metadata.ContentTypes))).ToList(); + return [.. extensions.Where(h => contentTypes.Any(d => d.MatchesAny(h.Metadata.ContentTypes)))]; } public static IList SelectMatchingExtensionValues( @@ -44,7 +44,7 @@ public static IList SelectMatchingExtensionValues p.Value).ToList(); + return [.. extensions.SelectMatchingExtensions(contentTypes).Select(p => p.Value)]; } public static Lazy SelectMatchingExtension( diff --git a/src/EditorFeatures/Core/Shared/Extensions/WorkspaceExtensions.cs b/src/EditorFeatures/Core/Shared/Extensions/WorkspaceExtensions.cs index 8077271979078..97055330eeb5b 100644 --- a/src/EditorFeatures/Core/Shared/Extensions/WorkspaceExtensions.cs +++ b/src/EditorFeatures/Core/Shared/Extensions/WorkspaceExtensions.cs @@ -4,9 +4,10 @@ using System.Collections.Generic; using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Editor.Shared.Extensions; @@ -17,12 +18,18 @@ internal static partial class IWorkspaceExtensions /// has the text of newDocument. If the document is open, then this method will determine a /// minimal set of changes to apply to the document. /// - internal static void ApplyDocumentChanges(this Workspace workspace, Document newDocument, CancellationToken cancellationToken) + internal static async Task ApplyDocumentChangesAsync( + this Workspace workspace, IThreadingContext threadingContext, Document newDocument, CancellationToken cancellationToken) { var oldSolution = workspace.CurrentSolution; var oldDocument = oldSolution.GetRequiredDocument(newDocument.Id); - var changes = newDocument.GetTextChangesAsync(oldDocument, cancellationToken).WaitAndGetResult(cancellationToken); + + // Stay on the current context if we can so we don't bounce to the BG just to try to bounce back to the UI thread. + var changes = await newDocument.GetTextChangesAsync(oldDocument, cancellationToken).ConfigureAwait(true); var newSolution = oldSolution.UpdateDocument(newDocument.Id, changes, cancellationToken); + + // VS has a requirement that we're on the main thread to apply changes. + await threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); workspace.TryApplyChanges(newSolution); } diff --git a/src/EditorFeatures/Core/Shared/Options/FeatureOnOffOptions.cs b/src/EditorFeatures/Core/Shared/Options/FeatureOnOffOptions.cs index 09f7c428c8300..57832cbf5def1 100644 --- a/src/EditorFeatures/Core/Shared/Options/FeatureOnOffOptions.cs +++ b/src/EditorFeatures/Core/Shared/Options/FeatureOnOffOptions.cs @@ -26,8 +26,6 @@ internal sealed class FeatureOnOffOptions public static readonly Option2 OfferRemoveUnusedReferences = new("dotnet_offer_remove_unused_references", defaultValue: true); - public static readonly Option2 OfferRemoveUnusedReferencesFeatureFlag = new("dotnet_offer_remove_unused_references_feature_flag", defaultValue: false); - /// /// Not used by Roslyn but exposed in C# and VB option UI. Used by TestWindow and Project System. /// TODO: remove https://github.com/dotnet/roslyn/issues/57253 diff --git a/src/EditorFeatures/Core/Shared/Tagging/EventSources/TaggerEventSources.cs b/src/EditorFeatures/Core/Shared/Tagging/EventSources/TaggerEventSources.cs index eb7393b38a54d..5b70580fabf45 100644 --- a/src/EditorFeatures/Core/Shared/Tagging/EventSources/TaggerEventSources.cs +++ b/src/EditorFeatures/Core/Shared/Tagging/EventSources/TaggerEventSources.cs @@ -23,7 +23,7 @@ public static ITaggerEventSource Compose( } public static ITaggerEventSource Compose(IEnumerable eventSources) - => new CompositionEventSource(eventSources.ToArray()); + => new CompositionEventSource([.. eventSources]); public static ITaggerEventSource OnCaretPositionChanged(ITextView textView, ITextBuffer subjectBuffer) => new CaretPositionChangedEventSource(textView, subjectBuffer); diff --git a/src/EditorFeatures/Core/Shared/Utilities/LinkedEditsTracker.cs b/src/EditorFeatures/Core/Shared/Utilities/LinkedEditsTracker.cs index c2b07f068d59d..daf545adc8e75 100644 --- a/src/EditorFeatures/Core/Shared/Utilities/LinkedEditsTracker.cs +++ b/src/EditorFeatures/Core/Shared/Utilities/LinkedEditsTracker.cs @@ -30,7 +30,7 @@ public LinkedEditsTracker(ITextBuffer subjectBuffer) } public IList GetActiveSpansForSnapshot(ITextSnapshot snapshot) - => _trackingSpans.Select(ts => ts.GetSpan(snapshot)).ToList(); + => [.. _trackingSpans.Select(ts => ts.GetSpan(snapshot))]; public void AddSpans(IEnumerable spans) { diff --git a/src/EditorFeatures/Core/Structure/AbstractStructureTaggerProvider.cs b/src/EditorFeatures/Core/Structure/AbstractStructureTaggerProvider.cs index aa3ae21b762d3..314e98daa3375 100644 --- a/src/EditorFeatures/Core/Structure/AbstractStructureTaggerProvider.cs +++ b/src/EditorFeatures/Core/Structure/AbstractStructureTaggerProvider.cs @@ -14,7 +14,6 @@ using Microsoft.CodeAnalysis.ErrorReporting; using Microsoft.CodeAnalysis.MetadataAsSource; using Microsoft.CodeAnalysis.Options; -using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.TestHooks; using Microsoft.CodeAnalysis.Structure; using Microsoft.CodeAnalysis.Text; @@ -51,9 +50,9 @@ internal abstract partial class AbstractStructureTaggerProvider( protected readonly EditorOptionsService EditorOptionsService = editorOptionsService; protected readonly IProjectionBufferFactoryService ProjectionBufferFactoryService = projectionBufferFactoryService; - protected override TaggerDelay EventChangeDelay => TaggerDelay.OnIdle; + protected sealed override TaggerDelay EventChangeDelay => TaggerDelay.OnIdle; - protected override bool ComputeInitialTagsSynchronously(ITextBuffer subjectBuffer) + protected sealed override bool ComputeInitialTagsSynchronously(ITextBuffer subjectBuffer) { // If we can't find this doc, or outlining is not enabled for it, no need to computed anything synchronously. @@ -219,11 +218,33 @@ private void ProcessSpans( } } - protected override bool TagEquals(IContainerStructureTag tag1, IContainerStructureTag tag2) + protected sealed override bool TagEquals(IContainerStructureTag latestTag, IContainerStructureTag previousTag) { - Contract.ThrowIfFalse(tag1 is StructureTag); - Contract.ThrowIfFalse(tag2 is StructureTag); - return tag1.Equals(tag2); + if (latestTag is not StructureTag latestStructureTag || previousTag is not StructureTag previousStructureTag) + { + Contract.Fail("Tags were the wrong type"); + return latestTag == previousTag; + } + + var latestSnapshot = latestStructureTag.Snapshot; + var previousSnapshot = previousStructureTag.Snapshot; + + var previousStructureStart = new SnapshotPoint(previousSnapshot, previousStructureTag.HeaderSpan.Start); + if (previousStructureStart.TranslateTo(latestSnapshot, PointTrackingMode.Negative) != + previousStructureStart.TranslateTo(latestSnapshot, PointTrackingMode.Positive)) + { + // We can't know that how we think this block moved is actually how the editor actually moved it. + // Specifically, the tracking mode is an implementation detail. As such, we don't want to reuse this tag as + // its stale data (as mapped by the editor) may not be where we'd expect the new block's data to be. This + // can happen when the user types right at the start of a structure tag, causing it to move inwards + // undesirably. + + // Only consider these tags the same if they are the same object in memory. Otherwise, consider them + // different so that we remove the old one and add the new one. + return latestTag == previousTag; + } + + return latestTag.Equals(previousTag); } internal abstract object? GetCollapsedHintForm(StructureTag structureTag); diff --git a/src/EditorFeatures/Core/Structure/StructureTag.cs b/src/EditorFeatures/Core/Structure/StructureTag.cs index f0fdcc67218c8..f2fc1bd744193 100644 --- a/src/EditorFeatures/Core/Structure/StructureTag.cs +++ b/src/EditorFeatures/Core/Structure/StructureTag.cs @@ -21,6 +21,8 @@ internal sealed class StructureTag(AbstractStructureTaggerProvider tagProvider, { private readonly AbstractStructureTaggerProvider _tagProvider = tagProvider; + public BlockSpan BlockSpan { get; } = blockSpan; + /// /// The contents of the buffer to show if we mouse over the collapsed indicator. /// @@ -29,8 +31,12 @@ internal sealed class StructureTag(AbstractStructureTaggerProvider tagProvider, public readonly string CollapsedText = blockSpan.BannerText; public ITextSnapshot Snapshot { get; } = snapshot; - public Span? OutliningSpan { get; } = blockSpan.TextSpan.ToSpan(); - public Span? HeaderSpan { get; } = DetermineHeaderSpan(blockSpan.TextSpan, blockSpan.HintSpan, snapshot); + + public Span OutliningSpan { get; } = blockSpan.TextSpan.ToSpan(); + public Span HeaderSpan { get; } = DetermineHeaderSpan(blockSpan.TextSpan, blockSpan.HintSpan, snapshot); + + Span? IStructureTag.OutliningSpan => OutliningSpan; + Span? IStructureTag.HeaderSpan => HeaderSpan; public IReadOnlyList? SubHeadings { get; } = blockSpan.SubHeadings.IsDefault ? null diff --git a/src/EditorFeatures/Core/Tagging/AbstractAsynchronousTaggerProvider.TagSource.cs b/src/EditorFeatures/Core/Tagging/AbstractAsynchronousTaggerProvider.TagSource.cs index cd42e5a18c093..18d853a4388a0 100644 --- a/src/EditorFeatures/Core/Tagging/AbstractAsynchronousTaggerProvider.TagSource.cs +++ b/src/EditorFeatures/Core/Tagging/AbstractAsynchronousTaggerProvider.TagSource.cs @@ -7,7 +7,6 @@ using System.Collections.Immutable; using System.Linq; using System.Threading; -using Microsoft.CodeAnalysis.Collections; using Microsoft.CodeAnalysis.Editor.Shared.Extensions; using Microsoft.CodeAnalysis.Editor.Shared.Tagging; using Microsoft.CodeAnalysis.Options; @@ -221,8 +220,7 @@ void Connect() _eventSource.Changed += OnEventSourceChanged; - if (_dataSource.TextChangeBehavior.HasFlag(TaggerTextChangeBehavior.RemoveAllTags) || - _dataSource.TextChangeBehavior.HasFlag(TaggerTextChangeBehavior.RemoveTagsThatIntersectEdits)) + if (_dataSource.TextChangeBehavior != TaggerTextChangeBehavior.None) { _subjectBuffer.Changed += OnSubjectBufferChanged; } @@ -269,8 +267,7 @@ void Disconnect() _textView.Caret.PositionChanged -= OnCaretPositionChanged; } - if (_dataSource.TextChangeBehavior.HasFlag(TaggerTextChangeBehavior.RemoveAllTags) || - _dataSource.TextChangeBehavior.HasFlag(TaggerTextChangeBehavior.RemoveTagsThatIntersectEdits)) + if (_dataSource.TextChangeBehavior != TaggerTextChangeBehavior.None) { _subjectBuffer.Changed -= OnSubjectBufferChanged; } diff --git a/src/EditorFeatures/Core/Tagging/AbstractAsynchronousTaggerProvider.TagSource_ProduceTags.cs b/src/EditorFeatures/Core/Tagging/AbstractAsynchronousTaggerProvider.TagSource_ProduceTags.cs index baa6b50ad5e03..a071145057f31 100644 --- a/src/EditorFeatures/Core/Tagging/AbstractAsynchronousTaggerProvider.TagSource_ProduceTags.cs +++ b/src/EditorFeatures/Core/Tagging/AbstractAsynchronousTaggerProvider.TagSource_ProduceTags.cs @@ -105,7 +105,7 @@ private void RemoveTagsThatIntersectEdit(TextContentChangedEventArgs e) { var (@this, e, tagsToRemove, allTagsList, allTagsSet) = args; - // Compre-and-swap loops until we can successfully update the tag trees. Clear out the collections + // Compare-and-swap loops until we can successfully update the tag trees. Clear out the collections // so we're back in an initial state before performing any work in this lambda. tagsToRemove.Clear(); allTagsList.Clear(); diff --git a/src/EditorFeatures/Core/Tagging/AbstractAsynchronousTaggerProvider.cs b/src/EditorFeatures/Core/Tagging/AbstractAsynchronousTaggerProvider.cs index 537f91ff1ed35..d0a37a1634e12 100644 --- a/src/EditorFeatures/Core/Tagging/AbstractAsynchronousTaggerProvider.cs +++ b/src/EditorFeatures/Core/Tagging/AbstractAsynchronousTaggerProvider.cs @@ -120,8 +120,8 @@ protected virtual void BeforeTagsChanged(ITextSnapshot snapshot) /// Subclasses should always override this. It is only virtual for binary compat. /// /// - protected virtual bool TagEquals(TTag tag1, TTag tag2) - => EqualityComparer.Default.Equals(tag1, tag2); + protected virtual bool TagEquals(TTag latestTag, TTag previousTag) + => EqualityComparer.Default.Equals(latestTag, previousTag); // Prevent accidental usage of object.Equals instead of TagEquals when comparing tags. [Obsolete("Did you mean to call TagEquals(TTag tag1, TTag tag2) instead", error: true)] diff --git a/src/EditorFeatures/Core/Tagging/EfficientTagger.cs b/src/EditorFeatures/Core/Tagging/EfficientTagger.cs index af187baaba78b..90cfe9a52606a 100644 --- a/src/EditorFeatures/Core/Tagging/EfficientTagger.cs +++ b/src/EditorFeatures/Core/Tagging/EfficientTagger.cs @@ -34,7 +34,7 @@ IEnumerable> ITagger.GetTags(NormalizedSnapshotSpanCollecti /// public IEnumerable> GetTags(NormalizedSnapshotSpanCollection spans) { - using var pooledObject = SegmentedListPool.GetPooledList>(out var list); + using var _ = SegmentedListPool.GetPooledList>(out var list); AddTags(spans, list); diff --git a/src/EditorFeatures/Core/TextDiffing/EditorTextDifferencingService.cs b/src/EditorFeatures/Core/TextDiffing/EditorTextDifferencingService.cs index e5abd7e39bca1..c49a214fa60c5 100644 --- a/src/EditorFeatures/Core/TextDiffing/EditorTextDifferencingService.cs +++ b/src/EditorFeatures/Core/TextDiffing/EditorTextDifferencingService.cs @@ -39,10 +39,10 @@ public async Task> GetTextChangesAsync(Document oldDo var diffResult = diffService.DiffSourceTexts(oldText, newText, differenceOptions); - return diffResult.Differences.Select(d => + return [.. diffResult.Differences.Select(d => new TextChange( diffResult.LeftDecomposition.GetSpanInOriginal(d.Left).ToTextSpan(), - newText.GetSubText(diffResult.RightDecomposition.GetSpanInOriginal(d.Right).ToTextSpan()).ToString())).ToImmutableArray(); + newText.GetSubText(diffResult.RightDecomposition.GetSpanInOriginal(d.Right).ToTextSpan()).ToString()))]; } private static StringDifferenceOptions GetDifferenceOptions(TextDifferenceTypes differenceTypes) diff --git a/src/EditorFeatures/Core/TextStructureNavigation/AbstractTextStructureNavigatorProvider.TextStructureNavigator.cs b/src/EditorFeatures/Core/TextStructureNavigation/AbstractTextStructureNavigatorProvider.TextStructureNavigator.cs index e17d767ce7001..8e5215dd4d870 100644 --- a/src/EditorFeatures/Core/TextStructureNavigation/AbstractTextStructureNavigatorProvider.TextStructureNavigator.cs +++ b/src/EditorFeatures/Core/TextStructureNavigation/AbstractTextStructureNavigatorProvider.TextStructureNavigator.cs @@ -2,11 +2,10 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System.Linq; using System.Threading; using Microsoft.CodeAnalysis.Internal.Log; +using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; using Microsoft.CodeAnalysis.Text.Shared.Extensions; using Microsoft.VisualStudio.Text; @@ -18,7 +17,7 @@ namespace Microsoft.CodeAnalysis.Editor.Implementation.TextStructureNavigation; internal partial class AbstractTextStructureNavigatorProvider { - private class TextStructureNavigator : ITextStructureNavigator + private sealed class TextStructureNavigator : ITextStructureNavigator { private readonly ITextBuffer _subjectBuffer; private readonly ITextStructureNavigator _naturalLanguageNavigator; @@ -66,51 +65,35 @@ private TextExtent GetExtentOfWordWorker(SnapshotPoint position, CancellationTok { var textLength = position.Snapshot.Length; if (textLength == 0) - { return _naturalLanguageNavigator.GetExtentOfWord(position); - } // If at the end of the file, go back one character so stuff works if (position == textLength && position > 0) - { position -= 1; - } // If we're at the EOL position, return the line break's extent var line = position.Snapshot.GetLineFromPosition(position); if (position >= line.End && position < line.EndIncludingLineBreak) - { return new TextExtent(new SnapshotSpan(line.End, line.EndIncludingLineBreak - line.End), isSignificant: false); - } var document = GetDocument(position); if (document != null) { - var root = document.GetSyntaxRootSynchronously(cancellationToken); + var root = document.GetRequiredSyntaxRootSynchronously(cancellationToken); var trivia = root.FindTrivia(position, findInsideTrivia: true); - if (trivia != default) - { - if (trivia.Span.Start == position && _provider.ShouldSelectEntireTriviaFromStart(trivia)) - { - // We want to select the entire comment - return new TextExtent(trivia.Span.ToSnapshotSpan(position.Snapshot), isSignificant: true); - } - } + // See if we want to select the entire comment + if (trivia != default && trivia.Span.Start == position && _provider.ShouldSelectEntireTriviaFromStart(trivia)) + return new TextExtent(trivia.Span.ToSnapshotSpan(position.Snapshot), isSignificant: true); var token = root.FindToken(position, findInsideTrivia: true); // If end of file, go back a token if (token.Span.Length == 0 && token.Span.Start == textLength) - { token = token.GetPreviousToken(); - } - if (token.Span.Length > 0 && token.Span.Contains(position) && !_provider.IsWithinNaturalLanguage(token, position)) - { - // Cursor position is in our domain - handle it. - return _provider.GetExtentOfWordFromToken(token, position); - } + if (token.Span.Length > 0 && token.Span.Contains(position)) + return _provider.GetExtentOfWordFromToken(_naturalLanguageNavigator, token, position); } // Fall back to natural language navigator do its thing. @@ -290,7 +273,7 @@ private static SnapshotSpan GetSpanOfPreviousSiblingWorker(SnapshotSpan activeSp return node == null ? activeSpan : node.Value.Span.ToSnapshotSpan(activeSpan.Snapshot); } - private static Document GetDocument(SnapshotPoint point) + private static Document? GetDocument(SnapshotPoint point) { var textLength = point.Snapshot.Length; if (textLength == 0) @@ -325,7 +308,7 @@ private static Document GetDocument(SnapshotPoint point) /// private static bool TryFindLeafToken(SnapshotPoint point, out SyntaxToken token, CancellationToken cancellationToken) { - var syntaxTree = GetDocument(point).GetSyntaxTreeSynchronously(cancellationToken); + var syntaxTree = GetDocument(point)?.GetSyntaxTreeSynchronously(cancellationToken); if (syntaxTree != null) { token = syntaxTree.GetRoot(cancellationToken).FindToken(point, true); diff --git a/src/EditorFeatures/Core/TextStructureNavigation/AbstractTextStructureNavigatorProvider.cs b/src/EditorFeatures/Core/TextStructureNavigation/AbstractTextStructureNavigatorProvider.cs index d8a18e85d28f3..b4b461ad0429e 100644 --- a/src/EditorFeatures/Core/TextStructureNavigation/AbstractTextStructureNavigatorProvider.cs +++ b/src/EditorFeatures/Core/TextStructureNavigation/AbstractTextStructureNavigatorProvider.cs @@ -2,40 +2,28 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using Microsoft.CodeAnalysis.Text.Shared.Extensions; using Microsoft.VisualStudio.Text; using Microsoft.VisualStudio.Text.Operations; using Microsoft.VisualStudio.Utilities; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Editor.Implementation.TextStructureNavigation; -internal abstract partial class AbstractTextStructureNavigatorProvider : ITextStructureNavigatorProvider +internal abstract partial class AbstractTextStructureNavigatorProvider( + ITextStructureNavigatorSelectorService selectorService, + IContentTypeRegistryService contentTypeService, + IUIThreadOperationExecutor uIThreadOperationExecutor) : ITextStructureNavigatorProvider { - private readonly ITextStructureNavigatorSelectorService _selectorService; - private readonly IContentTypeRegistryService _contentTypeService; - private readonly IUIThreadOperationExecutor _uiThreadOperationExecutor; - - protected AbstractTextStructureNavigatorProvider( - ITextStructureNavigatorSelectorService selectorService, - IContentTypeRegistryService contentTypeService, - IUIThreadOperationExecutor uIThreadOperationExecutor) - { - Contract.ThrowIfNull(selectorService); - Contract.ThrowIfNull(contentTypeService); - - _selectorService = selectorService; - _contentTypeService = contentTypeService; - _uiThreadOperationExecutor = uIThreadOperationExecutor; - } + private readonly ITextStructureNavigatorSelectorService _selectorService = selectorService; + private readonly IContentTypeRegistryService _contentTypeService = contentTypeService; + private readonly IUIThreadOperationExecutor _uiThreadOperationExecutor = uIThreadOperationExecutor; protected abstract bool ShouldSelectEntireTriviaFromStart(SyntaxTrivia trivia); - protected abstract bool IsWithinNaturalLanguage(SyntaxToken token, int position); - protected virtual TextExtent GetExtentOfWordFromToken(SyntaxToken token, SnapshotPoint position) - => new(token.Span.ToSnapshotSpan(position.Snapshot), isSignificant: true); + protected abstract TextExtent GetExtentOfWordFromToken(ITextStructureNavigator naturalLanguageNavigator, SyntaxToken token, SnapshotPoint position); + + protected static TextExtent GetTokenExtent(SyntaxToken token, ITextSnapshot snapshot) + => new(token.Span.ToSnapshotSpan(snapshot), isSignificant: true); public ITextStructureNavigator CreateTextStructureNavigator(ITextBuffer subjectBuffer) { diff --git a/src/EditorFeatures/Core/xlf/EditorFeaturesResources.cs.xlf b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.cs.xlf index 56be44ba2f553..deadfb68a2575 100644 --- a/src/EditorFeatures/Core/xlf/EditorFeaturesResources.cs.xlf +++ b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.cs.xlf @@ -792,11 +792,6 @@ Operace přejmenování nebyla řádně dokončená. Některý soubor nemusel být aktualizovaný. - - Rename '{0}' to '{1}' - Přejmenovat {0} na {1} - - Preview Warning Upozornění verze Preview diff --git a/src/EditorFeatures/Core/xlf/EditorFeaturesResources.de.xlf b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.de.xlf index ad1b8eb1c8674..7c5542620b5d3 100644 --- a/src/EditorFeatures/Core/xlf/EditorFeaturesResources.de.xlf +++ b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.de.xlf @@ -797,11 +797,6 @@ Der Umbenennungsvorgang wurde nicht ordnungsgemäß abgeschlossen. Möglicherweise wurden manche Dateien nicht aktualisiert. - - Rename '{0}' to '{1}' - "{0}" in "{1}" umbenennen - - Preview Warning Vorschau der Warnung anzeigen diff --git a/src/EditorFeatures/Core/xlf/EditorFeaturesResources.es.xlf b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.es.xlf index 0c702bb34dfcc..7def27cefa87b 100644 --- a/src/EditorFeatures/Core/xlf/EditorFeaturesResources.es.xlf +++ b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.es.xlf @@ -792,11 +792,6 @@ La operación de cambio de nombre no se completó correctamente. Puede que algún archivo no se haya actualizado. - - Rename '{0}' to '{1}' - Cambiar el nombre de '{0}' a '{1}' - - Preview Warning Vista previa de advertencia diff --git a/src/EditorFeatures/Core/xlf/EditorFeaturesResources.fr.xlf b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.fr.xlf index 27e951c1082d0..77e83a00bb46b 100644 --- a/src/EditorFeatures/Core/xlf/EditorFeaturesResources.fr.xlf +++ b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.fr.xlf @@ -792,11 +792,6 @@ Le changement de nom ne s'est pas effectué correctement. Certains fichiers risquent de ne pas avoir été mis à jour. - - Rename '{0}' to '{1}' - Renommer '{0}' en '{1}' - - Preview Warning Avertissement sur la pré-version diff --git a/src/EditorFeatures/Core/xlf/EditorFeaturesResources.it.xlf b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.it.xlf index 67cd5c2e8cb1f..494d58240b5f9 100644 --- a/src/EditorFeatures/Core/xlf/EditorFeaturesResources.it.xlf +++ b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.it.xlf @@ -792,11 +792,6 @@ L'operazione di ridenominazione non è stata completata correttamente. Alcuni file potrebbero non essere stati aggiornati. - - Rename '{0}' to '{1}' - Rinomina '{0}' in '{1}' - - Preview Warning Avviso di anteprima diff --git a/src/EditorFeatures/Core/xlf/EditorFeaturesResources.ja.xlf b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.ja.xlf index 7ec698d70edfa..173a32b73c844 100644 --- a/src/EditorFeatures/Core/xlf/EditorFeaturesResources.ja.xlf +++ b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.ja.xlf @@ -792,11 +792,6 @@ 名前の変更操作は正常に終了しませんでした。ファイルのいくつかは更新されなかった可能性があります。 - - Rename '{0}' to '{1}' - '{0}' を '{1}' に名前変更 - - Preview Warning 警告のプレビュー diff --git a/src/EditorFeatures/Core/xlf/EditorFeaturesResources.ko.xlf b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.ko.xlf index ee526ff96803d..6af82a2e1d86a 100644 --- a/src/EditorFeatures/Core/xlf/EditorFeaturesResources.ko.xlf +++ b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.ko.xlf @@ -792,11 +792,6 @@ 이름 바꾸기 작업이 제대로 완료되지 않았습니다. 일부 파일이 업데이트되지 않았을 수 있습니다. - - Rename '{0}' to '{1}' - '{1}'(으)로 '{0}' 이름 바꾸기 - - Preview Warning 경고 미리 보기 diff --git a/src/EditorFeatures/Core/xlf/EditorFeaturesResources.pl.xlf b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.pl.xlf index 34713163aaae5..db20f5ea0e5ab 100644 --- a/src/EditorFeatures/Core/xlf/EditorFeaturesResources.pl.xlf +++ b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.pl.xlf @@ -792,11 +792,6 @@ Operacja zmiany nazwy nie została prawidłowo ukończona. Niektóre pliki mogły nie zostać zaktualizowane. - - Rename '{0}' to '{1}' - Zmień nazwę elementu „{0}” na „{1}” - - Preview Warning Ostrzeżenie (wersja zapoznawcza) diff --git a/src/EditorFeatures/Core/xlf/EditorFeaturesResources.pt-BR.xlf b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.pt-BR.xlf index 0941a18b91be8..3106e84c43329 100644 --- a/src/EditorFeatures/Core/xlf/EditorFeaturesResources.pt-BR.xlf +++ b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.pt-BR.xlf @@ -792,11 +792,6 @@ A operação de renomear não foi corretamente concluída. Algum arquivo pode não ter sido atualizado. - - Rename '{0}' to '{1}' - Renomear "{0}" para "{1}" - - Preview Warning Aviso de Visualização diff --git a/src/EditorFeatures/Core/xlf/EditorFeaturesResources.ru.xlf b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.ru.xlf index dd51497a16675..159f84ac42a3b 100644 --- a/src/EditorFeatures/Core/xlf/EditorFeaturesResources.ru.xlf +++ b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.ru.xlf @@ -792,11 +792,6 @@ Операция переименования завершена неправильно. Некоторые файлы должны быть обновлены. - - Rename '{0}' to '{1}' - Переименовать "{0}" в "{1}" - - Preview Warning Предварительный просмотр предупреждения diff --git a/src/EditorFeatures/Core/xlf/EditorFeaturesResources.tr.xlf b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.tr.xlf index 16d5d43353709..98f893e21b5cc 100644 --- a/src/EditorFeatures/Core/xlf/EditorFeaturesResources.tr.xlf +++ b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.tr.xlf @@ -792,11 +792,6 @@ Yeniden adlandırma işlemi uygun şekilde tamamlanmadı. Bazı dosyalar güncelleştirilmemiş olabilir. - - Rename '{0}' to '{1}' - '{0}' öğesini '{1}' olarak yeniden adlandır - - Preview Warning Önizleme Uyarısı diff --git a/src/EditorFeatures/Core/xlf/EditorFeaturesResources.zh-Hans.xlf b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.zh-Hans.xlf index 4c41de21b844c..e626b6675a912 100644 --- a/src/EditorFeatures/Core/xlf/EditorFeaturesResources.zh-Hans.xlf +++ b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.zh-Hans.xlf @@ -792,11 +792,6 @@ 重命名操作未正确完成。可能未更新某个文件。 - - Rename '{0}' to '{1}' - 将“{0}” 重命名为“{1}” - - Preview Warning 预览警告 diff --git a/src/EditorFeatures/Core/xlf/EditorFeaturesResources.zh-Hant.xlf b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.zh-Hant.xlf index 7006148e113c3..3ef849680bea5 100644 --- a/src/EditorFeatures/Core/xlf/EditorFeaturesResources.zh-Hant.xlf +++ b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.zh-Hant.xlf @@ -792,11 +792,6 @@ 重新命名作業未正確完成。部分檔案可能尚未更新。 - - Rename '{0}' to '{1}' - 將 '{0}' 重新命名為 '{1}' - - Preview Warning 預覽警告 diff --git a/src/EditorFeatures/DiagnosticsTestUtilities/ChangeSignature/AbstractChangeSignatureTests.cs b/src/EditorFeatures/DiagnosticsTestUtilities/ChangeSignature/AbstractChangeSignatureTests.cs index e28a41fbf662b..d80d8fdd84195 100644 --- a/src/EditorFeatures/DiagnosticsTestUtilities/ChangeSignature/AbstractChangeSignatureTests.cs +++ b/src/EditorFeatures/DiagnosticsTestUtilities/ChangeSignature/AbstractChangeSignatureTests.cs @@ -54,10 +54,10 @@ internal async Task TestChangeSignatureViaCodeActionAsync( var refactoring = await GetCodeRefactoringAsync(workspace, testOptions); await TestActionAsync(workspace, expectedCode, refactoring.CodeActions[index].action, - conflictSpans: ImmutableArray.Empty, - renameSpans: ImmutableArray.Empty, - warningSpans: ImmutableArray.Empty, - navigationSpans: ImmutableArray.Empty, + conflictSpans: [], + renameSpans: [], + warningSpans: [], + navigationSpans: [], parameters: null); } else diff --git a/src/EditorFeatures/DiagnosticsTestUtilities/CodeActions/AbstractCodeActionOrUserDiagnosticTest.cs b/src/EditorFeatures/DiagnosticsTestUtilities/CodeActions/AbstractCodeActionOrUserDiagnosticTest.cs index aa7e59b651a1b..1134498bd3b88 100644 --- a/src/EditorFeatures/DiagnosticsTestUtilities/CodeActions/AbstractCodeActionOrUserDiagnosticTest.cs +++ b/src/EditorFeatures/DiagnosticsTestUtilities/CodeActions/AbstractCodeActionOrUserDiagnosticTest.cs @@ -466,17 +466,17 @@ private async Task TestAsync( parameters.treatPositionIndicatorsAsCode); const string UnnecessaryMarkupKey = "Unnecessary"; - var unnecessarySpans = initialSpanMap.GetOrAdd(UnnecessaryMarkupKey, _ => ImmutableArray.Empty); + var unnecessarySpans = initialSpanMap.GetOrAdd(UnnecessaryMarkupKey, _ => []); MarkupTestFile.GetSpans( expectedMarkup, out var expected, out var expectedSpanMap, parameters.treatPositionIndicatorsAsCode); - var conflictSpans = expectedSpanMap.GetOrAdd("Conflict", _ => ImmutableArray.Empty); - var renameSpans = expectedSpanMap.GetOrAdd("Rename", _ => ImmutableArray.Empty); - var warningSpans = expectedSpanMap.GetOrAdd("Warning", _ => ImmutableArray.Empty); - var navigationSpans = expectedSpanMap.GetOrAdd("Navigation", _ => ImmutableArray.Empty); + var conflictSpans = expectedSpanMap.GetOrAdd("Conflict", _ => []); + var renameSpans = expectedSpanMap.GetOrAdd("Rename", _ => []); + var warningSpans = expectedSpanMap.GetOrAdd("Warning", _ => []); + var navigationSpans = expectedSpanMap.GetOrAdd("Navigation", _ => []); using var workspace = CreateWorkspaceFromOptions(initialMarkup, parameters); // Ideally this check would always run, but there are several hundred tests that would need to be @@ -870,9 +870,9 @@ static void VerifyCodeAction( protected static ImmutableArray FlattenActions(ImmutableArray codeActions) { - return codeActions.SelectMany(a => a.NestedActions.Length > 0 + return [.. codeActions.SelectMany(a => a.NestedActions.Length > 0 ? a.NestedActions - : ImmutableArray.Create(a)).ToImmutableArray(); + : [a])]; } protected static ImmutableArray GetNestedActions(ImmutableArray codeActions) diff --git a/src/EditorFeatures/DiagnosticsTestUtilities/CodeActions/AbstractCodeActionTest.cs b/src/EditorFeatures/DiagnosticsTestUtilities/CodeActions/AbstractCodeActionTest.cs index d9c4f5743c053..d06f7a177be92 100644 --- a/src/EditorFeatures/DiagnosticsTestUtilities/CodeActions/AbstractCodeActionTest.cs +++ b/src/EditorFeatures/DiagnosticsTestUtilities/CodeActions/AbstractCodeActionTest.cs @@ -39,7 +39,7 @@ protected abstract CodeRefactoringProvider CreateCodeRefactoringProvider( var refactoring = await GetCodeRefactoringAsync(workspace, parameters); var actions = refactoring == null - ? ImmutableArray.Empty + ? [] : refactoring.CodeActions.Select(n => n.action).AsImmutable(); actions = MassageActions(actions); @@ -52,7 +52,7 @@ protected abstract CodeRefactoringProvider CreateCodeRefactoringProvider( document, span, fixAllScope.Value, CancellationToken.None).ConfigureAwait(false); if (documentsAndSpansToFix.IsEmpty) { - return (ImmutableArray.Empty, null); + return ([], null); } } @@ -63,7 +63,7 @@ protected abstract CodeRefactoringProvider CreateCodeRefactoringProvider( var fixAllCodeAction = await GetFixAllFixAsync(actionToInvoke, refactoring.Provider, document, span, fixAllScope.Value).ConfigureAwait(false); if (fixAllCodeAction == null) - return (ImmutableArray.Empty, null); + return ([], null); return (ImmutableArray.Create(fixAllCodeAction), fixAllCodeAction); } diff --git a/src/EditorFeatures/DiagnosticsTestUtilities/Diagnostics/AbstractUserDiagnosticTest.cs b/src/EditorFeatures/DiagnosticsTestUtilities/Diagnostics/AbstractUserDiagnosticTest.cs index 97d2aee076071..cedff2360b04a 100644 --- a/src/EditorFeatures/DiagnosticsTestUtilities/Diagnostics/AbstractUserDiagnosticTest.cs +++ b/src/EditorFeatures/DiagnosticsTestUtilities/Diagnostics/AbstractUserDiagnosticTest.cs @@ -103,7 +103,7 @@ protected static void AddAnalyzerToWorkspace(Workspace workspace, DiagnosticAnal AnalyzerReference[] analyzerReferences; if (analyzer != null) { - var analyzerImageReference = new AnalyzerImageReference(ImmutableArray.Create(analyzer)); + var analyzerImageReference = new AnalyzerImageReference([analyzer]); analyzerReferences = [analyzerImageReference]; } else @@ -135,7 +135,7 @@ protected static Document GetDocumentAndSelectSpan(EditorTestWorkspace workspace { if (diagnostics.IsEmpty()) { - return (ImmutableArray.Empty, ImmutableArray.Empty, null); + return ([], ImmutableArray.Empty, null); } var scope = GetFixAllScope(annotation); @@ -147,7 +147,7 @@ protected static Document GetDocumentAndSelectSpan(EditorTestWorkspace workspace document, span, scope.Value, CancellationToken.None).ConfigureAwait(false); if (documentsAndSpansToFix.IsEmpty) { - return (ImmutableArray.Empty, ImmutableArray.Empty, null); + return ([], ImmutableArray.Empty, null); } } @@ -161,7 +161,7 @@ protected static Document GetDocumentAndSelectSpan(EditorTestWorkspace workspace var context = new CodeFixContext( document, diagnostic.Location.SourceSpan, - ImmutableArray.Create(diagnostic), + [diagnostic], (a, d) => fixes.Add(new CodeFix(document.Project, a, d)), CancellationToken.None); diff --git a/src/EditorFeatures/DiagnosticsTestUtilities/Diagnostics/AbstractUserDiagnosticTest_GenerateTypeDialog.cs b/src/EditorFeatures/DiagnosticsTestUtilities/Diagnostics/AbstractUserDiagnosticTest_GenerateTypeDialog.cs index 45605d118ff13..7061aa8da7aa2 100644 --- a/src/EditorFeatures/DiagnosticsTestUtilities/Diagnostics/AbstractUserDiagnosticTest_GenerateTypeDialog.cs +++ b/src/EditorFeatures/DiagnosticsTestUtilities/Diagnostics/AbstractUserDiagnosticTest_GenerateTypeDialog.cs @@ -106,10 +106,10 @@ internal async Task TestWithMockedGenerateTypeDialog( { oldSolutionAndNewSolution = await TestOperationsAsync( testState.Workspace, expected, operations, - conflictSpans: ImmutableArray.Empty, - renameSpans: ImmutableArray.Empty, - warningSpans: ImmutableArray.Empty, - navigationSpans: ImmutableArray.Empty, + conflictSpans: [], + renameSpans: [], + warningSpans: [], + navigationSpans: [], expectedChangedDocumentId: testState.ExistingDocument.Id); } else @@ -128,10 +128,10 @@ internal async Task TestWithMockedGenerateTypeDialog( { Assert.NotNull(expectedTextWithUsings); await TestOperationsAsync(testState.Workspace, expectedTextWithUsings, operations, - conflictSpans: ImmutableArray.Empty, - renameSpans: ImmutableArray.Empty, - warningSpans: ImmutableArray.Empty, - navigationSpans: ImmutableArray.Empty, + conflictSpans: [], + renameSpans: [], + warningSpans: [], + navigationSpans: [], expectedChangedDocumentId: testState.InvocationDocument.Id); } diff --git a/src/EditorFeatures/DiagnosticsTestUtilities/MoveToNamespace/AbstractMoveToNamespaceTests.cs b/src/EditorFeatures/DiagnosticsTestUtilities/MoveToNamespace/AbstractMoveToNamespaceTests.cs index 75395d6d39b86..e221ea06844ec 100644 --- a/src/EditorFeatures/DiagnosticsTestUtilities/MoveToNamespace/AbstractMoveToNamespaceTests.cs +++ b/src/EditorFeatures/DiagnosticsTestUtilities/MoveToNamespace/AbstractMoveToNamespaceTests.cs @@ -51,7 +51,6 @@ public async Task TestMoveToNamespaceAsync( CancellationToken.None); var operationTasks = actions - .Cast() .Select(action => action.GetOperationsAsync(workspace.CurrentSolution, action.GetOptions(CancellationToken.None), CodeAnalysisProgress.None, CancellationToken.None)); foreach (var task in operationTasks) diff --git a/src/EditorFeatures/DiagnosticsTestUtilities/MoveType/AbstractMoveTypeTest.cs b/src/EditorFeatures/DiagnosticsTestUtilities/MoveType/AbstractMoveTypeTest.cs index 1937823ed5117..7d8739acaece3 100644 --- a/src/EditorFeatures/DiagnosticsTestUtilities/MoveType/AbstractMoveTypeTest.cs +++ b/src/EditorFeatures/DiagnosticsTestUtilities/MoveType/AbstractMoveTypeTest.cs @@ -20,164 +20,163 @@ using Roslyn.Test.Utilities; using Xunit; -namespace Microsoft.CodeAnalysis.Editor.UnitTests.MoveType +namespace Microsoft.CodeAnalysis.Editor.UnitTests.MoveType; + +public abstract class AbstractMoveTypeTest : AbstractCodeActionTest { - public abstract class AbstractMoveTypeTest : AbstractCodeActionTest - { - private readonly string RenameFileCodeActionTitle = FeaturesResources.Rename_file_to_0; - private readonly string RenameTypeCodeActionTitle = FeaturesResources.Rename_type_to_0; + private readonly string RenameFileCodeActionTitle = FeaturesResources.Rename_file_to_0; + private readonly string RenameTypeCodeActionTitle = FeaturesResources.Rename_type_to_0; - // TODO: Requires WPF due to IInlineRenameService dependency (https://github.com/dotnet/roslyn/issues/46153) - protected override TestComposition GetComposition() - => EditorTestCompositions.EditorFeaturesWpf; + // TODO: Requires WPF due to IInlineRenameService dependency (https://github.com/dotnet/roslyn/issues/46153) + protected override TestComposition GetComposition() + => EditorTestCompositions.EditorFeaturesWpf; - protected override CodeRefactoringProvider CreateCodeRefactoringProvider(EditorTestWorkspace workspace, TestParameters parameters) - => new MoveTypeCodeRefactoringProvider(); + protected override CodeRefactoringProvider CreateCodeRefactoringProvider(EditorTestWorkspace workspace, TestParameters parameters) + => new MoveTypeCodeRefactoringProvider(); - protected async Task TestRenameTypeToMatchFileAsync( - string originalCode, - string expectedCode = null, - bool expectedCodeAction = true, - object fixProviderData = null) + protected async Task TestRenameTypeToMatchFileAsync( + string originalCode, + string expectedCode = null, + bool expectedCodeAction = true, + object fixProviderData = null) + { + var testOptions = new TestParameters(fixProviderData: fixProviderData); + using var workspace = CreateWorkspaceFromOptions(originalCode, testOptions); + if (expectedCodeAction) { - var testOptions = new TestParameters(fixProviderData: fixProviderData); - using var workspace = CreateWorkspaceFromOptions(originalCode, testOptions); - if (expectedCodeAction) - { - Assert.True(expectedCode != null, $"{nameof(expectedCode)} should be present if {nameof(expectedCodeAction)} is true."); + Assert.True(expectedCode != null, $"{nameof(expectedCode)} should be present if {nameof(expectedCodeAction)} is true."); - var documentId = workspace.Documents[0].Id; - var documentName = workspace.Documents[0].Name; - MarkupTestFile.GetSpan(expectedCode, out var expectedText, out var span); + var documentId = workspace.Documents[0].Id; + var documentName = workspace.Documents[0].Name; + MarkupTestFile.GetSpan(expectedCode, out var expectedText, out var span); - var codeActionTitle = string.Format(RenameTypeCodeActionTitle, expectedText.Substring(span.Start, span.Length)); + var codeActionTitle = string.Format(RenameTypeCodeActionTitle, expectedText.Substring(span.Start, span.Length)); - var oldSolutionAndNewSolution = await TestOperationAsync( - testOptions, workspace, expectedText, codeActionTitle); + var oldSolutionAndNewSolution = await TestOperationAsync( + testOptions, workspace, expectedText, codeActionTitle); - // the original source document does not exist in the new solution. - var newSolution = oldSolutionAndNewSolution.Item2; + // the original source document does not exist in the new solution. + var newSolution = oldSolutionAndNewSolution.Item2; - var document = newSolution.GetDocument(documentId); - Assert.NotNull(document); - Assert.Equal(documentName, document.Name); - } - else - { - var (actions, _) = await GetCodeActionsAsync(workspace, testOptions); + var document = newSolution.GetDocument(documentId); + Assert.NotNull(document); + Assert.Equal(documentName, document.Name); + } + else + { + var (actions, _) = await GetCodeActionsAsync(workspace, testOptions); - if (actions.Length > 0) - { - var renameFileAction = actions.Any(static (action, self) => action.Title.StartsWith(self.RenameTypeCodeActionTitle), this); - Assert.False(renameFileAction, "Rename Type to match file name code action was not expected, but shows up."); - } + if (actions.Length > 0) + { + var renameFileAction = actions.Any(static (action, self) => action.Title.StartsWith(self.RenameTypeCodeActionTitle), this); + Assert.False(renameFileAction, "Rename Type to match file name code action was not expected, but shows up."); } } + } - protected async Task TestRenameFileToMatchTypeAsync( - string originalCode, - string expectedDocumentName = null, - bool expectedCodeAction = true, - IList destinationDocumentContainers = null, - object fixProviderData = null) + protected async Task TestRenameFileToMatchTypeAsync( + string originalCode, + string expectedDocumentName = null, + bool expectedCodeAction = true, + IList destinationDocumentContainers = null, + object fixProviderData = null) + { + var testOptions = new TestParameters(fixProviderData: fixProviderData); + using var workspace = CreateWorkspaceFromOptions(originalCode, testOptions); + if (expectedCodeAction) { - var testOptions = new TestParameters(fixProviderData: fixProviderData); - using var workspace = CreateWorkspaceFromOptions(originalCode, testOptions); - if (expectedCodeAction) - { - Assert.True(expectedDocumentName != null, $"{nameof(expectedDocumentName)} should be present if {nameof(expectedCodeAction)} is true."); + Assert.True(expectedDocumentName != null, $"{nameof(expectedDocumentName)} should be present if {nameof(expectedCodeAction)} is true."); - var oldDocumentId = workspace.Documents[0].Id; - var expectedText = workspace.Documents[0].GetTextBuffer().CurrentSnapshot.GetText(); - var spans = workspace.Documents[0].SelectedSpans; + var oldDocumentId = workspace.Documents[0].Id; + var expectedText = workspace.Documents[0].GetTextBuffer().CurrentSnapshot.GetText(); + var spans = workspace.Documents[0].SelectedSpans; - var codeActionTitle = string.Format(RenameFileCodeActionTitle, expectedDocumentName); + var codeActionTitle = string.Format(RenameFileCodeActionTitle, expectedDocumentName); - var oldSolutionAndNewSolution = await TestOperationAsync( - testOptions, workspace, expectedText, codeActionTitle); + var oldSolutionAndNewSolution = await TestOperationAsync( + testOptions, workspace, expectedText, codeActionTitle); - // The code action updated the Name of the file in-place - var newSolution = oldSolutionAndNewSolution.Item2; - var newDocument = newSolution.GetDocument(oldDocumentId); - Assert.Equal(expectedDocumentName, newDocument.Name); + // The code action updated the Name of the file in-place + var newSolution = oldSolutionAndNewSolution.Item2; + var newDocument = newSolution.GetDocument(oldDocumentId); + Assert.Equal(expectedDocumentName, newDocument.Name); - if (destinationDocumentContainers != null) - { - Assert.Equal(destinationDocumentContainers, newDocument.Folders); - } - } - else + if (destinationDocumentContainers != null) { - var (actions, _) = await GetCodeActionsAsync(workspace, testOptions); - - if (actions.Length > 0) - { - var renameFileAction = actions.Any(static (action, self) => action.Title.StartsWith(self.RenameFileCodeActionTitle), this); - Assert.False(renameFileAction, "Rename File to match type code action was not expected, but shows up."); - } + Assert.Equal(destinationDocumentContainers, newDocument.Folders); } } - - private async Task> TestOperationAsync( - TestParameters parameters, - EditorTestWorkspace workspace, - string expectedCode, - string operation) + else { - var (actions, _) = await GetCodeActionsAsync(workspace, parameters); - var action = actions.Single(a => a.Title.Equals(operation, StringComparison.CurrentCulture)); - var operations = await action.GetOperationsAsync( - workspace.CurrentSolution, CodeAnalysisProgress.None, CancellationToken.None); - - return await TestOperationsAsync(workspace, - expectedText: expectedCode, - operations: operations, - conflictSpans: ImmutableArray.Empty, - renameSpans: ImmutableArray.Empty, - warningSpans: ImmutableArray.Empty, - navigationSpans: ImmutableArray.Empty, - expectedChangedDocumentId: null); + var (actions, _) = await GetCodeActionsAsync(workspace, testOptions); + + if (actions.Length > 0) + { + var renameFileAction = actions.Any(static (action, self) => action.Title.StartsWith(self.RenameFileCodeActionTitle), this); + Assert.False(renameFileAction, "Rename File to match type code action was not expected, but shows up."); + } } + } + + private async Task> TestOperationAsync( + TestParameters parameters, + EditorTestWorkspace workspace, + string expectedCode, + string operation) + { + var (actions, _) = await GetCodeActionsAsync(workspace, parameters); + var action = actions.Single(a => a.Title.Equals(operation, StringComparison.CurrentCulture)); + var operations = await action.GetOperationsAsync( + workspace.CurrentSolution, CodeAnalysisProgress.None, CancellationToken.None); + + return await TestOperationsAsync(workspace, + expectedText: expectedCode, + operations: operations, + conflictSpans: [], + renameSpans: [], + warningSpans: [], + navigationSpans: [], + expectedChangedDocumentId: null); + } - private protected async Task TestMoveTypeToNewFileAsync( - string originalCode, - string expectedSourceTextAfterRefactoring, - string expectedDocumentName, - string destinationDocumentText, - ImmutableArray destinationDocumentContainers = default, - bool expectedCodeAction = true, - int index = 0, - OptionsCollection options = null) + private protected async Task TestMoveTypeToNewFileAsync( + string originalCode, + string expectedSourceTextAfterRefactoring, + string expectedDocumentName, + string destinationDocumentText, + ImmutableArray destinationDocumentContainers = default, + bool expectedCodeAction = true, + int index = 0, + OptionsCollection options = null) + { + var testOptions = new TestParameters(index: index, options: options); + if (expectedCodeAction) { - var testOptions = new TestParameters(index: index, options: options); - if (expectedCodeAction) - { - using var workspace = CreateWorkspaceFromOptions(originalCode, testOptions); + using var workspace = CreateWorkspaceFromOptions(originalCode, testOptions); - // replace with default values on null. - destinationDocumentContainers = destinationDocumentContainers.NullToEmpty(); + // replace with default values on null. + destinationDocumentContainers = destinationDocumentContainers.NullToEmpty(); - var sourceDocumentId = workspace.Documents[0].Id; + var sourceDocumentId = workspace.Documents[0].Id; - // Verify the newly added document and its text - var oldSolutionAndNewSolution = await TestAddDocumentAsync( - testOptions, workspace, destinationDocumentText, - expectedDocumentName, destinationDocumentContainers); + // Verify the newly added document and its text + var oldSolutionAndNewSolution = await TestAddDocumentAsync( + testOptions, workspace, destinationDocumentText, + expectedDocumentName, destinationDocumentContainers); - // Verify source document's text after moving type. - var oldSolution = oldSolutionAndNewSolution.Item1; - var newSolution = oldSolutionAndNewSolution.Item2; - var changedDocumentIds = SolutionUtilities.GetChangedDocuments(oldSolution, newSolution); - Assert.True(changedDocumentIds.Contains(sourceDocumentId), "source document was not changed."); + // Verify source document's text after moving type. + var oldSolution = oldSolutionAndNewSolution.Item1; + var newSolution = oldSolutionAndNewSolution.Item2; + var changedDocumentIds = SolutionUtilities.GetChangedDocuments(oldSolution, newSolution); + Assert.True(changedDocumentIds.Contains(sourceDocumentId), "source document was not changed."); - var modifiedSourceDocument = newSolution.GetDocument(sourceDocumentId); - var actualSourceTextAfterRefactoring = (await modifiedSourceDocument.GetTextAsync()).ToString(); - Assert.Equal(expectedSourceTextAfterRefactoring, actualSourceTextAfterRefactoring); - } - else - { - await TestMissingAsync(originalCode); - } + var modifiedSourceDocument = newSolution.GetDocument(sourceDocumentId); + var actualSourceTextAfterRefactoring = (await modifiedSourceDocument.GetTextAsync()).ToString(); + AssertEx.Equal(expectedSourceTextAfterRefactoring, actualSourceTextAfterRefactoring); + } + else + { + await TestMissingAsync(originalCode); } } } diff --git a/src/EditorFeatures/ExternalAccess/Debugger/GlassTestsHotReloadService.cs b/src/EditorFeatures/ExternalAccess/Debugger/GlassTestsHotReloadService.cs index 8c21d74f0f2f6..ec09b35381b6c 100644 --- a/src/EditorFeatures/ExternalAccess/Debugger/GlassTestsHotReloadService.cs +++ b/src/EditorFeatures/ExternalAccess/Debugger/GlassTestsHotReloadService.cs @@ -34,7 +34,7 @@ public async Task StartSessionAsync(Solution solution, CancellationToken cancell solution, new ManagedHotReloadServiceBridge(_debuggerService), NullPdbMatchingSourceTextProvider.Instance, - captureMatchingDocuments: ImmutableArray.Empty, + captureMatchingDocuments: [], captureAllMatchingDocuments: true, reportDiagnostics: false, cancellationToken).ConfigureAwait(false); diff --git a/src/EditorFeatures/Test/CodeActions/CodeChangeProviderMetadataTests.cs b/src/EditorFeatures/Test/CodeActions/CodeChangeProviderMetadataTests.cs index 41179b88e0b5b..70ba838ce02af 100644 --- a/src/EditorFeatures/Test/CodeActions/CodeChangeProviderMetadataTests.cs +++ b/src/EditorFeatures/Test/CodeActions/CodeChangeProviderMetadataTests.cs @@ -151,10 +151,9 @@ private static bool TryGetExportName(ExportDefinition export, [NotNullWhen(retur private static ImmutableHashSet GetPredefinedNamesFromType(Type namesType) { - return namesType.GetFields(BindingFlags.DeclaredOnly | BindingFlags.Static | BindingFlags.Public) + return [.. namesType.GetFields(BindingFlags.DeclaredOnly | BindingFlags.Static | BindingFlags.Public) .Where(field => field.FieldType == typeof(string)) - .Select(field => (string)field.GetValue(null)) - .ToImmutableHashSet(); + .Select(field => (string)field.GetValue(null))]; } private static IEnumerable<(ComposedPart Part, ExportDefinition Export)> FindComposedPartsWithExport( diff --git a/src/EditorFeatures/Test/CodeFixes/CodeFixServiceTests.cs b/src/EditorFeatures/Test/CodeFixes/CodeFixServiceTests.cs index 75005278fd3b5..5d9394ee00cb2 100644 --- a/src/EditorFeatures/Test/CodeFixes/CodeFixServiceTests.cs +++ b/src/EditorFeatures/Test/CodeFixes/CodeFixServiceTests.cs @@ -74,9 +74,7 @@ public async Task TestGetFixesAsyncWithDuplicateDiagnostics() // Add duplicate analyzers to get duplicate diagnostics. var analyzerReference = new MockAnalyzerReference( codeFix, - ImmutableArray.Create( - new MockAnalyzerReference.MockDiagnosticAnalyzer(), - new MockAnalyzerReference.MockDiagnosticAnalyzer())); + [new MockAnalyzerReference.MockDiagnosticAnalyzer(), new MockAnalyzerReference.MockDiagnosticAnalyzer()]); var tuple = ServiceSetup(codeFix); using var workspace = tuple.workspace; @@ -98,11 +96,12 @@ public async Task TestGetFixesAsyncHasNoDuplicateConfigurationActions() // Add analyzers with duplicate ID and/or category to get duplicate diagnostics. var analyzerReference = new MockAnalyzerReference( codeFix, - ImmutableArray.Create( + [ new MockAnalyzerReference.MockDiagnosticAnalyzer("ID1", "Category1"), new MockAnalyzerReference.MockDiagnosticAnalyzer("ID1", "Category1"), new MockAnalyzerReference.MockDiagnosticAnalyzer("ID1", "Category2"), - new MockAnalyzerReference.MockDiagnosticAnalyzer("ID2", "Category2"))); + new MockAnalyzerReference.MockDiagnosticAnalyzer("ID2", "Category2"), + ]); var tuple = ServiceSetup(codeFix, includeConfigurationFixProviders: true); using var workspace = tuple.workspace; @@ -161,7 +160,7 @@ public async Task TestGetFixesAsyncForDocumentDiagnosticAnalyzerAsync() // We need to ensure that we don't skip these document analyzers // when computing the diagnostics/code fixes for "Normal" priority bucket, which // normally only execute those analyzers which report at least one fixable supported diagnostic. - var documentDiagnosticAnalyzer = new MockAnalyzerReference.MockDocumentDiagnosticAnalyzer(reportedDiagnosticIds: ImmutableArray.Empty); + var documentDiagnosticAnalyzer = new MockAnalyzerReference.MockDocumentDiagnosticAnalyzer(reportedDiagnosticIds: []); Assert.Empty(documentDiagnosticAnalyzer.SupportedDiagnostics); var analyzers = ImmutableArray.Create(documentDiagnosticAnalyzer); @@ -290,7 +289,7 @@ private static async Task> GetAddedFixesAsync( errorReportingService.OnError = message => errorReported = true; GetDocumentAndExtensionManager(tuple.analyzerService, workspace, out var document, out var extensionManager); - var reference = new MockAnalyzerReference(codefix, ImmutableArray.Create(diagnosticAnalyzer)); + var reference = new MockAnalyzerReference(codefix, [diagnosticAnalyzer]); var project = workspace.CurrentSolution.Projects.Single().AddAnalyzerReference(reference); document = project.Documents.Single(); var fixes = await tuple.codeFixService.GetFixesAsync(document, TextSpan.FromBounds(0, 0), CancellationToken.None); @@ -330,7 +329,7 @@ private static (EditorTestWorkspace workspace, DiagnosticAnalyzerService analyze bool throwExceptionInFixerCreation = false, EditorTestHostDocument? additionalDocument = null, string code = "class Program { }") - => ServiceSetup(ImmutableArray.Create(codefix), includeConfigurationFixProviders, throwExceptionInFixerCreation, additionalDocument, code); + => ServiceSetup([codefix], includeConfigurationFixProviders, throwExceptionInFixerCreation, additionalDocument, code); private static (EditorTestWorkspace workspace, DiagnosticAnalyzerService analyzerService, CodeFixService codeFixService, IErrorLoggerService errorLogger) ServiceSetup( ImmutableArray codefixers, @@ -423,7 +422,7 @@ public MockFixer(string? registerFixWithTitle = null) public sealed override ImmutableArray FixableDiagnosticIds { - get { return ImmutableArray.Create(Id); } + get { return [Id]; } } public sealed override Task RegisterCodeFixesAsync(CodeFixContext context) @@ -449,8 +448,8 @@ private class MockAnalyzerReference : AnalyzerReference, ICodeFixProviderFactory public readonly ImmutableArray Analyzers; public readonly ImmutableArray Generators; - private static readonly ImmutableArray s_defaultFixers = ImmutableArray.Create(new MockFixer()); - private static readonly ImmutableArray s_defaultAnalyzers = ImmutableArray.Create(new MockDiagnosticAnalyzer()); + private static readonly ImmutableArray s_defaultFixers = [new MockFixer()]; + private static readonly ImmutableArray s_defaultAnalyzers = [new MockDiagnosticAnalyzer()]; public MockAnalyzerReference(ImmutableArray fixers, ImmutableArray analyzers, ImmutableArray generators) { @@ -460,12 +459,12 @@ public MockAnalyzerReference(ImmutableArray fixers, ImmutableAr } public MockAnalyzerReference(ImmutableArray fixers, ImmutableArray analyzers) - : this(fixers, analyzers, ImmutableArray.Empty) + : this(fixers, analyzers, []) { } public MockAnalyzerReference(CodeFixProvider? fixer, ImmutableArray analyzers) - : this(fixer != null ? ImmutableArray.Create(fixer) : ImmutableArray.Empty, + : this(fixer != null ? [fixer] : [], analyzers) { } @@ -508,7 +507,7 @@ public override ImmutableArray GetAnalyzers(string language) => Analyzers; public override ImmutableArray GetAnalyzersForAllLanguages() - => ImmutableArray.Empty; + => []; public override ImmutableArray GetGenerators(string language) => Generators; @@ -694,14 +693,14 @@ await TestNuGetAndVsixCodeFixersCoreAsync( nugetFixer: new NuGetCodeFixProvider(reportedDiagnosticIds), expectedDiagnosticIdsWithRegisteredCodeActionsByNuGetFixer: reportedDiagnosticIds, vsixFixer: null, - expectedDiagnosticIdsWithRegisteredCodeActionsByVsixFixer: ImmutableArray.Empty, + expectedDiagnosticIdsWithRegisteredCodeActionsByVsixFixer: [], diagnosticAnalyzer); // Only Vsix code fix provider which fixes both reported diagnostic IDs. // Verify only Vsix fixer's code action registered and they fix all IDs. await TestNuGetAndVsixCodeFixersCoreAsync( nugetFixer: null, - expectedDiagnosticIdsWithRegisteredCodeActionsByNuGetFixer: ImmutableArray.Empty, + expectedDiagnosticIdsWithRegisteredCodeActionsByNuGetFixer: [], vsixFixer: new VsixCodeFixProvider(reportedDiagnosticIds), expectedDiagnosticIdsWithRegisteredCodeActionsByVsixFixer: reportedDiagnosticIds, diagnosticAnalyzer); @@ -712,26 +711,26 @@ await TestNuGetAndVsixCodeFixersCoreAsync( nugetFixer: new NuGetCodeFixProvider(reportedDiagnosticIds), expectedDiagnosticIdsWithRegisteredCodeActionsByNuGetFixer: reportedDiagnosticIds, vsixFixer: new VsixCodeFixProvider(reportedDiagnosticIds), - expectedDiagnosticIdsWithRegisteredCodeActionsByVsixFixer: ImmutableArray.Empty, + expectedDiagnosticIdsWithRegisteredCodeActionsByVsixFixer: [], diagnosticAnalyzer); // Both NuGet and Vsix code fix provider register different fixable IDs. // Verify both NuGet and Vsix fixer's code actions registered. await TestNuGetAndVsixCodeFixersCoreAsync( - nugetFixer: new NuGetCodeFixProvider(ImmutableArray.Create(id1)), - expectedDiagnosticIdsWithRegisteredCodeActionsByNuGetFixer: ImmutableArray.Create(id1), - vsixFixer: new VsixCodeFixProvider(ImmutableArray.Create(id2)), - expectedDiagnosticIdsWithRegisteredCodeActionsByVsixFixer: ImmutableArray.Create(id2), + nugetFixer: new NuGetCodeFixProvider([id1]), + expectedDiagnosticIdsWithRegisteredCodeActionsByNuGetFixer: [id1], + vsixFixer: new VsixCodeFixProvider([id2]), + expectedDiagnosticIdsWithRegisteredCodeActionsByVsixFixer: [id2], diagnosticAnalyzer); // NuGet code fix provider registers subset of Vsix code fix provider fixable IDs. // Verify both NuGet and Vsix fixer's code actions registered, // there are no duplicates and NuGet ones are preferred for duplicates. await TestNuGetAndVsixCodeFixersCoreAsync( - nugetFixer: new NuGetCodeFixProvider(ImmutableArray.Create(id1)), - expectedDiagnosticIdsWithRegisteredCodeActionsByNuGetFixer: ImmutableArray.Create(id1), + nugetFixer: new NuGetCodeFixProvider([id1]), + expectedDiagnosticIdsWithRegisteredCodeActionsByNuGetFixer: [id1], vsixFixer: new VsixCodeFixProvider(reportedDiagnosticIds), - expectedDiagnosticIdsWithRegisteredCodeActionsByVsixFixer: ImmutableArray.Create(id2), + expectedDiagnosticIdsWithRegisteredCodeActionsByVsixFixer: [id2], diagnosticAnalyzer); } @@ -844,7 +843,7 @@ public CodeFixProviderWithDuplicateEquivalenceKeyActions(string diagnosticId, st _equivalenceKey = equivalenceKey; } - public override ImmutableArray FixableDiagnosticIds => ImmutableArray.Create(_diagnosticId); + public override ImmutableArray FixableDiagnosticIds => [_diagnosticId]; public override Task RegisterCodeFixesAsync(CodeFixContext context) { @@ -875,7 +874,7 @@ public async Task TestAdditionalDocumentCodeFixAsync() var fixer3 = new AdditionalFileFixerWithDocumentExtensions(); var fixer4 = new AdditionalFileFixerWithoutDocumentKindsAndExtensions(); var fixers = ImmutableArray.Create(fixer1, fixer2, fixer3, fixer4); - var analyzerReference = new MockAnalyzerReference(fixers, ImmutableArray.Create(analyzer)); + var analyzerReference = new MockAnalyzerReference(fixers, [analyzer]); // Verify available code fixes for .txt additional document var tuple = ServiceSetup(fixers, additionalDocument: new EditorTestHostDocument("Additional Document", filePath: "test.txt")); @@ -910,7 +909,7 @@ internal sealed class AdditionalFileAnalyzer : DiagnosticAnalyzer public const string DiagnosticId = "AFA0001"; private readonly DiagnosticDescriptor _descriptor = new(DiagnosticId, "AdditionalFileAnalyzer", "AdditionalFileAnalyzer", "AdditionalFileAnalyzer", DiagnosticSeverity.Warning, isEnabledByDefault: true); - public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create(_descriptor); + public override ImmutableArray SupportedDiagnostics => [_descriptor]; public override void Initialize(AnalysisContext context) { @@ -937,7 +936,7 @@ internal abstract class AbstractAdditionalFileCodeFixProvider : CodeFixProvider protected AbstractAdditionalFileCodeFixProvider(string title) => Title = title; - public sealed override ImmutableArray FixableDiagnosticIds => ImmutableArray.Create(AdditionalFileAnalyzer.DiagnosticId); + public sealed override ImmutableArray FixableDiagnosticIds => [AdditionalFileAnalyzer.DiagnosticId]; public sealed override Task RegisterCodeFixesAsync(CodeFixContext context) { @@ -1030,7 +1029,7 @@ void M() var codeFix = new FixerForDeprioritizedAnalyzer(); var analyzer = new DeprioritizedAnalyzer(actionKind); - var analyzerReference = new MockAnalyzerReference(codeFix, ImmutableArray.Create(analyzer)); + var analyzerReference = new MockAnalyzerReference(codeFix, [analyzer]); var tuple = ServiceSetup(codeFix, code: code); using var workspace = tuple.workspace; @@ -1176,7 +1175,7 @@ public DeprioritizedAnalyzer(ActionKind actionKind) _actionKind = actionKind; } - public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create(Descriptor); + public override ImmutableArray SupportedDiagnostics => [Descriptor]; public override void Initialize(AnalysisContext context) { @@ -1217,7 +1216,7 @@ public override void Initialize(AnalysisContext context) private sealed class FixerForDeprioritizedAnalyzer : CodeFixProvider { public static readonly string Title = $"Fix {DeprioritizedAnalyzer.Descriptor.Id}"; - public override ImmutableArray FixableDiagnosticIds => ImmutableArray.Create(DeprioritizedAnalyzer.Descriptor.Id); + public override ImmutableArray FixableDiagnosticIds => [DeprioritizedAnalyzer.Descriptor.Id]; public override Task RegisterCodeFixesAsync(CodeFixContext context) { diff --git a/src/EditorFeatures/Test/CodeFixes/ErrorCases/CodeFixExceptionInGetFixAllProvider.cs b/src/EditorFeatures/Test/CodeFixes/ErrorCases/CodeFixExceptionInGetFixAllProvider.cs index 573e4071378cf..90b80e556524e 100644 --- a/src/EditorFeatures/Test/CodeFixes/ErrorCases/CodeFixExceptionInGetFixAllProvider.cs +++ b/src/EditorFeatures/Test/CodeFixes/ErrorCases/CodeFixExceptionInGetFixAllProvider.cs @@ -16,7 +16,7 @@ public class ExceptionInGetFixAllProvider : CodeFixProvider { public sealed override ImmutableArray FixableDiagnosticIds { - get { return ImmutableArray.Create(CodeFixServiceTests.MockFixer.Id); } + get { return [CodeFixServiceTests.MockFixer.Id]; } } public sealed override FixAllProvider GetFixAllProvider() diff --git a/src/EditorFeatures/Test/CodeFixes/ErrorCases/CodeFixExceptionInRegisterMethod.cs b/src/EditorFeatures/Test/CodeFixes/ErrorCases/CodeFixExceptionInRegisterMethod.cs index 58c412399ab93..4757928870c09 100644 --- a/src/EditorFeatures/Test/CodeFixes/ErrorCases/CodeFixExceptionInRegisterMethod.cs +++ b/src/EditorFeatures/Test/CodeFixes/ErrorCases/CodeFixExceptionInRegisterMethod.cs @@ -15,7 +15,7 @@ public class ExceptionInRegisterMethod : CodeFixProvider { public sealed override ImmutableArray FixableDiagnosticIds { - get { return ImmutableArray.Create(CodeFixServiceTests.MockFixer.Id); } + get { return [CodeFixServiceTests.MockFixer.Id]; } } public sealed override Task RegisterCodeFixesAsync(CodeFixContext context) diff --git a/src/EditorFeatures/Test/CodeFixes/ErrorCases/CodeFixExceptionInRegisterMethodAsync.cs b/src/EditorFeatures/Test/CodeFixes/ErrorCases/CodeFixExceptionInRegisterMethodAsync.cs index 05467ccb038d4..2db9cae8269ca 100644 --- a/src/EditorFeatures/Test/CodeFixes/ErrorCases/CodeFixExceptionInRegisterMethodAsync.cs +++ b/src/EditorFeatures/Test/CodeFixes/ErrorCases/CodeFixExceptionInRegisterMethodAsync.cs @@ -15,7 +15,7 @@ public class ExceptionInRegisterMethodAsync : CodeFixProvider { public sealed override ImmutableArray FixableDiagnosticIds { - get { return ImmutableArray.Create(CodeFixServiceTests.MockFixer.Id); } + get { return [CodeFixServiceTests.MockFixer.Id]; } } public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) diff --git a/src/EditorFeatures/Test/CodeGeneration/CodeGenerationTests.CSharp.cs b/src/EditorFeatures/Test/CodeGeneration/CodeGenerationTests.CSharp.cs index bc6e0d5958a04..b788abaaf22a3 100644 --- a/src/EditorFeatures/Test/CodeGeneration/CodeGenerationTests.CSharp.cs +++ b/src/EditorFeatures/Test/CodeGeneration/CodeGenerationTests.CSharp.cs @@ -150,7 +150,7 @@ public async Task AddChainedConstructor() var input = "class [|C|] { public C(int i) { } }"; var expected = "class C { public C() : this(42) { } public C(int i) { } }"; await TestAddConstructorAsync(input, expected, - thisArguments: ImmutableArray.Create(CS.SyntaxFactory.ParseExpression("42"))); + thisArguments: [CS.SyntaxFactory.ParseExpression("42")]); } [Fact, Trait(Traits.Feature, Traits.Features.CodeGeneration)] @@ -490,8 +490,8 @@ public event System.Action E } }"; await TestAddEventAsync(input, expected, - addMethod: CodeGenerationSymbolFactory.CreateAccessorSymbol(ImmutableArray.Empty, Accessibility.NotApplicable, ImmutableArray.Empty), - removeMethod: CodeGenerationSymbolFactory.CreateAccessorSymbol(ImmutableArray.Empty, Accessibility.NotApplicable, ImmutableArray.Empty), + addMethod: CodeGenerationSymbolFactory.CreateAccessorSymbol([], Accessibility.NotApplicable, []), + removeMethod: CodeGenerationSymbolFactory.CreateAccessorSymbol([], Accessibility.NotApplicable, []), context: new CodeGenerationContext(addImports: false)); } @@ -622,7 +622,7 @@ public int M() }"; await TestAddMethodAsync(input, expected, returnType: typeof(int), - typeParameters: ImmutableArray.Create(CodeGenerationSymbolFactory.CreateTypeParameterSymbol("T")), + typeParameters: [CodeGenerationSymbolFactory.CreateTypeParameterSymbol("T")], statements: "return new T().GetHashCode();"); } @@ -678,7 +678,7 @@ await TestAddMethodAsync(input, expected, returnType: typeof(void), parameters: Parameters(Parameter(typeof(int), "i")), modifiers: new Editing.DeclarationModifiers(isUnsafe: true), - getExplicitInterfaces: s => s.LookupSymbols(input.IndexOf('M'), null, "M").OfType().ToImmutableArray()); + getExplicitInterfaces: s => [.. s.LookupSymbols(input.IndexOf('M'), null, "M").OfType()]); } [Fact, Trait(Traits.Feature, Traits.Features.CodeGeneration)] @@ -696,7 +696,7 @@ await TestAddMethodAsync(input, expected, name: "M", returnType: typeof(void), parameters: Parameters(Parameter(typeof(int), "i")), - getExplicitInterfaces: s => s.LookupSymbols(input.IndexOf('M'), null, "M").OfType().ToImmutableArray()); + getExplicitInterfaces: s => [.. s.LookupSymbols(input.IndexOf('M'), null, "M").OfType()]); } [Fact, Trait(Traits.Feature, Traits.Features.CodeGeneration)] diff --git a/src/EditorFeatures/Test/CodeGeneration/CodeGenerationTests.VisualBasic.cs b/src/EditorFeatures/Test/CodeGeneration/CodeGenerationTests.VisualBasic.cs index ca612fcdae7fc..6fc613ad97973 100644 --- a/src/EditorFeatures/Test/CodeGeneration/CodeGenerationTests.VisualBasic.cs +++ b/src/EditorFeatures/Test/CodeGeneration/CodeGenerationTests.VisualBasic.cs @@ -159,7 +159,7 @@ Public Sub New(i As Integer) End Sub End Class"; await TestAddConstructorAsync(input, expected, - thisArguments: ImmutableArray.Create(VB.SyntaxFactory.ParseExpression("42"))); + thisArguments: [VB.SyntaxFactory.ParseExpression("42")]); } [Fact, Trait(Traits.Feature, Traits.Features.CodeGeneration), WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/544476")] @@ -408,20 +408,19 @@ End Event End Class"; static ImmutableArray GetExplicitInterfaceEvent(SemanticModel semanticModel) { - return ImmutableArray.Create( - new CodeGenerationEventSymbol( + return [new CodeGenerationEventSymbol( GetTypeSymbol(typeof(System.ComponentModel.INotifyPropertyChanged))(semanticModel), attributes: default, Accessibility.Public, modifiers: default, GetTypeSymbol(typeof(System.ComponentModel.PropertyChangedEventHandler))(semanticModel), explicitInterfaceImplementations: default, - nameof(System.ComponentModel.INotifyPropertyChanged.PropertyChanged), null, null, null)); + nameof(System.ComponentModel.INotifyPropertyChanged.PropertyChanged), null, null, null)]; } await TestAddEventAsync(input, expected, addMethod: CodeGenerationSymbolFactory.CreateAccessorSymbol( - ImmutableArray.Empty, Accessibility.NotApplicable, ImmutableArray.Empty), + [], Accessibility.NotApplicable, []), getExplicitInterfaceImplementations: GetExplicitInterfaceEvent, type: typeof(System.ComponentModel.PropertyChangedEventHandler), context: new CodeGenerationContext(addImports: false)); @@ -445,7 +444,7 @@ End RaiseEvent End Event End Class"; await TestAddEventAsync(input, expected, - addMethod: CodeGenerationSymbolFactory.CreateAccessorSymbol(ImmutableArray.Empty, Accessibility.NotApplicable, ImmutableArray.Empty), + addMethod: CodeGenerationSymbolFactory.CreateAccessorSymbol([], Accessibility.NotApplicable, []), context: new CodeGenerationContext(addImports: false)); } @@ -474,11 +473,11 @@ End Event var raiseStatements = ImmutableArray.Create(VB.SyntaxFactory.ParseExecutableStatement("Console.WriteLine(2)")); await TestAddEventAsync(input, expected, addMethod: CodeGenerationSymbolFactory.CreateAccessorSymbol( - ImmutableArray.Empty, Accessibility.NotApplicable, addStatements), + [], Accessibility.NotApplicable, addStatements), removeMethod: CodeGenerationSymbolFactory.CreateAccessorSymbol( - ImmutableArray.Empty, Accessibility.NotApplicable, removeStatements), + [], Accessibility.NotApplicable, removeStatements), raiseMethod: CodeGenerationSymbolFactory.CreateAccessorSymbol( - ImmutableArray.Empty, Accessibility.NotApplicable, raiseStatements), + [], Accessibility.NotApplicable, raiseStatements), context: new CodeGenerationContext(addImports: false)); } @@ -590,7 +589,7 @@ End Function End Class"; await TestAddMethodAsync(input, expected, returnType: typeof(int), - typeParameters: ImmutableArray.Create(CodeGenerationSymbolFactory.CreateTypeParameterSymbol("T")), + typeParameters: [CodeGenerationSymbolFactory.CreateTypeParameterSymbol("T")], statements: "Return new T().GetHashCode()"); } @@ -644,7 +643,7 @@ await TestAddMethodAsync(input, expected, name: "M", returnType: typeof(void), parameters: Parameters(Parameter(typeof(int), "i")), - getExplicitInterfaces: s => s.LookupSymbols(input.IndexOf('M'), null, "M").OfType().ToImmutableArray()); + getExplicitInterfaces: s => [.. s.LookupSymbols(input.IndexOf('M'), null, "M").OfType()]); } [Fact, Trait(Traits.Feature, Traits.Features.CodeGeneration)] diff --git a/src/EditorFeatures/Test/CodeGeneration/CodeGenerationTests.cs b/src/EditorFeatures/Test/CodeGeneration/CodeGenerationTests.cs index ccfc183b2f1bc..9ef1f3e876c23 100644 --- a/src/EditorFeatures/Test/CodeGeneration/CodeGenerationTests.cs +++ b/src/EditorFeatures/Test/CodeGeneration/CodeGenerationTests.cs @@ -676,10 +676,10 @@ private static ITypeSymbol GetTypeSymbol(Compilation compilation, string typeFul } internal static ImmutableArray> Parameters(params Func[] p) - => p.ToImmutableArray(); + => [.. p]; internal static ImmutableArray> Members(params Func[] m) - => m.ToImmutableArray(); + => [.. m]; internal static Func CreateArrayType(Type type, int rank = 1) => s => CodeGenerationSymbolFactory.CreateArrayTypeSymbol(GetTypeSymbol(type)(s), rank); @@ -928,7 +928,7 @@ public ImmutableArray ParseStatements(string statements) } var delimiter = IsVisualBasic ? "\r\n" : ";"; - var parts = statements.Split(new[] { delimiter }, StringSplitOptions.RemoveEmptyEntries); + var parts = statements.Split([delimiter], StringSplitOptions.RemoveEmptyEntries); var list = new FixedSizeArrayBuilder(parts.Length); foreach (var p in parts) { diff --git a/src/EditorFeatures/Test/CodeRefactorings/CodeRefactoringServiceTest.cs b/src/EditorFeatures/Test/CodeRefactorings/CodeRefactoringServiceTest.cs index fc2789aba947c..7296d36472e53 100644 --- a/src/EditorFeatures/Test/CodeRefactorings/CodeRefactoringServiceTest.cs +++ b/src/EditorFeatures/Test/CodeRefactorings/CodeRefactoringServiceTest.cs @@ -133,7 +133,7 @@ private class StubAnalyzerReference : AnalyzerReference, ICodeRefactoringProvide public StubAnalyzerReference() : this(new StubRefactoring()) { } public StubAnalyzerReference(params CodeRefactoringProvider[] codeRefactorings) - => _refactorings = codeRefactorings.ToImmutableArray(); + => _refactorings = [.. codeRefactorings]; public override string Display => nameof(StubAnalyzerReference); @@ -142,10 +142,10 @@ public StubAnalyzerReference(params CodeRefactoringProvider[] codeRefactorings) public override object Id => nameof(StubAnalyzerReference); public override ImmutableArray GetAnalyzers(string language) - => ImmutableArray.Empty; + => []; public override ImmutableArray GetAnalyzersForAllLanguages() - => ImmutableArray.Empty; + => []; public ImmutableArray GetRefactorings() => _refactorings; diff --git a/src/EditorFeatures/Test/CommentSelection/CommentUncommentSelectionCommandHandlerTests.cs b/src/EditorFeatures/Test/CommentSelection/CommentUncommentSelectionCommandHandlerTests.cs index f25cb47b2d2a3..9a69cf6cd8b59 100644 --- a/src/EditorFeatures/Test/CommentSelection/CommentUncommentSelectionCommandHandlerTests.cs +++ b/src/EditorFeatures/Test/CommentSelection/CommentUncommentSelectionCommandHandlerTests.cs @@ -77,7 +77,7 @@ public void Create() public void Comment_EmptyLine() { var code = @"|start||end|"; - CommentSelection(code, Enumerable.Empty(), supportBlockComments: true); + CommentSelection(code, [], supportBlockComments: true); } [WpfFact] @@ -91,7 +91,7 @@ public void Comment_NoSelectionAtEndOfLine() public void Comment_Whitespace() { var code = @" |start| |end| "; - CommentSelection(code, Enumerable.Empty(), supportBlockComments: true); + CommentSelection(code, [], supportBlockComments: true); } [WpfFact] @@ -483,14 +483,14 @@ public void Uncomment_AtBeginningOfEndOfBlockComment() public void Uncomment_AtEndOfBlockComment() { var code = @"/*using System;*/|start||end|"; - UncommentSelection(code, Enumerable.Empty(), new Span(17, 0), supportBlockComments: true); + UncommentSelection(code, [], new Span(17, 0), supportBlockComments: true); } [WpfFact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/932411")] public void Uncomment_BlockCommentWithNoEnd() { var code = @"/*using |start||end|System;"; - UncommentSelection(code, Enumerable.Empty(), new Span(8, 0), supportBlockComments: true); + UncommentSelection(code, [], new Span(8, 0), supportBlockComments: true); } [WpfFact, WorkItem("https://github.com/dotnet/roslyn/issues/31669")] diff --git a/src/EditorFeatures/Test/Completion/CompletionServiceTests.cs b/src/EditorFeatures/Test/Completion/CompletionServiceTests.cs index a9f19a43d277a..b87c0c9542b2d 100644 --- a/src/EditorFeatures/Test/Completion/CompletionServiceTests.cs +++ b/src/EditorFeatures/Test/Completion/CompletionServiceTests.cs @@ -58,7 +58,7 @@ void Method() { Assert.NotEmpty(completions.ItemsList); - var item = Assert.Single(completions.ItemsList.Where(item => item.ProviderName == typeof(DebugAssertTestCompletionProvider).FullName)); + var item = Assert.Single(completions.ItemsList, item => item.ProviderName == typeof(DebugAssertTestCompletionProvider).FullName); Assert.Equal(nameof(DebugAssertTestCompletionProvider), item.DisplayText); var expectedDescriptionText = nameof(DebugAssertTestCompletionProvider); @@ -83,13 +83,13 @@ public MockAnalyzerReference(CompletionProvider completionProvider) public override object Id => nameof(MockAnalyzerReference); public override ImmutableArray GetAnalyzers(string language) - => ImmutableArray.Empty; + => []; public override ImmutableArray GetAnalyzersForAllLanguages() - => ImmutableArray.Empty; + => []; public ImmutableArray GetCompletionProviders() - => ImmutableArray.Create(_completionProvider); + => [_completionProvider]; } private sealed class DebugAssertTestCompletionProvider : CompletionProvider diff --git a/src/EditorFeatures/Test/Completion/FileSystemCompletionHelperTests.cs b/src/EditorFeatures/Test/Completion/FileSystemCompletionHelperTests.cs index 070047f3843d9..cccd067eaed16 100644 --- a/src/EditorFeatures/Test/Completion/FileSystemCompletionHelperTests.cs +++ b/src/EditorFeatures/Test/Completion/FileSystemCompletionHelperTests.cs @@ -28,9 +28,9 @@ private static void AssertItemsEqual(ImmutableArray actual, para public void GetItems_Windows1() { var fsc = new TestFileSystemCompletionHelper( - searchPaths: ImmutableArray.Create(@"X:\A", @"X:\B"), + searchPaths: [@"X:\A", @"X:\B"], baseDirectoryOpt: @"Z:\C", - allowableExtensions: ImmutableArray.Create(".abc", ".def"), + allowableExtensions: [".abc", ".def"], drives: new[] { @"X:\", @"Z:\" }, directories: new[] { @@ -90,9 +90,9 @@ public void GetItems_Windows1() public void GetItems_Windows_NoBaseDirectory() { var fsc = new TestFileSystemCompletionHelper( - searchPaths: ImmutableArray.Create(@"X:\A", @"X:\B"), + searchPaths: [@"X:\A", @"X:\B"], baseDirectoryOpt: null, - allowableExtensions: ImmutableArray.Create(".abc", ".def"), + allowableExtensions: [".abc", ".def"], drives: new[] { @"X:\" }, directories: new[] { @@ -126,9 +126,9 @@ public void GetItems_Windows_NoBaseDirectory() public void GetItems_Windows_NoSearchPaths() { var fsc = new TestFileSystemCompletionHelper( - searchPaths: ImmutableArray.Empty, + searchPaths: [], baseDirectoryOpt: null, - allowableExtensions: ImmutableArray.Create(".abc", ".def"), + allowableExtensions: [".abc", ".def"], drives: new[] { @"X:\" }, directories: new[] { @@ -158,9 +158,9 @@ public void GetItems_Windows_NoSearchPaths() public void GetItems_Windows_Network() { var fsc = new TestFileSystemCompletionHelper( - searchPaths: ImmutableArray.Empty, + searchPaths: [], baseDirectoryOpt: null, - allowableExtensions: ImmutableArray.Create(".cs"), + allowableExtensions: [".cs"], drives: Array.Empty(), directories: new[] { @@ -188,9 +188,9 @@ public void GetItems_Windows_Network() public void GetItems_Unix1() { var fsc = new TestFileSystemCompletionHelper( - searchPaths: ImmutableArray.Create(@"/A", @"/B"), + searchPaths: [@"/A", @"/B"], baseDirectoryOpt: @"/C", - allowableExtensions: ImmutableArray.Create(".abc", ".def"), + allowableExtensions: [".abc", ".def"], drives: Array.Empty(), directories: new[] { diff --git a/src/EditorFeatures/Test/Completion/TestFileSystemCompletionHelper.cs b/src/EditorFeatures/Test/Completion/TestFileSystemCompletionHelper.cs index 4e5eeec0956d9..8dbf052720d4b 100644 --- a/src/EditorFeatures/Test/Completion/TestFileSystemCompletionHelper.cs +++ b/src/EditorFeatures/Test/Completion/TestFileSystemCompletionHelper.cs @@ -33,13 +33,13 @@ public TestFileSystemCompletionHelper( Assert.True(drives.All(d => d.EndsWith(PathUtilities.DirectorySeparatorStr))); Assert.True(directories.All(d => !d.EndsWith(PathUtilities.DirectorySeparatorStr))); - _drives = ImmutableArray.CreateRange(drives); - _directories = ImmutableArray.CreateRange(directories); - _files = ImmutableArray.CreateRange(files); + _drives = [.. drives]; + _directories = [.. directories]; + _files = [.. files]; } protected override string[] GetLogicalDrives() - => _drives.ToArray(); + => [.. _drives]; protected override bool IsVisibleFileSystemEntry(string fullPath) => !fullPath.Contains("hidden"); diff --git a/src/EditorFeatures/Test/Diagnostics/DiagnosticAnalyzerServiceTests.cs b/src/EditorFeatures/Test/Diagnostics/DiagnosticAnalyzerServiceTests.cs index 6f787d5d6f1a0..204f0c4473ba7 100644 --- a/src/EditorFeatures/Test/Diagnostics/DiagnosticAnalyzerServiceTests.cs +++ b/src/EditorFeatures/Test/Diagnostics/DiagnosticAnalyzerServiceTests.cs @@ -57,7 +57,7 @@ public async Task TestHasSuccessfullyLoadedBeingFalse() { using var workspace = CreateWorkspace(); - var analyzerReference = new AnalyzerImageReference(ImmutableArray.Create(new Analyzer())); + var analyzerReference = new AnalyzerImageReference([new Analyzer()]); workspace.TryApplyChanges(workspace.CurrentSolution.WithAnalyzerReferences([analyzerReference])); var document = GetDocumentFromIncompleteProject(workspace); @@ -78,7 +78,7 @@ public async Task TestHasSuccessfullyLoadedBeingFalseFSAOn() { using var workspace = CreateWorkspace(); - var analyzerReference = new AnalyzerImageReference(ImmutableArray.Create(new Analyzer())); + var analyzerReference = new AnalyzerImageReference([new Analyzer()]); var globalOptions = GetGlobalOptions(workspace); globalOptions.SetGlobalOption(SolutionCrawlerOptionsStorage.BackgroundAnalysisScopeOption, LanguageNames.CSharp, BackgroundAnalysisScope.FullSolution); @@ -96,7 +96,7 @@ public async Task TestHasSuccessfullyLoadedBeingFalseWhenFileOpened() { using var workspace = CreateWorkspace(); - var analyzerReference = new AnalyzerImageReference(ImmutableArray.Create(new Analyzer())); + var analyzerReference = new AnalyzerImageReference([new Analyzer()]); workspace.TryApplyChanges(workspace.CurrentSolution.WithAnalyzerReferences([analyzerReference])); var document = GetDocumentFromIncompleteProject(workspace); @@ -111,7 +111,7 @@ public async Task TestHasSuccessfullyLoadedBeingFalseWhenFileOpenedWithCompilerA { using var workspace = CreateWorkspace(); - var analyzerReference = new AnalyzerImageReference(ImmutableArray.Create(new CSharpCompilerDiagnosticAnalyzer())); + var analyzerReference = new AnalyzerImageReference([new CSharpCompilerDiagnosticAnalyzer()]); workspace.TryApplyChanges(workspace.CurrentSolution.WithAnalyzerReferences([analyzerReference])); var document = GetDocumentFromIncompleteProject(workspace); @@ -127,7 +127,7 @@ public async Task TestHasSuccessfullyLoadedBeingFalseWithCompilerAnalyzerFSAOn() { using var workspace = CreateWorkspace(); - var analyzerReference = new AnalyzerImageReference(ImmutableArray.Create(new CSharpCompilerDiagnosticAnalyzer())); + var analyzerReference = new AnalyzerImageReference([new CSharpCompilerDiagnosticAnalyzer()]); var globalOptions = GetGlobalOptions(workspace); globalOptions.SetGlobalOption(SolutionCrawlerOptionsStorage.BackgroundAnalysisScopeOption, LanguageNames.CSharp, BackgroundAnalysisScope.FullSolution); @@ -146,7 +146,7 @@ public async Task TestDisabledByDefaultAnalyzerEnabledWithEditorConfig(bool enab { using var workspace = CreateWorkspace(); - var analyzerReference = new AnalyzerImageReference(ImmutableArray.Create(new DisabledByDefaultAnalyzer())); + var analyzerReference = new AnalyzerImageReference([new DisabledByDefaultAnalyzer()]); var globalOptions = GetGlobalOptions(workspace); globalOptions.SetGlobalOption(SolutionCrawlerOptionsStorage.BackgroundAnalysisScopeOption, LanguageNames.CSharp, BackgroundAnalysisScope.FullSolution); @@ -242,7 +242,8 @@ public async Task TestHostAnalyzerOrderingAsync() using var workspace = CreateWorkspace(); var exportProvider = workspace.Services.SolutionServices.ExportProvider; - var analyzerReference = new AnalyzerImageReference(ImmutableArray.Create( + var analyzerReference = new AnalyzerImageReference( + [ new Priority20Analyzer(), new Priority15Analyzer(), new Priority10Analyzer(), @@ -250,7 +251,8 @@ public async Task TestHostAnalyzerOrderingAsync() new Priority0Analyzer(), new CSharpCompilerDiagnosticAnalyzer(), new Analyzer() - )); +, + ]); workspace.TryApplyChanges(workspace.CurrentSolution.WithAnalyzerReferences([analyzerReference])); @@ -289,8 +291,7 @@ public async Task TestHostAnalyzerErrorNotLeaking() var solution = workspace.CurrentSolution; - var analyzerReference = new AnalyzerImageReference(ImmutableArray.Create( - new LeakDocumentAnalyzer(), new LeakProjectAnalyzer())); + var analyzerReference = new AnalyzerImageReference([new LeakDocumentAnalyzer(), new LeakProjectAnalyzer()]); var globalOptions = GetGlobalOptions(workspace); globalOptions.SetGlobalOption(SolutionCrawlerOptionsStorage.BackgroundAnalysisScopeOption, LanguageNames.CSharp, BackgroundAnalysisScope.FullSolution); @@ -375,7 +376,7 @@ private static AdhocWorkspace CreateWorkspaceWithProjectAndAnalyzer(DiagnosticAn var solution = workspace.CurrentSolution; solution = solution - .AddAnalyzerReference(new AnalyzerImageReference(ImmutableArray.Create(analyzer))) + .AddAnalyzerReference(new AnalyzerImageReference([analyzer])) .AddProject( ProjectInfo.Create( projectId, @@ -662,10 +663,9 @@ void M() var diagnostics = await incrementalAnalyzer.ForceAnalyzeProjectAsync(project, CancellationToken.None); - diagnostics = diagnostics + diagnostics = [.. diagnostics .Where(d => d.Id == IDEDiagnosticIds.RemoveUnnecessarySuppressionDiagnosticId) - .OrderBy(d => d.DataLocation.UnmappedFileSpan.GetClampedTextSpan(text)) - .ToImmutableArray(); + .OrderBy(d => d.DataLocation.UnmappedFileSpan.GetClampedTextSpan(text))]; var root = await document.GetSyntaxRootAsync(); text = await document.GetTextAsync(); @@ -698,7 +698,7 @@ internal async Task TestOnlyRequiredAnalyzerExecutedDuringDiagnosticComputation( var analyzer1Id = analyzer1.GetAnalyzerId(); var analyzer2 = new NamedTypeAnalyzer(); var analyzerIdsToRequestDiagnostics = ImmutableArray.Create(analyzer1Id); - var analyzerReference = new AnalyzerImageReference(ImmutableArray.Create(analyzer1, analyzer2)); + var analyzerReference = new AnalyzerImageReference([analyzer1, analyzer2]); workspace.TryApplyChanges(workspace.CurrentSolution.WithAnalyzerReferences([analyzerReference])); var project = workspace.CurrentSolution.Projects.Single(); var document = documentAnalysis ? project.Documents.Single() : null; @@ -743,7 +743,7 @@ void M() var analyzer = new FilterSpanTestAnalyzer(kind); var analyzerId = analyzer.GetAnalyzerId(); var analyzerIdsToRequestDiagnostics = ImmutableArray.Create(analyzerId); - var analyzerReference = new AnalyzerImageReference(ImmutableArray.Create(analyzer)); + var analyzerReference = new AnalyzerImageReference([analyzer]); project = project.AddAnalyzerReference(analyzerReference); workspace.TryApplyChanges(project.Solution); @@ -812,7 +812,7 @@ void M() using var workspace = TestWorkspace.CreateCSharp(source); var analyzer = new CancellationTestAnalyzer(actionKind); - var analyzerReference = new AnalyzerImageReference(ImmutableArray.Create(analyzer)); + var analyzerReference = new AnalyzerImageReference([analyzer]); workspace.TryApplyChanges(workspace.CurrentSolution.WithAnalyzerReferences([analyzerReference])); var project = workspace.CurrentSolution.Projects.Single(); @@ -916,7 +916,7 @@ private class Analyzer : DiagnosticAnalyzer internal static readonly DiagnosticDescriptor s_semanticRule = new DiagnosticDescriptor("semantic", "test", "test", "test", DiagnosticSeverity.Error, isEnabledByDefault: true); internal static readonly DiagnosticDescriptor s_compilationRule = new DiagnosticDescriptor("compilation", "test", "test", "test", DiagnosticSeverity.Error, isEnabledByDefault: true); - public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create(s_syntaxRule, s_semanticRule, s_compilationRule); + public override ImmutableArray SupportedDiagnostics => [s_syntaxRule, s_semanticRule, s_compilationRule]; public override void Initialize(AnalysisContext context) { @@ -932,7 +932,7 @@ private class DisabledByDefaultAnalyzer : DiagnosticAnalyzer internal static readonly DiagnosticDescriptor s_semanticRule = new DiagnosticDescriptor("semantic", "test", "test", "test", DiagnosticSeverity.Error, isEnabledByDefault: false); internal static readonly DiagnosticDescriptor s_compilationRule = new DiagnosticDescriptor("compilation", "test", "test", "test", DiagnosticSeverity.Error, isEnabledByDefault: false); - public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create(s_syntaxRule, s_semanticRule, s_compilationRule); + public override ImmutableArray SupportedDiagnostics => [s_syntaxRule, s_semanticRule, s_compilationRule]; public override void Initialize(AnalysisContext context) { @@ -946,7 +946,7 @@ private class NoNameAnalyzer : DocumentDiagnosticAnalyzer { internal static readonly DiagnosticDescriptor s_syntaxRule = new DiagnosticDescriptor("syntax", "test", "test", "test", DiagnosticSeverity.Error, isEnabledByDefault: true); - public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create(s_syntaxRule); + public override ImmutableArray SupportedDiagnostics => [s_syntaxRule]; public override Task> AnalyzeSyntaxAsync(Document document, CancellationToken cancellationToken) => Task.FromResult(ImmutableArray.Create(Diagnostic.Create(s_syntaxRule, Location.Create(document.FilePath, TextSpan.FromBounds(0, 0), new LinePositionSpan(new LinePosition(0, 0), new LinePosition(0, 0)))))); @@ -986,7 +986,7 @@ protected PriorityTestDocumentDiagnosticAnalyzer(int priority) => Priority = priority; public override int Priority { get; } - public override ImmutableArray SupportedDiagnostics => ImmutableArray.Empty; + public override ImmutableArray SupportedDiagnostics => []; public override Task> AnalyzeSemanticsAsync(Document document, CancellationToken cancellationToken) => Task.FromResult(ImmutableArray.Empty); public override Task> AnalyzeSyntaxAsync(Document document, CancellationToken cancellationToken) @@ -999,7 +999,7 @@ protected PriorityTestProjectDiagnosticAnalyzer(int priority) => Priority = priority; public override int Priority { get; } - public override ImmutableArray SupportedDiagnostics => ImmutableArray.Empty; + public override ImmutableArray SupportedDiagnostics => []; public override Task> AnalyzeProjectAsync(Project project, CancellationToken cancellationToken) => Task.FromResult(ImmutableArray.Empty); } @@ -1008,12 +1008,12 @@ private class LeakDocumentAnalyzer : DocumentDiagnosticAnalyzer { internal static readonly DiagnosticDescriptor s_syntaxRule = new DiagnosticDescriptor("leak", "test", "test", "test", DiagnosticSeverity.Error, isEnabledByDefault: true); - public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create(s_syntaxRule); + public override ImmutableArray SupportedDiagnostics => [s_syntaxRule]; public override async Task> AnalyzeSyntaxAsync(Document document, CancellationToken cancellationToken) { var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); - return ImmutableArray.Create(Diagnostic.Create(s_syntaxRule, root.GetLocation())); + return [Diagnostic.Create(s_syntaxRule, root.GetLocation())]; } public override Task> AnalyzeSemanticsAsync(Document document, CancellationToken cancellationToken) @@ -1023,7 +1023,7 @@ public override Task> AnalyzeSemanticsAsync(Document private class LeakProjectAnalyzer : ProjectDiagnosticAnalyzer { private static readonly DiagnosticDescriptor s_rule = new DiagnosticDescriptor("project", "test", "test", "test", DiagnosticSeverity.Error, isEnabledByDefault: true); - public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create(s_rule); + public override ImmutableArray SupportedDiagnostics => [s_rule]; public override Task> AnalyzeProjectAsync(Project project, CancellationToken cancellationToken) => SpecializedTasks.Default>(); } @@ -1034,7 +1034,7 @@ private class NamedTypeAnalyzer : DiagnosticAnalyzer private readonly ImmutableArray _supportedDiagnostics; public NamedTypeAnalyzer(DiagnosticSeverity defaultSeverity = DiagnosticSeverity.Warning) - => _supportedDiagnostics = ImmutableArray.Create(new DiagnosticDescriptor(DiagnosticId, "test", "test", "test", defaultSeverity, isEnabledByDefault: true)); + => _supportedDiagnostics = [new DiagnosticDescriptor(DiagnosticId, "test", "test", "test", defaultSeverity, isEnabledByDefault: true)]; public override ImmutableArray SupportedDiagnostics => _supportedDiagnostics; public bool ReceivedSymbolCallback { get; private set; } diff --git a/src/EditorFeatures/Test/Diagnostics/DiagnosticDataTests.cs b/src/EditorFeatures/Test/Diagnostics/DiagnosticDataTests.cs index b788b17fd447b..3a9b971543e5c 100644 --- a/src/EditorFeatures/Test/Diagnostics/DiagnosticDataTests.cs +++ b/src/EditorFeatures/Test/Diagnostics/DiagnosticDataTests.cs @@ -120,7 +120,7 @@ private static async Task VerifyTextSpanAsync(string code, int startLine, int st isEnabledByDefault: false, warningLevel: 1, projectId: document.Project.Id, - customTags: ImmutableArray.Empty, + customTags: [], properties: ImmutableDictionary.Empty, location: new DiagnosticDataLocation(new("originalFile1", new(startLine, startColumn), new(endLine, endColumn)), document.Id), language: document.Project.Language); @@ -153,10 +153,10 @@ public async Task DiagnosticData_ExternalAdditionalLocationIsPreserved() isEnabledByDefault: true, warningLevel: 1, projectId: document.Project.Id, - customTags: ImmutableArray.Empty, + customTags: [], properties: ImmutableDictionary.Empty, location: new DiagnosticDataLocation(new FileLinePositionSpan(document.FilePath, span: default), document.Id), - additionalLocations: ImmutableArray.Create(externalAdditionalLocation), + additionalLocations: [externalAdditionalLocation], language: document.Project.Language); var diagnostic = await diagnosticData.ToDiagnosticAsync(document.Project, CancellationToken.None); @@ -167,6 +167,43 @@ public async Task DiagnosticData_ExternalAdditionalLocationIsPreserved() Assert.Equal(externalAdditionalLocation.UnmappedFileSpan, roundTripAdditionalLocation.UnmappedFileSpan); } + [Fact] + public async Task DiagnosticData_NoneAdditionalLocationIsPreserved() + { + using var workspace = new TestWorkspace(composition: EditorTestCompositions.EditorFeatures); + + var additionalDocument = workspace.CurrentSolution.AddProject("TestProject", "TestProject", LanguageNames.CSharp) + .AddDocument("test.cs", "", filePath: "test.cs"); + + var document = additionalDocument.Project.Documents.Single(); + + var noneAdditionalLocation = new DiagnosticDataLocation(new FileLinePositionSpan("", default)); + + var diagnosticData = new DiagnosticData( + id: "test1", + category: "Test", + message: "test1 message", + severity: DiagnosticSeverity.Info, + defaultSeverity: DiagnosticSeverity.Info, + isEnabledByDefault: true, + warningLevel: 1, + projectId: document.Project.Id, + customTags: [], + properties: ImmutableDictionary.Empty, + location: new DiagnosticDataLocation(new FileLinePositionSpan(document.FilePath, span: default), document.Id), + additionalLocations: [noneAdditionalLocation], + language: document.Project.Language); + + var diagnostic = await diagnosticData.ToDiagnosticAsync(document.Project, CancellationToken.None); + var roundTripDiagnosticData = DiagnosticData.Create(diagnostic, document); + + var roundTripAdditionalLocation = Assert.Single(roundTripDiagnosticData.AdditionalLocations); + Assert.Null(noneAdditionalLocation.DocumentId); + Assert.Null(roundTripAdditionalLocation.DocumentId); + Assert.Equal(noneAdditionalLocation.UnmappedFileSpan, roundTripAdditionalLocation.UnmappedFileSpan); + Assert.Same(diagnostic.AdditionalLocations.Single(), Location.None); + } + [Fact] public async Task DiagnosticData_SourceGeneratedDocumentLocationIsPreserved() { @@ -199,10 +236,10 @@ class A isEnabledByDefault: true, warningLevel: 1, projectId: documentId.ProjectId, - customTags: ImmutableArray.Empty, + customTags: [], properties: ImmutableDictionary.Empty, location: location, - additionalLocations: ImmutableArray.Empty, + additionalLocations: [], language: project.Language); var diagnostic = await diagnosticData.ToDiagnosticAsync(project, CancellationToken.None); @@ -247,10 +284,10 @@ public async Task DiagnosticData_SourceFileAdditionalLocationIsPreserved(bool te isEnabledByDefault: true, warningLevel: 1, projectId: firstDocument.Project.Id, - customTags: ImmutableArray.Empty, + customTags: [], properties: ImmutableDictionary.Empty, location: new DiagnosticDataLocation(new FileLinePositionSpan(firstDocument.FilePath, span: default), firstDocument.Id), - additionalLocations: ImmutableArray.Create(additionalLocation), + additionalLocations: [additionalLocation], language: firstDocument.Project.Language); var diagnostic = await diagnosticData.ToDiagnosticAsync(firstDocument.Project, CancellationToken.None); diff --git a/src/EditorFeatures/Test/Diagnostics/IDEDiagnosticIDConfigurationTests.cs b/src/EditorFeatures/Test/Diagnostics/IDEDiagnosticIDConfigurationTests.cs index c676221e32194..8ddaef7086ff7 100644 --- a/src/EditorFeatures/Test/Diagnostics/IDEDiagnosticIDConfigurationTests.cs +++ b/src/EditorFeatures/Test/Diagnostics/IDEDiagnosticIDConfigurationTests.cs @@ -47,7 +47,7 @@ public class IDEDiagnosticIDConfigurationTests if (!IDEDiagnosticIdToOptionMappingHelper.TryGetMappedOptions(diagnosticId, languageName, out var options)) { - options = ImmutableHashSet.Empty; + options = []; } if (uniqueDiagnosticIds.Add(diagnosticId)) @@ -63,7 +63,7 @@ public class IDEDiagnosticIDConfigurationTests } diagnosticIdAndOptions.Sort(); - return diagnosticIdAndOptions.ToImmutableArray(); + return [.. diagnosticIdAndOptions]; } private static void ValidateHelpLinkForDiagnostic(string diagnosticId, string helpLinkUri) @@ -94,7 +94,7 @@ private static void ValidateHelpLinkForDiagnostic(string diagnosticId, string he private static Dictionary GetExpectedMap(string expected, out string[] expectedLines) { - expectedLines = expected.Split(new[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries); + expectedLines = expected.Split([Environment.NewLine], StringSplitOptions.RemoveEmptyEntries); Assert.True(expectedLines.Length % 2 == 0); var expectedMap = new Dictionary(); for (var i = 0; i < expectedLines.Length; i += 2) @@ -403,6 +403,9 @@ public void CSharp_VerifyIDEDiagnosticSeveritiesAreConfigurable() # IDE0120 dotnet_diagnostic.IDE0120.severity = %value% + + # IDE0121 + dotnet_diagnostic.IDE0121.severity = %value% # IDE0130 dotnet_diagnostic.IDE0130.severity = %value% @@ -879,6 +882,7 @@ public void CSharp_VerifyIDECodeStyleOptionsAreConfigurable() ("IDE0100", null, null), ("IDE0110", null, null), ("IDE0120", null, null), + ("IDE0121", null, null), ("IDE0130", "dotnet_style_namespace_match_folder", "true"), ("IDE0150", "csharp_style_prefer_null_check_over_type_check", "true"), ("IDE0160", "csharp_style_namespace_declarations", "block_scoped"), diff --git a/src/EditorFeatures/Test/Diagnostics/SuppressMessageAttributeWorkspaceTests.cs b/src/EditorFeatures/Test/Diagnostics/SuppressMessageAttributeWorkspaceTests.cs index bab2a0ad00529..55e0553125946 100644 --- a/src/EditorFeatures/Test/Diagnostics/SuppressMessageAttributeWorkspaceTests.cs +++ b/src/EditorFeatures/Test/Diagnostics/SuppressMessageAttributeWorkspaceTests.cs @@ -57,7 +57,7 @@ protected override async Task VerifyAsync(string source, string language, Diagno workspace.TryApplyChanges(workspace.CurrentSolution.WithAnalyzerReferences( [ - new AnalyzerImageReference(analyzers.ToImmutableArray()) + new AnalyzerImageReference([.. analyzers]) ]).WithProjectMetadataReferences( workspace.Projects.Single().Id, workspace.Projects.Single().MetadataReferences.Append(_unconditionalSuppressMessageRef.Value))); diff --git a/src/EditorFeatures/Test/EditorConfigSettings/Data/CodeStyleSettingsTest.cs b/src/EditorFeatures/Test/EditorConfigSettings/Data/CodeStyleSettingsTest.cs index ff33ba84388e2..0adf1b4e349d3 100644 --- a/src/EditorFeatures/Test/EditorConfigSettings/Data/CodeStyleSettingsTest.cs +++ b/src/EditorFeatures/Test/EditorConfigSettings/Data/CodeStyleSettingsTest.cs @@ -16,7 +16,7 @@ namespace Microsoft.CodeAnalysis.Editor.UnitTests.EditorConfigSettings.Data; [UseExportProvider] -public class CodeStyleSettingsTest +public static class CodeStyleSettingsTest { private static IGlobalOptionService GetGlobalOptions(Workspace workspace) => workspace.Services.SolutionServices.ExportProvider.GetExportedValue(); diff --git a/src/EditorFeatures/Test/EmbeddedLanguages/StackFrame/StackFrameParserTests.Utilities.cs b/src/EditorFeatures/Test/EmbeddedLanguages/StackFrame/StackFrameParserTests.Utilities.cs index 78eb7f83c2b55..c6f3acfd0e996 100644 --- a/src/EditorFeatures/Test/EmbeddedLanguages/StackFrame/StackFrameParserTests.Utilities.cs +++ b/src/EditorFeatures/Test/EmbeddedLanguages/StackFrame/StackFrameParserTests.Utilities.cs @@ -124,7 +124,7 @@ string PrintDifference() sb.AppendLine(); sb.Append("Actual: \t"); - var enumeratedString = new string(enumeratedParsedCharacters.Select(ch => (char)ch.Value).ToArray()); + var enumeratedString = new string([.. enumeratedParsedCharacters.Select(ch => (char)ch.Value)]); PrintString(enumeratedString, start, end, sb); sb.AppendLine(); diff --git a/src/EditorFeatures/Test/EmbeddedLanguages/StackFrame/StackFrameParserTests.cs b/src/EditorFeatures/Test/EmbeddedLanguages/StackFrame/StackFrameParserTests.cs index c1dcb1b69a437..f3103f3d45bcb 100644 --- a/src/EditorFeatures/Test/EmbeddedLanguages/StackFrame/StackFrameParserTests.cs +++ b/src/EditorFeatures/Test/EmbeddedLanguages/StackFrame/StackFrameParserTests.cs @@ -516,7 +516,7 @@ public void TestLanguages(string at, string @in, string line) fileInformation: FileInformation( Path(@"C:\repos\languages\Program.cs"), ColonToken, - line: CreateToken(StackFrameKind.NumberToken, "16", leadingTrivia: ImmutableArray.Create(CreateTrivia(StackFrameKind.LineTrivia, $"{line} "))), + line: CreateToken(StackFrameKind.NumberToken, "16", leadingTrivia: [CreateTrivia(StackFrameKind.LineTrivia, $"{line} ")]), inTrivia: CreateTrivia(StackFrameKind.InTrivia, $" {@in} ")) ); } diff --git a/src/EditorFeatures/Test/EmbeddedLanguages/StackFrame/StackFrameSyntaxFactory.cs b/src/EditorFeatures/Test/EmbeddedLanguages/StackFrame/StackFrameSyntaxFactory.cs index a3d8e2019e623..0f0e876957617 100644 --- a/src/EditorFeatures/Test/EmbeddedLanguages/StackFrame/StackFrameSyntaxFactory.cs +++ b/src/EditorFeatures/Test/EmbeddedLanguages/StackFrame/StackFrameSyntaxFactory.cs @@ -21,17 +21,17 @@ internal static class StackFrameSyntaxFactory public static StackFrameToken CreateToken(StackFrameKind kind, string s, ImmutableArray leadingTrivia = default, ImmutableArray trailingTrivia = default) => new( kind, - leadingTrivia.IsDefaultOrEmpty ? ImmutableArray.Empty : leadingTrivia, + leadingTrivia.IsDefaultOrEmpty ? [] : leadingTrivia, CodeAnalysis.EmbeddedLanguages.VirtualChars.VirtualCharSequence.Create(0, s), - trailingTrivia.IsDefaultOrEmpty ? ImmutableArray.Empty : trailingTrivia, - ImmutableArray.Empty, + trailingTrivia.IsDefaultOrEmpty ? [] : trailingTrivia, + [], value: null!); public static StackFrameTrivia CreateTrivia(StackFrameKind kind, string text) - => new(kind, CodeAnalysis.EmbeddedLanguages.VirtualChars.VirtualCharSequence.Create(0, text), ImmutableArray.Empty); + => new(kind, CodeAnalysis.EmbeddedLanguages.VirtualChars.VirtualCharSequence.Create(0, text), []); public static ImmutableArray CreateTriviaArray(params string[] strings) - => strings.Select(s => CreateTrivia(StackFrameKind.SkippedTextTrivia, s)).ToImmutableArray(); + => [.. strings.Select(s => CreateTrivia(StackFrameKind.SkippedTextTrivia, s))]; public static readonly StackFrameToken DotToken = CreateToken(StackFrameKind.DotToken, "."); public static readonly StackFrameToken CommaToken = CreateToken(StackFrameKind.CommaToken, ","); @@ -113,11 +113,11 @@ public static StackFrameQualifiedNameNode QualifiedName(string s, ImmutableArray if (current is null) { - current = Identifier(IdentifierToken(identifier, leadingTrivia: leadingTrivia, trailingTrivia: ImmutableArray.Empty)); + current = Identifier(IdentifierToken(identifier, leadingTrivia: leadingTrivia, trailingTrivia: [])); } else if (i == identifiers.Length - 1) { - var rhs = Identifier(IdentifierToken(identifier, leadingTrivia: ImmutableArray.Empty, trailingTrivia: trailingTrivia)); + var rhs = Identifier(IdentifierToken(identifier, leadingTrivia: [], trailingTrivia: trailingTrivia)); current = QualifiedName(current, rhs); } else @@ -155,13 +155,13 @@ public static StackFrameIdentifierNameNode Identifier(string name, StackFrameTri => Identifier(IdentifierToken(name, leadingTrivia, trailingTrivia)); public static StackFrameArrayRankSpecifier ArrayRankSpecifier(int commaCount = 0, StackFrameTrivia? leadingTrivia = null, StackFrameTrivia? trailingTrivia = null) - => new(OpenBracketToken.With(leadingTrivia: leadingTrivia.ToImmutableArray()), CloseBracketToken.With(trailingTrivia: trailingTrivia.ToImmutableArray()), Enumerable.Repeat(CommaToken, commaCount).ToImmutableArray()); + => new(OpenBracketToken.With(leadingTrivia: leadingTrivia.ToImmutableArray()), CloseBracketToken.With(trailingTrivia: trailingTrivia.ToImmutableArray()), [.. Enumerable.Repeat(CommaToken, commaCount)]); public static StackFrameArrayRankSpecifier ArrayRankSpecifier(StackFrameToken openToken, StackFrameToken closeToken, params StackFrameToken[] commaTokens) - => new(openToken, closeToken, commaTokens.ToImmutableArray()); + => new(openToken, closeToken, [.. commaTokens]); public static StackFrameArrayTypeNode ArrayType(StackFrameNameNode identifier, params StackFrameArrayRankSpecifier[] arrayTokens) - => new(identifier, arrayTokens.ToImmutableArray()); + => new(identifier, [.. arrayTokens]); public static StackFrameGenericNameNode GenericType(string identifierName, int arity) => new(CreateToken(StackFrameKind.IdentifierToken, identifierName), GraveAccentToken, CreateToken(StackFrameKind.NumberToken, arity.ToString())); @@ -208,7 +208,7 @@ public static StackFrameToken Path(string path) => CreateToken(StackFrameKind.PathToken, path); public static StackFrameToken Line(int lineNumber) - => CreateToken(StackFrameKind.NumberToken, lineNumber.ToString(), leadingTrivia: ImmutableArray.Create(LineTrivia)); + => CreateToken(StackFrameKind.NumberToken, lineNumber.ToString(), leadingTrivia: [LineTrivia]); public static StackFrameLocalMethodNameNode LocalMethod(StackFrameGeneratedMethodNameNode encapsulatingMethod, string identifier, string suffix) => new( diff --git a/src/EditorFeatures/Test/InheritanceMargin/InheritanceMarginTests.cs b/src/EditorFeatures/Test/InheritanceMargin/InheritanceMarginTests.cs index 8ebab9e8a3091..8aa2239eb0ced 100644 --- a/src/EditorFeatures/Test/InheritanceMargin/InheritanceMarginTests.cs +++ b/src/EditorFeatures/Test/InheritanceMargin/InheritanceMarginTests.cs @@ -266,7 +266,7 @@ public TargetInfo( TargetSymbolDisplayName = targetSymbolDisplayName; Relationship = relationship; InMetadata = inMetadata; - LocationTags = ImmutableArray.Empty; + LocationTags = []; } public TargetInfo( @@ -275,7 +275,7 @@ public TargetInfo( params string[] locationTags) { TargetSymbolDisplayName = targetSymbolDisplayName; - LocationTags = locationTags.ToImmutableArray(); + LocationTags = [.. locationTags]; Relationship = relationship; } } @@ -314,7 +314,7 @@ public static TestInheritanceTargetItem Create( return new TestInheritanceTargetItem( targetInfo.TargetSymbolDisplayName, targetInfo.Relationship, - ImmutableArray.Empty, + [], isInMetadata: true, targetInfo.LanguageGlyph, targetInfo.ProjectName); @@ -447,11 +447,10 @@ interface {|target2:IBar2|} : IBar { } var itemOnLine3 = new TestInheritanceMemberItem( lineNumber: 3, memberName: "interface IBar2", - targets: ImmutableArray.Empty - .Add(new TargetInfo( + targets: [new TargetInfo( targetSymbolDisplayName: "IBar", locationTag: "target1", - relationship: InheritanceRelationship.InheritedInterface)) + relationship: InheritanceRelationship.InheritedInterface)] ); return VerifyInSingleDocumentAsync( diff --git a/src/EditorFeatures/Test/MetadataAsSource/AbstractMetadataAsSourceTests.TestContext.cs b/src/EditorFeatures/Test/MetadataAsSource/AbstractMetadataAsSourceTests.TestContext.cs index e462801ef3299..6ff99e88f0424 100644 --- a/src/EditorFeatures/Test/MetadataAsSource/AbstractMetadataAsSourceTests.TestContext.cs +++ b/src/EditorFeatures/Test/MetadataAsSource/AbstractMetadataAsSourceTests.TestContext.cs @@ -289,7 +289,7 @@ private static TestWorkspace CreateWorkspace( // We construct our own composition here because we only want the decompilation metadata as source provider // to be available. var composition = EditorTestCompositions.EditorFeatures - .WithExcludedPartTypes(ImmutableHashSet.Create(typeof(IMetadataAsSourceFileProvider))) + .WithExcludedPartTypes([typeof(IMetadataAsSourceFileProvider)]) .AddParts(typeof(DecompilationMetadataAsSourceFileProvider)); return TestWorkspace.Create(xmlString, composition: composition); diff --git a/src/EditorFeatures/Test/MetadataAsSource/DocCommentFormatterTests.cs b/src/EditorFeatures/Test/MetadataAsSource/DocCommentFormatterTests.cs index 94110ae5f1fd8..8e7b0a4beaa05 100644 --- a/src/EditorFeatures/Test/MetadataAsSource/DocCommentFormatterTests.cs +++ b/src/EditorFeatures/Test/MetadataAsSource/DocCommentFormatterTests.cs @@ -77,7 +77,7 @@ public void Exception() var comment = @"throws NotImplementedException"; var expected = -$@"{FeaturesResources.Exceptions_colon} +$@"{WorkspacesResources.Exceptions_colon} T:System.NotImplementedException: throws NotImplementedException"; @@ -92,7 +92,7 @@ public void MultipleExceptionTags() throws InvalidOperationException"; var expected = -$@"{FeaturesResources.Exceptions_colon} +$@"{WorkspacesResources.Exceptions_colon} T:System.NotImplementedException: throws NotImplementedException @@ -111,7 +111,7 @@ public void MultipleExceptionTagsWithSameType() also throws NotImplementedException for reason Y"; var expected = -$@"{FeaturesResources.Exceptions_colon} +$@"{WorkspacesResources.Exceptions_colon} T:System.NotImplementedException: throws NotImplementedException for reason X @@ -236,7 +236,7 @@ This returns nothing. {FeaturesResources.Value_colon} This has no value. -{FeaturesResources.Exceptions_colon} +{WorkspacesResources.Exceptions_colon} System.GooException: Thrown for an unknown reason diff --git a/src/EditorFeatures/Test/Preview/PreviewWorkspaceTests.cs b/src/EditorFeatures/Test/Preview/PreviewWorkspaceTests.cs index ab3ea7c0ab6ab..f9615f64a65a9 100644 --- a/src/EditorFeatures/Test/Preview/PreviewWorkspaceTests.cs +++ b/src/EditorFeatures/Test/Preview/PreviewWorkspaceTests.cs @@ -162,7 +162,7 @@ public void TestPreviewWorkspaceDoesNotLeakItself() private static void ExecuteAnalyzers(PreviewWorkspace previewWorkspace, ImmutableArray analyzers) { - var analyzerOptions = new AnalyzerOptions(additionalFiles: ImmutableArray.Empty); + var analyzerOptions = new AnalyzerOptions(additionalFiles: []); var project = previewWorkspace.CurrentSolution.Projects.Single(); var compilationWithAnalyzersOptions = new CompilationWithAnalyzersOptions(analyzerOptions, onAnalyzerException: null, concurrentAnalysis: false, logAnalyzerExecutionTime: false); var compilation = project.GetRequiredCompilationAsync(CancellationToken.None).Result; diff --git a/src/EditorFeatures/Test/RenameTracking/RenameTrackingTaggerProviderTests.cs b/src/EditorFeatures/Test/RenameTracking/RenameTrackingTaggerProviderTests.cs index 82fb7dd786c14..7f088bd377916 100644 --- a/src/EditorFeatures/Test/RenameTracking/RenameTrackingTaggerProviderTests.cs +++ b/src/EditorFeatures/Test/RenameTracking/RenameTrackingTaggerProviderTests.cs @@ -874,32 +874,21 @@ End Enum [WpfFact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1028072")] public void RenameTrackingDoesNotThrowAggregateException() { - var waitForResult = false; var notRenamable = Task.FromResult(RenameTrackingTaggerProvider.TriggerIdentifierKind.NotRenamable); - Assert.False(RenameTrackingTaggerProvider.IsRenamableIdentifier(notRenamable, waitForResult, CancellationToken.None)); + Assert.False(RenameTrackingTaggerProvider.IsRenamableIdentifierFastCheck(notRenamable, out _)); var source = new TaskCompletionSource(); - Assert.False(RenameTrackingTaggerProvider.IsRenamableIdentifier(source.Task, waitForResult, CancellationToken.None)); + Assert.False(RenameTrackingTaggerProvider.IsRenamableIdentifierFastCheck(source.Task, out _)); source.TrySetResult(RenameTrackingTaggerProvider.TriggerIdentifierKind.RenamableReference); - Assert.True(RenameTrackingTaggerProvider.IsRenamableIdentifier(source.Task, waitForResult, CancellationToken.None)); + Assert.True(RenameTrackingTaggerProvider.IsRenamableIdentifierFastCheck(source.Task, out _)); source = new TaskCompletionSource(); source.TrySetCanceled(); - Assert.False(RenameTrackingTaggerProvider.IsRenamableIdentifier(source.Task, waitForResult, CancellationToken.None)); - Assert.False(RenameTrackingTaggerProvider.WaitForIsRenamableIdentifier(source.Task, CancellationToken.None)); + Assert.False(RenameTrackingTaggerProvider.IsRenamableIdentifierFastCheck(source.Task, out _)); source = new TaskCompletionSource(); source.TrySetException(new OperationCanceledException()); - Assert.False(RenameTrackingTaggerProvider.IsRenamableIdentifier(source.Task, waitForResult, CancellationToken.None)); - Assert.False(RenameTrackingTaggerProvider.WaitForIsRenamableIdentifier(source.Task, CancellationToken.None)); - Assert.False(RenameTrackingTaggerProvider.WaitForIsRenamableIdentifier(source.Task, new CancellationTokenSource().Token)); - - source = new TaskCompletionSource(); - Assert.Throws(() => RenameTrackingTaggerProvider.WaitForIsRenamableIdentifier(source.Task, new CancellationToken(canceled: true))); - var thrownException = new Exception(); - source.TrySetException(thrownException); - var caughtException = Assert.Throws(() => RenameTrackingTaggerProvider.WaitForIsRenamableIdentifier(source.Task, CancellationToken.None)); - Assert.Same(thrownException, caughtException); + Assert.False(RenameTrackingTaggerProvider.IsRenamableIdentifierFastCheck(source.Task, out _)); } [WpfFact] diff --git a/src/EditorFeatures/Test/RenameTracking/RenameTrackingTestState.cs b/src/EditorFeatures/Test/RenameTracking/RenameTrackingTestState.cs index 69dd2485e62a6..e74ee8de48d20 100644 --- a/src/EditorFeatures/Test/RenameTracking/RenameTrackingTestState.cs +++ b/src/EditorFeatures/Test/RenameTracking/RenameTrackingTestState.cs @@ -190,7 +190,7 @@ public async Task AssertTag(string expectedFromName, string expectedToName, bool // There should only be one code action for the tag var codeAction = await TryGetCodeActionAsync(tag.Span.Span.ToTextSpan()); Assert.NotNull(codeAction); - Assert.Equal(string.Format(EditorFeaturesResources.Rename_0_to_1, expectedFromName, expectedToName), codeAction.Title); + Assert.Equal(string.Format(WorkspacesResources.Rename_0_to_1, expectedFromName, expectedToName), codeAction.Title); if (invokeAction) { diff --git a/src/EditorFeatures/Test/Snippets/RoslynLSPSnippetConvertTests.cs b/src/EditorFeatures/Test/Snippets/RoslynLSPSnippetConvertTests.cs index cf998b5eae274..86fddcb98fb11 100644 --- a/src/EditorFeatures/Test/Snippets/RoslynLSPSnippetConvertTests.cs +++ b/src/EditorFeatures/Test/Snippets/RoslynLSPSnippetConvertTests.cs @@ -401,7 +401,7 @@ public void TestExtendTextChangeInsertion() using var workspace = CreateWorkspaceFromCode(testString); var document = workspace.CurrentSolution.GetRequiredDocument(workspace.Documents.First().Id); var lspSnippetString = RoslynLSPSnippetConverter.GenerateLSPSnippetAsync(document, caretPosition: 12, - ImmutableArray.Empty, new TextChange(new TextSpan(8, 0), "quux"), triggerLocation: 12, CancellationToken.None).Result; + [], new TextChange(new TextSpan(8, 0), "quux"), triggerLocation: 12, CancellationToken.None).Result; AssertEx.EqualOrDiff("quux$0", lspSnippetString); } @@ -412,7 +412,7 @@ public void TestExtendTextChangeReplacement() using var workspace = CreateWorkspaceFromCode(testString); var document = workspace.CurrentSolution.GetRequiredDocument(workspace.Documents.First().Id); var lspSnippetString = RoslynLSPSnippetConverter.GenerateLSPSnippetAsync(document, caretPosition: 12, - ImmutableArray.Empty, new TextChange(new TextSpan(4, 4), "bar quux"), triggerLocation: 12, CancellationToken.None).Result; + [], new TextChange(new TextSpan(4, 4), "bar quux"), triggerLocation: 12, CancellationToken.None).Result; AssertEx.EqualOrDiff("bar quux$0", lspSnippetString); } diff --git a/src/EditorFeatures/Test/Structure/AbstractStructureTaggerProviderTests.cs b/src/EditorFeatures/Test/Structure/AbstractStructureTaggerProviderTests.cs index d11dfbb20674f..113e6ad3f8298 100644 --- a/src/EditorFeatures/Test/Structure/AbstractStructureTaggerProviderTests.cs +++ b/src/EditorFeatures/Test/Structure/AbstractStructureTaggerProviderTests.cs @@ -1,4 +1,4 @@ -// Licensed to the .NET Foundation under one or more agreements. +// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. @@ -16,7 +16,7 @@ public class AbstractStructureTaggerProviderTests private static void TextContainsRegionOrUsing(string input, bool expected, string language) { var exportProvider = EditorTestCompositions.EditorFeatures.ExportProviderFactory.CreateExportProvider(); - var buffer = EditorFactory.CreateBuffer(exportProvider, input.Split(new string[] { Environment.NewLine }, StringSplitOptions.None)); + var buffer = EditorFactory.CreateBuffer(exportProvider, input.Split([Environment.NewLine], StringSplitOptions.None)); var textSnapshot = buffer.CurrentSnapshot; var actual = AbstractStructureTaggerProvider.ContainsRegionOrImport(textSnapshot, collapseRegions: true, collapseImports: true, language); diff --git a/src/EditorFeatures/Test/SymbolFinder/DependentTypeFinderTests.cs b/src/EditorFeatures/Test/SymbolFinder/DependentTypeFinderTests.cs index 5b768839c6340..7bc0ab4d97aeb 100644 --- a/src/EditorFeatures/Test/SymbolFinder/DependentTypeFinderTests.cs +++ b/src/EditorFeatures/Test/SymbolFinder/DependentTypeFinderTests.cs @@ -581,7 +581,7 @@ public async Task ImplementingTypesDoesProduceDelegates(TestHost host) Assert.NotEmpty(delegates); // We should find delegates when looking for implementations Assert.True(delegates.Any(i => i.Locations.Any(loc => loc.IsInMetadata)), "We should find a metadata delegate"); - Assert.Single(delegates.Where(i => i.Locations.Any(loc => loc.IsInSource))); // We should find a single source delegate + Assert.Single(delegates, i => i.Locations.Any(loc => loc.IsInSource)); // We should find a single source delegate } [Theory, CombinatorialData] @@ -611,7 +611,7 @@ enum E Assert.NotEmpty(enums); // We should find enums when looking for implementations Assert.True(enums.Any(i => i.Locations.Any(loc => loc.IsInMetadata)), "We should find a metadata enum"); - Assert.Single(enums.Where(i => i.Locations.Any(loc => loc.IsInSource))); // We should find a single source type + Assert.Single(enums, i => i.Locations.Any(loc => loc.IsInSource)); // We should find a single source type } [Theory, CombinatorialData] diff --git a/src/EditorFeatures/Test/Tagging/TagSpanIntervalTreeTests.cs b/src/EditorFeatures/Test/Tagging/TagSpanIntervalTreeTests.cs index 00f7a8c40d236..07509e0931741 100644 --- a/src/EditorFeatures/Test/Tagging/TagSpanIntervalTreeTests.cs +++ b/src/EditorFeatures/Test/Tagging/TagSpanIntervalTreeTests.cs @@ -80,7 +80,7 @@ public void TestSingleIntersectingSpanAtEndWithEdit() public void TestManySpansWithEdit() { // Create a buffer with the second half of the buffer covered with spans - var (tree, buffer) = CreateTree(new string('c', 100), Enumerable.Range(50, count: 50).Select(s => new Span(s, 1)).ToArray()); + var (tree, buffer) = CreateTree(new string('c', 100), [.. Enumerable.Range(50, count: 50).Select(s => new Span(s, 1))]); buffer.Insert(0, new string('c', 100)); // We should have 50 spans if we start looking at just the end @@ -94,7 +94,7 @@ public void TestManySpansWithEdit() public void TestManySpansWithEdit2() { // Cover the full buffer with spans - var (tree, buffer) = CreateTree(new string('c', 100), Enumerable.Range(0, count: 100).Select(s => new Span(s, 1)).ToArray()); + var (tree, buffer) = CreateTree(new string('c', 100), [.. Enumerable.Range(0, count: 100).Select(s => new Span(s, 1))]); buffer.Insert(0, new string('c', 100)); // We should see one span anywhere in the beginning of the buffer, since this is edge inclusive @@ -109,7 +109,7 @@ public void TestManySpansWithEdit2() public void TestManySpansWithDeleteAndEditAtStart() { // Cover the full buffer with spans - var (tree, buffer) = CreateTree(new string('c', 100), Enumerable.Range(0, count: 100).Select(s => new Span(s, 1)).ToArray()); + var (tree, buffer) = CreateTree(new string('c', 100), [.. Enumerable.Range(0, count: 100).Select(s => new Span(s, 1))]); buffer.Delete(new Span(0, 50)); buffer.Insert(0, new string('c', 50)); @@ -123,7 +123,7 @@ public void TestManySpansWithDeleteAndEditAtStart() public void TestManySpansWithDeleteAndEditAtEnd() { // Cover the full buffer with spans - var (tree, buffer) = CreateTree(new string('c', 100), Enumerable.Range(0, count: 100).Select(s => new Span(s, 1)).ToArray()); + var (tree, buffer) = CreateTree(new string('c', 100), [.. Enumerable.Range(0, count: 100).Select(s => new Span(s, 1))]); buffer.Delete(new Span(50, 50)); buffer.Insert(50, new string('c', 50)); @@ -137,7 +137,7 @@ public void TestManySpansWithDeleteAndEditAtEnd() public void TestTagSpanOrdering() { // Cover the full buffer with spans - var (tree, buffer) = CreateTree(new string('c', 100), Enumerable.Range(0, count: 100).Select(s => new Span(s, 1)).ToArray()); + var (tree, buffer) = CreateTree(new string('c', 100), [.. Enumerable.Range(0, count: 100).Select(s => new Span(s, 1))]); var lastStart = -1; foreach (var tag in GetIntersectingSpans(tree, new SnapshotSpan(buffer.CurrentSnapshot, 0, buffer.CurrentSnapshot.Length))) diff --git a/src/EditorFeatures/Test/UnusedReferences/ProjectAssets/ProjectAssetsReaderTests.cs b/src/EditorFeatures/Test/UnusedReferences/ProjectAssets/ProjectAssetsReaderTests.cs index 2b1a9d499c121..4f19dda5df521 100644 --- a/src/EditorFeatures/Test/UnusedReferences/ProjectAssets/ProjectAssetsReaderTests.cs +++ b/src/EditorFeatures/Test/UnusedReferences/ProjectAssets/ProjectAssetsReaderTests.cs @@ -66,9 +66,9 @@ public void ProjectReferencesReadHaveTheirPathAsTheItemSpecification() private static ReferenceInfo ProjectReference(string projectPath, params ReferenceInfo[] dependencies) => ProjectReference(projectPath, false, dependencies); private static ReferenceInfo ProjectReference(string projectPath, bool treatAsUsed, params ReferenceInfo[] dependencies) - => new(ReferenceType.Project, projectPath, treatAsUsed, ImmutableArray.Create(Path.ChangeExtension(projectPath, "dll")), dependencies.ToImmutableArray()); + => new(ReferenceType.Project, projectPath, treatAsUsed, [Path.ChangeExtension(projectPath, "dll")], [.. dependencies]); private static ReferenceInfo PackageReference(string assemblyPath, params ReferenceInfo[] dependencies) => PackageReference(assemblyPath, false, dependencies); private static ReferenceInfo PackageReference(string assemblyPath, bool treatAsUsed, params ReferenceInfo[] dependencies) - => new(ReferenceType.Package, Path.GetFileNameWithoutExtension(assemblyPath), treatAsUsed, ImmutableArray.Create(assemblyPath), dependencies.ToImmutableArray()); + => new(ReferenceType.Package, Path.GetFileNameWithoutExtension(assemblyPath), treatAsUsed, [assemblyPath], [.. dependencies]); } diff --git a/src/EditorFeatures/Test/UnusedReferences/UnusedReferencesRemoverTests.cs b/src/EditorFeatures/Test/UnusedReferences/UnusedReferencesRemoverTests.cs index 2616844f8c5c1..f2542981ace3b 100644 --- a/src/EditorFeatures/Test/UnusedReferences/UnusedReferencesRemoverTests.cs +++ b/src/EditorFeatures/Test/UnusedReferences/UnusedReferencesRemoverTests.cs @@ -111,8 +111,8 @@ public void GetUnusedReferences_ReferencesThatDoNotContributeToCompilation_AreNo ReferenceType.Package, itemSpecification: "Analyzer", treatAsUsed: false, - compilationAssemblies: ImmutableArray.Empty, - dependencies: ImmutableArray.Empty); + compilationAssemblies: [], + dependencies: []); var unusedReferences = GetUnusedReferences(usedAssemblies, usedProjectAssemblyNames: Empty, analyzerReference); @@ -161,7 +161,7 @@ public async Task ApplyReferenceUpdates_MixOfChangeAndNoChangeUpdates_ChangesAre } private static ImmutableArray GetUnusedReferences(string[] usedCompilationAssemblies, string[] usedProjectAssemblyNames, params ReferenceInfo[] references) - => UnusedReferencesRemover.GetUnusedReferences(new(usedCompilationAssemblies), new(usedProjectAssemblyNames), references.ToImmutableArray()); + => UnusedReferencesRemover.GetUnusedReferences([.. usedCompilationAssemblies], [.. usedProjectAssemblyNames], [.. references]); private static async Task> ApplyReferenceUpdatesAsync(params ReferenceUpdate[] referenceUpdates) { @@ -170,10 +170,10 @@ private static async Task> ApplyReferenceUpdates await UnusedReferencesRemover.ApplyReferenceUpdatesAsync( referenceCleanupService, string.Empty, - referenceUpdates.ToImmutableArray(), + [.. referenceUpdates], CancellationToken.None).ConfigureAwait(false); - return referenceCleanupService.AppliedUpdates.ToImmutableArray(); + return [.. referenceCleanupService.AppliedUpdates]; } private static ReferenceInfo ProjectReference(string assemblyPath, params ReferenceInfo[] dependencies) @@ -182,8 +182,8 @@ private static ReferenceInfo ProjectReference(string assemblyPath, bool treatAsU => new(ReferenceType.Project, itemSpecification: Path.GetFileName(assemblyPath), treatAsUsed, - compilationAssemblies: ImmutableArray.Create(assemblyPath), - dependencies.ToImmutableArray()); + compilationAssemblies: [assemblyPath], + [.. dependencies]); private static ReferenceInfo PackageReference(string assemblyPath, params ReferenceInfo[] dependencies) => PackageReference(assemblyPath, treatAsUsed: false, dependencies); @@ -191,8 +191,8 @@ private static ReferenceInfo PackageReference(string assemblyPath, bool treatAsU => new(ReferenceType.Package, itemSpecification: Path.GetFileName(assemblyPath), treatAsUsed, - compilationAssemblies: ImmutableArray.Create(assemblyPath), - dependencies.ToImmutableArray()); + compilationAssemblies: [assemblyPath], + [.. dependencies]); private static ReferenceInfo AssemblyReference(string assemblyPath) => AssemblyReference(assemblyPath, treatAsUsed: false); @@ -200,8 +200,8 @@ private static ReferenceInfo AssemblyReference(string assemblyPath, bool treatAs => new(ReferenceType.Assembly, itemSpecification: Path.GetFileName(assemblyPath), treatAsUsed, - compilationAssemblies: ImmutableArray.Create(assemblyPath), - dependencies: ImmutableArray.Empty); + compilationAssemblies: [assemblyPath], + dependencies: []); private class TestReferenceCleanupService : IReferenceCleanupService { diff --git a/src/EditorFeatures/Test/Utilities/BloomFilterTests.cs b/src/EditorFeatures/Test/Utilities/BloomFilterTests.cs index 139e4596d29aa..39386a91e4807 100644 --- a/src/EditorFeatures/Test/Utilities/BloomFilterTests.cs +++ b/src/EditorFeatures/Test/Utilities/BloomFilterTests.cs @@ -165,8 +165,8 @@ public void TestSerialization2() [Fact] public void TestInt64() { - var longs = CreateLongs(GenerateStrings(2000).Skip(500).Take(1000).Select(s => s.GetHashCode()).ToList()); - var testLongs = CreateLongs(GenerateStrings(100000).Select(s => s.GetHashCode()).ToList()); + var longs = CreateLongs([.. GenerateStrings(2000).Skip(500).Take(1000).Select(s => s.GetHashCode())]); + var testLongs = CreateLongs([.. GenerateStrings(100000).Select(s => s.GetHashCode())]); for (var d = 0.1; d >= 0.0001; d /= 10) { diff --git a/src/EditorFeatures/Test/ValueTracking/CSharpValueTrackingTests.cs b/src/EditorFeatures/Test/ValueTracking/CSharpValueTrackingTests.cs index 364dc4db543ec..7e84fc12a83f4 100644 --- a/src/EditorFeatures/Test/ValueTracking/CSharpValueTrackingTests.cs +++ b/src/EditorFeatures/Test/ValueTracking/CSharpValueTrackingTests.cs @@ -20,19 +20,21 @@ protected override TestWorkspace CreateWorkspace(string code, TestComposition co public async Task TestProperty(TestHost testHost) { var code = -@" -class C -{ - public string $$S { get; set; } = """"; + """ - public void SetS(string s) - { - S = s; - } + class C + { + public string $$S { get; set; } = ""; - public string GetS() => S; -} -"; + public void SetS(string s) + { + S = s; + } + + public string GetS() => S; + } + + """; using var workspace = CreateWorkspace(code, testHost); // @@ -42,30 +44,32 @@ public void SetS(string s) // await ValidateItemsAsync( workspace, - itemInfo: new[] - { + itemInfo: + [ (7, "s"), (3, "public string S { get; set; } = \"\";"), - }); + ]); } [Theory, CombinatorialData] public async Task TestPropertyWithThis(TestHost testHost) { var code = -@" -class C -{ - public string $$S { get; set; } = """"; + """ - public void SetS(string s) - { - this.S = s; - } + class C + { + public string $$S { get; set; } = ""; - public string GetS() => this.S; -} -"; + public void SetS(string s) + { + this.S = s; + } + + public string GetS() => this.S; + } + + """; using var workspace = CreateWorkspace(code, testHost); // @@ -75,29 +79,31 @@ public void SetS(string s) // await ValidateItemsAsync( workspace, - itemInfo: new[] - { + itemInfo: + [ (7, "s"), (3, "public string S { get; set; } = \"\";"), - }); + ]); } [Theory, CombinatorialData] public async Task TestField(TestHost testHost) { var code = -@" -class C -{ - private string $$_s = """"; + """ - public void SetS(string s) - { - _s = s; - } + class C + { + private string $$_s = ""; + + public void SetS(string s) + { + _s = s; + } - public string GetS() => _s; -}"; + public string GetS() => _s; + } + """; using var workspace = CreateWorkspace(code, testHost); var initialItems = await GetTrackedItemsAsync(workspace); @@ -108,29 +114,33 @@ public void SetS(string s) // await ValidateItemsAsync( workspace, - itemInfo: new[] - { + itemInfo: + [ (7, "s"), - (3, "_s = \"\"") - }); + (3, """ + _s = "" + """) + ]); } [Theory, CombinatorialData] public async Task TestFieldWithThis(TestHost testHost) { var code = -@" -class C -{ - private string $$_s = """"; + """ - public void SetS(string s) - { - this._s = s; - } + class C + { + private string $$_s = ""; + + public void SetS(string s) + { + this._s = s; + } - public string GetS() => this._s; -}"; + public string GetS() => this._s; + } + """; using var workspace = CreateWorkspace(code, testHost); var initialItems = await GetTrackedItemsAsync(workspace); @@ -141,27 +151,31 @@ public void SetS(string s) // await ValidateItemsAsync( workspace, - itemInfo: new[] - { + itemInfo: + [ (7, "s"), - (3, "_s = \"\"") - }); + (3, """ + _s = "" + """) + ]); } [Theory, CombinatorialData] public async Task TestLocal(TestHost testHost) { var code = -@" -class C -{ - public int Add(int x, int y) - { - var $$z = x; - z += y; - return z; - } -}"; + """ + + class C + { + public int Add(int x, int y) + { + var $$z = x; + z += y; + return z; + } + } + """; using var workspace = CreateWorkspace(code, testHost); var initialItems = await GetTrackedItemsAsync(workspace); @@ -179,15 +193,17 @@ public int Add(int x, int y) public async Task TestParameter(TestHost testHost) { var code = -@" -class C -{ - public int Add(int $$x, int y) - { - x += y; - return x; - } -}"; + """ + + class C + { + public int Add(int $$x, int y) + { + x += y; + return x; + } + } + """; using var workspace = CreateWorkspace(code, testHost); var initialItems = await GetTrackedItemsAsync(workspace); @@ -202,18 +218,69 @@ public int Add(int $$x, int y) } [Theory, CombinatorialData] - public async Task TestMissingOnMethod(TestHost testHost) + public async Task TestParameter2(TestHost testHost) { var code = -@" -class C -{ - public int $$Add(int x, int y) - { - x += y; - return x; + """ + + class C + { + public void InvokeM(string arg) + { + M(arg); + M(); + M("test"); + } + + public void M(string? $$x = null) + { + } + } + """; + using var workspace = CreateWorkspace(code, testHost); + var initialItems = await GetTrackedItemsAsync(workspace); + + // + // public void M(|string? x = null|) + // M(|"test"|) + // |M("test")| + // M(|arg|) + // |M(arg)| + // + Assert.Equal(1, initialItems.Length); + ValidateItem(initialItems[0], 10); + + var items = await ValidateChildrenAsync( + workspace, + initialItems.Single(), + childInfo: + [ + (7, """ + "test" + """), // M(|"test"|) + (7, """ + M("test") + """), // |M("test")| + (5, "arg"), // M(|arg|) + (5, "M(arg)"), // |M(arg)| + ]); } -}"; + + [Theory, CombinatorialData] + public async Task TestMissingOnMethod(TestHost testHost) + { + var code = + """ + + class C + { + public int $$Add(int x, int y) + { + x += y; + return x; + } + } + """; using var workspace = CreateWorkspace(code, testHost); var initialItems = await GetTrackedItemsAsync(workspace); Assert.Empty(initialItems); @@ -223,15 +290,17 @@ class C public async Task TestMissingOnClass(TestHost testHost) { var code = -@" -class $$C -{ - public int Add(int x, int y) - { - x += y; - return x; - } -}"; + """ + + class $$C + { + public int Add(int x, int y) + { + x += y; + return x; + } + } + """; using var workspace = CreateWorkspace(code, testHost); var initialItems = await GetTrackedItemsAsync(workspace); Assert.Empty(initialItems); @@ -241,18 +310,20 @@ public int Add(int x, int y) public async Task TestMissingOnNamespace(TestHost testHost) { var code = -@" -namespace $$N -{ - class C - { - public int Add(int x, int y) - { - x += y; - return x; - } - } -}"; + """ + + namespace $$N + { + class C + { + public int Add(int x, int y) + { + x += y; + return x; + } + } + } + """; using var workspace = CreateWorkspace(code, testHost); var initialItems = await GetTrackedItemsAsync(workspace); Assert.Empty(initialItems); @@ -262,47 +333,49 @@ public int Add(int x, int y) public async Task MethodTracking1(TestHost testHost) { var code = -@" -class C -{ - public string S { get; set; } = """"; - - public void SetS(string s) - { - S$$ = s; - } - - public string GetS() => S; -} - -class Other -{ - public void CallS(C c, string str) - { - c.SetS(str); - } + """ - public void CallS(C c) - { - CallS(c, CalculateDefault(c)); - } + class C + { + public string S { get; set; } = ""; - private string CalculateDefault(C c) - { - if (c is null) - { - return ""null""; - } + public void SetS(string s) + { + S$$ = s; + } - if (string.IsNullOrEmpty(c.S)) - { - return ""defaultstring""; - } + public string GetS() => S; + } - return """"; - } -} -"; + class Other + { + public void CallS(C c, string str) + { + c.SetS(str); + } + + public void CallS(C c) + { + CallS(c, CalculateDefault(c)); + } + + private string CalculateDefault(C c) + { + if (c is null) + { + return "null"; + } + + if (string.IsNullOrEmpty(c.S)) + { + return "defaultstring"; + } + + return ""; + } + } + + """; using var workspace = CreateWorkspace(code, testHost); var initialItems = await GetTrackedItemsAsync(workspace); @@ -323,11 +396,11 @@ private string CalculateDefault(C c) var items = await ValidateChildrenAsync( workspace, initialItems.Single(), - childInfo: new[] - { + childInfo: + [ (17, "str"), // |> c.SetS([|str|]); [Code.cs:17] (17, "c.SetS(str)"), // |> [|c.SetS(str)|]; [Code.cs:17] - }); + ]); // |> [|c.SetS(s)|]; [Code.cs:17] await ValidateChildrenEmptyAsync(workspace, items[1]); @@ -336,13 +409,13 @@ private string CalculateDefault(C c) items = await ValidateChildrenAsync( workspace, items[0], - childInfo: new[] - { + childInfo: + [ (22, "c" ), // |> CallS([|c|], CalculateDefault(c)) [Code.cs:22] (22, "c" ), // |> CallS(c, CalculateDefault([|c|])) [Code.cs:22] (22, "CalculateDefault(c)" ), // |> CallS(c, [|CalculateDefault(c)|]) [Code.cs:22] (22, "CallS(c, CalculateDefault(c))" ) // |> [|CallS(c, CalculateDefault(c))|] [Code.cs:22] - }); + ]); // |> CallS([|c|], CalculateDefault(c)) [Code.cs:22] await ValidateChildrenEmptyAsync(workspace, items[0]); @@ -355,12 +428,18 @@ private string CalculateDefault(C c) var children = await ValidateChildrenAsync( workspace, items[2], - childInfo: new[] - { - (37, "\"\""), // |> return "" [Code.cs:37] - (34, "\"defaultstring\""), // |> return "defaultstring" [Code.cs:34] - (29, "\"null\""), // |> return "null" [Code.cs:29] - }); + childInfo: + [ + (37, """ + "" + """), // |> return "" [Code.cs:37] + (34, """ + "defaultstring" + """), // |> return "defaultstring" [Code.cs:34] + (29, """ + "null" + """), // |> return "null" [Code.cs:29] + ]); foreach (var child in children) { @@ -372,63 +451,65 @@ private string CalculateDefault(C c) public async Task MethodTracking2(TestHost testHost) { var code = -@" -class C -{ - public string S { get; set; } = """"; - - public void SetS(string s) - { - S$$ = s; - } - - public string GetS() => S; -} - -class Other -{ - private readonly string _adornment; - public Other(string adornment) - { - _adornment = adornment; - } - - public void CallS(C c, string s) - { - c.SetS(s); - } + """ - public void CallS(C c) - { - CallS(c, CalculateDefault(c) + _adornment); - } - - private string CalculateDefault(C c) - { - if (c is null) - { - return ""null""; - } + class C + { + public string S { get; set; } = ""; - if (string.IsNullOrEmpty(c.S)) - { - return ""defaultstring""; - } + public void SetS(string s) + { + S$$ = s; + } - return """"; - } -} + public string GetS() => S; + } -class Program -{ - public static void Main(string[] args) - { - var other = new Other(""some value""); - var c = new C(); - other.CallS(c); - } -} -"; + class Other + { + private readonly string _adornment; + public Other(string adornment) + { + _adornment = adornment; + } + + public void CallS(C c, string s) + { + c.SetS(s); + } + + public void CallS(C c) + { + CallS(c, CalculateDefault(c) + _adornment); + } + + private string CalculateDefault(C c) + { + if (c is null) + { + return "null"; + } + + if (string.IsNullOrEmpty(c.S)) + { + return "defaultstring"; + } + + return ""; + } + } + + class Program + { + public static void Main(string[] args) + { + var other = new Other("some value"); + var c = new C(); + other.CallS(c); + } + } + + """; using var workspace = CreateWorkspace(code, testHost); var initialItems = await GetTrackedItemsAsync(workspace); @@ -456,11 +537,11 @@ public static void Main(string[] args) var items = await ValidateChildrenAsync( workspace, initialItems.Single(), - childInfo: new[] - { + childInfo: + [ (23, "s"), // |> c.SetS([|s|]); [Code.cs:23] (23, "c.SetS(s)"), // |> c.SetS(s); [Code.cs:23] - }); + ]); // |> c.SetS(s); [Code.cs:23] await ValidateChildrenEmptyAsync(workspace, items[1]); @@ -469,23 +550,23 @@ public static void Main(string[] args) items = await ValidateChildrenAsync( workspace, items[0], - childInfo: new[] - { + childInfo: + [ (28, "c" ), // |> CallS([|c|], CalculateDefault(c) + _adornment) [Code.cs:28] (28, "_adornment" ), // |> CallS(c, CalculateDefault(c) + [|_adornment|]) [Code.cs:28] (28, "c" ), // |> CallS(c, CalculateDefault([|c|]) + _adornment) [Code.cs:28] (28, "CalculateDefault(c)" ), // |> CallS(c, [|CalculateDefault|](c) + _adornment) [Code.cs:28] (28, "CallS(c, CalculateDefault(c) + _adornment)" ), // |> [|CallS(c, CalculateDefault(c) + _adornment)|] [Code.cs:28] - }); + ]); // |> CallS([|c|], CalculateDefault(c) + _adornment) [Code.cs:28] var children = await ValidateChildrenAsync( workspace, items[0], - childInfo: new[] - { + childInfo: + [ (53, "other.CallS(c)"), // |> other.CallS([|c|]); [Code.cs:53] - }); + ]); await ValidateChildrenEmptyAsync(workspace, children); @@ -493,10 +574,10 @@ public static void Main(string[] args) children = await ValidateChildrenAsync( workspace, items[2], - childInfo: new[] - { + childInfo: + [ (53, "other.CallS(c)"), // |> other.CallS([|c|]); [Code.cs:53] - }); + ]); await ValidateChildrenEmptyAsync(workspace, children); @@ -504,30 +585,38 @@ public static void Main(string[] args) children = await ValidateChildrenAsync( workspace, items[1], - childInfo: new[] - { + childInfo: + [ (18, "adornment"), // |> _adornment = [|adornment|] [Code.cs:18] - }); + ]); children = await ValidateChildrenAsync( workspace, children.Single(), - childInfo: new[] - { - (51, "\"some value\"") // |> var other = new Other([|"some value"|]); [Code.cs:51] - }); + childInfo: + [ + (51, """ + "some value" + """) // |> var other = new Other([|"some value"|]); [Code.cs:51] + ]); await ValidateChildrenEmptyAsync(workspace, children); // |> CallS(c, [|CalculateDefault(c)|] + _adornment) [Code.cs:28] children = await ValidateChildrenAsync( workspace, items[3], - childInfo: new[] - { - (43, "\"\""), // |> return "" [Code.cs:37] - (40, "\"defaultstring\""), // |> return "defaultstring" [Code.cs:34] - (35, "\"null\""), // |> return "null" [Code.cs:29] - }); + childInfo: + [ + (43, """ + "" + """), // |> return "" [Code.cs:37] + (40, """ + "defaultstring" + """), // |> return "defaultstring" [Code.cs:34] + (35, """ + "null" + """), // |> return "null" [Code.cs:29] + ]); await ValidateChildrenEmptyAsync(workspace, children); @@ -539,28 +628,30 @@ public static void Main(string[] args) public async Task MethodTracking3(TestHost testHost) { var code = -@" -using System.Threading.Tasks; + """ -namespace N -{ - class C - { - public int Add(int x, int y) - { - x += y; - return x; - } - - public Task AddAsync(int x, int y) => Task.FromResult(Add(x,y)); + using System.Threading.Tasks; - public async Task Double(int x) - { - x = await AddAsync(x, x); - return $$x; - } - } -}"; + namespace N + { + class C + { + public int Add(int x, int y) + { + x += y; + return x; + } + + public Task AddAsync(int x, int y) => Task.FromResult(Add(x,y)); + + public async Task Double(int x) + { + x = await AddAsync(x, x); + return $$x; + } + } + } + """; // // |> return [|x|] [Code.cs:18] // |> x = await AddAsync([|x|], x) [Code.cs:17] @@ -577,24 +668,24 @@ public async Task Double(int x) var children = await ValidateChildrenAsync( workspace, initialItems.Single(), - childInfo: new[] - { + childInfo: + [ (17, "x"), // |> x = await AddAsync([|x|], x) [Code.cs:17] (17, "x"), // |> x = await AddAsync(x, [|x|]) [Code.cs:17] (17, "AddAsync(x, x)") // |> x = await [|AddAsync(x, x)|] [Code.cs:17] - }); + ]); // |> x = await [|AddAsync(x, x)|] [Code.cs:17] children = await ValidateChildrenAsync( workspace, children[2], - childInfo: new[] - { + childInfo: + [ (13, "x"), // |> Task.FromResult(Add([|x|], y)) [Code.cs:13] (13, "y"), // |> Task.FromResult(Add(x, [|y|])) [Code.cs:13] (13, "Add(x,y)"), // |> Task.FromResult([|Add(x, y)|]) [Code.cs:13] (13, "Task.FromResult(Add(x,y))"), // |> [|Task.FromResult|](Add(x, y)) [Code.cs:13] - }); + ]); // |> [|Task.FromResult|](Add(x, y)) [Code.cs:13] await ValidateChildrenEmptyAsync(workspace, children[3]); @@ -603,43 +694,45 @@ public async Task Double(int x) children = await ValidateChildrenAsync( workspace, children[2], - childInfo: new[] - { + childInfo: + [ (10, "x") // |> return x [Code.cs:10] - }); + ]); } [Theory, CombinatorialData] public async Task OutParam(TestHost testHost) { - var code = @" -class C -{ - bool TryConvertInt(object o, out int i) - { - if (int.TryParse(o.ToString(), out i)) - { - return true; - } + var code = """ - return false; - } - - void M() - { - int i = 0; - object o = ""5""; - - if (TryConvertInt(o, out i)) - { - Console.WriteLine($$i); - } - else - { - i = 2; - } - } -}"; + class C + { + bool TryConvertInt(object o, out int i) + { + if (int.TryParse(o.ToString(), out i)) + { + return true; + } + + return false; + } + + void M() + { + int i = 0; + object o = "5"; + + if (TryConvertInt(o, out i)) + { + Console.WriteLine($$i); + } + else + { + i = 2; + } + } + } + """; // // |> Console.WriteLine($$i); [Code.cs:20] @@ -658,12 +751,12 @@ void M() var children = await ValidateChildrenAsync( workspace, initialItems.Single(), - childInfo: new[] - { + childInfo: + [ (24, "2"), // |> i = [|2|] [Code.cs:24] (18, "i"), // |> if (TryConvertInt(o, out [|i|])) [Code.cs:18] (15, "0"), // |> int i = 0 [Code.cs:15] - }); + ]); // |> i = [|2|] [Code.cs:24] await ValidateChildrenEmptyAsync(workspace, children[0]); @@ -672,10 +765,10 @@ void M() children = await ValidateChildrenAsync( workspace, children[1], - childInfo: new[] - { + childInfo: + [ (5, "i") // |> if (int.TryParse(o.ToString(), out [|i|])) [Code.cs:5] - }); + ]); await ValidateChildrenEmptyAsync(workspace, children.Single()); } @@ -684,22 +777,24 @@ void M() public async Task TestVariableReferenceStart(TestHost testHost) { var code = -@" -class Test -{ - public static void M() - { - int x = GetM(); - Console.Write(x); - var y = $$x + 1; - } + """ - public static int GetM() - { - var x = 0; - return x; - } -}"; + class Test + { + public static void M() + { + int x = GetM(); + Console.Write(x); + var y = $$x + 1; + } + + public static int GetM() + { + var x = 0; + return x; + } + } + """; // // |> var y = x + 1; [Code.cs:7] @@ -710,34 +805,34 @@ public static int GetM() var items = await ValidateItemsAsync( workspace, - itemInfo: new[] - { + itemInfo: + [ (7, "x") // |> var y = [|x|] + 1; [Code.cs:7] - }); + ]); items = await ValidateChildrenAsync( workspace, items.Single(), - childInfo: new[] - { + childInfo: + [ (5, "GetM()") // |> int x = [|GetM()|] [Code.cs:5] - }); + ]); items = await ValidateChildrenAsync( workspace, items.Single(), - childInfo: new[] - { + childInfo: + [ (13, "x") // |> return [|x|]; [Code.cs:13] - }); + ]); items = await ValidateChildrenAsync( workspace, items.Single(), - childInfo: new[] - { + childInfo: + [ (12, "0") // |> var x = [|0|]; [Code.cs:12] - }); + ]); await ValidateChildrenEmptyAsync(workspace, items.Single()); } @@ -746,22 +841,24 @@ public static int GetM() public async Task TestVariableReferenceStart2(TestHost testHost) { var code = -@" -class Test -{ - public static void M() - { - int x = GetM(); - Console.Write($$x); - var y = x + 1; - } + """ - public static int GetM() - { - var x = 0; - return x; - } -}"; + class Test + { + public static void M() + { + int x = GetM(); + Console.Write($$x); + var y = x + 1; + } + + public static int GetM() + { + var x = 0; + return x; + } + } + """; // // |> Console.Write(x); [Code.cs:6] @@ -772,34 +869,34 @@ public static int GetM() var items = await ValidateItemsAsync( workspace, - itemInfo: new[] - { + itemInfo: + [ (6, "x") // |> Console.Write([|x|]); [Code.cs:7] - }); + ]); items = await ValidateChildrenAsync( workspace, items.Single(), - childInfo: new[] - { + childInfo: + [ (5, "GetM()") // |> int x = [|GetM()|] [Code.cs:5] - }); + ]); items = await ValidateChildrenAsync( workspace, items.Single(), - childInfo: new[] - { + childInfo: + [ (13, "x") // |> return [|x|]; [Code.cs:13] - }); + ]); items = await ValidateChildrenAsync( workspace, items.Single(), - childInfo: new[] - { + childInfo: + [ (12, "0") // |> var x = [|0|]; [Code.cs:12] - }); + ]); await ValidateChildrenEmptyAsync(workspace, items.Single()); } @@ -808,25 +905,27 @@ public static int GetM() public async Task TestVariableReferenceStart3(TestHost testHost) { var code = -@" -class Test -{ - public static void M() - { - int x = GetM(); - Console.Write($$x); - var y = x + 1; - x += 1; - Console.Write(x); - Console.Write(y); - } + """ - public static int GetM() - { - var x = 0; - return x; - } -}"; + class Test + { + public static void M() + { + int x = GetM(); + Console.Write($$x); + var y = x + 1; + x += 1; + Console.Write(x); + Console.Write(y); + } + + public static int GetM() + { + var x = 0; + return x; + } + } + """; // // |> Console.Write(x); [Code.cs:6] @@ -838,37 +937,37 @@ public static int GetM() var items = await ValidateItemsAsync( workspace, - itemInfo: new[] - { + itemInfo: + [ (6, "x") // |> Console.Write([|x|]); [Code.cs:7] - }); + ]); items = await ValidateChildrenAsync( workspace, items.Single(), - childInfo: new[] - { + childInfo: + [ (8, "1"), // |> x += 1; [Codec.s:8] (5, "GetM()"), // |> int x = [|GetM()|] [Code.cs:5] - }); + ]); await ValidateChildrenEmptyAsync(workspace, items[0]); items = await ValidateChildrenAsync( workspace, items[1], - childInfo: new[] - { + childInfo: + [ (16, "x") // |> return [|x|]; [Code.cs:13] - }); + ]); items = await ValidateChildrenAsync( workspace, items.Single(), - childInfo: new[] - { + childInfo: + [ (15, "0") // |> var x = [|0|]; [Code.cs:12] - }); + ]); await ValidateChildrenEmptyAsync(workspace, items.Single()); } @@ -877,25 +976,27 @@ public static int GetM() public async Task TestMultipleDeclarators(TestHost testHost) { var code = -@" -class Test -{ - public static void M() - { - int x = GetM(), z = 5; - Console.Write($$x); - var y = x + 1 + z; - x += 1; - Console.Write(x); - Console.Write(y); - } + """ - public static int GetM() - { - var x = 0; - return x; - } -}"; + class Test + { + public static void M() + { + int x = GetM(), z = 5; + Console.Write($$x); + var y = x + 1 + z; + x += 1; + Console.Write(x); + Console.Write(y); + } + + public static int GetM() + { + var x = 0; + return x; + } + } + """; // // |> Console.Write(x); [Code.cs:6] @@ -907,37 +1008,37 @@ public static int GetM() var items = await ValidateItemsAsync( workspace, - itemInfo: new[] - { + itemInfo: + [ (6, "x") // |> Console.Write([|x|]); [Code.cs:7] - }); + ]); items = await ValidateChildrenAsync( workspace, items.Single(), - childInfo: new[] - { + childInfo: + [ (8, "1"), // |> x += 1; [Codec.s:8] (5, "GetM()"), // |> int x = [|GetM()|] [Code.cs:5] - }); + ]); await ValidateChildrenEmptyAsync(workspace, items[0]); items = await ValidateChildrenAsync( workspace, items[1], - childInfo: new[] - { + childInfo: + [ (16, "x") // |> return [|x|]; [Code.cs:13] - }); + ]); items = await ValidateChildrenAsync( workspace, items.Single(), - childInfo: new[] - { + childInfo: + [ (15, "0") // |> var x = [|0|]; [Code.cs:12] - }); + ]); await ValidateChildrenEmptyAsync(workspace, items.Single()); } @@ -946,19 +1047,21 @@ public static int GetM() public async Task TestIndex(TestHost testHost) { var code = -@" -class Test -{ - public int this[string $$key] => 0; + """ - public int M(Test localTest) - { - var assignedVariable = this[""test""]; - System.Console.WriteLine(this[""test""]); - - return localTest[""test""]; - } -}"; + class Test + { + public int this[string $$key] => 0; + + public int M(Test localTest) + { + var assignedVariable = this["test"]; + System.Console.WriteLine(this["test"]); + + return localTest["test"]; + } + } + """; // // |> public int this[string [|key|]] => 0; [Code.cs:4] @@ -969,21 +1072,27 @@ public int M(Test localTest) var items = await ValidateItemsAsync( workspace, - itemInfo: new[] - { + itemInfo: + [ (3, "string key") // |>public int this[[|string key|]] => 0; [Code.cs:4] - }); + ]); items = await ValidateChildrenAsync( workspace, items.Single(), - childInfo: new[] - { + childInfo: + [ (10, "localTest"), // return [|localTest|]["test"]; [Code.cs:10] (This is included because it is part of a return statement, and follows same logic as other references for if it is tracked) - (10, "\"test\""), // return localTest[[|"test"|]]; [Code.cs:10] - (8, "\"test\""), // System.Console.WriteLine(this[[|"test"|]]); [Code.cs:8] - (7, "\"test\""), // var assignedVariable = this[[|"test"|]]; [Code.cs:7] - }); + (10, """ + "test" + """), // return localTest[[|"test"|]]; [Code.cs:10] + (8, """ + "test" + """), // System.Console.WriteLine(this[[|"test"|]]); [Code.cs:8] + (7, """ + "test" + """), // var assignedVariable = this[[|"test"|]]; [Code.cs:7] + ]); await ValidateChildrenEmptyAsync(workspace, items[0]); await ValidateChildrenEmptyAsync(workspace, items[1]); @@ -995,42 +1104,44 @@ public int M(Test localTest) public async Task TestPropertyValue(TestHost testHost) { var code = -@" -class Test -{ - private int _i; - public int I - { - get => _i; - set - { - _i = $$value; - } - } + """ - public int M(Test localTest) - { - localTest.I = 5; - } -}"; + class Test + { + private int _i; + public int I + { + get => _i; + set + { + _i = $$value; + } + } + + public int M(Test localTest) + { + localTest.I = 5; + } + } + """; // _i = [|value|]; [Code.cs:9] // |> localTest.I = [|5|]; [Code.cs:15] using var workspace = CreateWorkspace(code, testHost); var items = await ValidateItemsAsync( workspace, - itemInfo: new[] - { + itemInfo: + [ (9, "value") // _i = [|value|]; [Code.cs:9] - }); + ]); items = await ValidateChildrenAsync( workspace, items.Single(), - childInfo: new[] - { + childInfo: + [ (15, "5") // localTest.I = [|5|]; [Code.cs:15] - }); + ]); await ValidateChildrenEmptyAsync(workspace, items.Single()); } diff --git a/src/EditorFeatures/Test/ValueTracking/VisualBasicValueTrackingTests.cs b/src/EditorFeatures/Test/ValueTracking/VisualBasicValueTrackingTests.cs index a0c24189d13ff..27cac4cf07b74 100644 --- a/src/EditorFeatures/Test/ValueTracking/VisualBasicValueTrackingTests.cs +++ b/src/EditorFeatures/Test/ValueTracking/VisualBasicValueTrackingTests.cs @@ -91,18 +91,18 @@ End Class var items = await ValidateItemsAsync( workspace, - itemInfo: new[] - { + itemInfo: + [ (8, "value") // _s = [|value|] [Code.vb:8] - }); + ]); var childItems = await ValidateChildrenAsync( workspace, items.Single(), - childInfo: new[] - { + childInfo: + [ (14, "s") // Me.S = [|s|] [Code.vb:14] - }); + ]); await ValidateChildrenEmptyAsync(workspace, childItems.Single()); } @@ -135,11 +135,11 @@ End Class // await ValidateItemsAsync( workspace, - itemInfo: new[] - { + itemInfo: + [ (5, "s"), (2, "_s") - }); + ]); } [Theory, CombinatorialData] @@ -222,34 +222,34 @@ End Function var items = await ValidateItemsAsync( workspace, - itemInfo: new[] - { + itemInfo: + [ (5, "x") // |> Dim y = [|x|] + 1; [Code.vb:7] - }); + ]); items = await ValidateChildrenAsync( workspace, items.Single(), - childInfo: new[] - { + childInfo: + [ (3, "GetM()") // |> Dim x = [|GetM()|] [Code.vb:5] - }); + ]); items = await ValidateChildrenAsync( workspace, items.Single(), - childInfo: new[] - { + childInfo: + [ (10, "x") // |> return [|x|]; [Code.vb:13] - }); + ]); items = await ValidateChildrenAsync( workspace, items.Single(), - childInfo: new[] - { + childInfo: + [ (9, "0") // |> var x = [|0|]; [Code.vb:12] - }); + ]); await ValidateChildrenEmptyAsync(workspace, items.Single()); } @@ -281,34 +281,34 @@ End Function var items = await ValidateItemsAsync( workspace, - itemInfo: new[] - { + itemInfo: + [ (4, "x") // |> Dim y = [|x|] + 1; [Code.vb:7] - }); + ]); items = await ValidateChildrenAsync( workspace, items.Single(), - childInfo: new[] - { + childInfo: + [ (3, "GetM()") // |> Dim x = [|GetM()|] [Code.vb:5] - }); + ]); items = await ValidateChildrenAsync( workspace, items.Single(), - childInfo: new[] - { + childInfo: + [ (10, "x") // |> return [|x|]; [Code.vb:13] - }); + ]); items = await ValidateChildrenAsync( workspace, items.Single(), - childInfo: new[] - { + childInfo: + [ (9, "0") // |> var x = [|0|]; [Code.vb:12] - }); + ]); await ValidateChildrenEmptyAsync(workspace, items.Single()); } @@ -342,34 +342,34 @@ End Function var items = await ValidateItemsAsync( workspace, - itemInfo: new[] - { + itemInfo: + [ (7, "x") // |> Dim y = [|x|] + 1; [Code.vb:7] - }); + ]); items = await ValidateChildrenAsync( workspace, items.Single(), - childInfo: new[] - { + childInfo: + [ (5, "GetM()") // |> Dim x = [|GetM()|], z = 1, m As Boolean, n As Boolean, o As Boolean [Code.vb:5] - }); + ]); items = await ValidateChildrenAsync( workspace, items.Single(), - childInfo: new[] - { + childInfo: + [ (12, "x") // |> return [|x|]; [Code.vb:12] - }); + ]); items = await ValidateChildrenAsync( workspace, items.Single(), - childInfo: new[] - { + childInfo: + [ (11, "0") // |> var x = [|0|]; [Code.vb:11] - }); + ]); await ValidateChildrenEmptyAsync(workspace, items.Single()); } diff --git a/src/EditorFeatures/Test2/Diagnostics/ImplementInterface/ImplementInterfaceCrossLanguageTests.vb b/src/EditorFeatures/Test2/Diagnostics/ImplementInterface/ImplementInterfaceCrossLanguageTests.vb index e86559bb1f672..a7f32cacf221a 100644 --- a/src/EditorFeatures/Test2/Diagnostics/ImplementInterface/ImplementInterfaceCrossLanguageTests.vb +++ b/src/EditorFeatures/Test2/Diagnostics/ImplementInterface/ImplementInterfaceCrossLanguageTests.vb @@ -224,8 +224,7 @@ End Class Await TestAsync(input, expected) End Function - - + Public Async Function Test_IndexerWithNoRequiredParameters_02() As Task Dim input = @@ -257,8 +256,8 @@ Imports System.Collections.Generic Class C Implements I - - Public ReadOnly Property Item(y As IEnumerable(Of Integer)) As Integer Implements I.Item + + Default Public ReadOnly Property Item(y As IEnumerable(Of Integer)) As Integer Implements I.Item Get Throw New NotImplementedException() End Get diff --git a/src/EditorFeatures/Test2/Expansion/AbstractExpansionTest.vb b/src/EditorFeatures/Test2/Expansion/AbstractExpansionTest.vb index dbd1782c5984a..bf180f3f0b201 100644 --- a/src/EditorFeatures/Test2/Expansion/AbstractExpansionTest.vb +++ b/src/EditorFeatures/Test2/Expansion/AbstractExpansionTest.vb @@ -56,7 +56,7 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.Expansion End Function Private Shared Function GetExpressionSyntaxWithSameSpan(node As SyntaxNode, spanEnd As Integer) As SyntaxNode - While Not node Is Nothing And Not node.Parent Is Nothing And node.Parent.SpanStart = node.SpanStart + While node IsNot Nothing And node.Parent IsNot Nothing And node.Parent.SpanStart = node.SpanStart node = node.Parent If node.Span.End = spanEnd Then Exit While diff --git a/src/EditorFeatures/Test2/FindReferences/FindReferencesTests.AliasSymbols.vb b/src/EditorFeatures/Test2/FindReferences/FindReferencesTests.AliasSymbols.vb index 43a880ca44f44..e0a7c24152ca6 100644 --- a/src/EditorFeatures/Test2/FindReferences/FindReferencesTests.AliasSymbols.vb +++ b/src/EditorFeatures/Test2/FindReferences/FindReferencesTests.AliasSymbols.vb @@ -483,6 +483,23 @@ namespace N } + + Await TestAPIAndFeature(input, kind, host) + End Function + + + + Public Async Function TestAliasToPrimitive1(kind As TestKind, host As TestHost) As Task + Dim input = + + + + using $$TBitMap = [|ulong|]; + + var size = sizeof([|TBitMap|]); + var array = new [|TBitMap|][10]; + + Await TestAPIAndFeature(input, kind, host) End Function diff --git a/src/EditorFeatures/Test2/FindReferences/FindReferencesTests.ConstructorSymbols.vb b/src/EditorFeatures/Test2/FindReferences/FindReferencesTests.ConstructorSymbols.vb index 89cc1601bf898..21ea35471f180 100644 --- a/src/EditorFeatures/Test2/FindReferences/FindReferencesTests.ConstructorSymbols.vb +++ b/src/EditorFeatures/Test2/FindReferences/FindReferencesTests.ConstructorSymbols.vb @@ -1278,6 +1278,107 @@ Namespace Test End Namespace]]> + + Await TestAPIAndFeature(input, kind, host) + End Function + + + + Public Async Function TestImplicitObjectCreation(kind As TestKind, host As TestHost) As Task + Dim input = + + + + + + + Await TestAPIAndFeature(input, kind, host) + End Function + + + + Public Async Function TestPrimaryConstructor1(kind As TestKind, host As TestHost) As Task + Dim input = + + + + class Program + { + public {|Definition:$$Program|}(int i) + { + } + } + + class Derived() : [|Program|](0) + { + } + + + + Await TestAPIAndFeature(input, kind, host) + End Function + + + + Public Async Function TestPrimaryConstructor2(kind As TestKind, host As TestHost) As Task + Dim input = + + + + class Program + { + public {|Definition:$$Program|}(int i) + { + } + } + + class Derived() : global::[|Program|](0) + { + } + + + + Await TestAPIAndFeature(input, kind, host) + End Function + + + + Public Async Function TestPrimaryConstructor3(kind As TestKind, host As TestHost) As Task + Dim input = + + + + namespace N + { + class Program + { + public {|Definition:$$Program|}(int i) + { + } + } + } + + class Derived() : N.[|Program|](0) + { + } + + Await TestAPIAndFeature(input, kind, host) End Function diff --git a/src/EditorFeatures/Test2/FindReferences/FindReferencesTests.DynamicTypeSymbol.vb b/src/EditorFeatures/Test2/FindReferences/FindReferencesTests.DynamicTypeSymbol.vb new file mode 100644 index 0000000000000..b8a63ca91175a --- /dev/null +++ b/src/EditorFeatures/Test2/FindReferences/FindReferencesTests.DynamicTypeSymbol.vb @@ -0,0 +1,179 @@ +' Licensed to the .NET Foundation under one or more agreements. +' The .NET Foundation licenses this file to you under the MIT license. +' See the LICENSE file in the project root for more information. + +Imports System.Threading.Tasks +Imports Microsoft.CodeAnalysis.Remote.Testing + +Namespace Microsoft.CodeAnalysis.Editor.UnitTests.FindReferences + + Partial Public Class FindReferencesTests + + Public Async Function DynamicTypeSymbol1(kind As TestKind, host As TestHost) As Task + Dim input = + + + + class C + { + [|$$dynamic|] i; + [|dynamic|] j; + } + + + + Await TestAPIAndFeature(input, kind, host) + End Function + + + Public Async Function DynamicTypeSymbol_AcrossMethods(kind As TestKind, host As TestHost) As Task + Dim input = + + + + class C + { + void M() + { + [|$$dynamic|] i; + } + + void N() + { + [|dynamic|] j; + } + } + + + + Await TestAPIAndFeature(input, kind, host) + End Function + + + Public Async Function DynamicTypeSymbol_WithTypeSyntax1(kind As TestKind, host As TestHost) As Task + Dim input = + + + + class C + { + void M() + { + [|$$dynamic|] i; + } + + void N() + { + [|dynamic|][] j; + } + } + + + + Await TestAPIAndFeature(input, kind, host) + End Function + + + Public Async Function DynamicTypeSymbol_WithTypeSyntax2(kind As TestKind, host As TestHost) As Task + Dim input = + + + + class C + { + void M() + { + [|$$dynamic|] i; + } + + void N() + { + List<[|dynamic|]> j; + } + } + + + + Await TestAPIAndFeature(input, kind, host) + End Function + + + Public Async Function DynamicTypeSymbol_AcrossDocuments(kind As TestKind, host As TestHost) As Task + Dim input = + + + + class C + { + void M() + { + [|$$dynamic|] i; + } + } + + + class D + { + void N() + { + [|dynamic|] j; + } + } + + + + Await TestAPIAndFeature(input, kind, host) + End Function + + + Public Async Function DynamicTypeSymbol_AcrossProjects(kind As TestKind, host As TestHost) As Task + Dim input = + + + + class C + { + void M() + { + [|$$dynamic|] i; + } + } + + + + + class D + { + void N() + { + [|dynamic|] j; + } + } + + + + Await TestAPIAndFeature(input, kind, host) + End Function + + + Public Async Function DynamicTypeSymbol_NonMatch1(kind As TestKind, host As TestHost) As Task + Dim input = + + + + class C + { + [|$$dynamic|] i; + + void M(int dynamic) + { + dynamic.ToString(); + } + } + + + + Await TestAPIAndFeature(input, kind, host) + End Function + End Class +End Namespace diff --git a/src/EditorFeatures/Test2/FindReferences/FindReferencesTests.IndexerSymbols.vb b/src/EditorFeatures/Test2/FindReferences/FindReferencesTests.IndexerSymbols.vb index 435764b1ec97d..1e3b74b43cce6 100644 --- a/src/EditorFeatures/Test2/FindReferences/FindReferencesTests.IndexerSymbols.vb +++ b/src/EditorFeatures/Test2/FindReferences/FindReferencesTests.IndexerSymbols.vb @@ -336,6 +336,32 @@ public class Test } + + Await TestAPIAndFeature(input, kind, host) + End Function + + + + Public Async Function TestCSharp_Indexer_AtReferenceLocation(kind As TestKind, host As TestHost) As Task + Dim input = + + + +class C +{ + public int {|Definition:this|}[int y] { get { } } +} + +class D +{ + void Goo() + { + var q = new C(); + var b = q[||]$$[4]; + } +} + + Await TestAPIAndFeature(input, kind, host) End Function diff --git a/src/EditorFeatures/Test2/FindReferences/FindReferencesTests.OrdinaryMethodSymbols.vb b/src/EditorFeatures/Test2/FindReferences/FindReferencesTests.OrdinaryMethodSymbols.vb index 2901406150ff1..3441b85505e33 100644 --- a/src/EditorFeatures/Test2/FindReferences/FindReferencesTests.OrdinaryMethodSymbols.vb +++ b/src/EditorFeatures/Test2/FindReferences/FindReferencesTests.OrdinaryMethodSymbols.vb @@ -3969,6 +3969,276 @@ End Class Await TestAPI(input, host) End Function + + + Public Async Function CSharp_TestDisposeUsedInUsingDeclaration1(host As TestHost) As Task + Dim input = + + + + struct S + { + public void {|Definition:$$Dispose|}() { } + } + + class C + { + void M() + { + [|using|] (var s = new S()) + { + } + } + } + + + + Await TestAPI(input, host) + End Function + + + + Public Async Function CSharp_TestDisposeUsedInUsingDeclaration2(host As TestHost) As Task + Dim input = + + + + struct S + { + public void {|Definition:Dispose|}() { } + } + + class C + { + void M() + { + [|$$using|] (var s = new S()) + { + } + } + } + + + + Await TestAPI(input, host) + End Function + + + + Public Async Function CSharp_TestDisposeUsedInUsingDeclaration3(host As TestHost) As Task + Dim input = + + + + struct S + { + public void {|Definition:$$Dispose|}() { } + } + + class C + { + void M() + { + [|using|] var s = new S(); + } + } + + + + Await TestAPI(input, host) + End Function + + + + Public Async Function CSharp_TestDisposeUsedInUsingDeclaration4(host As TestHost) As Task + Dim input = + + + + struct S + { + public void {|Definition:Dispose|}() { } + } + + class C + { + void M() + { + [|$$using|] var s = new S(); + } + } + + + + Await TestAPI(input, host) + End Function + + + + Public Async Function CSharp_TestDisposeUsedInUsingDeclaration5(host As TestHost) As Task + Dim input = + + + + struct S + { + public void {|Definition:$$Dispose|}() { } + } + + class C + { + void M() + { + [|using|] (new S()) + { + } + } + } + + + + Await TestAPI(input, host) + End Function + + + + Public Async Function CSharp_TestDisposeUsedInUsingDeclaration6(host As TestHost) As Task + Dim input = + + + + struct S + { + public void {|Definition:Dispose|}() { } + } + + class C + { + void M() + { + [|$$using|] (new S()) + { + } + } + } + + + + Await TestAPI(input, host) + End Function + + + + Public Async Function VisualBasic_TestDisposeUsedInUsingDeclaration1(host As TestHost) As Task + Dim input = + + + + imports System + structure S + implements IDisposable + + public sub {|Definition:$$Dispose|}() Implements IDisposable.[|Dispose|] + end sub + end structure + + class C + sub M() + [|using|] (new S()) + end using + end sub + end class + + + + + Await TestAPI(input, host) + End Function + + + + Public Async Function VisualBasic_TestDisposeUsedInUsingDeclaration2(host As TestHost) As Task + Dim input = + + + + imports System + structure S + implements IDisposable + + public sub {|Definition:Dispose|}() Implements IDisposable.[|Dispose|] + end sub + end structure + + class C + sub M() + [|$$using|] (new S()) + end using + end sub + end class + + + + + Await TestAPI(input, host) + End Function + + + + Public Async Function VisualBasic_TestDisposeUsedInUsingDeclaration3(host As TestHost) As Task + Dim input = + + + + imports System + structure S + implements IDisposable + + public sub {|Definition:$$Dispose|}() Implements IDisposable.[|Dispose|] + end sub + end structure + + class C + sub M() + [|using|] x = new S() + end using + end sub + end class + + + + + Await TestAPI(input, host) + End Function + + + + Public Async Function VisualBasic_TestDisposeUsedInUsingDeclaration4(host As TestHost) As Task + Dim input = + + + + imports System + structure S + implements IDisposable + + public sub {|Definition:Dispose|}() Implements IDisposable.[|Dispose|] + end sub + end structure + + class C + sub M() + [|$$using|] x = new S() + end using + end sub + end class + + + + + Await TestAPI(input, host) + End Function + #Region "Collection Initializers" diff --git a/src/EditorFeatures/Test2/FindReferences/FindReferencesTests.vb b/src/EditorFeatures/Test2/FindReferences/FindReferencesTests.vb index bf3b704ec7316..cc93b9245b854 100644 --- a/src/EditorFeatures/Test2/FindReferences/FindReferencesTests.vb +++ b/src/EditorFeatures/Test2/FindReferences/FindReferencesTests.vb @@ -258,9 +258,10 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.FindReferences Dim project = document.Project result = result.Concat( - Await SymbolFinder.TestAccessor.FindReferencesAsync( + Await SymbolFinder.FindReferencesAsync( symbol, project.Solution, - progress:=Nothing, documents:=scope, options, CancellationToken.None)) + progress:=DirectCast(Nothing, IFindReferencesProgress), + documents:=scope, options, CancellationToken.None)) End If Dim actualDefinitions = diff --git a/src/EditorFeatures/Test2/GoToDefinition/CSharpGoToDefinitionTests.vb b/src/EditorFeatures/Test2/GoToDefinition/CSharpGoToDefinitionTests.vb index 5fc5369d1ed53..68843dbf48673 100644 --- a/src/EditorFeatures/Test2/GoToDefinition/CSharpGoToDefinitionTests.vb +++ b/src/EditorFeatures/Test2/GoToDefinition/CSharpGoToDefinitionTests.vb @@ -3819,6 +3819,98 @@ class Program Await TestAsync(workspace) End Function + + Public Async Function TestCSharpGoToDefinition_OnElementAccessExpression1() As Task + Dim workspace = + + + +class C +{ + int [||]this[int i] => i; + + void M(C c) + { + var v = c$$[0]; + } +}s + + + + + Await TestAsync(workspace) + End Function + + + Public Async Function TestCSharpGoToDefinition_OnElementAccessExpression2() As Task + Dim workspace = + + + +class C +{ + int [||]this[int i] => i; + + void M(C c) + { + var v = c[0]$$; + } +}s + + + + + Await TestAsync(workspace) + End Function + + + Public Async Function TestAbstractExplicitInterfaceImplementation1() As Task + Dim workspace = + + + where T1 : I1 +{ + static abstract void [|M1|](); + void M3(); +} + +interface I3 : I1 where T3 : I3 +{ + static abstract void I1.$$M1(); + abstract void I1.M3(); +} + ]]> + + + + Await TestAsync(workspace) + End Function + + + Public Async Function TestAbstractExplicitInterfaceImplementation2() As Task + Dim workspace = + + + where T1 : I1 +{ + static abstract void M1(); + void [|M3|](); +} + +interface I3 : I1 where T3 : I3 +{ + static abstract void I1.M1(); + abstract void I1.$$M3(); +} + ]]> + + + + Await TestAsync(workspace) + End Function + Public Async Function TestInterceptors_AttributeMissingVersion() As Task Dim workspace = @@ -4153,6 +4245,124 @@ public partial class Program End Using End Function + + Public Async Function TestCSharpGotoDefinitionOnPartialMethodDefinition() As Task + Dim workspace = + + + + partial class Test + { + partial void $$M(); + } + + + partial class Test + { + partial void [|M|]() + { + throw new NotImplementedException(); + } + } + + + + + Await TestAsync(workspace) + End Function + + + Public Async Function TestCSharpGotoDefinitionOnPartialMethodImplementation() As Task + Dim workspace = + + + + partial class Test + { + partial void [|M|](); + } + + + partial class Test + { + partial void $$M() + { + throw new NotImplementedException(); + } + } + + + + + Await TestAsync(workspace) + End Function + + + Public Async Function TestCSharpGotoDefinitionOnPartialPropertyDefinition() As Task + Dim workspace = + + + + partial class Test + { + public partial string $$Prop { get; set; } + } + + + partial class Test + { + public partial string [|Prop|] + { + get + { + throw new NotImplementedException(); + } + set + { + throw new NotImplementedException(); + } + } + } + + + + + Await TestAsync(workspace) + End Function + + + Public Async Function TestCSharpGotoDefinitionOnPartialPropertyImplementation() As Task + Dim workspace = + + + + partial class Test + { + public partial string [|Prop|] { get; set; } + } + + + partial class Test + { + public partial string $$Prop + { + get + { + throw new NotImplementedException(); + } + set + { + throw new NotImplementedException(); + } + } + } + + + + + Await TestAsync(workspace) + End Function + #Enable Warning RSEXPERIMENTAL002 ' Type is for evaluation purposes only and is subject to change or removal in future updates. End Class End Namespace diff --git a/src/EditorFeatures/Test2/GoToDefinition/GoToDefinitionCommandHandlerTests.vb b/src/EditorFeatures/Test2/GoToDefinition/GoToDefinitionCommandHandlerTests.vb index 57c189557e160..bdd248e842de0 100644 --- a/src/EditorFeatures/Test2/GoToDefinition/GoToDefinitionCommandHandlerTests.vb +++ b/src/EditorFeatures/Test2/GoToDefinition/GoToDefinitionCommandHandlerTests.vb @@ -10,7 +10,6 @@ Imports Microsoft.CodeAnalysis.GoToDefinition Imports Microsoft.CodeAnalysis.Navigation Imports Microsoft.CodeAnalysis.Options Imports Microsoft.CodeAnalysis.Shared.TestHooks -Imports Microsoft.CodeAnalysis.Text Imports Microsoft.VisualStudio.Text Imports Microsoft.VisualStudio.Text.Editor.Commanding.Commands Imports Microsoft.VisualStudio.Utilities @@ -18,7 +17,7 @@ Imports Roslyn.Utilities Namespace Microsoft.CodeAnalysis.Editor.UnitTests.GoToDefinition - Public Class GoToDefinitionCommandHandlerTests + Public NotInheritable Class GoToDefinitionCommandHandlerTests Public Async Function TestInLinkedFiles() As Task Dim definition = diff --git a/src/EditorFeatures/Test2/GoToDefinition/GoToDefinitionTestsBase.vb b/src/EditorFeatures/Test2/GoToDefinition/GoToDefinitionTestsBase.vb index f4daa0e32fa88..ae2fc2c0e3982 100644 --- a/src/EditorFeatures/Test2/GoToDefinition/GoToDefinitionTestsBase.vb +++ b/src/EditorFeatures/Test2/GoToDefinition/GoToDefinitionTestsBase.vb @@ -11,7 +11,7 @@ Imports Microsoft.CodeAnalysis.Navigation Imports Microsoft.VisualStudio.Text Namespace Microsoft.CodeAnalysis.Editor.UnitTests.GoToDefinition - Public Class GoToDefinitionTestsBase + Public MustInherit Class GoToDefinitionTestsBase Public Shared Async Function TestAsync( workspaceDefinition As XElement, Optional expectedResult As Boolean = True) As Task diff --git a/src/EditorFeatures/Test2/GoToImplementation/GoToImplementationTests.vb b/src/EditorFeatures/Test2/GoToImplementation/GoToImplementationTests.vb index 86ca0d5c2262c..3532f2aee9852 100644 --- a/src/EditorFeatures/Test2/GoToImplementation/GoToImplementationTests.vb +++ b/src/EditorFeatures/Test2/GoToImplementation/GoToImplementationTests.vb @@ -10,7 +10,7 @@ Imports Microsoft.CodeAnalysis.Classification Namespace Microsoft.CodeAnalysis.Editor.UnitTests.GoToImplementation <[UseExportProvider]> - Public Class GoToImplementationTests + Public NotInheritable Class GoToImplementationTests Private Shared Async Function TestAsync(workspaceDefinition As XElement, host As TestHost, Optional shouldSucceed As Boolean = True, Optional metadataDefinitions As String() = Nothing) As Task Await GoToHelpers.TestAsync( workspaceDefinition, @@ -39,6 +39,7 @@ $$ End Function + Public Async Function TestWithSingleClass(host As TestHost) As Task Dim workspace = @@ -58,7 +59,7 @@ class [|$$C|] { } -abstract class [|$$C|] +abstract class $$C { } @@ -137,12 +138,13 @@ enum [|$$C|] End Function + Public Async Function TestWithNonAbstractClass(host As TestHost) As Task Dim workspace = -class [|$$C|] +class $$C { } @@ -188,6 +190,7 @@ interface $$I { } End Function + Public Async Function TestWithOneMethodImplementation_01(host As TestHost) As Task Dim workspace = @@ -203,13 +206,14 @@ interface I { void $$M(); } End Function + Public Async Function TestWithOneMethodImplementation_02(host As TestHost) As Task Dim workspace = class C : I { public void [|M|]() { } } -interface I { void [|$$M|]() {} } +interface I { void $$M() {} } @@ -218,13 +222,14 @@ interface I { void [|$$M|]() {} } End Function + Public Async Function TestWithOneMethodImplementation_03(host As TestHost) As Task Dim workspace = class C : I { void I.[|M|]() { } } -interface I { void [|$$M|]() {} } +interface I { void $$M() {} } @@ -252,6 +257,7 @@ interface I { void $$M(); } End Function + Public Async Function TestWithOneMethodImplementation_05(host As TestHost) As Task Dim workspace = @@ -262,7 +268,7 @@ interface C : I void I.[|M|]() { } void M(); } -interface I { void [|$$M|]() {} } +interface I { void $$M() {} } @@ -428,6 +434,7 @@ class C End Function + Public Async Function TestWithOverridableMethodOnBase(host As TestHost) As Task Dim workspace = @@ -435,7 +442,7 @@ class C class C { - public virtual void [|$$M|]() { } + public virtual void $$M() { } } class D : C @@ -475,13 +482,14 @@ class D : C + Public Async Function TestWithIntermediateAbstractOverrides(host As TestHost) As Task Dim workspace = abstract class A { - public virtual void $$[|M|]() { } + public virtual void $$M() { } } abstract class B : A { public abstract override void M(); diff --git a/src/EditorFeatures/Test2/InlineHints/AbstractInlineHintsTests.vb b/src/EditorFeatures/Test2/InlineHints/AbstractInlineHintsTests.vb index 8010a93bedcbc..65b0fff2670fb 100644 --- a/src/EditorFeatures/Test2/InlineHints/AbstractInlineHintsTests.vb +++ b/src/EditorFeatures/Test2/InlineHints/AbstractInlineHintsTests.vb @@ -4,12 +4,8 @@ Imports System.Collections.Immutable Imports System.Threading -Imports Microsoft.CodeAnalysis.Editor.InlineHints -Imports Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces Imports Microsoft.CodeAnalysis.InlineHints Imports Microsoft.CodeAnalysis.LanguageService -Imports Microsoft.CodeAnalysis.Options -Imports Microsoft.CodeAnalysis.[Shared].Utilities Imports Microsoft.CodeAnalysis.Text Namespace Microsoft.CodeAnalysis.Editor.UnitTests.InlineHints @@ -30,8 +26,10 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.InlineHints Dim snapshot = hostDocument.GetTextBuffer().CurrentSnapshot Dim document = workspace.CurrentSolution.GetDocument(hostDocument.Id) Dim tagService = document.GetRequiredLanguageService(Of IInlineParameterNameHintsService) + + Dim span = If(hostDocument.SelectedSpans.Any(), hostDocument.SelectedSpans.Single(), New TextSpan(0, snapshot.Length)) Dim inlineHints = Await tagService.GetInlineHintsAsync( - document, New Text.TextSpan(0, snapshot.Length), options, displayOptions, displayAllOverride:=False, CancellationToken.None) + document, span, options, displayOptions, displayAllOverride:=False, CancellationToken.None) Dim producedTags = From hint In inlineHints Select hint.DisplayParts.GetFullText().TrimEnd() + hint.Span.ToString @@ -88,8 +86,10 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.InlineHints Dim snapshot = hostDocument.GetTextBuffer().CurrentSnapshot Dim document = workspace.CurrentSolution.GetDocument(hostDocument.Id) Dim tagService = document.GetRequiredLanguageService(Of IInlineTypeHintsService) + + Dim span = If(hostDocument.SelectedSpans.Any(), hostDocument.SelectedSpans.Single(), New TextSpan(0, snapshot.Length)) Dim typeHints = Await tagService.GetInlineHintsAsync( - document, New Text.TextSpan(0, snapshot.Length), options, displayOptions, displayAllOverride:=ephemeral, CancellationToken.None) + document, span, options, displayOptions, displayAllOverride:=ephemeral, CancellationToken.None) Dim producedTags = From hint In typeHints Select hint.DisplayParts.GetFullText() + ":" + hint.Span.ToString() diff --git a/src/EditorFeatures/Test2/InlineHints/CSharpInlineParameterNameHintsTests.vb b/src/EditorFeatures/Test2/InlineHints/CSharpInlineParameterNameHintsTests.vb index ae22b2ce65d06..0bcf0d758f3bd 100644 --- a/src/EditorFeatures/Test2/InlineHints/CSharpInlineParameterNameHintsTests.vb +++ b/src/EditorFeatures/Test2/InlineHints/CSharpInlineParameterNameHintsTests.vb @@ -1247,6 +1247,139 @@ class C void N(bool async) { + } +} + + + + + Await VerifyParamHints(input, output) + End Function + + + Public Async Function TestOnlyProduceTagsWithinSelection() As Task + Dim input = + + + +class A +{ + int testMethod(int a, int b, int c, int d, int e) + { + return x; + } + void Main() + { + testMethod(1, [|{|b:|}2, {|c:|}3, {|d:|}4|], 5); + } +} + + + + + Dim output = + + + +class A +{ + int testMethod(int a, int b, int c, int d, int e) + { + return x; + } + void Main() + { + testMethod(1, b: 2, c: 3, d: 4, 5); + } +} + + + + + Await VerifyParamHints(input, output) + End Function + + + Public Async Function TestExistingNamedParameter1() As Task + Dim input = + + + +class C +{ + static void Main(string[] args) + { + Goo({|a:|}1, 2, b: 0); + } + + static void Goo(int a, int b) + { + + } +} + + + + + Dim output = + + + +class C +{ + static void Main(string[] args) + { + Goo(a: 1, 2, b: 0); + } + + static void Goo(int a, int b) + { + + } +} + + + + + Await VerifyParamHints(input, output) + End Function + + + Public Async Function TestExistingNamedParameter2() As Task + Dim input = + + + +class C +{ + static void Main(string[] args) + { + Goo({|a:|}1, {|b:|}2, c: 0); + } + + static void Goo(int a, int b) + { + + } +} + + + + + Dim output = + + + +class C +{ + static void Main(string[] args) + { + Goo(a: 1, b: 2, c: 0); + } + + static void Goo(int a, int b) + { + } } diff --git a/src/EditorFeatures/Test2/InlineHints/CSharpInlineTypeHintsTests.vb b/src/EditorFeatures/Test2/InlineHints/CSharpInlineTypeHintsTests.vb index 4277f072d60f1..8a2c2582e62e1 100644 --- a/src/EditorFeatures/Test2/InlineHints/CSharpInlineTypeHintsTests.vb +++ b/src/EditorFeatures/Test2/InlineHints/CSharpInlineTypeHintsTests.vb @@ -4,7 +4,7 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.InlineHints - Public Class CSharpInlineTypeHintsTests + Public NotInheritable Class CSharpInlineTypeHintsTests Inherits AbstractInlineHintsTests @@ -766,7 +766,7 @@ class A class A { - void M(System.Threading.CancellationToken ct = new CancellationToken()) { } + void M(System.Threading.CancellationToken ct = new System.Threading.CancellationToken()) { } } @@ -848,5 +848,91 @@ class A Await VerifyTypeHints(input, output) End Function + + + Public Async Function TestOnlyProduceTagsWithinSelection() As Task + Dim input = + + + +class A +{ + void Main() + { + var a = 0; + [|var {|int :|}b = 0; + var {|int :|}c = 0;|] + var d = 0; + } +} + + + + + Dim output = + + + +class A +{ + void Main() + { + var a = 0; + int b = 0; + int c = 0; + var d = 0; + } +} + + + + + Await VerifyTypeHints(input, output) + End Function + + + Public Async Function TestAlias() As Task + Dim input = + + + +using System.Collections.Generic; +using TestFile = (string Path, string Content); + +class C +{ + void M() + { + var {|List<TestFile> :|}testFiles = GetTestFiles(); + } + + List<TestFile> GetTestFiles() => default; +} + + + + + Dim output = + + + +using System.Collections.Generic; +using TestFile = (string Path, string Content); + +class C +{ + void M() + { + List<TestFile> testFiles = GetTestFiles(); + } + + List<TestFile> GetTestFiles() => default; +} + + + + + Await VerifyTypeHints(input, output) + End Function End Class End Namespace diff --git a/src/EditorFeatures/Test2/IntelliSense/CSharpCompletionCommandHandlerTests_AwaitCompletion.vb b/src/EditorFeatures/Test2/IntelliSense/CSharpCompletionCommandHandlerTests_AwaitCompletion.vb index fda906222de42..021397c61035a 100644 --- a/src/EditorFeatures/Test2/IntelliSense/CSharpCompletionCommandHandlerTests_AwaitCompletion.vb +++ b/src/EditorFeatures/Test2/IntelliSense/CSharpCompletionCommandHandlerTests_AwaitCompletion.vb @@ -2,8 +2,6 @@ ' The .NET Foundation licenses this file to you under the MIT license. ' See the LICENSE file in the project root for more information. -Imports Microsoft.CodeAnalysis.CSharp - Namespace Microsoft.CodeAnalysis.Editor.UnitTests.IntelliSense @@ -428,7 +426,7 @@ public class C End Function - Public Async Function AwaitCompletionDoesNotAddAsync_NotTask() As Task + Public Async Function AwaitCompletionDoesAddAsync_NotTask() As Task Using state = TestStateFactory.CreateCSharpTestState( + Public Async Function FixupReturnType_Method_Void() As Task + Using state = TestStateFactory.CreateCSharpTestState( + + ) + state.SendTypeChars("aw") + Await state.AssertSelectedCompletionItem(displayText:="await", isHardSelected:=True) + + state.SendTab() + AssertEx.Equal(" +using System.Threading.Tasks; + +public class C +{ + public async Task Main() + { + await + } +} +", state.GetDocumentText()) + End Using + End Function + + + Public Async Function FixupReturnType_LocalFunction_Void() As Task + Using state = TestStateFactory.CreateCSharpTestState( + + ) + state.SendTypeChars("aw") + Await state.AssertSelectedCompletionItem(displayText:="await", isHardSelected:=True) + + state.SendTab() + AssertEx.Equal(" +using System.Threading.Tasks; + +public class C +{ + public void Main() + { + async Task Goo() + { + await + } + } +} +", state.GetDocumentText()) + End Using + End Function + + + Public Async Function FixupReturnType_ParenthesizedLambda_Void() As Task + Using state = TestStateFactory.CreateCSharpTestState( + + { + $$ + } + } +} +]]> + ) + state.SendTypeChars("aw") + Await state.AssertSelectedCompletionItem(displayText:="await", isHardSelected:=True) + + state.SendTab() + AssertEx.Equal(" +using System.Threading.Tasks; + +public class C +{ + public void Main() + { + var v = async Task () => + { + await + } + } +} +", state.GetDocumentText()) + End Using + End Function + + + Public Async Function FixupReturnType_Method_NonVoid() As Task + Using state = TestStateFactory.CreateCSharpTestState( + + ) + state.SendTypeChars("aw") + Await state.AssertSelectedCompletionItem(displayText:="await", isHardSelected:=True) + + state.SendTab() + AssertEx.Equal(" +using System.Threading.Tasks; + +public class C +{ + public async Task Main() + { + await + } +} +", state.GetDocumentText()) + End Using + End Function + + + Public Async Function FixupReturnType_LocalFunction_NonVoid() As Task + Using state = TestStateFactory.CreateCSharpTestState( + + ) + state.SendTypeChars("aw") + Await state.AssertSelectedCompletionItem(displayText:="await", isHardSelected:=True) + + state.SendTab() + AssertEx.Equal(" +using System.Threading.Tasks; + +public class C +{ + public void Main() + { + async Task Goo() + { + await + } + } +} +", state.GetDocumentText()) + End Using + End Function + + + Public Async Function FixupReturnType_ParenthesizedLambda_NonVoid() As Task + Using state = TestStateFactory.CreateCSharpTestState( + + { + $$ + } + } +} +]]> + ) + state.SendTypeChars("aw") + Await state.AssertSelectedCompletionItem(displayText:="await", isHardSelected:=True) + + state.SendTab() + AssertEx.Equal(" +using System.Threading.Tasks; + +public class C +{ + public void Main() + { + var v = async Task () => + { + await + } + } +} +", state.GetDocumentText()) + End Using + End Function + + + + ")> + + ")> + + Public Async Function NoFixupReturnType_Method(taskType As String) As Task + Using state = TestStateFactory.CreateCSharpTestState( + + ) + state.SendTypeChars("aw") + Await state.AssertSelectedCompletionItem(displayText:="await", isHardSelected:=True) + + state.SendTab() + AssertEx.Equal(" +using System.Threading.Tasks; + +public class C +{ + public async Task Main() + { + await + } +} +", state.GetDocumentText()) + End Using + End Function + + + Public Async Function NoFixupReturnType_SimpleLambda() As Task + Using state = TestStateFactory.CreateCSharpTestState( + v = a => + { + $$ + } + } +} +]]> + ) + state.SendTypeChars("aw") + Await state.AssertSelectedCompletionItem(displayText:="await", isHardSelected:=True) + + state.SendTab() + AssertEx.Equal(" +using System; +using System.Threading.Tasks; + +public class C +{ + public Task Main() + { + Func v = async a => + { + await + } + } +} +", state.GetDocumentText()) + End Using + End Function + + + Public Async Function NoFixupReturnType_ParenthesizedLambda() As Task + Using state = TestStateFactory.CreateCSharpTestState( + v = (a) => + { + $$ + } + } +} +]]> + ) + state.SendTypeChars("aw") + Await state.AssertSelectedCompletionItem(displayText:="await", isHardSelected:=True) + + state.SendTab() + AssertEx.Equal(" +using System; +using System.Threading.Tasks; + +public class C +{ + public Task Main() + { + Func v = async (a) => + { + await + } + } +} ", state.GetDocumentText()) End Using End Function diff --git a/src/EditorFeatures/Test2/IntelliSense/CSharpSignatureHelpCommandHandlerTests.vb b/src/EditorFeatures/Test2/IntelliSense/CSharpSignatureHelpCommandHandlerTests.vb index 95d6b23a8dbd3..34a9bc96ce441 100644 --- a/src/EditorFeatures/Test2/IntelliSense/CSharpSignatureHelpCommandHandlerTests.vb +++ b/src/EditorFeatures/Test2/IntelliSense/CSharpSignatureHelpCommandHandlerTests.vb @@ -499,7 +499,7 @@ class C state.SendEscape() End If - state.SendUpKey() + state.CurrentSignatureHelpPresenterSession.SelectPreviousItem() Await state.AssertSelectedSignatureHelpItem("void C.M(int i, int j, int k)") state.SendTypeChars("1") @@ -545,7 +545,7 @@ class C state.SendEscape() End If - state.SendDownKey() + state.CurrentSignatureHelpPresenterSession.SelectNextItem() Await state.AssertSelectedSignatureHelpItem("void C.M(int i, string x)") state.SendTypeChars("1") @@ -580,7 +580,7 @@ class C state.SendTypeChars("1, """" ") Await state.AssertSelectedSignatureHelpItem("void C.M(int i, string x)") - state.SendUpKey() + state.CurrentSignatureHelpPresenterSession.SelectPreviousItem() Await state.AssertSelectedSignatureHelpItem("void C.M(int i, int j)") state.SendTypeChars(",") diff --git a/src/EditorFeatures/Test2/IntelliSense/IntellisenseQuickInfoBuilderTests.vb b/src/EditorFeatures/Test2/IntelliSense/IntellisenseQuickInfoBuilderTests.vb index 4f22f1996a6c3..c4319d68e0699 100644 --- a/src/EditorFeatures/Test2/IntelliSense/IntellisenseQuickInfoBuilderTests.vb +++ b/src/EditorFeatures/Test2/IntelliSense/IntellisenseQuickInfoBuilderTests.vb @@ -382,7 +382,7 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.IntelliSense New ContainerElement( ContainerElementStyle.Stacked, New ClassifiedTextElement( - New ClassifiedTextRun(ClassificationTypeNames.Text, FeaturesResources.Exceptions_colon)), + New ClassifiedTextRun(ClassificationTypeNames.Text, WorkspacesResources.Exceptions_colon)), New ClassifiedTextElement( New ClassifiedTextRun(ClassificationTypeNames.WhiteSpace, " "), New ClassifiedTextRun(ClassificationTypeNames.ClassName, "IOException", navigationAction:=Sub() Return, "IOException")))) diff --git a/src/EditorFeatures/Test2/IntelliSense/ModelTests.vb b/src/EditorFeatures/Test2/IntelliSense/ModelTests.vb deleted file mode 100644 index afd666e86d679..0000000000000 --- a/src/EditorFeatures/Test2/IntelliSense/ModelTests.vb +++ /dev/null @@ -1,127 +0,0 @@ -' Licensed to the .NET Foundation under one or more agreements. -' The .NET Foundation licenses this file to you under the MIT license. -' See the LICENSE file in the project root for more information. - -Imports System.Threading -Imports Microsoft.CodeAnalysis.Editor.Implementation.IntelliSense -Imports Microsoft.CodeAnalysis.Editor.Shared.Utilities -Imports Microsoft.CodeAnalysis.Shared.TestHooks -Imports Moq - -Namespace Microsoft.CodeAnalysis.Editor.UnitTests.IntelliSense - - - - Public Class ModelTests - Public Class Model - End Class - - Private Class TestModelComputation - Inherits ModelComputation(Of Model) - - Public Sub New(threadingContext As IThreadingContext, controller As IController(Of Model)) - MyBase.New(threadingContext, controller, TaskScheduler.Default) - End Sub - - Friend Shared Function Create(threadingContext As IThreadingContext, Optional controller As IController(Of Model) = Nothing) As TestModelComputation - If controller Is Nothing Then - Dim mock = New Mock(Of IController(Of Model))(MockBehavior.Strict) - controller = mock.Object - End If - - Return New TestModelComputation(threadingContext, controller) - End Function - - Friend Sub Wait() - WaitForController() - End Sub - End Class - - - Public Sub ChainingTaskStartsAsyncOperation() - Dim threadingContext = EditorTestCompositions.EditorFeatures.ExportProviderFactory.CreateExportProvider().GetExportedValue(Of IThreadingContext) - Dim controller = New Mock(Of IController(Of Model))(MockBehavior.Strict) - controller.Setup(Function(c) c.BeginAsyncOperation("", Nothing, It.IsAny(Of String), It.IsAny(Of Integer))).Returns(EmptyAsyncToken.Instance) - Dim modelComputation = TestModelComputation.Create(threadingContext, controller:=controller.Object) - - modelComputation.ChainTaskAndNotifyControllerWhenFinished(Function(m) m) - - controller.Verify(Sub(c) c.BeginAsyncOperation( - It.IsAny(Of String), - Nothing, - It.IsAny(Of String), - It.IsAny(Of Integer))) - End Sub - - - Public Sub ChainingTaskThatCompletesNotifiesController() - Dim threadingContext = EditorTestCompositions.EditorFeatures.ExportProviderFactory.CreateExportProvider().GetExportedValue(Of IThreadingContext) - Dim model = New Model() - Dim controller = New Mock(Of IController(Of Model))(MockBehavior.Strict) - controller.Setup(Function(c) c.BeginAsyncOperation("", Nothing, It.IsAny(Of String), It.IsAny(Of Integer))).Returns(EmptyAsyncToken.Instance) - controller.Setup(Sub(c) c.OnModelUpdated(model, True)) - Dim modelComputation = TestModelComputation.Create(threadingContext, controller:=controller.Object) - - modelComputation.ChainTaskAndNotifyControllerWhenFinished(Function(m) model) - modelComputation.Wait() - - controller.Verify(Sub(c) c.OnModelUpdated(model, True)) - End Sub - - - Public Sub ControllerIsOnlyUpdatedAfterLastTaskCompletes() - Dim threadingContext = EditorTestCompositions.EditorFeatures.ExportProviderFactory.CreateExportProvider().GetExportedValue(Of IThreadingContext) - Dim model = New Model() - Dim controller = New Mock(Of IController(Of Model))(MockBehavior.Strict) - controller.Setup(Function(c) c.BeginAsyncOperation("", Nothing, It.IsAny(Of String), It.IsAny(Of Integer))).Returns(EmptyAsyncToken.Instance) - controller.Setup(Sub(c) c.OnModelUpdated(model, True)) - Dim modelComputation = TestModelComputation.Create(threadingContext, controller:=controller.Object) - Dim gate = New Object - - Monitor.Enter(gate) - modelComputation.ChainTaskAndNotifyControllerWhenFinished(Function(m) - SyncLock gate - Return Nothing - End SyncLock - End Function) - modelComputation.ChainTaskAndNotifyControllerWhenFinished(Function(m) model) - Monitor.Exit(gate) - modelComputation.Wait() - - controller.Verify(Sub(c) c.OnModelUpdated(model, True), Times.Once) - End Sub - - - Public Async Function ControllerIsNotUpdatedIfComputationIsCancelled() As Task - Dim threadingContext = EditorTestCompositions.EditorFeatures.ExportProviderFactory.CreateExportProvider().GetExportedValue(Of IThreadingContext) - Dim controller = New Mock(Of IController(Of Model))(MockBehavior.Strict) - Dim token = New Mock(Of IAsyncToken)(MockBehavior.Strict) - controller.Setup(Function(c) c.BeginAsyncOperation( - It.IsAny(Of String), - Nothing, - It.IsAny(Of String), - It.IsAny(Of Integer))).Returns(token.Object) - Dim modelComputation = TestModelComputation.Create(threadingContext, controller:=controller.Object) - Dim model = New Model() - Dim checkpoint1 = New Checkpoint - Dim checkpoint2 = New Checkpoint - Dim checkpoint3 = New Checkpoint - - token.Setup(Sub(t) t.Dispose()).Callback(Sub() checkpoint3.Release()) - - modelComputation.ChainTaskAndNotifyControllerWhenFinished(Function(m, c) - checkpoint1.Release() - checkpoint2.Task.Wait() - c.ThrowIfCancellationRequested() - Return Task.FromResult(model) - End Function) - Await checkpoint1.Task - modelComputation.Stop() - checkpoint2.Release() - Await checkpoint3.Task - - controller.Verify(Sub(c) c.OnModelUpdated(model, True), Times.Never) - End Function - - End Class -End Namespace diff --git a/src/EditorFeatures/Test2/IntelliSense/SessionTests.vb b/src/EditorFeatures/Test2/IntelliSense/SessionTests.vb index a1aeeaf6d1a43..cdb99aaf35b2f 100644 --- a/src/EditorFeatures/Test2/IntelliSense/SessionTests.vb +++ b/src/EditorFeatures/Test2/IntelliSense/SessionTests.vb @@ -24,7 +24,7 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.IntelliSense controller.Setup(Sub(c) c.StopModelComputation()) Dim session = New Session(Of IController(Of Model), Model, IIntelliSensePresenterSession)( controller.Object, - New ModelComputation(Of Model)(threadingContext, controller.Object, TaskScheduler.Default), + New ModelComputation(Of Model)(threadingContext, controller.Object), presenter.Object) presenter.Raise(Sub(p) AddHandler p.Dismissed, Nothing, New EventArgs()) @@ -41,7 +41,7 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.IntelliSense Dim controller = New Mock(Of IController(Of Model))(MockBehavior.Strict) Dim session = New Session(Of IController(Of Model), Model, IIntelliSensePresenterSession)( controller.Object, - New ModelComputation(Of Model)(threadingContext, controller.Object, TaskScheduler.Default), + New ModelComputation(Of Model)(threadingContext, controller.Object), presenter.Object) session.Stop() diff --git a/src/EditorFeatures/Test2/IntelliSense/SignatureHelpControllerTests.vb b/src/EditorFeatures/Test2/IntelliSense/SignatureHelpControllerTests.vb index 0b99ed7563aa2..2409e8479831e 100644 --- a/src/EditorFeatures/Test2/IntelliSense/SignatureHelpControllerTests.vb +++ b/src/EditorFeatures/Test2/IntelliSense/SignatureHelpControllerTests.vb @@ -25,61 +25,37 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.IntelliSense <[UseExportProvider]> Public Class SignatureHelpControllerTests - Public Sub InvokeSignatureHelpWithoutDocumentShouldNotStartNewSession() + Public Async Function InvokeSignatureHelpWithoutDocumentShouldNotStartNewSession() As Task Dim emptyProvider = New Mock(Of IDocumentProvider)(MockBehavior.Strict) emptyProvider.Setup(Function(p) p.GetDocument(It.IsAny(Of ITextSnapshot), It.IsAny(Of CancellationToken))).Returns(DirectCast(Nothing, Document)) - Dim controller As Controller = CreateController(CreateWorkspace(), documentProvider:=emptyProvider) + Dim controller As Controller = Await CreateController(CreateWorkspace(), documentProvider:=emptyProvider) GetMocks(controller).PresenterSession.Setup(Sub(p) p.Dismiss()) - controller.WaitForController() + Await controller.WaitForModelComputation_ForTestingPurposesOnlyAsync() Assert.Equal(0, GetMocks(controller).Provider.GetItemsCount) - End Sub + End Function - Public Sub InvokeSignatureHelpWithDocumentShouldStartNewSession() - Dim controller = CreateController(CreateWorkspace()) + Public Async Function InvokeSignatureHelpWithDocumentShouldStartNewSession() As Task + Dim controller = Await CreateController(CreateWorkspace()) GetMocks(controller).Presenter.Verify(Function(p) p.CreateSession(It.IsAny(Of ITextView), It.IsAny(Of ITextBuffer), It.IsAny(Of ISignatureHelpSession)), Times.Once) - End Sub + End Function - Public Sub EmptyModelShouldStopSession() + Public Async Function EmptyModelShouldStopSession() As Task Dim presenterSession = New Mock(Of ISignatureHelpPresenterSession)(MockBehavior.Strict) presenterSession.Setup(Sub(p) p.Dismiss()) - Dim controller = CreateController(CreateWorkspace(), presenterSession:=presenterSession, items:={}, waitForPresentation:=True) - - GetMocks(controller).PresenterSession.Verify(Sub(p) p.Dismiss(), Times.Once) - End Sub - - - Public Sub UpKeyShouldDismissWhenThereIsOnlyOneItem() - Dim controller = CreateController(CreateWorkspace(), items:=CreateItems(1), waitForPresentation:=True) - - GetMocks(controller).PresenterSession.Setup(Sub(p) p.Dismiss()) - - Dim handled = controller.TryHandleUpKey() + Dim controller = Await CreateController(CreateWorkspace(), presenterSession:=presenterSession, items:={}, waitForPresentation:=True) - Assert.False(handled) GetMocks(controller).PresenterSession.Verify(Sub(p) p.Dismiss(), Times.Once) - End Sub - - - Public Sub UpKeyShouldNavigateWhenThereAreMultipleItems() - Dim controller = CreateController(CreateWorkspace(), items:=CreateItems(2), waitForPresentation:=True) - - GetMocks(controller).PresenterSession.Setup(Sub(p) p.SelectPreviousItem()) - - Dim handled = controller.TryHandleUpKey() - - Assert.True(handled) - GetMocks(controller).PresenterSession.Verify(Sub(p) p.SelectPreviousItem(), Times.Once) - End Sub + End Function - Public Sub UpKeyShouldNotCrashWhenSessionIsDismissed() + Public Async Function UpKeyShouldNotCrashWhenSessionIsDismissed() As Task Dim options = New MemberDisplayOptions() ' Create a provider that will return an empty state when queried the second time @@ -88,7 +64,7 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.IntelliSense slowProvider.Setup(Function(p) p.IsRetriggerCharacter(" "c)).Returns(True) slowProvider.Setup(Function(p) p.GetItemsAsync(It.IsAny(Of Document), It.IsAny(Of Integer), It.IsAny(Of SignatureHelpTriggerInfo), options, It.IsAny(Of CancellationToken))) _ .Returns(Task.FromResult(New SignatureHelpItems(CreateItems(2), TextSpan.FromBounds(0, 0), selectedItem:=0, semanticParameterIndex:=0, syntacticArgumentCount:=0, argumentName:=Nothing))) - Dim controller = CreateController(CreateWorkspace(), provider:=slowProvider.Object, waitForPresentation:=True) + Dim controller = Await CreateController(CreateWorkspace(), provider:=slowProvider.Object, waitForPresentation:=True) ' Now force an update to the model that will result in stopping the session slowProvider.Setup(Function(p) p.GetItemsAsync(It.IsAny(Of Document), It.IsAny(Of Integer), It.IsAny(Of SignatureHelpTriggerInfo), options, It.IsAny(Of CancellationToken))) _ @@ -97,164 +73,42 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.IntelliSense DirectCast(controller, IChainedCommandHandler(Of TypeCharCommandArgs)).ExecuteCommand( New TypeCharCommandArgs(CreateMock(Of ITextView), CreateMock(Of ITextBuffer), " "c), Sub() GetMocks(controller).Buffer.Insert(0, " "), TestCommandExecutionContext.Create()) - - GetMocks(controller).PresenterSession.Setup(Sub(p) p.Dismiss()) - - Dim handled = controller.TryHandleUpKey() ' this will block on the model being updated which should dismiss the session - - Assert.False(handled) - GetMocks(controller).PresenterSession.Verify(Sub(p) p.Dismiss(), Times.Once) - End Sub - - - Public Sub DownKeyShouldNotBlockOnModelComputation() - Dim options = New MemberDisplayOptions() - Dim mre = New ManualResetEvent(False) - Dim controller = CreateController(CreateWorkspace(), items:=CreateItems(2), waitForPresentation:=False) - Dim slowProvider = New Mock(Of ISignatureHelpProvider)(MockBehavior.Strict) - slowProvider.Setup(Function(p) p.GetItemsAsync(It.IsAny(Of Document), It.IsAny(Of Integer), It.IsAny(Of SignatureHelpTriggerInfo), options, It.IsAny(Of CancellationToken))) _ - .Returns(Function() - mre.WaitOne() - Return Task.FromResult(New SignatureHelpItems(CreateItems(2), TextSpan.FromBounds(0, 0), selectedItem:=0, semanticParameterIndex:=0, syntacticArgumentCount:=0, argumentName:=Nothing)) - End Function) - - GetMocks(controller).PresenterSession.Setup(Sub(p) p.Dismiss()) - GetMocks(controller).PresenterSession.Setup(Function(p) p.EditorSessionIsActive).Returns(False) - - Dim handled = controller.TryHandleDownKey() - - Assert.False(handled) - End Sub - - - Public Sub UpKeyShouldNotBlockOnModelComputation() - Dim options = New MemberDisplayOptions() - Dim mre = New ManualResetEvent(False) - Dim controller = CreateController(CreateWorkspace(), items:=CreateItems(2), waitForPresentation:=False) - Dim slowProvider = New Mock(Of ISignatureHelpProvider)(MockBehavior.Strict) - slowProvider.Setup(Function(p) p.GetItemsAsync(It.IsAny(Of Document), It.IsAny(Of Integer), It.IsAny(Of SignatureHelpTriggerInfo), options, It.IsAny(Of CancellationToken))) _ - .Returns(Function() - mre.WaitOne() - Return Task.FromResult(New SignatureHelpItems(CreateItems(2), TextSpan.FromBounds(0, 0), selectedItem:=0, semanticParameterIndex:=0, syntacticArgumentCount:=0, argumentName:=Nothing)) - End Function) - - GetMocks(controller).PresenterSession.Setup(Sub(p) p.Dismiss()) - GetMocks(controller).PresenterSession.Setup(Function(p) p.EditorSessionIsActive).Returns(False) - - Dim handled = controller.TryHandleUpKey() - - Assert.False(handled) - End Sub - - - Public Async Function UpKeyShouldBlockOnRecomputationAfterPresentation() As Task - Dim options = New MemberDisplayOptions() - Dim workspace = CreateWorkspace() - Dim threadingContext = workspace.GetService(Of IThreadingContext)() - - Dim worker = Async Function() - Dim slowProvider = New Mock(Of ISignatureHelpProvider)(MockBehavior.Strict) - slowProvider.Setup(Function(p) p.IsTriggerCharacter(" "c)).Returns(True) - slowProvider.Setup(Function(p) p.IsRetriggerCharacter(" "c)).Returns(True) - slowProvider.Setup(Function(p) p.GetItemsAsync(It.IsAny(Of Document), It.IsAny(Of Integer), It.IsAny(Of SignatureHelpTriggerInfo), options, It.IsAny(Of CancellationToken))) _ - .Returns(Task.FromResult(New SignatureHelpItems(CreateItems(2), TextSpan.FromBounds(0, 0), selectedItem:=0, semanticParameterIndex:=0, syntacticArgumentCount:=0, argumentName:=Nothing))) - - Await threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync() - Dim controller = CreateController(workspace, provider:=slowProvider.Object, waitForPresentation:=True) - - ' Update session so that providers are requeried. - ' SlowProvider now blocks on the checkpoint's task. - Dim checkpoint = New Checkpoint() - slowProvider.Setup(Function(p) p.GetItemsAsync(It.IsAny(Of Document), It.IsAny(Of Integer), It.IsAny(Of SignatureHelpTriggerInfo), options, It.IsAny(Of CancellationToken))) _ - .Returns(Function() - checkpoint.Task.Wait() - Return Task.FromResult(New SignatureHelpItems(CreateItems(2), TextSpan.FromBounds(0, 2), selectedItem:=0, semanticParameterIndex:=0, syntacticArgumentCount:=0, argumentName:=Nothing)) - End Function) - - Await threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync() - DirectCast(controller, IChainedCommandHandler(Of TypeCharCommandArgs)).ExecuteCommand( - New TypeCharCommandArgs(CreateMock(Of ITextView), CreateMock(Of ITextBuffer), " "c), - Sub() GetMocks(controller).Buffer.Insert(0, " "), TestCommandExecutionContext.Create()) - - GetMocks(controller).PresenterSession.Setup(Sub(p) p.SelectPreviousItem()) - - Dim handled = threadingContext.JoinableTaskFactory.RunAsync(Async Function() - Await Task.Yield() - ' Send the controller an up key, which should block on the computation - Return controller.TryHandleUpKey() - End Function) - checkpoint.Release() ' Allow slowprovider to finish - Await handled.JoinAsync().ConfigureAwait(False) - - ' We expect 2 calls to the presenter (because we had an existing presentation session when we started the second computation). - Assert.True(handled.Task.Result) - GetMocks(controller).PresenterSession.Verify(Sub(p) p.PresentItems(It.IsAny(Of ITrackingSpan), It.IsAny(Of IList(Of SignatureHelpItem)), - It.IsAny(Of SignatureHelpItem), It.IsAny(Of Integer?)), Times.Exactly(2)) - End Function - - Await worker().ConfigureAwait(False) - End Function - Public Sub DownKeyShouldNavigateWhenThereAreMultipleItems() - Dim controller = CreateController(CreateWorkspace(), items:=CreateItems(2), waitForPresentation:=True) - - GetMocks(controller).PresenterSession.Setup(Sub(p) p.SelectNextItem()) - - Dim handled = controller.TryHandleDownKey() - - Assert.True(handled) - GetMocks(controller).PresenterSession.Verify(Sub(p) p.SelectNextItem(), Times.Once) - End Sub - - - Public Sub UpAndDownKeysShouldStillNavigateWhenDuplicateItemsAreFiltered() - Dim item = CreateItems(1).Single() - Dim controller = CreateController(CreateWorkspace(), items:={item, item}, waitForPresentation:=True) - - GetMocks(controller).PresenterSession.Setup(Sub(p) p.Dismiss()) - - Dim handled = controller.TryHandleUpKey() - - Assert.False(handled) - GetMocks(controller).PresenterSession.Verify(Sub(p) p.Dismiss(), Times.Once) - End Sub - - - Public Sub CaretMoveWithActiveSessionShouldRecomputeModel() - Dim controller = CreateController(CreateWorkspace(), waitForPresentation:=True) + Public Async Function CaretMoveWithActiveSessionShouldRecomputeModel() As Task + Dim controller = Await CreateController(CreateWorkspace(), waitForPresentation:=True) Mock.Get(GetMocks(controller).View.Object.Caret).Raise(Sub(c) AddHandler c.PositionChanged, Nothing, New CaretPositionChangedEventArgs(Nothing, Nothing, Nothing)) - controller.WaitForController() + Await controller.WaitForModelComputation_ForTestingPurposesOnlyAsync() ' GetItemsAsync is called once initially, and then once as a result of handling the PositionChanged event Assert.Equal(2, GetMocks(controller).Provider.GetItemsCount) - End Sub + End Function - Public Sub RetriggerActiveSessionOnClosingBrace() - Dim controller = CreateController(CreateWorkspace(), waitForPresentation:=True) + Public Async Function RetriggerActiveSessionOnClosingBrace() As Task + Dim controller = Await CreateController(CreateWorkspace(), waitForPresentation:=True) DirectCast(controller, IChainedCommandHandler(Of TypeCharCommandArgs)).ExecuteCommand( New TypeCharCommandArgs(CreateMock(Of ITextView), CreateMock(Of ITextBuffer), ")"c), Sub() GetMocks(controller).Buffer.Insert(0, ")"), TestCommandExecutionContext.Create()) - controller.WaitForController() + Await controller.WaitForModelComputation_ForTestingPurposesOnlyAsync() ' GetItemsAsync is called once initially, and then once as a result of handling the typechar command Assert.Equal(2, GetMocks(controller).Provider.GetItemsCount) - End Sub + End Function - Public Sub TypingNonTriggerCharacterShouldNotRequestDocument() - Dim controller = CreateController(CreateWorkspace(), triggerSession:=False) + Public Async Function TypingNonTriggerCharacterShouldNotRequestDocument() As Task + Dim controller = Await CreateController(CreateWorkspace(), triggerSession:=False) DirectCast(controller, IChainedCommandHandler(Of TypeCharCommandArgs)).ExecuteCommand( New TypeCharCommandArgs(CreateMock(Of ITextView), CreateMock(Of ITextBuffer), "a"c), Sub() GetMocks(controller).Buffer.Insert(0, "a"), TestCommandExecutionContext.Create()) GetMocks(controller).DocumentProvider.Verify(Function(p) p.GetDocument(It.IsAny(Of ITextSnapshot), It.IsAny(Of CancellationToken)), Times.Never) - End Sub + End Function Private Shared ReadOnly s_controllerMocksMap As New ConditionalWeakTable(Of Controller, ControllerMocks) Private Shared Function GetMocks(controller As Controller) As ControllerMocks @@ -273,13 +127,14 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.IntelliSense , composition:=EditorTestCompositions.EditorFeatures) End Function - Private Shared Function CreateController(workspace As TestWorkspace, - Optional documentProvider As Mock(Of IDocumentProvider) = Nothing, - Optional presenterSession As Mock(Of ISignatureHelpPresenterSession) = Nothing, - Optional items As IList(Of SignatureHelpItem) = Nothing, - Optional provider As ISignatureHelpProvider = Nothing, - Optional waitForPresentation As Boolean = False, - Optional triggerSession As Boolean = True) As Controller + Private Shared Async Function CreateController( + workspace As TestWorkspace, + Optional documentProvider As Mock(Of IDocumentProvider) = Nothing, + Optional presenterSession As Mock(Of ISignatureHelpPresenterSession) = Nothing, + Optional items As IList(Of SignatureHelpItem) = Nothing, + Optional provider As ISignatureHelpProvider = Nothing, + Optional waitForPresentation As Boolean = False, + Optional triggerSession As Boolean = True) As Task(Of Controller) Dim document = workspace.CurrentSolution.GetDocument(workspace.Documents.Single().Id) Dim threadingContext = workspace.GetService(Of IThreadingContext) @@ -330,7 +185,7 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.IntelliSense DirectCast(controller, IChainedCommandHandler(Of InvokeSignatureHelpCommandArgs)).ExecuteCommand( New InvokeSignatureHelpCommandArgs(view.Object, buffer), Nothing, TestCommandExecutionContext.Create()) If waitForPresentation Then - controller.WaitForController() + Await controller.WaitForModelComputation_ForTestingPurposesOnlyAsync() End If End If diff --git a/src/EditorFeatures/Test2/ReferenceHighlighting/CSharpReferenceHighlightingTests.vb b/src/EditorFeatures/Test2/ReferenceHighlighting/CSharpReferenceHighlightingTests.vb index a1ea88a9c4d59..67fe4efaf2994 100644 --- a/src/EditorFeatures/Test2/ReferenceHighlighting/CSharpReferenceHighlightingTests.vb +++ b/src/EditorFeatures/Test2/ReferenceHighlighting/CSharpReferenceHighlightingTests.vb @@ -5,7 +5,7 @@ Imports Microsoft.CodeAnalysis.Remote.Testing Namespace Microsoft.CodeAnalysis.Editor.UnitTests.ReferenceHighlighting - Public Class CSharpReferenceHighlightingTests + Public NotInheritable Class CSharpReferenceHighlightingTests Inherits AbstractReferenceHighlightingTests diff --git a/src/EditorFeatures/Test2/Rename/RenameTagProducerTests.vb b/src/EditorFeatures/Test2/Rename/RenameTagProducerTests.vb index 8a3efbe29e7f9..043732945a107 100644 --- a/src/EditorFeatures/Test2/Rename/RenameTagProducerTests.vb +++ b/src/EditorFeatures/Test2/Rename/RenameTagProducerTests.vb @@ -352,12 +352,11 @@ public class Class1 void Test(int i) {{ }} void M() {{ -{{|conflict:{{|conflict:/* {String.Format(WorkspacesResources.Unmerged_change_from_project_0, "CSharpAssembly1")} -{WorkspacesResources.Before_colon} +{{|conflict:{{|conflict:<<<<<<< {String.Format(WorkspacesResources.TODO_Unmerged_change_from_project_0, "CSharpAssembly1")}, {WorkspacesResources.Before_colon} Test(5); -{WorkspacesResources.After_colon} +======= Test((long)5); -*|}}|}}/ +>>>>>>> {WorkspacesResources.After}|}}|}} Test((double)5); }} }}" diff --git a/src/EditorFeatures/Test2/Simplification/AbstractSimplificationTests.vb b/src/EditorFeatures/Test2/Simplification/AbstractSimplificationTests.vb index 223273cfd4e09..5b1eb5edb3dcc 100644 --- a/src/EditorFeatures/Test2/Simplification/AbstractSimplificationTests.vb +++ b/src/EditorFeatures/Test2/Simplification/AbstractSimplificationTests.vb @@ -131,7 +131,7 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.Simplification End Function Private Shared Function GetExpressionSyntaxWithSameSpan(node As SyntaxNode, spanEnd As Integer) As SyntaxNode - While Not node Is Nothing And Not node.Parent Is Nothing And node.Parent.SpanStart = node.SpanStart + While node IsNot Nothing And node.Parent IsNot Nothing And node.Parent.SpanStart = node.SpanStart node = node.Parent If node.Span.End = spanEnd Then Exit While diff --git a/src/EditorFeatures/TestUtilities/ChangeSignature/TestChangeSignatureOptionsService.cs b/src/EditorFeatures/TestUtilities/ChangeSignature/TestChangeSignatureOptionsService.cs index 7025cbf43b80a..18d1b47e9c2d4 100644 --- a/src/EditorFeatures/TestUtilities/ChangeSignature/TestChangeSignatureOptionsService.cs +++ b/src/EditorFeatures/TestUtilities/ChangeSignature/TestChangeSignatureOptionsService.cs @@ -11,34 +11,29 @@ using Microsoft.CodeAnalysis.Test.Utilities.ChangeSignature; using Roslyn.Utilities; -namespace Microsoft.CodeAnalysis.Editor.UnitTests.ChangeSignature -{ - [ExportWorkspaceService(typeof(IChangeSignatureOptionsService), ServiceLayer.Test), Shared, PartNotDiscoverable] - internal class TestChangeSignatureOptionsService : IChangeSignatureOptionsService - { - public AddedParameterOrExistingIndex[]? UpdatedSignature = null; +namespace Microsoft.CodeAnalysis.Editor.UnitTests.ChangeSignature; - [ImportingConstructor] - [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - public TestChangeSignatureOptionsService() - { - } +[ExportWorkspaceService(typeof(IChangeSignatureOptionsService), ServiceLayer.Test), Shared, PartNotDiscoverable] +[method: ImportingConstructor] +[method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] +internal sealed class TestChangeSignatureOptionsService() : IChangeSignatureOptionsService +{ + public AddedParameterOrExistingIndex[]? UpdatedSignature = null; - ChangeSignatureOptionsResult IChangeSignatureOptionsService.GetChangeSignatureOptions( - Document document, - int positionForTypeBinding, - ISymbol symbol, - ParameterConfiguration parameters) - { - var list = parameters.ToListOfParameters(); - var updateParameters = UpdatedSignature != null - ? UpdatedSignature.Select(item => item.IsExisting ? list[item.OldIndex ?? -1] : item.GetAddedParameter(document)).ToImmutableArray() - : new ImmutableArray(); - return new ChangeSignatureOptionsResult(new SignatureChange( - parameters, - UpdatedSignature == null - ? parameters - : ParameterConfiguration.Create(updateParameters, parameters.ThisParameter != null, selectedIndex: 0)), previewChanges: false); - } + ChangeSignatureOptionsResult IChangeSignatureOptionsService.GetChangeSignatureOptions( + SemanticDocument document, + int positionForTypeBinding, + ISymbol symbol, + ParameterConfiguration parameters) + { + var list = parameters.ToListOfParameters(); + var updateParameters = UpdatedSignature != null + ? [.. UpdatedSignature.Select(item => item.IsExisting ? list[item.OldIndex ?? -1] : item.GetAddedParameter(document.Document))] + : new ImmutableArray(); + return new ChangeSignatureOptionsResult(new SignatureChange( + parameters, + UpdatedSignature == null + ? parameters + : ParameterConfiguration.Create(updateParameters, parameters.ThisParameter != null, selectedIndex: 0)), previewChanges: false); } } diff --git a/src/EditorFeatures/TestUtilities/Classification/AbstractClassifierTests.cs b/src/EditorFeatures/TestUtilities/Classification/AbstractClassifierTests.cs index 6e9f9b7b8dcee..2b60abf89acd3 100644 --- a/src/EditorFeatures/TestUtilities/Classification/AbstractClassifierTests.cs +++ b/src/EditorFeatures/TestUtilities/Classification/AbstractClassifierTests.cs @@ -45,7 +45,7 @@ protected async Task TestAsync( { var start = allCode.IndexOf(code, StringComparison.Ordinal); var length = code.Length; - spans = ImmutableArray.Create(new TextSpan(start, length)); + spans = [new TextSpan(start, length)]; } else { @@ -56,7 +56,7 @@ protected async Task TestAsync( } else { - spans = ImmutableArray.Create(new TextSpan(0, allCode.Length)); + spans = [new TextSpan(0, allCode.Length)]; } } @@ -65,7 +65,7 @@ protected async Task TestAsync( var actualOrdered = actual.OrderBy((t1, t2) => t1.TextSpan.Start - t2.TextSpan.Start); var actualFormatted = actualOrdered.SelectAsArray(a => new FormattedClassification(allCode.Substring(a.TextSpan.Start, a.TextSpan.Length), a.ClassificationType)); - AssertEx.Equal(expected.ToImmutableArray(), actualFormatted); + AssertEx.Equal([.. expected], actualFormatted); } private async Task TestAsync( @@ -273,7 +273,7 @@ protected static async Task> GetSemanticClassific using var _ = Classifier.GetPooledList(out var result); await service.AddSemanticClassificationsAsync(document, spans, options, result, CancellationToken.None); await service.AddEmbeddedLanguageClassificationsAsync(document, spans, options, result, CancellationToken.None); - return result.ToImmutableArray(); + return [.. result]; } protected static async Task> GetSyntacticClassificationsAsync(Document document, ImmutableArray spans) @@ -283,7 +283,7 @@ protected static async Task> GetSyntacticClassifi using var _ = Classifier.GetPooledList(out var results); service.AddSyntacticClassifications(root, spans, results, CancellationToken.None); - return results.ToImmutableArray(); + return [.. results]; } protected static async Task> GetAllClassificationsAsync(Document document, ImmutableArray spans) @@ -303,7 +303,7 @@ from t in syntacticClassifications where !classificationsSpans.Contains(t.TextSpan) select t); - return allClassifications.ToImmutableArray(); + return [.. allClassifications]; } } } diff --git a/src/EditorFeatures/TestUtilities/Completion/AbstractCompletionProviderTests.cs b/src/EditorFeatures/TestUtilities/Completion/AbstractCompletionProviderTests.cs index 3725fdab236d6..55e0869431cca 100644 --- a/src/EditorFeatures/TestUtilities/Completion/AbstractCompletionProviderTests.cs +++ b/src/EditorFeatures/TestUtilities/Completion/AbstractCompletionProviderTests.cs @@ -102,7 +102,7 @@ protected static async Task CanUseSpeculativeSemanticModelAsync(Document d internal virtual CompletionService GetCompletionService(Project project) { var completionService = project.Services.GetRequiredService(); - var completionProviders = completionService.GetTestAccessor().GetImportedAndBuiltInProviders(ImmutableHashSet.Empty); + var completionProviders = completionService.GetTestAccessor().GetImportedAndBuiltInProviders([]); var completionProvider = Assert.Single(completionProviders); Assert.IsType(GetCompletionProviderType(), completionProvider); @@ -110,7 +110,7 @@ internal virtual CompletionService GetCompletionService(Project project) } internal static ImmutableHashSet GetRoles(Document document) - => document.SourceCodeKind == SourceCodeKind.Regular ? ImmutableHashSet.Empty : ImmutableHashSet.Create(PredefinedInteractiveTextViewRoles.InteractiveTextViewRole); + => document.SourceCodeKind == SourceCodeKind.Regular ? [] : [PredefinedInteractiveTextViewRoles.InteractiveTextViewRole]; protected abstract string ItemPartiallyWritten(string expectedItemOrNull); diff --git a/src/EditorFeatures/TestUtilities/Debugging/AbstractDataTipInfoGetterTests.cs b/src/EditorFeatures/TestUtilities/Debugging/AbstractDataTipInfoGetterTests.cs new file mode 100644 index 0000000000000..9c966d5b4de63 --- /dev/null +++ b/src/EditorFeatures/TestUtilities/Debugging/AbstractDataTipInfoGetterTests.cs @@ -0,0 +1,75 @@ +// 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.Linq; +using System.Threading; +using System.Threading.Tasks; +using System.Xml.Linq; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp.Debugging; +using Microsoft.CodeAnalysis.Debugging; +using Microsoft.CodeAnalysis.Editor.UnitTests.Extensions; +using Microsoft.CodeAnalysis.Shared.Extensions; +using Microsoft.CodeAnalysis.Text; +using Roslyn.Utilities; +using Xunit; + +namespace Microsoft.CodeAnalysis.Test.Utilities.Debugging; + +public abstract class AbstractDataTipInfoGetterTests +{ + protected abstract EditorTestWorkspace CreateWorkspace(string markup); + + protected Task TestAsync(XElement markup, string? expectedText = null) + => TestAsync(markup.NormalizedValue(), expectedText); + + protected Task TestNoDataTipAsync(XElement markup) + => TestNoDataTipAsync(markup.NormalizedValue()); + + protected async Task TestAsync(string markup, string? expectedText = null) + { + await TestSpanGetterAsync(markup, async (workspace, document, position, expectedSpan) => + { + var service = document.GetRequiredLanguageService(); + var result = await service.GetDataTipInfoAsync(document, position, includeKind: true, CancellationToken.None); + + Assert.Equal(expectedSpan, result.Span); + Assert.Equal(expectedText, result.Text); + + var linqExpressionSpans = workspace.DocumentWithCursor.AnnotatedSpans.GetValueOrDefault("LinqExpression").NullToEmpty(); + + Assert.Equal(result.Kind == DebugDataTipInfoKind.LinqExpression, linqExpressionSpans.Length == 1); + if (linqExpressionSpans.Length == 1) + { + Assert.Equal(linqExpressionSpans.Single(), result.ExpressionSpan); + } + }); + } + + protected async Task TestNoDataTipAsync(string markup) + { + await TestSpanGetterAsync(markup, async (workspace, document, position, expectedSpan) => + { + var result = await DataTipInfoGetter.GetInfoAsync(document, position, includeKind: true, CancellationToken.None); + Assert.True(result.IsDefault); + }); + } + + private async Task TestSpanGetterAsync(string markup, Func continuation) + { + using var workspace = CreateWorkspace(markup); + var testHostDocument = workspace.Documents.Single(); + var position = testHostDocument.CursorPosition!.Value; + var expectedSpan = testHostDocument.SelectedSpans.Any() + ? testHostDocument.SelectedSpans.Single() + : (TextSpan?)null; + + await continuation( + workspace, + workspace.CurrentSolution.Projects.First().Documents.First(), + position, + expectedSpan); + } +} diff --git a/src/EditorFeatures/TestUtilities/Diagnostics/GenerateType/GenerateTypeTestState.cs b/src/EditorFeatures/TestUtilities/Diagnostics/GenerateType/GenerateTypeTestState.cs index 221fceff97804..2f977f5ff775e 100644 --- a/src/EditorFeatures/TestUtilities/Diagnostics/GenerateType/GenerateTypeTestState.cs +++ b/src/EditorFeatures/TestUtilities/Diagnostics/GenerateType/GenerateTypeTestState.cs @@ -15,7 +15,7 @@ namespace Microsoft.CodeAnalysis.Editor.UnitTests.Diagnostics.GenerateType { internal sealed class GenerateTypeTestState { - public static List FixIds = new List(new[] { "CS0246", "CS0234", "CS0103", "BC30002", "BC30451", "BC30456" }); + public static List FixIds = ["CS0246", "CS0234", "CS0103", "BC30002", "BC30451", "BC30456"]; private readonly EditorTestHostDocument _testDocument; public EditorTestWorkspace Workspace { get; } public Document InvocationDocument { get; } diff --git a/src/EditorFeatures/TestUtilities/ExtractInterface/AbstractExtractInterfaceTests.cs b/src/EditorFeatures/TestUtilities/ExtractInterface/AbstractExtractInterfaceTests.cs index a78b7a2ffe961..6e8b6d2f410c5 100644 --- a/src/EditorFeatures/TestUtilities/ExtractInterface/AbstractExtractInterfaceTests.cs +++ b/src/EditorFeatures/TestUtilities/ExtractInterface/AbstractExtractInterfaceTests.cs @@ -10,158 +10,158 @@ using Microsoft.CodeAnalysis.Editor.UnitTests.CodeActions; using Microsoft.CodeAnalysis.Test.Utilities; using Microsoft.CodeAnalysis.VisualBasic; +using Roslyn.Test.Utilities; using Xunit; -namespace Microsoft.CodeAnalysis.Editor.UnitTests.ExtractInterface +namespace Microsoft.CodeAnalysis.Editor.UnitTests.ExtractInterface; + +[UseExportProvider] +public abstract class AbstractExtractInterfaceTests { - [UseExportProvider] - public abstract class AbstractExtractInterfaceTests + public static async Task TestExtractInterfaceCommandCSharpAsync( + string markup, + bool expectedSuccess, + string expectedMemberName = null, + string expectedInterfaceName = null, + string expectedNamespaceName = null, + string expectedTypeParameterSuffix = null, + string expectedUpdatedOriginalDocumentCode = null, + string expectedInterfaceCode = null) { - public static async Task TestExtractInterfaceCommandCSharpAsync( - string markup, - bool expectedSuccess, - string expectedMemberName = null, - string expectedInterfaceName = null, - string expectedNamespaceName = null, - string expectedTypeParameterSuffix = null, - string expectedUpdatedOriginalDocumentCode = null, - string expectedInterfaceCode = null) - { - await TestExtractInterfaceCommandAsync( - markup, - LanguageNames.CSharp, - expectedSuccess, - expectedMemberName, - expectedInterfaceName, - expectedNamespaceName, - expectedTypeParameterSuffix, - expectedUpdatedOriginalDocumentCode, - expectedInterfaceCode); - } + await TestExtractInterfaceCommandAsync( + markup, + LanguageNames.CSharp, + expectedSuccess, + expectedMemberName, + expectedInterfaceName, + expectedNamespaceName, + expectedTypeParameterSuffix, + expectedUpdatedOriginalDocumentCode, + expectedInterfaceCode); + } - public static async Task TestExtractInterfaceCodeActionCSharpAsync( - string markup, - string expectedMarkup) - { - await TestExtractInterfaceCodeActionAsync( - markup, - LanguageNames.CSharp, - expectedMarkup); - } + public static async Task TestExtractInterfaceCodeActionCSharpAsync( + string markup, + string expectedMarkup) + { + await TestExtractInterfaceCodeActionAsync( + markup, + LanguageNames.CSharp, + expectedMarkup); + } - public static async Task TestExtractInterfaceCommandVisualBasicAsync( - string markup, - bool expectedSuccess, - string expectedMemberName = null, - string expectedInterfaceName = null, - string expectedNamespaceName = null, - string expectedTypeParameterSuffix = null, - string expectedUpdatedOriginalDocumentCode = null, - string expectedInterfaceCode = null, - string rootNamespace = null) - { - await TestExtractInterfaceCommandAsync( - markup, - LanguageNames.VisualBasic, - expectedSuccess, - expectedMemberName, - expectedInterfaceName, - expectedNamespaceName, - expectedTypeParameterSuffix, - expectedUpdatedOriginalDocumentCode, - expectedInterfaceCode, - new VisualBasicCompilationOptions(OutputKind.DynamicallyLinkedLibrary, rootNamespace: rootNamespace)); - } + public static async Task TestExtractInterfaceCommandVisualBasicAsync( + string markup, + bool expectedSuccess, + string expectedMemberName = null, + string expectedInterfaceName = null, + string expectedNamespaceName = null, + string expectedTypeParameterSuffix = null, + string expectedUpdatedOriginalDocumentCode = null, + string expectedInterfaceCode = null, + string rootNamespace = null) + { + await TestExtractInterfaceCommandAsync( + markup, + LanguageNames.VisualBasic, + expectedSuccess, + expectedMemberName, + expectedInterfaceName, + expectedNamespaceName, + expectedTypeParameterSuffix, + expectedUpdatedOriginalDocumentCode, + expectedInterfaceCode, + new VisualBasicCompilationOptions(OutputKind.DynamicallyLinkedLibrary, rootNamespace: rootNamespace)); + } - public static async Task TestExtractInterfaceCodeActionVisualBasicAsync( - string markup, - string expectedMarkup) - { - await TestExtractInterfaceCodeActionAsync( - markup, - LanguageNames.VisualBasic, - expectedMarkup); - } + public static async Task TestExtractInterfaceCodeActionVisualBasicAsync( + string markup, + string expectedMarkup) + { + await TestExtractInterfaceCodeActionAsync( + markup, + LanguageNames.VisualBasic, + expectedMarkup); + } + + private static async Task TestExtractInterfaceCommandAsync( + string markup, + string languageName, + bool expectedSuccess, + string expectedMemberName = null, + string expectedInterfaceName = null, + string expectedNamespaceName = null, + string expectedTypeParameterSuffix = null, + string expectedUpdatedOriginalDocumentCode = null, + string expectedInterfaceCode = null, + CompilationOptions compilationOptions = null) + { + using var testState = ExtractInterfaceTestState.Create(markup, languageName, compilationOptions, + options: new OptionsCollection(languageName) + { + { CodeStyleOptions2.AccessibilityModifiersRequired, AccessibilityModifiersRequired.Never, NotificationOption2.Silent } + }); - private static async Task TestExtractInterfaceCommandAsync( - string markup, - string languageName, - bool expectedSuccess, - string expectedMemberName = null, - string expectedInterfaceName = null, - string expectedNamespaceName = null, - string expectedTypeParameterSuffix = null, - string expectedUpdatedOriginalDocumentCode = null, - string expectedInterfaceCode = null, - CompilationOptions compilationOptions = null) + var result = await testState.ExtractViaCommandAsync(); + + if (expectedSuccess) { - using var testState = ExtractInterfaceTestState.Create(markup, languageName, compilationOptions, - options: new OptionsCollection(languageName) - { - { CodeStyleOptions2.AccessibilityModifiersRequired, AccessibilityModifiersRequired.Never, NotificationOption2.Silent } - }); + Assert.True(result.Succeeded); + Assert.False(testState.Workspace.Documents.Select(d => d.Id).Contains(result.NavigationDocumentId)); + Assert.NotNull(result.UpdatedSolution.GetDocument(result.NavigationDocumentId)); - var result = await testState.ExtractViaCommandAsync(); + if (expectedMemberName != null) + { + Assert.Equal(1, testState.TestExtractInterfaceOptionsService.AllExtractableMembers.Count()); + Assert.Equal(expectedMemberName, testState.TestExtractInterfaceOptionsService.AllExtractableMembers.Single().Name); + } - if (expectedSuccess) + if (expectedInterfaceName != null) { - Assert.True(result.Succeeded); - Assert.False(testState.Workspace.Documents.Select(d => d.Id).Contains(result.NavigationDocumentId)); - Assert.NotNull(result.UpdatedSolution.GetDocument(result.NavigationDocumentId)); - - if (expectedMemberName != null) - { - Assert.Equal(1, testState.TestExtractInterfaceOptionsService.AllExtractableMembers.Count()); - Assert.Equal(expectedMemberName, testState.TestExtractInterfaceOptionsService.AllExtractableMembers.Single().Name); - } - - if (expectedInterfaceName != null) - { - Assert.Equal(expectedInterfaceName, testState.TestExtractInterfaceOptionsService.DefaultInterfaceName); - } - - if (expectedNamespaceName != null) - { - Assert.Equal(expectedNamespaceName, testState.TestExtractInterfaceOptionsService.DefaultNamespace); - } - - if (expectedTypeParameterSuffix != null) - { - Assert.Equal(expectedTypeParameterSuffix, testState.TestExtractInterfaceOptionsService.GeneratedNameTypeParameterSuffix); - } - - if (expectedUpdatedOriginalDocumentCode != null) - { - var updatedOriginalDocument = result.UpdatedSolution.GetDocument(testState.ExtractFromDocument.Id); - var updatedCode = (await updatedOriginalDocument.GetTextAsync()).ToString(); - Assert.Equal(expectedUpdatedOriginalDocumentCode, updatedCode); - } - - if (expectedInterfaceCode != null) - { - var interfaceDocument = result.UpdatedSolution.GetDocument(result.NavigationDocumentId); - var interfaceCode = (await interfaceDocument.GetTextAsync()).ToString(); - Assert.Equal(expectedInterfaceCode, interfaceCode); - } + Assert.Equal(expectedInterfaceName, testState.TestExtractInterfaceOptionsService.DefaultInterfaceName); } - else + + if (expectedNamespaceName != null) { - Assert.False(result.Succeeded); + Assert.Equal(expectedNamespaceName, testState.TestExtractInterfaceOptionsService.DefaultNamespace); } - } - private static async Task TestExtractInterfaceCodeActionAsync( - string markup, - string languageName, - string expectedMarkup, - CompilationOptions compilationOptions = null) - { - using var testState = ExtractInterfaceTestState.Create(markup, languageName, compilationOptions); + if (expectedTypeParameterSuffix != null) + { + Assert.Equal(expectedTypeParameterSuffix, testState.TestExtractInterfaceOptionsService.GeneratedNameTypeParameterSuffix); + } - var updatedSolution = await testState.ExtractViaCodeAction(); - var updatedDocument = updatedSolution.GetDocument(testState.ExtractFromDocument.Id); - var updatedCode = (await updatedDocument.GetTextAsync()).ToString(); - Assert.Equal(expectedMarkup, updatedCode); + if (expectedUpdatedOriginalDocumentCode != null) + { + var updatedOriginalDocument = result.UpdatedSolution.GetDocument(testState.ExtractFromDocument.Id); + var updatedCode = (await updatedOriginalDocument.GetTextAsync()).ToString(); + Assert.Equal(expectedUpdatedOriginalDocumentCode, updatedCode); + } + + if (expectedInterfaceCode != null) + { + var interfaceDocument = result.UpdatedSolution.GetDocument(result.NavigationDocumentId); + var interfaceCode = (await interfaceDocument.GetTextAsync()).ToString(); + Assert.Equal(expectedInterfaceCode, interfaceCode); + } + } + else + { + Assert.False(result.Succeeded); } } + + private static async Task TestExtractInterfaceCodeActionAsync( + string markup, + string languageName, + string expectedMarkup, + CompilationOptions compilationOptions = null) + { + using var testState = ExtractInterfaceTestState.Create(markup, languageName, compilationOptions); + + var updatedSolution = await testState.ExtractViaCodeAction(); + var updatedDocument = updatedSolution.GetDocument(testState.ExtractFromDocument.Id); + var updatedCode = (await updatedDocument.GetTextAsync()).ToString(); + AssertEx.Equal(expectedMarkup, updatedCode); + } } diff --git a/src/EditorFeatures/TestUtilities/ExtractInterface/ExtractInterfaceTestState.cs b/src/EditorFeatures/TestUtilities/ExtractInterface/ExtractInterfaceTestState.cs index 1874449ca25d0..3c3d768448bb6 100644 --- a/src/EditorFeatures/TestUtilities/ExtractInterface/ExtractInterfaceTestState.cs +++ b/src/EditorFeatures/TestUtilities/ExtractInterface/ExtractInterfaceTestState.cs @@ -8,6 +8,7 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; +using System.Xml.Linq; using Microsoft.CodeAnalysis.Editor.UnitTests.CodeActions; using Microsoft.CodeAnalysis.ExtractInterface; using Microsoft.CodeAnalysis.Notification; @@ -38,10 +39,12 @@ public static ExtractInterfaceTestState Create( ParseOptions parseOptions = null, OptionsCollection options = null) { - var workspace = languageName == LanguageNames.CSharp - ? EditorTestWorkspace.CreateCSharp(markup, composition: Composition, compilationOptions: compilationOptions, parseOptions: parseOptions) - : EditorTestWorkspace.CreateVisualBasic(markup, composition: Composition, compilationOptions: compilationOptions, parseOptions: parseOptions); - + var workspace = + markup.Trim().StartsWith("") + ? EditorTestWorkspace.CreateWorkspace(XElement.Parse(markup), composition: Composition) + : languageName == LanguageNames.CSharp + ? EditorTestWorkspace.CreateCSharp(markup, composition: Composition, compilationOptions: compilationOptions, parseOptions: parseOptions) + : EditorTestWorkspace.CreateVisualBasic(markup, composition: Composition, compilationOptions: compilationOptions, parseOptions: parseOptions); workspace.SetAnalyzerFallbackAndGlobalOptions(options); return new ExtractInterfaceTestState(workspace); diff --git a/src/EditorFeatures/TestUtilities/ExtractInterface/TestExtractInterfaceOptions.cs b/src/EditorFeatures/TestUtilities/ExtractInterface/TestExtractInterfaceOptions.cs index 01a72da76d171..b2b8c730ec0e7 100644 --- a/src/EditorFeatures/TestUtilities/ExtractInterface/TestExtractInterfaceOptions.cs +++ b/src/EditorFeatures/TestUtilities/ExtractInterface/TestExtractInterfaceOptions.cs @@ -8,63 +8,56 @@ using System.Collections.Generic; using System.Composition; using System.Threading; -using System.Threading.Tasks; -using Microsoft.CodeAnalysis.CodeGeneration; using Microsoft.CodeAnalysis.ExtractInterface; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Notification; -namespace Microsoft.CodeAnalysis.Editor.UnitTests.ExtractInterface +namespace Microsoft.CodeAnalysis.Editor.UnitTests.ExtractInterface; + +[ExportWorkspaceService(typeof(IExtractInterfaceOptionsService), ServiceLayer.Test), Shared, PartNotDiscoverable] +[method: ImportingConstructor] +[method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] +internal sealed class TestExtractInterfaceOptionsService() : IExtractInterfaceOptionsService { - [ExportWorkspaceService(typeof(IExtractInterfaceOptionsService), ServiceLayer.Test), Shared, PartNotDiscoverable] - internal class TestExtractInterfaceOptionsService : IExtractInterfaceOptionsService + public IEnumerable AllExtractableMembers { get; private set; } + public string DefaultInterfaceName { get; private set; } + public List ConflictingTypeNames { get; private set; } + public string DefaultNamespace { get; private set; } + public string GeneratedNameTypeParameterSuffix { get; set; } + + public bool IsCancelled { get; set; } + public string ChosenInterfaceName { get; set; } + public string ChosenFileName { get; set; } + public IEnumerable ChosenMembers { get; set; } + public bool SameFile { get; set; } + + public ExtractInterfaceOptionsResult GetExtractInterfaceOptions( + ISyntaxFactsService syntaxFactsService, + INotificationService notificationService, + List extractableMembers, + string defaultInterfaceName, + List conflictingTypeNames, + string defaultNamespace, + string generatedNameTypeParameterSuffix, + string languageName, + CancellationToken cancellationToken) { - [ImportingConstructor] - [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - public TestExtractInterfaceOptionsService() - { - } - - public IEnumerable AllExtractableMembers { get; private set; } - public string DefaultInterfaceName { get; private set; } - public List ConflictingTypeNames { get; private set; } - public string DefaultNamespace { get; private set; } - public string GeneratedNameTypeParameterSuffix { get; set; } - - public bool IsCancelled { get; set; } - public string ChosenInterfaceName { get; set; } - public string ChosenFileName { get; set; } - public IEnumerable ChosenMembers { get; set; } - public bool SameFile { get; set; } - - public Task GetExtractInterfaceOptionsAsync( - ISyntaxFactsService syntaxFactsService, - INotificationService notificationService, - List extractableMembers, - string defaultInterfaceName, - List conflictingTypeNames, - string defaultNamespace, - string generatedNameTypeParameterSuffix, - string languageName, - CancellationToken cancellationToken) - { - this.AllExtractableMembers = extractableMembers; - this.DefaultInterfaceName = defaultInterfaceName; - this.ConflictingTypeNames = conflictingTypeNames; - this.DefaultNamespace = defaultNamespace; - this.GeneratedNameTypeParameterSuffix = generatedNameTypeParameterSuffix; - - var result = IsCancelled - ? ExtractInterfaceOptionsResult.Cancelled - : new ExtractInterfaceOptionsResult( - isCancelled: false, - includedMembers: (ChosenMembers ?? AllExtractableMembers).AsImmutable(), - interfaceName: ChosenInterfaceName ?? defaultInterfaceName, - fileName: ChosenFileName ?? defaultInterfaceName, - location: SameFile ? ExtractInterfaceOptionsResult.ExtractLocation.SameFile : ExtractInterfaceOptionsResult.ExtractLocation.NewFile); - - return Task.FromResult(result); - } + this.AllExtractableMembers = extractableMembers; + this.DefaultInterfaceName = defaultInterfaceName; + this.ConflictingTypeNames = conflictingTypeNames; + this.DefaultNamespace = defaultNamespace; + this.GeneratedNameTypeParameterSuffix = generatedNameTypeParameterSuffix; + + var result = IsCancelled + ? ExtractInterfaceOptionsResult.Cancelled + : new ExtractInterfaceOptionsResult( + isCancelled: false, + includedMembers: (ChosenMembers ?? AllExtractableMembers).AsImmutable(), + interfaceName: ChosenInterfaceName ?? defaultInterfaceName, + fileName: ChosenFileName ?? defaultInterfaceName, + location: SameFile ? ExtractInterfaceOptionsResult.ExtractLocation.SameFile : ExtractInterfaceOptionsResult.ExtractLocation.NewFile); + + return result; } } diff --git a/src/EditorFeatures/TestUtilities/LanguageServer/AbstractLanguageServerProtocolTests.cs b/src/EditorFeatures/TestUtilities/LanguageServer/AbstractLanguageServerProtocolTests.cs index ef7eda21bdaa2..6e9c24d36d9c6 100644 --- a/src/EditorFeatures/TestUtilities/LanguageServer/AbstractLanguageServerProtocolTests.cs +++ b/src/EditorFeatures/TestUtilities/LanguageServer/AbstractLanguageServerProtocolTests.cs @@ -87,7 +87,7 @@ public Task> MapSpansAsync(Document document, I ImmutableArray mappedResult = default; if (document.Name == GeneratedFileName) { - mappedResult = spans.Select(span => new MappedSpanResult(s_mappedFilePath, s_mappedLinePosition, new TextSpan(0, 5))).ToImmutableArray(); + mappedResult = [.. spans.Select(span => new MappedSpanResult(s_mappedFilePath, s_mappedLinePosition, new TextSpan(0, 5)))]; } return Task.FromResult(mappedResult); @@ -290,7 +290,7 @@ private protected static LSP.CompletionParams CreateCompletionParams( item.Icon = tags.ToImmutableArray().GetFirstGlyph().GetImageElement().ToLSPImageElement(); if (commitCharacters != null) - item.CommitCharacters = commitCharacters.Value.Select(c => c.ToString()).ToArray(); + item.CommitCharacters = [.. commitCharacters.Value.Select(c => c.ToString())]; return item; } @@ -468,7 +468,7 @@ protected static async Task RemoveGeneratorAsync(AnalyzerReference reference, Ed // Linked files will return duplicate annotated Locations for each document that links to the same file. // Since the test output only cares about the actual file, make sure we de-dupe before returning. - locations[name] = locationsForName.Distinct().ToList(); + locations[name] = [.. locationsForName.Distinct()]; } } @@ -710,26 +710,26 @@ public Task ReplaceTextAsync(Uri documentUri, params (LSP.Range Range, string Te { var didChangeParams = CreateDidChangeTextDocumentParams( documentUri, - changes.ToImmutableArray()); + [.. changes]); return ExecuteRequestAsync(LSP.Methods.TextDocumentDidChangeName, didChangeParams, CancellationToken.None); } public Task InsertTextAsync(Uri documentUri, params (int Line, int Column, string Text)[] changes) { - return ReplaceTextAsync(documentUri, changes.Select(change => (new LSP.Range + return ReplaceTextAsync(documentUri, [.. changes.Select(change => (new LSP.Range { Start = new LSP.Position { Line = change.Line, Character = change.Column }, End = new LSP.Position { Line = change.Line, Character = change.Column } - }, change.Text)).ToArray()); + }, change.Text))]); } public Task DeleteTextAsync(Uri documentUri, params (int StartLine, int StartColumn, int EndLine, int EndColumn)[] changes) { - return ReplaceTextAsync(documentUri, changes.Select(change => (new LSP.Range + return ReplaceTextAsync(documentUri, [.. changes.Select(change => (new LSP.Range { Start = new LSP.Position { Line = change.StartLine, Character = change.StartColumn }, End = new LSP.Position { Line = change.EndLine, Character = change.EndColumn } - }, string.Empty)).ToArray()); + }, string.Empty))]); } public Task CloseDocumentAsync(Uri documentUri) @@ -790,7 +790,7 @@ internal async Task WaitForDiagnosticsAsync() internal T GetRequiredLspService() where T : class, ILspService => LanguageServer.GetTestAccessor().GetRequiredLspService(); - internal ImmutableArray GetTrackedTexts() => GetManager().GetTrackedLspText().Values.Select(v => v.Text).ToImmutableArray(); + internal ImmutableArray GetTrackedTexts() => [.. GetManager().GetTrackedLspText().Values.Select(v => v.Text)]; internal Task RunCodeAnalysisAsync(ProjectId? projectId) => _codeAnalysisService.RunAnalysisAsync(GetCurrentSolution(), projectId, onAfterProjectAnalyzed: _ => { }, CancellationToken.None); diff --git a/src/EditorFeatures/TestUtilities/NavigateTo/AbstractNavigateToTests.cs b/src/EditorFeatures/TestUtilities/NavigateTo/AbstractNavigateToTests.cs index 22b76a49786d6..eb051ead2cfc8 100644 --- a/src/EditorFeatures/TestUtilities/NavigateTo/AbstractNavigateToTests.cs +++ b/src/EditorFeatures/TestUtilities/NavigateTo/AbstractNavigateToTests.cs @@ -47,25 +47,25 @@ public abstract partial class AbstractNavigateToTests protected INavigateToItemProvider _provider; protected NavigateToTestAggregator _aggregator; - internal static readonly PatternMatch s_emptyExactPatternMatch = new PatternMatch(PatternMatchKind.Exact, true, true, ImmutableArray.Empty); - internal static readonly PatternMatch s_emptyPrefixPatternMatch = new PatternMatch(PatternMatchKind.Prefix, true, true, ImmutableArray.Empty); - internal static readonly PatternMatch s_emptySubstringPatternMatch = new PatternMatch(PatternMatchKind.Substring, true, true, ImmutableArray.Empty); - internal static readonly PatternMatch s_emptyCamelCaseExactPatternMatch = new PatternMatch(PatternMatchKind.CamelCaseExact, true, true, ImmutableArray.Empty); - internal static readonly PatternMatch s_emptyCamelCasePrefixPatternMatch = new PatternMatch(PatternMatchKind.CamelCasePrefix, true, true, ImmutableArray.Empty); - internal static readonly PatternMatch s_emptyCamelCaseNonContiguousPrefixPatternMatch = new PatternMatch(PatternMatchKind.CamelCaseNonContiguousPrefix, true, true, ImmutableArray.Empty); - internal static readonly PatternMatch s_emptyCamelCaseSubstringPatternMatch = new PatternMatch(PatternMatchKind.CamelCaseSubstring, true, true, ImmutableArray.Empty); - internal static readonly PatternMatch s_emptyCamelCaseNonContiguousSubstringPatternMatch = new PatternMatch(PatternMatchKind.CamelCaseNonContiguousSubstring, true, true, ImmutableArray.Empty); - internal static readonly PatternMatch s_emptyFuzzyPatternMatch = new PatternMatch(PatternMatchKind.Fuzzy, true, true, ImmutableArray.Empty); - - internal static readonly PatternMatch s_emptyExactPatternMatch_NotCaseSensitive = new PatternMatch(PatternMatchKind.Exact, true, false, ImmutableArray.Empty); - internal static readonly PatternMatch s_emptyPrefixPatternMatch_NotCaseSensitive = new PatternMatch(PatternMatchKind.Prefix, true, false, ImmutableArray.Empty); - internal static readonly PatternMatch s_emptySubstringPatternMatch_NotCaseSensitive = new PatternMatch(PatternMatchKind.Substring, true, false, ImmutableArray.Empty); - internal static readonly PatternMatch s_emptyCamelCaseExactPatternMatch_NotCaseSensitive = new PatternMatch(PatternMatchKind.CamelCaseExact, true, false, ImmutableArray.Empty); - internal static readonly PatternMatch s_emptyCamelCasePrefixPatternMatch_NotCaseSensitive = new PatternMatch(PatternMatchKind.CamelCasePrefix, true, false, ImmutableArray.Empty); - internal static readonly PatternMatch s_emptyCamelCaseNonContiguousPrefixPatternMatch_NotCaseSensitive = new PatternMatch(PatternMatchKind.CamelCaseNonContiguousPrefix, true, false, ImmutableArray.Empty); - internal static readonly PatternMatch s_emptyCamelCaseSubstringPatternMatch_NotCaseSensitive = new PatternMatch(PatternMatchKind.CamelCaseSubstring, true, false, ImmutableArray.Empty); - internal static readonly PatternMatch s_emptyCamelCaseNonContiguousSubstringPatternMatch_NotCaseSensitive = new PatternMatch(PatternMatchKind.CamelCaseNonContiguousSubstring, true, false, ImmutableArray.Empty); - internal static readonly PatternMatch s_emptyFuzzyPatternMatch_NotCaseSensitive = new PatternMatch(PatternMatchKind.Fuzzy, true, false, ImmutableArray.Empty); + internal static readonly PatternMatch s_emptyExactPatternMatch = new PatternMatch(PatternMatchKind.Exact, true, true, []); + internal static readonly PatternMatch s_emptyPrefixPatternMatch = new PatternMatch(PatternMatchKind.Prefix, true, true, []); + internal static readonly PatternMatch s_emptySubstringPatternMatch = new PatternMatch(PatternMatchKind.Substring, true, true, []); + internal static readonly PatternMatch s_emptyCamelCaseExactPatternMatch = new PatternMatch(PatternMatchKind.CamelCaseExact, true, true, []); + internal static readonly PatternMatch s_emptyCamelCasePrefixPatternMatch = new PatternMatch(PatternMatchKind.CamelCasePrefix, true, true, []); + internal static readonly PatternMatch s_emptyCamelCaseNonContiguousPrefixPatternMatch = new PatternMatch(PatternMatchKind.CamelCaseNonContiguousPrefix, true, true, []); + internal static readonly PatternMatch s_emptyCamelCaseSubstringPatternMatch = new PatternMatch(PatternMatchKind.CamelCaseSubstring, true, true, []); + internal static readonly PatternMatch s_emptyCamelCaseNonContiguousSubstringPatternMatch = new PatternMatch(PatternMatchKind.CamelCaseNonContiguousSubstring, true, true, []); + internal static readonly PatternMatch s_emptyFuzzyPatternMatch = new PatternMatch(PatternMatchKind.Fuzzy, true, true, []); + + internal static readonly PatternMatch s_emptyExactPatternMatch_NotCaseSensitive = new PatternMatch(PatternMatchKind.Exact, true, false, []); + internal static readonly PatternMatch s_emptyPrefixPatternMatch_NotCaseSensitive = new PatternMatch(PatternMatchKind.Prefix, true, false, []); + internal static readonly PatternMatch s_emptySubstringPatternMatch_NotCaseSensitive = new PatternMatch(PatternMatchKind.Substring, true, false, []); + internal static readonly PatternMatch s_emptyCamelCaseExactPatternMatch_NotCaseSensitive = new PatternMatch(PatternMatchKind.CamelCaseExact, true, false, []); + internal static readonly PatternMatch s_emptyCamelCasePrefixPatternMatch_NotCaseSensitive = new PatternMatch(PatternMatchKind.CamelCasePrefix, true, false, []); + internal static readonly PatternMatch s_emptyCamelCaseNonContiguousPrefixPatternMatch_NotCaseSensitive = new PatternMatch(PatternMatchKind.CamelCaseNonContiguousPrefix, true, false, []); + internal static readonly PatternMatch s_emptyCamelCaseSubstringPatternMatch_NotCaseSensitive = new PatternMatch(PatternMatchKind.CamelCaseSubstring, true, false, []); + internal static readonly PatternMatch s_emptyCamelCaseNonContiguousSubstringPatternMatch_NotCaseSensitive = new PatternMatch(PatternMatchKind.CamelCaseNonContiguousSubstring, true, false, []); + internal static readonly PatternMatch s_emptyFuzzyPatternMatch_NotCaseSensitive = new PatternMatch(PatternMatchKind.Fuzzy, true, false, []); protected abstract EditorTestWorkspace CreateWorkspace(string content, TestComposition composition); protected abstract string Language { get; } @@ -224,11 +224,7 @@ protected static int CompareNavigateToItems(NavigateToItem a, NavigateToItem b) => ComparerWithState.CompareTo(a, b, s_comparisonComponents); private static readonly ImmutableArray> s_comparisonComponents = - ImmutableArray.Create>( - item => (int)item.PatternMatch.Kind, - item => item.Name, - item => item.Kind, - item => item.SecondarySort); + [item => (int)item.PatternMatch.Kind, item => item.Name, item => item.Kind, item => item.SecondarySort]; private class FirstDocIsVisibleDocumentTrackingService : IDocumentTrackingService { @@ -244,7 +240,7 @@ public DocumentId TryGetActiveDocument() => null; public ImmutableArray GetVisibleDocuments() - => ImmutableArray.Create(_workspace.CurrentSolution.Projects.First().DocumentIds.First()); + => [_workspace.CurrentSolution.Projects.First().DocumentIds.First()]; [ExportWorkspaceServiceFactory(typeof(IDocumentTrackingService), ServiceLayer.Test), Shared, PartNotDiscoverable] public class Factory : IWorkspaceServiceFactory diff --git a/src/EditorFeatures/TestUtilities/Notification/TestGlobalOperationNotificationService.cs b/src/EditorFeatures/TestUtilities/Notification/TestGlobalOperationNotificationService.cs index db6cb65d8fed5..d0b89fb4cdd71 100644 --- a/src/EditorFeatures/TestUtilities/Notification/TestGlobalOperationNotificationService.cs +++ b/src/EditorFeatures/TestUtilities/Notification/TestGlobalOperationNotificationService.cs @@ -4,22 +4,17 @@ using System; using System.Composition; +using System.Threading; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Notification; using Microsoft.CodeAnalysis.Shared.TestHooks; using Microsoft.VisualStudio.Composition; -namespace Microsoft.CodeAnalysis.Test.Utilities.Notification -{ - [Export(typeof(IGlobalOperationNotificationService)), PartNotDiscoverable, Shared] - internal sealed class TestGlobalOperationNotificationService : AbstractGlobalOperationNotificationService - { - [ImportingConstructor] - [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - public TestGlobalOperationNotificationService( - IAsynchronousOperationListenerProvider listenerProvider) - : base(listenerProvider) - { - } - } -} +namespace Microsoft.CodeAnalysis.Test.Utilities.Notification; + +[Export(typeof(IGlobalOperationNotificationService)), PartNotDiscoverable, Shared] +[method: ImportingConstructor] +[method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] +internal sealed class TestGlobalOperationNotificationService( + IAsynchronousOperationListenerProvider listenerProvider) + : AbstractGlobalOperationNotificationService(listenerProvider, CancellationToken.None); diff --git a/src/EditorFeatures/TestUtilities/PullMemberUp/TestPullMemberUpService.cs b/src/EditorFeatures/TestUtilities/PullMemberUp/TestPullMemberUpService.cs index 1202cac72ec42..116e802fd6861 100644 --- a/src/EditorFeatures/TestUtilities/PullMemberUp/TestPullMemberUpService.cs +++ b/src/EditorFeatures/TestUtilities/PullMemberUp/TestPullMemberUpService.cs @@ -61,7 +61,7 @@ public PullMembersUpOptions GetPullMemberUpOptions(Document document, ImmutableA { if (i.Name == DestinationName) { - return PullMembersUpOptionsBuilder.BuildPullMembersUpOptions(i, selectedMember.ToImmutableArray()); + return PullMembersUpOptionsBuilder.BuildPullMembersUpOptions(i, [.. selectedMember]); } } } @@ -73,7 +73,7 @@ public PullMembersUpOptions GetPullMemberUpOptions(Document document, ImmutableA } else { - return PullMembersUpOptionsBuilder.BuildPullMembersUpOptions(destination, selectedMember.ToImmutableArray()); + return PullMembersUpOptionsBuilder.BuildPullMembersUpOptions(destination, [.. selectedMember]); } } } diff --git a/src/EditorFeatures/TestUtilities/QuickInfo/AbstractSemanticQuickInfoSourceTests.cs b/src/EditorFeatures/TestUtilities/QuickInfo/AbstractSemanticQuickInfoSourceTests.cs index 3e967228a0845..7bf676cb51eca 100644 --- a/src/EditorFeatures/TestUtilities/QuickInfo/AbstractSemanticQuickInfoSourceTests.cs +++ b/src/EditorFeatures/TestUtilities/QuickInfo/AbstractSemanticQuickInfoSourceTests.cs @@ -53,7 +53,7 @@ internal static void AssertSection( FormattedClassification[] expectedClassifications = null) { var textBlock = sections.FirstOrDefault(tb => tb.Kind == textBlockKind); - var text = textBlock != null ? textBlock.TaggedParts : ImmutableArray.Empty; + var text = textBlock != null ? textBlock.TaggedParts : []; AssertTaggedText(expectedText, text, expectedClassifications); } diff --git a/src/EditorFeatures/TestUtilities/QuickInfo/ToolTipAssert.cs b/src/EditorFeatures/TestUtilities/QuickInfo/ToolTipAssert.cs index e49efc27989a8..a72f944442327 100644 --- a/src/EditorFeatures/TestUtilities/QuickInfo/ToolTipAssert.cs +++ b/src/EditorFeatures/TestUtilities/QuickInfo/ToolTipAssert.cs @@ -203,13 +203,13 @@ private static void ContainerToString(object element, string indent, StringBuild private static string ContainerStyleToString(ContainerElementStyle style) { var stringValue = style.ToString(); - return string.Join(" Or ", stringValue.Split(new[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries).Select(value => $"{nameof(ContainerElementStyle)}.{value}")); + return string.Join(" Or ", stringValue.Split([',', ' '], StringSplitOptions.RemoveEmptyEntries).Select(value => $"{nameof(ContainerElementStyle)}.{value}")); } private static string TextRunStyleToString(ClassifiedTextRunStyle style) { var stringValue = style.ToString(); - return string.Join(" Or ", stringValue.Split(new[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries).Select(value => $"{nameof(ClassifiedTextRunStyle)}.{value}")); + return string.Join(" Or ", stringValue.Split([',', ' '], StringSplitOptions.RemoveEmptyEntries).Select(value => $"{nameof(ClassifiedTextRunStyle)}.{value}")); } private static string GetKnownClassification(string classification) diff --git a/src/EditorFeatures/TestUtilities/Rename/RenamerTests.cs b/src/EditorFeatures/TestUtilities/Rename/RenamerTests.cs index df48af1b2af08..3b70d661c01e3 100644 --- a/src/EditorFeatures/TestUtilities/Rename/RenamerTests.cs +++ b/src/EditorFeatures/TestUtilities/Rename/RenamerTests.cs @@ -116,7 +116,7 @@ private static string[] GetDocumentFolders(string filePath) return splitPath; } - return splitPath.Take(splitPath.Length - 1).ToArray(); + return [.. splitPath.Take(splitPath.Length - 1)]; } protected Task TestRenameDocument(string startText, string expectedText, string newDocumentName = null, string newDocumentPath = null, string documentName = null, string documentPath = null, string[] expectedErrors = null) diff --git a/src/EditorFeatures/TestUtilities/Squiggles/TestDiagnosticTagProducer.cs b/src/EditorFeatures/TestUtilities/Squiggles/TestDiagnosticTagProducer.cs index 6e3ef4081cb3f..67f6f4c7346da 100644 --- a/src/EditorFeatures/TestUtilities/Squiggles/TestDiagnosticTagProducer.cs +++ b/src/EditorFeatures/TestUtilities/Squiggles/TestDiagnosticTagProducer.cs @@ -39,7 +39,7 @@ internal static DiagnosticData CreateDiagnosticData(EditorTestHostDocument docum isEnabledByDefault: true, warningLevel: 0, projectId: document.Project.Id, - customTags: ImmutableArray.Empty, + customTags: [], properties: ImmutableDictionary.Empty, location: new DiagnosticDataLocation(new FileLinePositionSpan(document.FilePath, linePosSpan), document.Id), language: document.Project.Language); diff --git a/src/EditorFeatures/TestUtilities/TestExtensionErrorHandler.cs b/src/EditorFeatures/TestUtilities/TestExtensionErrorHandler.cs index fb7d6e162fed6..34aa78fcbf086 100644 --- a/src/EditorFeatures/TestUtilities/TestExtensionErrorHandler.cs +++ b/src/EditorFeatures/TestUtilities/TestExtensionErrorHandler.cs @@ -17,7 +17,7 @@ namespace Microsoft.CodeAnalysis.Editor.UnitTests [Export(typeof(ITestErrorHandler))] internal class TestExtensionErrorHandler : IExtensionErrorHandler, ITestErrorHandler { - public ImmutableList Exceptions { get; private set; } = ImmutableList.Empty; + public ImmutableList Exceptions { get; private set; } = []; [ImportingConstructor] [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] diff --git a/src/EditorFeatures/TestUtilities/TextEditorFactoryExtensions.cs b/src/EditorFeatures/TestUtilities/TextEditorFactoryExtensions.cs index 910d8bda58004..699e1ed12f691 100644 --- a/src/EditorFeatures/TestUtilities/TextEditorFactoryExtensions.cs +++ b/src/EditorFeatures/TestUtilities/TextEditorFactoryExtensions.cs @@ -24,11 +24,14 @@ public static DisposableTextView CreateDisposableTextView(this ITextEditorFactor // depend on it, just disable it if (roles.IsDefault) { - roles = ImmutableArray.Create(PredefinedTextViewRoles.Analyzable, + roles = + [ + PredefinedTextViewRoles.Analyzable, PredefinedTextViewRoles.Document, PredefinedTextViewRoles.Editable, PredefinedTextViewRoles.Interactive, - PredefinedTextViewRoles.Zoomable); + PredefinedTextViewRoles.Zoomable, + ]; } var roleSet = textEditorFactory.CreateTextViewRoleSet(roles); diff --git a/src/EditorFeatures/TestUtilities/Workspaces/EditorTestHostDocument.cs b/src/EditorFeatures/TestUtilities/Workspaces/EditorTestHostDocument.cs index e5d02f832476e..5eeb3f804859d 100644 --- a/src/EditorFeatures/TestUtilities/Workspaces/EditorTestHostDocument.cs +++ b/src/EditorFeatures/TestUtilities/Workspaces/EditorTestHostDocument.cs @@ -20,12 +20,14 @@ namespace Microsoft.CodeAnalysis.Test.Utilities; public class EditorTestHostDocument : TestHostDocument { - private static readonly ImmutableArray s_defaultRoles = ImmutableArray.Create - (PredefinedTextViewRoles.Analyzable, + private static readonly ImmutableArray s_defaultRoles = + [ + PredefinedTextViewRoles.Analyzable, PredefinedTextViewRoles.Document, PredefinedTextViewRoles.Editable, PredefinedTextViewRoles.Interactive, - PredefinedTextViewRoles.Zoomable); + PredefinedTextViewRoles.Zoomable, + ]; private readonly ImmutableArray _roles; diff --git a/src/EditorFeatures/TestUtilities/Workspaces/EditorTestWorkspace.cs b/src/EditorFeatures/TestUtilities/Workspaces/EditorTestWorkspace.cs index b174b79c8b6b5..d9b54b3d39d54 100644 --- a/src/EditorFeatures/TestUtilities/Workspaces/EditorTestWorkspace.cs +++ b/src/EditorFeatures/TestUtilities/Workspaces/EditorTestWorkspace.cs @@ -262,7 +262,7 @@ public EditorTestHostDocument CreateProjectionBufferDocument( { mappedSpans[string.Empty] = mappedSpans.TryGetValue(string.Empty, out var emptyTextSpans) ? emptyTextSpans - : ImmutableArray.Empty; + : []; foreach (var span in document.SelectedSpans) { var snapshotSpan = span.ToSnapshotSpan(document.GetTextBuffer().CurrentSnapshot); @@ -272,11 +272,11 @@ public EditorTestHostDocument CreateProjectionBufferDocument( // Order unnamed spans as they would be ordered by the normal span finding // algorithm in MarkupTestFile - mappedSpans[string.Empty] = mappedSpans[string.Empty].OrderBy(s => s.End).ThenBy(s => -s.Start).ToImmutableArray(); + mappedSpans[string.Empty] = [.. mappedSpans[string.Empty].OrderBy(s => s.End).ThenBy(s => -s.Start)]; foreach (var (key, spans) in document.AnnotatedSpans) { - mappedSpans[key] = mappedSpans.TryGetValue(key, out var textSpans) ? textSpans : ImmutableArray.Empty; + mappedSpans[key] = mappedSpans.TryGetValue(key, out var textSpans) ? textSpans : []; foreach (var span in spans) { diff --git a/src/EditorFeatures/TestUtilities/Workspaces/NoCompilationDocumentDiagnosticAnalyzer.cs b/src/EditorFeatures/TestUtilities/Workspaces/NoCompilationDocumentDiagnosticAnalyzer.cs index c943f8d559ae8..04438702003ae 100644 --- a/src/EditorFeatures/TestUtilities/Workspaces/NoCompilationDocumentDiagnosticAnalyzer.cs +++ b/src/EditorFeatures/TestUtilities/Workspaces/NoCompilationDocumentDiagnosticAnalyzer.cs @@ -19,7 +19,7 @@ internal class NoCompilationDocumentDiagnosticAnalyzer : DocumentDiagnosticAnaly public static readonly DiagnosticDescriptor Descriptor = new DiagnosticDescriptor( "NC0000", "No Compilation Syntax Error", "No Compilation Syntax Error", "Error", DiagnosticSeverity.Error, isEnabledByDefault: true); - public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create(Descriptor); + public override ImmutableArray SupportedDiagnostics => [Descriptor]; public override Task> AnalyzeSemanticsAsync(Document document, CancellationToken cancellationToken) => SpecializedTasks.EmptyImmutableArray(); diff --git a/src/EditorFeatures/TestUtilities2/Intellisense/TestState.vb b/src/EditorFeatures/TestUtilities2/Intellisense/TestState.vb index 26ff01d1018b4..bf3cf355128fe 100644 --- a/src/EditorFeatures/TestUtilities2/Intellisense/TestState.vb +++ b/src/EditorFeatures/TestUtilities2/Intellisense/TestState.vb @@ -34,7 +34,6 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.IntelliSense Protected ReadOnly SessionTestState As IIntelliSenseTestState Private ReadOnly SignatureHelpBeforeCompletionCommandHandler As SignatureHelpBeforeCompletionCommandHandler - Protected ReadOnly SignatureHelpAfterCompletionCommandHandler As SignatureHelpAfterCompletionCommandHandler Protected ReadOnly CompleteStatementCommandHandler As CompleteStatementCommandHandler Private ReadOnly FormatCommandHandler As FormatCommandHandler @@ -73,7 +72,6 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.IntelliSense Me.SignatureHelpBeforeCompletionCommandHandler = GetExportedValue(Of SignatureHelpBeforeCompletionCommandHandler)() - Me.SignatureHelpAfterCompletionCommandHandler = GetExportedValue(Of SignatureHelpAfterCompletionCommandHandler)() Me.CompleteStatementCommandHandler = GetExportedValue(Of CompleteStatementCommandHandler)() Me.FormatCommandHandler = If(includeFormatCommandHandler, GetExportedValue(Of FormatCommandHandler)(), Nothing) @@ -171,23 +169,19 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.IntelliSense End Function Public Overloads Sub SendEscape() - MyBase.SendEscape(Sub(a, n, c) EditorCompletionCommandHandler.ExecuteCommand(a, Sub() SignatureHelpAfterCompletionCommandHandler.ExecuteCommand(a, n, c), c), Sub() Return) + MyBase.SendEscape(Sub(a, n, c) EditorCompletionCommandHandler.ExecuteCommand(a, Sub() Me.CurrentSignatureHelpPresenterSession?.Dismiss(), c), Sub() Return) End Sub Public Overloads Sub SendDownKey() MyBase.SendDownKey( - Sub(a, n, c) EditorCompletionCommandHandler.ExecuteCommand(a, Sub() SignatureHelpAfterCompletionCommandHandler.ExecuteCommand(a, n, c), c), - Sub() - EditorOperations.MoveLineDown(extendSelection:=False) - End Sub) + Sub(a, n, c) EditorCompletionCommandHandler.ExecuteCommand(a, Sub() EditorOperations.MoveLineDown(extendSelection:=False), c), + Sub() EditorOperations.MoveLineDown(extendSelection:=False)) End Sub Public Overloads Sub SendUpKey() MyBase.SendUpKey( - Sub(a, n, c) EditorCompletionCommandHandler.ExecuteCommand(a, Sub() SignatureHelpAfterCompletionCommandHandler.ExecuteCommand(a, n, c), c), - Sub() - EditorOperations.MoveLineUp(extendSelection:=False) - End Sub) + Sub(a, n, c) EditorCompletionCommandHandler.ExecuteCommand(a, Sub() EditorOperations.MoveLineUp(extendSelection:=False), c), + Sub() EditorOperations.MoveLineUp(extendSelection:=False)) End Sub Public Overloads Sub SendPageUp() @@ -521,7 +515,7 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.IntelliSense Public Async Function AssertSessionIsNothingOrNoCompletionItemLike(text As String) As Task Await WaitForAsynchronousOperationsAsync() Dim session = GetExportedValue(Of IAsyncCompletionBroker)().GetSession(TextView) - If Not session Is Nothing Then + If session IsNot Nothing Then Await AssertCompletionItemsDoNotContainAny(text) End If End Function diff --git a/src/EditorFeatures/Text/Shared/Extensions/ITextSnapshotLineExtensions.cs b/src/EditorFeatures/Text/Shared/Extensions/ITextSnapshotLineExtensions.cs index 03d29a37b110b..71421eb46de34 100644 --- a/src/EditorFeatures/Text/Shared/Extensions/ITextSnapshotLineExtensions.cs +++ b/src/EditorFeatures/Text/Shared/Extensions/ITextSnapshotLineExtensions.cs @@ -19,19 +19,11 @@ internal static class ITextSnapshotLineExtensions /// public static int? GetFirstNonWhitespacePosition(this ITextSnapshotLine line) { - Contract.ThrowIfNull(line); - - var text = line.GetText(); - - for (var i = 0; i < text.Length; i++) - { - if (!char.IsWhiteSpace(text[i])) - { - return line.Start + i; - } - } + var firstNonWhitespaceOffset = line.GetFirstNonWhitespaceOffset(); - return null; + return firstNonWhitespaceOffset.HasValue + ? firstNonWhitespaceOffset + line.Start + : null; } /// @@ -43,11 +35,10 @@ internal static class ITextSnapshotLineExtensions { Contract.ThrowIfNull(line); - var text = line.GetText(); - - for (var i = 0; i < text.Length; i++) + var snapshot = line.Snapshot; + for (var i = 0; i < line.Length; i++) { - if (!char.IsWhiteSpace(text[i])) + if (!char.IsWhiteSpace(snapshot[line.Start + i])) { return i; } @@ -71,16 +62,15 @@ public static bool IsEmptyOrWhitespace(this ITextSnapshotLine line, int startInd Contract.ThrowIfNull(line, "line"); Contract.ThrowIfFalse(startIndex >= 0); - var text = line.GetText(); - if (endIndex == -1) { - endIndex = text.Length; + endIndex = line.Length; } + var snapshot = line.Snapshot; for (var i = startIndex; i < endIndex; i++) { - if (!char.IsWhiteSpace(text[i])) + if (!char.IsWhiteSpace(snapshot[line.Start + i])) { return false; } diff --git a/src/EditorFeatures/VisualBasic/EndConstructGeneration/EndConstructCommandHandler.vb b/src/EditorFeatures/VisualBasic/EndConstructGeneration/EndConstructCommandHandler.vb index 7d593f2862e37..4759ff490677e 100644 --- a/src/EditorFeatures/VisualBasic/EndConstructGeneration/EndConstructCommandHandler.vb +++ b/src/EditorFeatures/VisualBasic/EndConstructGeneration/EndConstructCommandHandler.vb @@ -32,33 +32,33 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.EndConstructGeneration Implements IChainedCommandHandler(Of TypeCharCommandArgs) Implements IChainedCommandHandler(Of AutomaticLineEnderCommandArgs) + Private ReadOnly _threadingContext As IThreadingContext Private ReadOnly _editorOperationsFactoryService As IEditorOperationsFactoryService Private ReadOnly _undoHistoryRegistry As ITextUndoHistoryRegistry Private ReadOnly _editorOptionsService As EditorOptionsService - Public Sub New(editorOperationsFactoryService As IEditorOperationsFactoryService, - undoHistoryRegistry As ITextUndoHistoryRegistry, - editorOptionsService As EditorOptionsService) - + Public Sub New( + threadingContext As IThreadingContext, + editorOperationsFactoryService As IEditorOperationsFactoryService, + undoHistoryRegistry As ITextUndoHistoryRegistry, + editorOptionsService As EditorOptionsService) + _threadingContext = threadingContext _editorOperationsFactoryService = editorOperationsFactoryService _undoHistoryRegistry = undoHistoryRegistry _editorOptionsService = editorOptionsService End Sub - Public ReadOnly Property DisplayName As String Implements INamed.DisplayName - Get - Return VBEditorResources.End_Construct - End Get - End Property + Public ReadOnly Property DisplayName As String = VBEditorResources.End_Construct Implements INamed.DisplayName Public Function GetCommandState_ReturnKeyCommandHandler(args As ReturnKeyCommandArgs, nextHandler As Func(Of CommandState)) As CommandState Implements IChainedCommandHandler(Of ReturnKeyCommandArgs).GetCommandState Return nextHandler() End Function Public Sub ExecuteCommand_ReturnKeyCommandHandler(args As ReturnKeyCommandArgs, nextHandler As Action, context As CommandExecutionContext) Implements IChainedCommandHandler(Of ReturnKeyCommandArgs).ExecuteCommand - ExecuteEndConstructOnReturn(args.TextView, args.SubjectBuffer, nextHandler) + _threadingContext.JoinableTaskFactory.Run(Function() ExecuteEndConstructOnReturnAsync( + args.TextView, args.SubjectBuffer, nextHandler, context.OperationContext.UserCancellationToken)) End Sub Public Function GetCommandState_TypeCharCommandHandler(args As TypeCharCommandArgs, nextHandler As Func(Of CommandState)) As CommandState Implements IChainedCommandHandler(Of TypeCharCommandArgs).GetCommandState @@ -66,21 +66,25 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.EndConstructGeneration End Function Public Sub ExecuteCommand_TypeCharCommandHandler(args As TypeCharCommandArgs, nextHandler As Action, context As CommandExecutionContext) Implements IChainedCommandHandler(Of TypeCharCommandArgs).ExecuteCommand - nextHandler() - - If Not _editorOptionsService.GlobalOptions.GetOption(EndConstructGenerationOptionsStorage.EndConstruct, LanguageNames.VisualBasic) Then - Return - End If - - Dim textSnapshot = args.SubjectBuffer.CurrentSnapshot - Dim document = textSnapshot.GetOpenDocumentInCurrentContextWithChanges() - If document Is Nothing Then - Return - End If - - ' End construct is not cancellable. - Dim endConstructService = document.GetLanguageService(Of IEndConstructGenerationService)() - endConstructService.TryDo(args.TextView, args.SubjectBuffer, args.TypedChar, CancellationToken.None) + _threadingContext.JoinableTaskFactory.Run( + Async Function() + nextHandler() + + If Not _editorOptionsService.GlobalOptions.GetOption(EndConstructGenerationOptionsStorage.EndConstruct, LanguageNames.VisualBasic) Then + Return + End If + + Dim textSnapshot = args.SubjectBuffer.CurrentSnapshot + Dim document = textSnapshot.GetOpenDocumentInCurrentContextWithChanges() + If document Is Nothing Then + Return + End If + + ' End construct is not cancellable. + Dim endConstructService = document.GetLanguageService(Of IEndConstructGenerationService)() + Await endConstructService.TryDoAsync( + args.TextView, args.SubjectBuffer, args.TypedChar, context.OperationContext.UserCancellationToken).ConfigureAwait(True) + End Function) End Sub Public Function GetCommandState_AutomaticLineEnderCommandHandler(args As AutomaticLineEnderCommandArgs, nextHandler As Func(Of CommandState)) As CommandState Implements IChainedCommandHandler(Of AutomaticLineEnderCommandArgs).GetCommandState @@ -88,17 +92,25 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.EndConstructGeneration End Function Public Sub ExecuteCommand_AutomaticLineEnderCommandHandler(args As AutomaticLineEnderCommandArgs, nextHandler As Action, context As CommandExecutionContext) Implements IChainedCommandHandler(Of AutomaticLineEnderCommandArgs).ExecuteCommand - ExecuteEndConstructOnReturn(args.TextView, args.SubjectBuffer, Sub() - Dim operations = Me._editorOperationsFactoryService.GetEditorOperations(args.TextView) - If operations Is Nothing Then - nextHandler() - Else - operations.InsertNewLine() - End If - End Sub) + _threadingContext.JoinableTaskFactory.Run(Function() ExecuteEndConstructOnReturnAsync( + args.TextView, + args.SubjectBuffer, + Sub() + Dim operations = Me._editorOperationsFactoryService.GetEditorOperations(args.TextView) + If operations Is Nothing Then + nextHandler() + Else + operations.InsertNewLine() + End If + End Sub, + context.OperationContext.UserCancellationToken)) End Sub - Private Sub ExecuteEndConstructOnReturn(textView As ITextView, subjectBuffer As ITextBuffer, nextHandler As Action) + Private Async Function ExecuteEndConstructOnReturnAsync( + textView As ITextView, + subjectBuffer As ITextBuffer, + nextHandler As Action, + cancellationToken As CancellationToken) As Task If Not _editorOptionsService.GlobalOptions.GetOption(EndConstructGenerationOptionsStorage.EndConstruct, LanguageNames.VisualBasic) OrElse Not subjectBuffer.CanApplyChangeDocumentToWorkspace() Then nextHandler() @@ -111,18 +123,24 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.EndConstructGeneration Return End If - CleanupBeforeEndConstruct(textView, subjectBuffer, document, CancellationToken.None) + Await CleanupBeforeEndConstructAsync( + textView, subjectBuffer, document, cancellationToken).ConfigureAwait(True) Dim endConstructService = document.GetLanguageService(Of IEndConstructGenerationService)() - Dim result = endConstructService.TryDo(textView, subjectBuffer, vbLf(0), CancellationToken.None) + Dim result = Await endConstructService.TryDoAsync( + textView, subjectBuffer, vbLf(0), cancellationToken).ConfigureAwait(True) If Not result Then nextHandler() Return End If - End Sub + End Function - Private Sub CleanupBeforeEndConstruct(view As ITextView, buffer As ITextBuffer, document As Document, cancellationToken As CancellationToken) + Private Async Function CleanupBeforeEndConstructAsync( + view As ITextView, + buffer As ITextBuffer, + document As Document, + cancellationToken As CancellationToken) As Task Dim position = view.GetCaretPoint(buffer) If Not position.HasValue Then Return @@ -141,15 +159,16 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.EndConstructGeneration End Function) Dim options = buffer.GetCodeCleanupOptions(_editorOptionsService, document.Project.GetFallbackAnalyzerOptions(), document.Project.Services, explicitFormat:=False, allowImportsInHiddenRegions:=document.AllowImportsInHiddenRegions()) - Dim cleanDocument = CodeCleaner.CleanupAsync(document, GetSpanToCleanup(statement), Options, codeCleanups, cancellationToken:=cancellationToken).WaitAndGetResult(cancellationToken) - Dim changes = cleanDocument.GetTextChangesAsync(document, cancellationToken).WaitAndGetResult(cancellationToken) + Dim cleanDocument = Await CodeCleaner.CleanupAsync( + document, GetSpanToCleanup(statement), options, codeCleanups, cancellationToken).ConfigureAwait(True) + Dim changes = cleanDocument.GetTextChangesSynchronously(document, cancellationToken) Using transaction = New CaretPreservingEditTransaction(VBEditorResources.End_Construct, view, _undoHistoryRegistry, _editorOperationsFactoryService) transaction.MergePolicy = AutomaticCodeChangeMergePolicy.Instance buffer.ApplyChanges(changes) transaction.Complete() End Using - End Sub + End Function Private Shared Function GetSpanToCleanup(statement As StatementSyntax) As TextSpan Dim firstToken = statement.GetFirstToken() diff --git a/src/EditorFeatures/VisualBasic/EndConstructGeneration/EndConstructState.vb b/src/EditorFeatures/VisualBasic/EndConstructGeneration/EndConstructState.vb index bbbe521955a7e..9705c29bd91d1 100644 --- a/src/EditorFeatures/VisualBasic/EndConstructGeneration/EndConstructState.vb +++ b/src/EditorFeatures/VisualBasic/EndConstructGeneration/EndConstructState.vb @@ -2,15 +2,17 @@ ' The .NET Foundation licenses this file to you under the MIT license. ' See the LICENSE file in the project root for more information. +Imports System.Threading + Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.EndConstructGeneration - Friend Class EndConstructState + Friend NotInheritable Class EndConstructState Private ReadOnly _caretPosition As Integer - Private ReadOnly _semanticModel As Lazy(Of SemanticModel) + Private ReadOnly _semanticModel As AsyncLazy(Of SemanticModel) Private ReadOnly _tree As SyntaxTree Private ReadOnly _tokenToLeft As SyntaxToken Private ReadOnly _newLineCharacter As String - Public Sub New(caretPosition As Integer, semanticModel As Lazy(Of SemanticModel), syntaxTree As SyntaxTree, tokenToLeft As SyntaxToken, newLineCharacter As String) + Public Sub New(caretPosition As Integer, semanticModel As AsyncLazy(Of SemanticModel), syntaxTree As SyntaxTree, tokenToLeft As SyntaxToken, newLineCharacter As String) ThrowIfNull(syntaxTree) _caretPosition = caretPosition @@ -26,11 +28,9 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.EndConstructGeneration End Get End Property - Public ReadOnly Property SemanticModel As SemanticModel - Get - Return _semanticModel.Value - End Get - End Property + Public Function GetSemanticModelAsync(cancellationToken As CancellationToken) As Task(Of SemanticModel) + Return _semanticModel.GetValueAsync(cancellationToken) + End Function Public ReadOnly Property SyntaxTree As SyntaxTree Get diff --git a/src/EditorFeatures/VisualBasic/EndConstructGeneration/EndConstructStatementVisitor.vb b/src/EditorFeatures/VisualBasic/EndConstructGeneration/EndConstructStatementVisitor.vb index ecf27a11ee082..09789a442303d 100644 --- a/src/EditorFeatures/VisualBasic/EndConstructGeneration/EndConstructStatementVisitor.vb +++ b/src/EditorFeatures/VisualBasic/EndConstructGeneration/EndConstructStatementVisitor.vb @@ -12,25 +12,51 @@ Imports Microsoft.VisualStudio.Text.Editor Imports Microsoft.VisualStudio.Text.Editor.OptionsExtensionMethods Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.EndConstructGeneration - Partial Friend Class EndConstructStatementVisitor + Partial Friend NotInheritable Class EndConstructStatementVisitor Inherits VisualBasicSyntaxVisitor(Of AbstractEndConstructResult) Private ReadOnly _textView As ITextView Private ReadOnly _subjectBuffer As ITextBuffer - Private ReadOnly _cancellationToken As CancellationToken Private ReadOnly _state As EndConstructState + Private ReadOnly _cancellationToken As CancellationToken + + ''' + ''' Note: this is only passed in when return true. Any functions that require + ''' a semantic model must declare their need up front so we do not pay the cost for semantics for all the cases + ''' that do not need it. + ''' + Private ReadOnly _semanticModel As SemanticModel - Public Sub New(textView As ITextView, - subjectBuffer As ITextBuffer, - state As EndConstructState, - cancellationToken As CancellationToken) + Public Sub New( + textView As ITextView, + subjectBuffer As ITextBuffer, + state As EndConstructState, + semanticModel As SemanticModel, + cancellationToken As CancellationToken) _textView = textView _subjectBuffer = subjectBuffer _state = state + _semanticModel = semanticModel _cancellationToken = cancellationToken End Sub + Public Shared Function NeedsSemanticModel(node As SyntaxNode) As Boolean + ' All of these call HandleMethodBlockSyntax, which needs semantics + If TypeOf node Is MethodStatementSyntax OrElse + TypeOf node Is SubNewStatementSyntax OrElse + TypeOf node Is OperatorStatementSyntax Then + Return True + End If + + ' Calls GenerateAddOrRemoveHandler and GenerateRaiseEventHandler, both which needs semantics + If TypeOf node Is EventStatementSyntax Then + Return True + End If + + Return False + End Function + Public Overrides Function VisitDoStatement(node As DoStatementSyntax) As AbstractEndConstructResult Dim needsEnd = node.GetAncestorsOrThis(Of DoLoopBlockSyntax)().Any(Function(block) block.LoopStatement.IsMissing) @@ -100,11 +126,12 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.EndConstructGeneration End If End Function - Private Function TryGenerateResultForConstructorSpitWithInitializeComponent(methodBlock As MethodBlockBaseSyntax) As AbstractEndConstructResult + Private Function TryGenerateResultForConstructorSpitWithInitializeComponent( + methodBlock As MethodBlockBaseSyntax) As AbstractEndConstructResult If methodBlock.BlockStatement.Kind = SyntaxKind.SubNewStatement Then - Dim boundConstructor = _state.SemanticModel.GetDeclaredSymbol(DirectCast(methodBlock.BlockStatement, SubNewStatementSyntax)) + Dim boundConstructor = _semanticModel.GetDeclaredSymbol(DirectCast(methodBlock.BlockStatement, SubNewStatementSyntax)) If boundConstructor IsNot Nothing Then - If boundConstructor.ContainingType.IsDesignerGeneratedTypeWithInitializeComponent(_state.SemanticModel.Compilation) Then + If boundConstructor.ContainingType.IsDesignerGeneratedTypeWithInitializeComponent(_semanticModel.Compilation) Then Dim aligningWhitespace = _subjectBuffer.CurrentSnapshot.GetAligningWhitespace(methodBlock.BlockStatement.SpanStart) Dim innerAligningWhitespace = aligningWhitespace & " " @@ -161,10 +188,10 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.EndConstructGeneration Dim aligningWhitespace = _subjectBuffer.CurrentSnapshot.GetAligningWhitespace(node.SpanStart) Dim stringBuilder As New StringBuilder stringBuilder.Append(_textView.Options.GetNewLineCharacter()) - StringBuilder.Append(aligningWhitespace & " Case ") + stringBuilder.Append(aligningWhitespace & " Case ") Dim finalCaretPoint = stringBuilder.Length stringBuilder.AppendLine() - StringBuilder.Append(aligningWhitespace & "End Select") + stringBuilder.Append(aligningWhitespace & "End Select") Return New ReplaceSpanResult(New SnapshotSpan(_subjectBuffer.CurrentSnapshot, _state.CaretPosition, 0), stringBuilder.ToString(), newCaretPosition:=finalCaretPoint) diff --git a/src/EditorFeatures/VisualBasic/EndConstructGeneration/EndConstructStatementVisitor_CustomEvents.vb b/src/EditorFeatures/VisualBasic/EndConstructGeneration/EndConstructStatementVisitor_CustomEvents.vb index 5c8274840d942..6640cc9406133 100644 --- a/src/EditorFeatures/VisualBasic/EndConstructGeneration/EndConstructStatementVisitor_CustomEvents.vb +++ b/src/EditorFeatures/VisualBasic/EndConstructGeneration/EndConstructStatementVisitor_CustomEvents.vb @@ -37,21 +37,21 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.EndConstructGeneration End Function Private Function GenerateAddOrRemoveHandler(eventStatement As EventStatementSyntax, kind As SyntaxKind) As String() - Dim type = _state.SemanticModel.GetTypeInfo(DirectCast(eventStatement.AsClause, SimpleAsClauseSyntax).Type, Me._cancellationToken) + Dim type = _semanticModel.GetTypeInfo(DirectCast(eventStatement.AsClause, SimpleAsClauseSyntax).Type, Me._cancellationToken) Dim position As Integer = eventStatement.SpanStart Dim aligningWhitespace = _subjectBuffer.CurrentSnapshot.GetAligningWhitespace(position) & " " - Return {aligningWhitespace & SyntaxFacts.GetText(kind) & "(value As " & type.Type.ToMinimalDisplayString(_state.SemanticModel, position, SymbolDisplayFormats.NameFormat) & ")", + Return {aligningWhitespace & SyntaxFacts.GetText(kind) & "(value As " & type.Type.ToMinimalDisplayString(_semanticModel, position, SymbolDisplayFormats.NameFormat) & ")", "", aligningWhitespace & "End " & SyntaxFacts.GetText(kind)} End Function Private Function GenerateRaiseEventHandler(eventStatement As EventStatementSyntax) As String() - Dim type = TryCast(_state.SemanticModel.GetTypeInfo(DirectCast(eventStatement.AsClause, SimpleAsClauseSyntax).Type, Me._cancellationToken).Type, INamedTypeSymbol) + Dim type = TryCast(_semanticModel.GetTypeInfo(DirectCast(eventStatement.AsClause, SimpleAsClauseSyntax).Type, Me._cancellationToken).Type, INamedTypeSymbol) Dim signature = "" If type IsNot Nothing AndAlso type.DelegateInvokeMethod IsNot Nothing Then Dim parameterStrings = type.DelegateInvokeMethod.Parameters.Select( - Function(p) p.ToMinimalDisplayString(_state.SemanticModel, eventStatement.SpanStart)) + Function(p) p.ToMinimalDisplayString(_semanticModel, eventStatement.SpanStart)) signature = String.Join(", ", parameterStrings) End If diff --git a/src/EditorFeatures/VisualBasic/EndConstructGeneration/EndConstructStatementVisitor_IfStatement.vb b/src/EditorFeatures/VisualBasic/EndConstructGeneration/EndConstructStatementVisitor_IfStatement.vb index f723001094a47..b47d0ee67032a 100644 --- a/src/EditorFeatures/VisualBasic/EndConstructGeneration/EndConstructStatementVisitor_IfStatement.vb +++ b/src/EditorFeatures/VisualBasic/EndConstructGeneration/EndConstructStatementVisitor_IfStatement.vb @@ -7,7 +7,6 @@ Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.EndConstructGeneration Partial Friend Class EndConstructStatementVisitor - Public Overrides Function VisitIfStatement(node As IfStatementSyntax) As AbstractEndConstructResult Dim needsEnd = node.GetAncestorsOrThis(Of MultiLineIfBlockSyntax)().Any(Function(block) block.EndIfStatement.IsMissing) diff --git a/src/EditorFeatures/VisualBasic/EndConstructGeneration/VisualBasicEndConstructGenerationService.vb b/src/EditorFeatures/VisualBasic/EndConstructGeneration/VisualBasicEndConstructGenerationService.vb index eb290da618bfd..11b3e8dee49be 100644 --- a/src/EditorFeatures/VisualBasic/EndConstructGeneration/VisualBasicEndConstructGenerationService.vb +++ b/src/EditorFeatures/VisualBasic/EndConstructGeneration/VisualBasicEndConstructGenerationService.vb @@ -161,12 +161,13 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.EndConstructGeneration Dim bufferOptions = _editorOptionsFactoryService.GetOptions(subjectBuffer) Return New EndConstructState( - caretPosition.Value, New Lazy(Of SemanticModel)(Function() document.GetSemanticModelAsync(cancellationToken).WaitAndGetResult(cancellationToken)), tree, tokenToLeft, bufferOptions.GetNewLineCharacter()) + caretPosition.Value, AsyncLazy.Create(Function(c) document.GetSemanticModelAsync(c)), tree, tokenToLeft, bufferOptions.GetNewLineCharacter()) End Function - Friend Overridable Function TryDoEndConstructForEnterKey(textView As ITextView, - subjectBuffer As ITextBuffer, - cancellationToken As CancellationToken) As Boolean + Friend Overridable Async Function TryDoEndConstructForEnterKeyAsync( + textView As ITextView, + subjectBuffer As ITextBuffer, + cancellationToken As CancellationToken) As Task(Of Boolean) Using Logger.LogBlock(FunctionId.EndConstruct_DoStatement, cancellationToken) Using transaction = New CaretPreservingEditTransaction(VBEditorResources.End_Construct, textView, _undoHistoryRegistry, _editorOperationsFactoryService) transaction.MergePolicy = AutomaticCodeChangeMergePolicy.Instance @@ -285,7 +286,10 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.EndConstructGeneration Return False End If - Dim visitor = New EndConstructStatementVisitor(textView, subjectBuffer, state, cancellationToken) + Dim semanticModel = If(EndConstructStatementVisitor.NeedsSemanticModel(statement), + Await state.GetSemanticModelAsync(cancellationToken).ConfigureAwait(True), + Nothing) + Dim visitor = New EndConstructStatementVisitor(textView, subjectBuffer, state, semanticModel, cancellationToken) Dim result = visitor.Visit(statement) If result Is Nothing Then @@ -480,10 +484,10 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.EndConstructGeneration End Using End Function - Public Function TryDo(textView As ITextView, subjectBuffer As ITextBuffer, typedChar As Char, cancellationToken As CancellationToken) As Boolean Implements IEndConstructGenerationService.TryDo + Public Async Function TryDoAsync(textView As ITextView, subjectBuffer As ITextBuffer, typedChar As Char, cancellationToken As CancellationToken) As Task(Of Boolean) Implements IEndConstructGenerationService.TryDoAsync Select Case typedChar Case vbLf(0) - Return Me.TryDoEndConstructForEnterKey(textView, subjectBuffer, cancellationToken) + Return Await Me.TryDoEndConstructForEnterKeyAsync(textView, subjectBuffer, cancellationToken).ConfigureAwait(True) Case ">"c Return Me.TryDoXmlElementEndConstruct(textView, subjectBuffer, cancellationToken) Case "-"c diff --git a/src/EditorFeatures/VisualBasic/ImplementAbstractClass/ImplementAbstractClassCommandHandler.vb b/src/EditorFeatures/VisualBasic/ImplementAbstractClass/ImplementAbstractClassCommandHandler.vb index d1a469235b50f..2d9b2bd791135 100644 --- a/src/EditorFeatures/VisualBasic/ImplementAbstractClass/ImplementAbstractClassCommandHandler.vb +++ b/src/EditorFeatures/VisualBasic/ImplementAbstractClass/ImplementAbstractClassCommandHandler.vb @@ -5,9 +5,9 @@ Imports System.ComponentModel.Composition Imports System.Diagnostics.CodeAnalysis Imports System.Threading +Imports Microsoft.CodeAnalysis.Editor.[Shared].Utilities Imports Microsoft.CodeAnalysis.Editor.VisualBasic.Utilities.CommandHandlers Imports Microsoft.CodeAnalysis.ImplementAbstractClass -Imports Microsoft.CodeAnalysis.ImplementType Imports Microsoft.CodeAnalysis.Options Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Imports Microsoft.VisualStudio.Commanding @@ -26,16 +26,17 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.ImplementAbstractClass - Public Sub New(editorOperationsFactoryService As IEditorOperationsFactoryService, - globalOptions As IGlobalOptionService) - MyBase.New(editorOperationsFactoryService, globalOptions) + Public Sub New( + threadingContext As IThreadingContext, + editorOperationsFactoryService As IEditorOperationsFactoryService, + globalOptions As IGlobalOptionService) + MyBase.New(threadingContext, editorOperationsFactoryService, globalOptions) End Sub Protected Overrides Async Function TryGetNewDocumentAsync( document As Document, typeSyntax As TypeSyntax, - cancellationToken As CancellationToken - ) As Task(Of Document) + cancellationToken As CancellationToken) As Task(Of Document) If typeSyntax.Parent.Kind <> SyntaxKind.InheritsStatement Then Return Nothing @@ -47,13 +48,13 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.ImplementAbstractClass End If Dim updatedDocument = Await ImplementAbstractClassData.TryImplementAbstractClassAsync( - document, classBlock, classBlock.ClassStatement.Identifier, cancellationToken).ConfigureAwait(False) + document, classBlock, classBlock.ClassStatement.Identifier, cancellationToken).ConfigureAwait(True) If updatedDocument Is Nothing Then Return Nothing End If - Dim changes = Await updatedDocument.GetTextChangesAsync(document, cancellationToken).ConfigureAwait(False) + Dim changes = Await updatedDocument.GetTextChangesAsync(document, cancellationToken).ConfigureAwait(True) If changes.Any() Then Return updatedDocument End If diff --git a/src/EditorFeatures/VisualBasic/ImplementInterface/ImplementInterfaceCommandHandler.vb b/src/EditorFeatures/VisualBasic/ImplementInterface/ImplementInterfaceCommandHandler.vb index d0dfc3f1ebe9c..445fee3dc4f21 100644 --- a/src/EditorFeatures/VisualBasic/ImplementInterface/ImplementInterfaceCommandHandler.vb +++ b/src/EditorFeatures/VisualBasic/ImplementInterface/ImplementInterfaceCommandHandler.vb @@ -5,6 +5,7 @@ Imports System.ComponentModel.Composition Imports System.Diagnostics.CodeAnalysis Imports System.Threading +Imports Microsoft.CodeAnalysis.Editor.[Shared].Utilities Imports Microsoft.CodeAnalysis.Editor.VisualBasic.Utilities.CommandHandlers Imports Microsoft.CodeAnalysis.ImplementInterface Imports Microsoft.CodeAnalysis.ImplementType @@ -26,31 +27,32 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.ImplementInterface - Public Sub New(editorOperationsFactoryService As IEditorOperationsFactoryService, - globalOptions As IGlobalOptionService) - MyBase.New(editorOperationsFactoryService, globalOptions) + Public Sub New( + threadingContext As IThreadingContext, + editorOperationsFactoryService As IEditorOperationsFactoryService, + globalOptions As IGlobalOptionService) + MyBase.New(threadingContext, editorOperationsFactoryService, globalOptions) End Sub Protected Overrides Async Function TryGetNewDocumentAsync( document As Document, typeSyntax As TypeSyntax, - cancellationToken As CancellationToken - ) As Task(Of Document) + cancellationToken As CancellationToken) As Task(Of Document) If typeSyntax.Parent.Kind <> SyntaxKind.ImplementsStatement Then Return Nothing End If Dim service = document.GetLanguageService(Of IImplementInterfaceService)() - Dim options = Await document.GetImplementTypeOptionsAsync(cancellationToken).ConfigureAwait(False) + Dim options = Await document.GetImplementTypeOptionsAsync(cancellationToken).ConfigureAwait(True) Dim updatedDocument = Await service.ImplementInterfaceAsync( document, options, typeSyntax.Parent, - cancellationToken).ConfigureAwait(False) + cancellationToken).ConfigureAwait(True) - Dim changes = Await updatedDocument.GetTextChangesAsync(document, cancellationToken).ConfigureAwait(False) + Dim changes = Await updatedDocument.GetTextChangesAsync(document, cancellationToken).ConfigureAwait(True) If changes.Any() Then Return updatedDocument End If diff --git a/src/EditorFeatures/VisualBasic/LineCommit/CommitCommandHandler.vb b/src/EditorFeatures/VisualBasic/LineCommit/CommitCommandHandler.vb index 045cac342f8de..084902a4de5a7 100644 --- a/src/EditorFeatures/VisualBasic/LineCommit/CommitCommandHandler.vb +++ b/src/EditorFeatures/VisualBasic/LineCommit/CommitCommandHandler.vb @@ -139,7 +139,7 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.LineCommit Try ' Evil: we really want a enter in VB to be always grouped as a single undo transaction, and so make sure all ' things from here on out are grouped as one. - Using transaction = _textUndoHistoryRegistry.GetHistory(args.TextView.TextBuffer).CreateTransaction(VBEditorResources.Insert_new_line) + Using transaction = _textUndoHistoryRegistry.GetHistory(args.TextView.TextBuffer).CreateTransaction(EditorFeaturesResources.Insert_new_line) transaction.MergePolicy = AutomaticCodeChangeMergePolicy.Instance nextHandler() @@ -221,13 +221,13 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.LineCommit End Function Public Sub ExecuteCommand(args As PasteCommandArgs, nextHandler As Action, context As CommandExecutionContext) Implements IChainedCommandHandler(Of PasteCommandArgs).ExecuteCommand - Using context.OperationContext.AddScope(allowCancellation:=True, VBEditorResources.Formatting_pasted_text) + Using context.OperationContext.AddScope(allowCancellation:=True, EditorFeaturesResources.Formatting_pasted_text) CommitOnPaste(args, nextHandler, context.OperationContext.UserCancellationToken) End Using End Sub Private Sub CommitOnPaste(args As PasteCommandArgs, nextHandler As Action, cancellationToken As CancellationToken) - Using transaction = _textUndoHistoryRegistry.GetHistory(args.TextView.TextBuffer).CreateTransaction(VBEditorResources.Paste) + Using transaction = _textUndoHistoryRegistry.GetHistory(args.TextView.TextBuffer).CreateTransaction(EditorFeaturesResources.Paste) Dim oldVersion = args.SubjectBuffer.CurrentSnapshot.Version ' Do the paste in the same transaction as the commit/format diff --git a/src/EditorFeatures/VisualBasic/LineCommit/CommitFormatter.vb b/src/EditorFeatures/VisualBasic/LineCommit/CommitFormatter.vb index 89db5228db666..884c6285bdc93 100644 --- a/src/EditorFeatures/VisualBasic/LineCommit/CommitFormatter.vb +++ b/src/EditorFeatures/VisualBasic/LineCommit/CommitFormatter.vb @@ -121,7 +121,7 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.LineCommit End If End If - Dim changes = finalDocument.GetTextChangesAsync(document, cancellationToken).WaitAndGetResult(cancellationToken) + Dim changes = finalDocument.GetTextChangesSynchronously(document, cancellationToken) buffer.ApplyChanges(changes) End Using End Sub diff --git a/src/EditorFeatures/VisualBasic/LineCommit/ContainingStatementInfo.vb b/src/EditorFeatures/VisualBasic/LineCommit/ContainingStatementInfo.vb index 7f22244e1e3f9..ea2e9e3cd8c64 100644 --- a/src/EditorFeatures/VisualBasic/LineCommit/ContainingStatementInfo.vb +++ b/src/EditorFeatures/VisualBasic/LineCommit/ContainingStatementInfo.vb @@ -108,7 +108,7 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.LineCommit End If Dim containingStatement = token.GetAncestors(Of StatementSyntax) _ - .Where(Function(a) Not TypeOf a Is LambdaHeaderSyntax) _ + .Where(Function(a) TypeOf a IsNot LambdaHeaderSyntax) _ .FirstOrDefault() Dim containingTypeStatement = TryCast(containingStatement, TypeStatementSyntax) diff --git a/src/EditorFeatures/VisualBasic/NavigationBar/VisualBasicEditorNavigationBarItemService_CodeGeneration.vb b/src/EditorFeatures/VisualBasic/NavigationBar/VisualBasicEditorNavigationBarItemService_CodeGeneration.vb index 5dd41c53a9ebe..88c0bab8cf3e8 100644 --- a/src/EditorFeatures/VisualBasic/NavigationBar/VisualBasicEditorNavigationBarItemService_CodeGeneration.vb +++ b/src/EditorFeatures/VisualBasic/NavigationBar/VisualBasicEditorNavigationBarItemService_CodeGeneration.vb @@ -37,9 +37,10 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.NavigationBar Await ThreadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken) Using transaction = New CaretPreservingEditTransaction(VBEditorResources.Generate_Member, textView, _textUndoHistoryRegistry, _editorOperationsFactoryService) - newDocument.Project.Solution.Workspace.ApplyDocumentChanges(newDocument, cancellationToken) - Dim solution = newDocument.Project.Solution + Await solution.Workspace.ApplyDocumentChangesAsync( + ThreadingContext, newDocument, cancellationToken).ConfigureAwait(True) + Await NavigateToPositionAsync( solution.Workspace, solution.GetRequiredDocument(navigationPoint.Tree).Id, navigationPoint.Position, navigationPoint.VirtualSpaces, cancellationToken).ConfigureAwait(True) diff --git a/src/EditorFeatures/VisualBasic/TextStructureNavigation/VisualBasicTextStructureNavigatorProvider.vb b/src/EditorFeatures/VisualBasic/TextStructureNavigation/VisualBasicTextStructureNavigatorProvider.vb index 140f423b5166a..442da951f5d49 100644 --- a/src/EditorFeatures/VisualBasic/TextStructureNavigation/VisualBasicTextStructureNavigatorProvider.vb +++ b/src/EditorFeatures/VisualBasic/TextStructureNavigation/VisualBasicTextStructureNavigatorProvider.vb @@ -3,7 +3,6 @@ ' See the LICENSE file in the project root for more information. Imports System.ComponentModel.Composition -Imports Microsoft.CodeAnalysis.Editor.Host Imports Microsoft.CodeAnalysis.Editor.Implementation.TextStructureNavigation Imports Microsoft.CodeAnalysis.Host.Mef Imports Microsoft.VisualStudio.Text @@ -11,10 +10,9 @@ Imports Microsoft.VisualStudio.Text.Operations Imports Microsoft.VisualStudio.Utilities Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.TextStructureNavigation - - Friend Class VisualBasicTextStructureNavigatorProvider + Friend NotInheritable Class VisualBasicTextStructureNavigatorProvider Inherits AbstractTextStructureNavigatorProvider @@ -30,7 +28,7 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.TextStructureNavigation Return trivia.Kind() = SyntaxKind.CommentTrivia End Function - Protected Overrides Function IsWithinNaturalLanguage(token As SyntaxToken, position As Integer) As Boolean + Private Shared Function IsWithinNaturalLanguage(token As SyntaxToken, position As Integer) As Boolean Select Case token.Kind Case SyntaxKind.StringLiteralToken ' This, in combination with the override of GetExtentOfWordFromToken() below, treats the closing @@ -57,15 +55,20 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.TextStructureNavigation Return False End Function - Protected Overrides Function GetExtentOfWordFromToken(token As SyntaxToken, position As SnapshotPoint) As TextExtent + Protected Overrides Function GetExtentOfWordFromToken(navigator As ITextStructureNavigator, token As SyntaxToken, position As SnapshotPoint) As TextExtent + If IsWithinNaturalLanguage(token, position) Then + ' Defer to the editor to determine this. + Return navigator.GetExtentOfWord(position) + End If + If token.Kind() = SyntaxKind.StringLiteralToken AndAlso position.Position = token.Span.End - 1 AndAlso token.Text.EndsWith("""", StringComparison.Ordinal) Then ' Special case to treat the closing quote of a string literal as a separate token. This allows the ' cursor to stop during word navigation (Ctrl+LeftArrow, etc.) immediately before AND after the ' closing quote, just like it did in VS2013 and like it currently does for interpolated strings. - Dim Span = New Span(position.Position, 1) + Dim span = New Span(position.Position, 1) Return New TextExtent(New SnapshotSpan(position.Snapshot, Span), isSignificant:=True) Else - Return MyBase.GetExtentOfWordFromToken(token, position) + Return GetTokenExtent(token, position.Snapshot) End If End Function End Class diff --git a/src/EditorFeatures/VisualBasic/Utilities/CommandHandlers/AbstractImplementAbstractClassOrInterfaceCommandHandler.vb b/src/EditorFeatures/VisualBasic/Utilities/CommandHandlers/AbstractImplementAbstractClassOrInterfaceCommandHandler.vb index 598e16f37a888..d529709ebbfcc 100644 --- a/src/EditorFeatures/VisualBasic/Utilities/CommandHandlers/AbstractImplementAbstractClassOrInterfaceCommandHandler.vb +++ b/src/EditorFeatures/VisualBasic/Utilities/CommandHandlers/AbstractImplementAbstractClassOrInterfaceCommandHandler.vb @@ -6,8 +6,8 @@ Imports System.Threading Imports Microsoft.CodeAnalysis Imports Microsoft.CodeAnalysis.CodeCleanup Imports Microsoft.CodeAnalysis.Editor.Implementation.EndConstructGeneration +Imports Microsoft.CodeAnalysis.Editor.Shared.Utilities Imports Microsoft.CodeAnalysis.Formatting -Imports Microsoft.CodeAnalysis.ImplementType Imports Microsoft.CodeAnalysis.Options Imports Microsoft.CodeAnalysis.Simplification Imports Microsoft.CodeAnalysis.Text @@ -24,6 +24,7 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.Utilities.CommandHandlers Friend MustInherit Class AbstractImplementAbstractClassOrInterfaceCommandHandler Implements ICommandHandler(Of ReturnKeyCommandArgs) + Private ReadOnly _threadingContext As IThreadingContext Private ReadOnly _editorOperationsFactoryService As IEditorOperationsFactoryService Private ReadOnly _globalOptions As IGlobalOptionService @@ -33,8 +34,11 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.Utilities.CommandHandlers End Get End Property - Protected Sub New(editorOperationsFactoryService As IEditorOperationsFactoryService, - globalOptions As IGlobalOptionService) + Protected Sub New( + threadingContext As IThreadingContext, + editorOperationsFactoryService As IEditorOperationsFactoryService, + globalOptions As IGlobalOptionService) + _threadingContext = threadingContext _editorOperationsFactoryService = editorOperationsFactoryService _globalOptions = globalOptions End Sub @@ -45,20 +49,25 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.Utilities.CommandHandlers cancellationToken As CancellationToken) As Task(Of Document) Private Function ExecuteCommand(args As ReturnKeyCommandArgs, context As CommandExecutionContext) As Boolean Implements ICommandHandler(Of ReturnKeyCommandArgs).ExecuteCommand + Return _threadingContext.JoinableTaskFactory.Run(Function() ExecuteCommandAsync(args, context)) + End Function + + Private Async Function ExecuteCommandAsync(args As ReturnKeyCommandArgs, context As CommandExecutionContext) As Task(Of Boolean) Dim caretPointOpt = args.TextView.GetCaretPoint(args.SubjectBuffer) If caretPointOpt Is Nothing Then Return False End If ' Implement interface is not cancellable. + ' TODO: Switch to a background work indicator to do this work. Dim _cancellationToken = CancellationToken.None - If Not TryExecute(args, _cancellationToken) Then + If Not Await TryExecuteAsync(args, _cancellationToken).ConfigureAwait(True) Then Return False End If ' It's possible that there may be an end construct to generate at this position. ' We'll go ahead and generate it before determining whether we need to move the caret - TryGenerateEndConstruct(args, _cancellationToken) + Await TryGenerateEndConstructAsync(args, _cancellationToken).ConfigureAwait(True) Dim snapshot = args.SubjectBuffer.CurrentSnapshot Dim caretPosition = args.TextView.GetCaretPoint(args.SubjectBuffer).Value @@ -83,7 +92,9 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.Utilities.CommandHandlers Return True End Function - Private Shared Function TryGenerateEndConstruct(args As ReturnKeyCommandArgs, cancellationToken As CancellationToken) As Boolean + Private Shared Async Function TryGenerateEndConstructAsync( + args As ReturnKeyCommandArgs, + cancellationToken As CancellationToken) As Task(Of Boolean) Dim textSnapshot = args.SubjectBuffer.CurrentSnapshot Dim document = textSnapshot.GetOpenDocumentInCurrentContextWithChanges() @@ -103,10 +114,13 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.Utilities.CommandHandlers Dim endConstructGenerationService = document.GetLanguageService(Of IEndConstructGenerationService)() - Return endConstructGenerationService.TryDo(args.TextView, args.SubjectBuffer, vbLf(0), cancellationToken) + Return Await endConstructGenerationService.TryDoAsync( + args.TextView, args.SubjectBuffer, vbLf(0), cancellationToken).ConfigureAwait(True) End Function - Private Overloads Function TryExecute(args As ReturnKeyCommandArgs, cancellationToken As CancellationToken) As Boolean + Private Overloads Async Function TryExecuteAsync( + args As ReturnKeyCommandArgs, + cancellationToken As CancellationToken) As Task(Of Boolean) If Not _globalOptions.GetOption(AutomaticInsertionOfAbstractOrInterfaceMembersOptionsStorage.AutomaticInsertionOfAbstractOrInterfaceMembers, LanguageNames.VisualBasic) Then Return False End If @@ -164,17 +178,17 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.Utilities.CommandHandlers Return False End If - Dim newDocument = TryGetNewDocumentAsync(document, identifier, cancellationToken).WaitAndGetResult(cancellationToken) + Dim newDocument = Await TryGetNewDocumentAsync(document, identifier, cancellationToken).ConfigureAwait(True) If newDocument Is Nothing Then Return False End If - Dim cleanupOptions = newDocument.GetCodeCleanupOptionsAsync(cancellationToken).AsTask().WaitAndGetResult(cancellationToken) + Dim cleanupOptions = Await newDocument.GetCodeCleanupOptionsAsync(cancellationToken).ConfigureAwait(True) - newDocument = Simplifier.ReduceAsync(newDocument, Simplifier.Annotation, cleanupOptions.SimplifierOptions, cancellationToken).WaitAndGetResult(cancellationToken) - newDocument = Formatter.FormatAsync(newDocument, Formatter.Annotation, cleanupOptions.FormattingOptions, cancellationToken).WaitAndGetResult(cancellationToken) + newDocument = Await Simplifier.ReduceAsync(newDocument, Simplifier.Annotation, cleanupOptions.SimplifierOptions, cancellationToken).ConfigureAwait(True) + newDocument = Await Formatter.FormatAsync(newDocument, Formatter.Annotation, cleanupOptions.FormattingOptions, cancellationToken).ConfigureAwait(True) - Dim changes = newDocument.GetTextChangesAsync(document, cancellationToken).WaitAndGetResult(cancellationToken) + Dim changes = Await newDocument.GetTextChangesAsync(document, cancellationToken).ConfigureAwait(True) args.SubjectBuffer.ApplyChanges(changes) ' Place the cursor back to where it logically was after this diff --git a/src/EditorFeatures/VisualBasic/VBEditorResources.resx b/src/EditorFeatures/VisualBasic/VBEditorResources.resx index fe28efc13036a..bd2c3e4fc3195 100644 --- a/src/EditorFeatures/VisualBasic/VBEditorResources.resx +++ b/src/EditorFeatures/VisualBasic/VBEditorResources.resx @@ -129,15 +129,6 @@ Formatting Document... - - Insert new line - - - Formatting pasted text... - - - Paste - Format on Save diff --git a/src/EditorFeatures/VisualBasic/xlf/VBEditorResources.cs.xlf b/src/EditorFeatures/VisualBasic/xlf/VBEditorResources.cs.xlf index 88e6b385c91ad..40adc24fafd91 100644 --- a/src/EditorFeatures/VisualBasic/xlf/VBEditorResources.cs.xlf +++ b/src/EditorFeatures/VisualBasic/xlf/VBEditorResources.cs.xlf @@ -32,21 +32,6 @@ Formátuje se dokument... - - Insert new line - Vložit nový řádek - - - - Formatting pasted text... - Formátuje se vložený text... - - - - Paste - Vložit - - Format on Save Formátovat při uložení diff --git a/src/EditorFeatures/VisualBasic/xlf/VBEditorResources.de.xlf b/src/EditorFeatures/VisualBasic/xlf/VBEditorResources.de.xlf index 06bb3a2ef9322..14ba408a9f3bd 100644 --- a/src/EditorFeatures/VisualBasic/xlf/VBEditorResources.de.xlf +++ b/src/EditorFeatures/VisualBasic/xlf/VBEditorResources.de.xlf @@ -32,21 +32,6 @@ Dokument wird formatiert... - - Insert new line - Neue Zeile einfügen - - - - Formatting pasted text... - Eingefügter Text wird formatiert... - - - - Paste - Einfügen - - Format on Save Format wird gespeichert diff --git a/src/EditorFeatures/VisualBasic/xlf/VBEditorResources.es.xlf b/src/EditorFeatures/VisualBasic/xlf/VBEditorResources.es.xlf index c66c433c08f84..0d4a9bd33baf8 100644 --- a/src/EditorFeatures/VisualBasic/xlf/VBEditorResources.es.xlf +++ b/src/EditorFeatures/VisualBasic/xlf/VBEditorResources.es.xlf @@ -32,21 +32,6 @@ Dando formato al documento... - - Insert new line - Insertar nueva línea - - - - Formatting pasted text... - Dando formato al texto pegado... - - - - Paste - Pegar - - Format on Save Aplicar formato al guardar diff --git a/src/EditorFeatures/VisualBasic/xlf/VBEditorResources.fr.xlf b/src/EditorFeatures/VisualBasic/xlf/VBEditorResources.fr.xlf index 49a5f9eff36eb..b0aec3fcd8767 100644 --- a/src/EditorFeatures/VisualBasic/xlf/VBEditorResources.fr.xlf +++ b/src/EditorFeatures/VisualBasic/xlf/VBEditorResources.fr.xlf @@ -32,21 +32,6 @@ Mise en forme du document... - - Insert new line - Insérer une nouvelle ligne - - - - Formatting pasted text... - Mise en forme du texte collé... - - - - Paste - Coller - - Format on Save Mettre en forme lors de l'enregistrement diff --git a/src/EditorFeatures/VisualBasic/xlf/VBEditorResources.it.xlf b/src/EditorFeatures/VisualBasic/xlf/VBEditorResources.it.xlf index ba3f0561e77b5..44eec76916864 100644 --- a/src/EditorFeatures/VisualBasic/xlf/VBEditorResources.it.xlf +++ b/src/EditorFeatures/VisualBasic/xlf/VBEditorResources.it.xlf @@ -32,21 +32,6 @@ Formattazione del documento... - - Insert new line - Inserisci nuova riga - - - - Formatting pasted text... - Formattazione del testo incollato... - - - - Paste - Incolla - - Format on Save Formatta dopo salvataggio diff --git a/src/EditorFeatures/VisualBasic/xlf/VBEditorResources.ja.xlf b/src/EditorFeatures/VisualBasic/xlf/VBEditorResources.ja.xlf index 19e3d6a0997f8..321a8e9123b74 100644 --- a/src/EditorFeatures/VisualBasic/xlf/VBEditorResources.ja.xlf +++ b/src/EditorFeatures/VisualBasic/xlf/VBEditorResources.ja.xlf @@ -32,21 +32,6 @@ ドキュメントを書式設定しています... - - Insert new line - 改行の挿入 - - - - Formatting pasted text... - 貼り付けたテキストを書式設定しています... - - - - Paste - 貼り付け - - Format on Save 保存の形式 diff --git a/src/EditorFeatures/VisualBasic/xlf/VBEditorResources.ko.xlf b/src/EditorFeatures/VisualBasic/xlf/VBEditorResources.ko.xlf index b5aaf6566249b..291aa4bb95515 100644 --- a/src/EditorFeatures/VisualBasic/xlf/VBEditorResources.ko.xlf +++ b/src/EditorFeatures/VisualBasic/xlf/VBEditorResources.ko.xlf @@ -32,21 +32,6 @@ 문서 서식을 지정하는 중... - - Insert new line - 새 줄 삽입 - - - - Formatting pasted text... - 붙여넣은 텍스트의 서식을 지정하는 중... - - - - Paste - 붙여넣기 - - Format on Save 저장 시 서식 지정 diff --git a/src/EditorFeatures/VisualBasic/xlf/VBEditorResources.pl.xlf b/src/EditorFeatures/VisualBasic/xlf/VBEditorResources.pl.xlf index 1e5631858f1a9..6bbc0685966a4 100644 --- a/src/EditorFeatures/VisualBasic/xlf/VBEditorResources.pl.xlf +++ b/src/EditorFeatures/VisualBasic/xlf/VBEditorResources.pl.xlf @@ -32,21 +32,6 @@ Trwa formatowanie dokumentu... - - Insert new line - Wstaw nowy wiersz - - - - Formatting pasted text... - Trwa formatowanie wklejonego tekstu... - - - - Paste - Wklej - - Format on Save Sformatuj przy zapisywaniu diff --git a/src/EditorFeatures/VisualBasic/xlf/VBEditorResources.pt-BR.xlf b/src/EditorFeatures/VisualBasic/xlf/VBEditorResources.pt-BR.xlf index c58cf8fd6d22c..293697d0e825a 100644 --- a/src/EditorFeatures/VisualBasic/xlf/VBEditorResources.pt-BR.xlf +++ b/src/EditorFeatures/VisualBasic/xlf/VBEditorResources.pt-BR.xlf @@ -32,21 +32,6 @@ Formatando documento... - - Insert new line - Inserir Nova Linha - - - - Formatting pasted text... - Formatando texto colado... - - - - Paste - Colar - - Format on Save Formatar em Salvar diff --git a/src/EditorFeatures/VisualBasic/xlf/VBEditorResources.ru.xlf b/src/EditorFeatures/VisualBasic/xlf/VBEditorResources.ru.xlf index 8dcceed7fa120..690f7a41ba682 100644 --- a/src/EditorFeatures/VisualBasic/xlf/VBEditorResources.ru.xlf +++ b/src/EditorFeatures/VisualBasic/xlf/VBEditorResources.ru.xlf @@ -32,21 +32,6 @@ Идет форматирование документа... - - Insert new line - Вставить новую строку - - - - Formatting pasted text... - Идет форматирование вставленного текста... - - - - Paste - Вставить - - Format on Save Форматировать при сохранении diff --git a/src/EditorFeatures/VisualBasic/xlf/VBEditorResources.tr.xlf b/src/EditorFeatures/VisualBasic/xlf/VBEditorResources.tr.xlf index ad3a0dba7f81e..6c8d0822e071e 100644 --- a/src/EditorFeatures/VisualBasic/xlf/VBEditorResources.tr.xlf +++ b/src/EditorFeatures/VisualBasic/xlf/VBEditorResources.tr.xlf @@ -32,21 +32,6 @@ Belge biçimlendiriliyor... - - Insert new line - Yeni Satır Ekle - - - - Formatting pasted text... - Yapıştırılan metin biçimlendiriliyor... - - - - Paste - Yapıştır - - Format on Save Kaydetmede Biçimlendir diff --git a/src/EditorFeatures/VisualBasic/xlf/VBEditorResources.zh-Hans.xlf b/src/EditorFeatures/VisualBasic/xlf/VBEditorResources.zh-Hans.xlf index bcc70a0b32b09..999cf2055c011 100644 --- a/src/EditorFeatures/VisualBasic/xlf/VBEditorResources.zh-Hans.xlf +++ b/src/EditorFeatures/VisualBasic/xlf/VBEditorResources.zh-Hans.xlf @@ -32,21 +32,6 @@ 正在设置文档格式... - - Insert new line - 插入新行 - - - - Formatting pasted text... - 正在设置已粘贴文本的格式... - - - - Paste - 粘贴 - - Format on Save 在保存时格式化 diff --git a/src/EditorFeatures/VisualBasic/xlf/VBEditorResources.zh-Hant.xlf b/src/EditorFeatures/VisualBasic/xlf/VBEditorResources.zh-Hant.xlf index 6d32ce5305caf..4cdb0ea2d1761 100644 --- a/src/EditorFeatures/VisualBasic/xlf/VBEditorResources.zh-Hant.xlf +++ b/src/EditorFeatures/VisualBasic/xlf/VBEditorResources.zh-Hant.xlf @@ -32,21 +32,6 @@ 正在格式化文件... - - Insert new line - 插入新行 - - - - Formatting pasted text... - 正在格式化貼上的文字... - - - - Paste - 貼上 - - Format on Save 儲存時格式化 diff --git a/src/EditorFeatures/VisualBasicTest/AutomaticCompletion/AutomaticLineEnderTests.vb b/src/EditorFeatures/VisualBasicTest/AutomaticCompletion/AutomaticLineEnderTests.vb index a03d3c22cf3cd..90c5bcc51eb35 100644 --- a/src/EditorFeatures/VisualBasicTest/AutomaticCompletion/AutomaticLineEnderTests.vb +++ b/src/EditorFeatures/VisualBasicTest/AutomaticCompletion/AutomaticLineEnderTests.vb @@ -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. +Imports Microsoft.CodeAnalysis.Editor.[Shared].Utilities Imports Microsoft.CodeAnalysis.Editor.UnitTests.AutomaticCompletion Imports Microsoft.CodeAnalysis.Editor.UnitTests.Extensions Imports Microsoft.CodeAnalysis.Editor.UnitTests.Utilities @@ -271,6 +272,7 @@ End Module Protected Overrides Function CreateNextHandler(workspace As EditorTestWorkspace) As Action Dim endConstructor = New EndConstructCommandHandler( + workspace.GetService(Of IThreadingContext), workspace.GetService(Of IEditorOperationsFactoryService), workspace.GetService(Of ITextUndoHistoryRegistry), workspace.GetService(Of EditorOptionsService)) diff --git a/src/EditorFeatures/VisualBasicTest/CodeActions/AddImport/AddImportTests_NuGet.vb b/src/EditorFeatures/VisualBasicTest/CodeActions/AddImport/AddImportTests_NuGet.vb index 0fe7d8e661b29..4ce41e50adf16 100644 --- a/src/EditorFeatures/VisualBasicTest/CodeActions/AddImport/AddImportTests_NuGet.vb +++ b/src/EditorFeatures/VisualBasicTest/CodeActions/AddImport/AddImportTests_NuGet.vb @@ -8,10 +8,7 @@ Imports Microsoft.CodeAnalysis.AddImport Imports Microsoft.CodeAnalysis.CodeActions Imports Microsoft.CodeAnalysis.CodeFixes Imports Microsoft.CodeAnalysis.Diagnostics -Imports Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces -Imports Microsoft.CodeAnalysis.Options Imports Microsoft.CodeAnalysis.Packaging -Imports Microsoft.CodeAnalysis.Shared.Utilities Imports Microsoft.CodeAnalysis.SymbolSearch Imports Microsoft.CodeAnalysis.VisualBasic.AddImport Imports Moq @@ -56,9 +53,9 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.CodeActions.AddImp Returns(SpecializedTasks.True) Dim packageServiceMock = New Mock(Of ISymbolSearchService)(MockBehavior.Strict) - packageServiceMock.Setup(Function(s) s.FindReferenceAssembliesWithTypeAsync("NuGetType", 0, It.IsAny(Of CancellationToken))). - Returns(Function() ValueTaskFactory.FromResult(ImmutableArray(Of ReferenceAssemblyWithTypeResult).Empty)) - packageServiceMock.Setup(Function(s) s.FindPackagesWithTypeAsync(PackageSourceHelper.NugetOrgSourceName, "NuGetType", 0, It.IsAny(Of CancellationToken)())). + packageServiceMock.Setup(Function(s) s.FindReferenceAssembliesAsync(New TypeQuery("NuGetType", 0), It.IsAny(Of NamespaceQuery), It.IsAny(Of CancellationToken))). + Returns(Function() ValueTaskFactory.FromResult(ImmutableArray(Of ReferenceAssemblyResult).Empty)) + packageServiceMock.Setup(Function(s) s.FindPackagesAsync(PackageSourceHelper.NugetOrgSourceName, New TypeQuery("NuGetType", 0), It.IsAny(Of NamespaceQuery), It.IsAny(Of CancellationToken)())). Returns(Function() CreateSearchResult("NuGetPackage", "NuGetType", CreateNameParts("NuGetNamespace"))) Await TestInRegularAndScriptAsync( @@ -85,9 +82,9 @@ End Class", fixProviderData:=New ProviderData(installerServiceMock.Object, packa Returns(SpecializedTasks.True) Dim packageServiceMock = New Mock(Of ISymbolSearchService)(MockBehavior.Strict) - packageServiceMock.Setup(Function(s) s.FindReferenceAssembliesWithTypeAsync("NuGetType", 0, It.IsAny(Of CancellationToken))). - Returns(Function() ValueTaskFactory.FromResult(ImmutableArray(Of ReferenceAssemblyWithTypeResult).Empty)) - packageServiceMock.Setup(Function(s) s.FindPackagesWithTypeAsync(PackageSourceHelper.NugetOrgSourceName, "NuGetType", 0, It.IsAny(Of CancellationToken)())). + packageServiceMock.Setup(Function(s) s.FindReferenceAssembliesAsync(New TypeQuery("NuGetType", 0), It.IsAny(Of NamespaceQuery), It.IsAny(Of CancellationToken))). + Returns(Function() ValueTaskFactory.FromResult(ImmutableArray(Of ReferenceAssemblyResult).Empty)) + packageServiceMock.Setup(Function(s) s.FindPackagesAsync(PackageSourceHelper.NugetOrgSourceName, New TypeQuery("NuGetType", 0), It.IsAny(Of NamespaceQuery), It.IsAny(Of CancellationToken)())). Returns(Function() CreateSearchResult("NuGetPackage", "NuGetType", CreateNameParts("NS1", "NS2"))) Await TestInRegularAndScriptAsync( @@ -114,9 +111,9 @@ End Class", fixProviderData:=New ProviderData(installerServiceMock.Object, packa Returns(SpecializedTasks.False) Dim packageServiceMock = New Mock(Of ISymbolSearchService)(MockBehavior.Strict) - packageServiceMock.Setup(Function(s) s.FindReferenceAssembliesWithTypeAsync("NuGetType", 0, It.IsAny(Of CancellationToken))). - Returns(Function() ValueTaskFactory.FromResult(ImmutableArray(Of ReferenceAssemblyWithTypeResult).Empty)) - packageServiceMock.Setup(Function(s) s.FindPackagesWithTypeAsync(PackageSourceHelper.NugetOrgSourceName, "NuGetType", 0, It.IsAny(Of CancellationToken)())). + packageServiceMock.Setup(Function(s) s.FindReferenceAssembliesAsync(New TypeQuery("NuGetType", 0), It.IsAny(Of NamespaceQuery), It.IsAny(Of CancellationToken))). + Returns(Function() ValueTaskFactory.FromResult(ImmutableArray(Of ReferenceAssemblyResult).Empty)) + packageServiceMock.Setup(Function(s) s.FindPackagesAsync(PackageSourceHelper.NugetOrgSourceName, New TypeQuery("NuGetType", 0), It.IsAny(Of NamespaceQuery), It.IsAny(Of CancellationToken)())). Returns(Function() CreateSearchResult("NuGetPackage", "NuGetType", CreateNameParts("NS1", "NS2"))) Await TestInRegularAndScriptAsync( @@ -139,9 +136,9 @@ End Class", fixProviderData:=New ProviderData(installerServiceMock.Object, packa Returns(True) Dim packageServiceMock = New Mock(Of ISymbolSearchService)(MockBehavior.Strict) - packageServiceMock.Setup(Function(s) s.FindReferenceAssembliesWithTypeAsync("NuGetType", 0, It.IsAny(Of CancellationToken))). - Returns(Function() ValueTaskFactory.FromResult(ImmutableArray(Of ReferenceAssemblyWithTypeResult).Empty)) - packageServiceMock.Setup(Function(s) s.FindPackagesWithTypeAsync(PackageSourceHelper.NugetOrgSourceName, "NuGetType", 0, It.IsAny(Of CancellationToken)())). + packageServiceMock.Setup(Function(s) s.FindReferenceAssembliesAsync(New TypeQuery("NuGetType", 0), It.IsAny(Of NamespaceQuery), It.IsAny(Of CancellationToken))). + Returns(Function() ValueTaskFactory.FromResult(ImmutableArray(Of ReferenceAssemblyResult).Empty)) + packageServiceMock.Setup(Function(s) s.FindPackagesAsync(PackageSourceHelper.NugetOrgSourceName, New TypeQuery("NuGetType", 0), It.IsAny(Of NamespaceQuery), It.IsAny(Of CancellationToken)())). Returns(Function() CreateSearchResult("NuGetPackage", "NuGetType", CreateNameParts("NS1", "NS2"))) Await TestMissingInRegularAndScriptAsync( @@ -164,9 +161,9 @@ New TestParameters(fixProviderData:=New ProviderData(installerServiceMock.Object Returns(ImmutableArray.Create("1.0", "2.0")) Dim packageServiceMock = New Mock(Of ISymbolSearchService)(MockBehavior.Strict) - packageServiceMock.Setup(Function(s) s.FindReferenceAssembliesWithTypeAsync("NuGetType", 0, It.IsAny(Of CancellationToken))). - Returns(Function() ValueTaskFactory.FromResult(ImmutableArray(Of ReferenceAssemblyWithTypeResult).Empty)) - packageServiceMock.Setup(Function(s) s.FindPackagesWithTypeAsync(PackageSourceHelper.NugetOrgSourceName, "NuGetType", 0, It.IsAny(Of CancellationToken)())). + packageServiceMock.Setup(Function(s) s.FindReferenceAssembliesAsync(New TypeQuery("NuGetType", 0), It.IsAny(Of NamespaceQuery), It.IsAny(Of CancellationToken))). + Returns(Function() ValueTaskFactory.FromResult(ImmutableArray(Of ReferenceAssemblyResult).Empty)) + packageServiceMock.Setup(Function(s) s.FindPackagesAsync(PackageSourceHelper.NugetOrgSourceName, New TypeQuery("NuGetType", 0), It.IsAny(Of NamespaceQuery), It.IsAny(Of CancellationToken)())). Returns(Function() CreateSearchResult("NuGetPackage", "NuGetType", CreateNameParts("NS1", "NS2"))) Dim data = New ProviderData(installerServiceMock.Object, packageServiceMock.Object) @@ -206,9 +203,9 @@ parameters:=New TestParameters(index:=2, fixProviderData:=data)) Returns(SpecializedTasks.True) Dim packageServiceMock = New Mock(Of ISymbolSearchService)(MockBehavior.Strict) - packageServiceMock.Setup(Function(s) s.FindReferenceAssembliesWithTypeAsync("NuGetType", 0, It.IsAny(Of CancellationToken))). - Returns(Function() ValueTaskFactory.FromResult(ImmutableArray(Of ReferenceAssemblyWithTypeResult).Empty)) - packageServiceMock.Setup(Function(s) s.FindPackagesWithTypeAsync(PackageSourceHelper.NugetOrgSourceName, "NuGetType", 0, It.IsAny(Of CancellationToken)())). + packageServiceMock.Setup(Function(s) s.FindReferenceAssembliesAsync(New TypeQuery("NuGetType", 0), It.IsAny(Of NamespaceQuery), It.IsAny(Of CancellationToken))). + Returns(Function() ValueTaskFactory.FromResult(ImmutableArray(Of ReferenceAssemblyResult).Empty)) + packageServiceMock.Setup(Function(s) s.FindPackagesAsync(PackageSourceHelper.NugetOrgSourceName, New TypeQuery("NuGetType", 0), It.IsAny(Of NamespaceQuery), It.IsAny(Of CancellationToken)())). Returns(Function() CreateSearchResult("NuGetPackage", "NuGetType", CreateNameParts("NuGetNamespace"))) Await TestInRegularAndScriptAsync( @@ -238,9 +235,9 @@ End Class", fixProviderData:=New ProviderData(installerServiceMock.Object, packa Returns(SpecializedTasks.True) Dim packageServiceMock = New Mock(Of ISymbolSearchService)(MockBehavior.Strict) - packageServiceMock.Setup(Function(s) s.FindReferenceAssembliesWithTypeAsync("NuGetType", 0, It.IsAny(Of CancellationToken))). - Returns(Function() ValueTaskFactory.FromResult(ImmutableArray(Of ReferenceAssemblyWithTypeResult).Empty)) - packageServiceMock.Setup(Function(s) s.FindPackagesWithTypeAsync(PackageSourceHelper.NugetOrgSourceName, "NuGetType", 0, It.IsAny(Of CancellationToken)())). + packageServiceMock.Setup(Function(s) s.FindReferenceAssembliesAsync(New TypeQuery("NuGetType", 0), It.IsAny(Of NamespaceQuery), It.IsAny(Of CancellationToken))). + Returns(Function() ValueTaskFactory.FromResult(ImmutableArray(Of ReferenceAssemblyResult).Empty)) + packageServiceMock.Setup(Function(s) s.FindPackagesAsync(PackageSourceHelper.NugetOrgSourceName, New TypeQuery("NuGetType", 0), It.IsAny(Of NamespaceQuery), It.IsAny(Of CancellationToken)())). Returns(Function() CreateSearchResult("NuGetPackage", "NuGetType", CreateNameParts("NuGetNamespace"))) Await TestInRegularAndScriptAsync( @@ -257,8 +254,8 @@ End Class", fixProviderData:=New ProviderData(installerServiceMock.Object, packa installerServiceMock.Verify() End Function - Private Shared Function CreateSearchResult(packageName As String, typeName As String, nameParts As ImmutableArray(Of String)) As ValueTask(Of ImmutableArray(Of PackageWithTypeResult)) - Return CreateSearchResult(New PackageWithTypeResult( + Private Shared Function CreateSearchResult(packageName As String, typeName As String, nameParts As ImmutableArray(Of String)) As ValueTask(Of ImmutableArray(Of PackageResult)) + Return CreateSearchResult(New PackageResult( packageName:=packageName, rank:=0, typeName:=typeName, @@ -266,7 +263,7 @@ End Class", fixProviderData:=New ProviderData(installerServiceMock.Object, packa containingNamespaceNames:=nameParts)) End Function - Private Shared Function CreateSearchResult(ParamArray results As PackageWithTypeResult()) As ValueTask(Of ImmutableArray(Of PackageWithTypeResult)) + Private Shared Function CreateSearchResult(ParamArray results As PackageResult()) As ValueTask(Of ImmutableArray(Of PackageResult)) Return ValueTaskFactory.FromResult(ImmutableArray.Create(results)) End Function diff --git a/src/EditorFeatures/VisualBasicTest/CodeActions/MoveType/BasicMoveTypeTestsBase.vb b/src/EditorFeatures/VisualBasicTest/CodeActions/MoveType/BasicMoveTypeTestsBase.vb index f66698bdd9201..629faf6778e08 100644 --- a/src/EditorFeatures/VisualBasicTest/CodeActions/MoveType/BasicMoveTypeTestsBase.vb +++ b/src/EditorFeatures/VisualBasicTest/CodeActions/MoveType/BasicMoveTypeTestsBase.vb @@ -32,7 +32,7 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.CodeRefactorings.M ) As Task Dim expectedText As String = Nothing - If Not expectedCode Is Nothing Then + If expectedCode IsNot Nothing Then expectedText = expectedCode.ConvertTestSourceTag() End If diff --git a/src/EditorFeatures/VisualBasicTest/CodeActions/MoveType/MoveTypeTests.MoveToNewFile.vb b/src/EditorFeatures/VisualBasicTest/CodeActions/MoveType/MoveTypeTests.MoveToNewFile.vb index 18ae6eaee372e..97dcf5832cf1c 100644 --- a/src/EditorFeatures/VisualBasicTest/CodeActions/MoveType/MoveTypeTests.MoveToNewFile.vb +++ b/src/EditorFeatures/VisualBasicTest/CodeActions/MoveType/MoveTypeTests.MoveToNewFile.vb @@ -4,7 +4,7 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.CodeRefactorings.MoveType - Partial Public Class MoveTypeTests + Partial Public NotInheritable Class MoveTypeTests Inherits BasicMoveTypeTestsBase @@ -311,5 +311,37 @@ end class Await TestMoveTypeToNewFileAsync( code, codeAfterMove, expectedDocumentName, destinationDocumentText) End Function + + + Public Async Function MoveNestedTypeToNewFile_SiblingMethods() As Task + Dim code = +" +Public Class Class1 + Class Class2[||] + End Class + + Sub M1() + End Sub +End Class +" + Dim codeAfterMove = +" +Partial Public Class Class1 + + Sub M1() + End Sub +End Class +" + Dim expectedDocumentName = "Class2.vb" + + Dim destinationDocumentText = +" +Partial Public Class Class1 + Class Class2 + End Class +End Class +" + Await TestMoveTypeToNewFileAsync(code, codeAfterMove, expectedDocumentName, destinationDocumentText) + End Function End Class End Namespace diff --git a/src/EditorFeatures/VisualBasicTest/Completion/CompletionProviders/OverrideCompletionProviderTests.vb b/src/EditorFeatures/VisualBasicTest/Completion/CompletionProviders/OverrideCompletionProviderTests.vb index d55e1f46ff1ed..0b165bcdbd844 100644 --- a/src/EditorFeatures/VisualBasicTest/Completion/CompletionProviders/OverrideCompletionProviderTests.vb +++ b/src/EditorFeatures/VisualBasicTest/Completion/CompletionProviders/OverrideCompletionProviderTests.vb @@ -1203,6 +1203,55 @@ End Class]]> Await VerifyCustomCommitProviderAsync(markupBeforeCommit.Value.Replace(vbLf, vbCrLf), "M(i As Integer)", expectedCode.Value.Replace(vbLf, vbCrLf)) End Function + + Public Async Function CommitTriviaOnMissingTokenArePreserved() As Task + Dim markupBeforeCommit = i As Integer) + End Sub +End Class + +Public Class Class2 + Inherits Class1 + + Public Overrides Sub $$ + ' Comment on body +End Class]]> + + Dim expectedCode = i As Integer) + End Sub +End Class + +Public Class Class2 + Inherits Class1 + + Public Overrides Sub M( i As Integer) + MyBase.M(i)$$ + End Sub + ' Comment on body +End Class]]> + + Await VerifyCustomCommitProviderAsync(markupBeforeCommit.Value.Replace(vbLf, vbCrLf), "M(i As Integer)", expectedCode.Value.Replace(vbLf, vbCrLf)) + End Function + Public Async Function TestCommitGenericMethod() As Task Dim markupBeforeCommit = Class CBase diff --git a/src/EditorFeatures/VisualBasicTest/Debugging/DataTipInfoGetterTests.vb b/src/EditorFeatures/VisualBasicTest/Debugging/DataTipInfoGetterTests.vb index 43736ac2f28b0..2261f004afe66 100644 --- a/src/EditorFeatures/VisualBasicTest/Debugging/DataTipInfoGetterTests.vb +++ b/src/EditorFeatures/VisualBasicTest/Debugging/DataTipInfoGetterTests.vb @@ -2,57 +2,16 @@ ' The .NET Foundation licenses this file to you under the MIT license. ' See the LICENSE file in the project root for more information. -Imports System.Threading -Imports System.Threading.Tasks -Imports Microsoft.CodeAnalysis -Imports Microsoft.CodeAnalysis.Editor.UnitTests.Extensions -Imports Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces -Imports Microsoft.CodeAnalysis.Test.Utilities -Imports Microsoft.CodeAnalysis.Text -Imports Microsoft.CodeAnalysis.VisualBasic.Debugging -Imports Roslyn.Test.Utilities -Imports Roslyn.Utilities +Imports Microsoft.CodeAnalysis.Test.Utilities.Debugging Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.Debugging - <[UseExportProvider]> - Public Class DataTipInfoGetterTests - - Private Shared Async Function TestNoDataTipAsync(input As XElement) As Task - Dim parsedInput As String = Nothing - Dim expectedPosition As Integer - MarkupTestFile.GetPosition(input.NormalizedValue, parsedInput, expectedPosition) - - Await TestSpanGetterAsync(input.NormalizedValue, expectedPosition, - Async Function(document, position) - Dim result = Await DataTipInfoGetter.GetInfoAsync(document, position, CancellationToken.None) - Assert.True(result.IsDefault) - End Function) - End Function + Public NotInheritable Class DataTipInfoGetterTests + Inherits AbstractDataTipInfoGetterTests - Private Shared Async Function TestAsync(input As XElement, Optional expectedText As String = Nothing) As Task - Dim parsedInput As String = Nothing - Dim expectedPosition As Integer - Dim textSpan As TextSpan - MarkupTestFile.GetPositionAndSpan(input.NormalizedValue, parsedInput, expectedPosition, textSpan) - - Await TestSpanGetterAsync(input.NormalizedValue, expectedPosition, - Async Function(document, position) - Dim result = Await DataTipInfoGetter.GetInfoAsync(document, position, CancellationToken.None) - Assert.False(result.IsDefault) - Assert.Equal(textSpan, result.Span) - If Not String.IsNullOrEmpty(expectedText) Then - Assert.Equal(expectedText, result.Text) - End If - End Function) - End Function - - Private Shared Async Function TestSpanGetterAsync(parsedInput As String, position As Integer, continuation As Func(Of Document, Integer, Task)) As Task - Using workspace = TestWorkspace.CreateVisualBasic(parsedInput) - Dim debugInfo = New VisualBasicLanguageDebugInfoService() - Await continuation(workspace.CurrentSolution.Projects.First.Documents.First, position) - End Using + Protected Overrides Function CreateWorkspace(markup As String) As EditorTestWorkspace + Return EditorTestWorkspace.CreateVisualBasic(markup) End Function @@ -438,5 +397,60 @@ End Class Await TestAsync(<%= String.Format(sourceTemplate, "[|Me.row?.It$$em(""Test Row"")|].Length") %>) Await TestAsync(<%= String.Format(sourceTemplate, "[|Me?.row?.It$$em(""Test Row"")|].Length") %>) End Function + + + Public Async Function TestLinq1() As Task + Await TestAsync( +imports System.Linq +class C + sub Goo(args as integer()) + dim x = $$[|args|].Select(function(a) a.ToString()) + end sub +end class) + End Function + + + Public Async Function TestLinq2() As Task + Await TestAsync( +imports System.Linq +class C + sub Goo(args as integer()) + dim x = {|LinqExpression:[|args.$$Select(function(a) a.ToString())|]|} + end sub +end class) + End Function + + + Public Async Function TestLinq3() As Task + Await TestAsync( +imports System.Linq +class C + sub Goo(args as integer()) + dim x = [|$$args|].Select(function(a) a.ToString()).Where(function(a) a.Length >= 0) + end sub +end class) + End Function + + + Public Async Function TestLinq4() As Task + Await TestAsync( +imports System.Linq +class C + sub Goo(args as integer()) + dim x = {|LinqExpression:[|args.$$Select(function(a) a.ToString())|]|}.Where(function(a) a.Length >= 0) + end sub +end class) + End Function + + + Public Async Function TestLinq5() As Task + Await TestAsync( +imports System.Linq +class C + sub Goo(args as integer()) + dim x = {|LinqExpression:[|args.Select(function(a) a.ToString()).$$Where(function(a) a.Length >= 0)|]|} + end sub +end class) + End Function End Class End Namespace diff --git a/src/EditorFeatures/VisualBasicTest/EndConstructGeneration/CharacterTypingTests.vb b/src/EditorFeatures/VisualBasicTest/EndConstructGeneration/CharacterTypingTests.vb index d00841abcb342..1a32ab75fd050 100644 --- a/src/EditorFeatures/VisualBasicTest/EndConstructGeneration/CharacterTypingTests.vb +++ b/src/EditorFeatures/VisualBasicTest/EndConstructGeneration/CharacterTypingTests.vb @@ -9,8 +9,8 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.EndConstructGenera Public Class CharacterTypingTests - Public Sub TestXmlEndConstructApplied() - VerifyEndConstructAppliedAfterChar( + Public Async Function TestXmlEndConstructApplied() As Task + Await VerifyEndConstructAppliedAfterCharAsync( before:= .NormalizedValue, typedChar:=">"c, endCaretPos:={3, 21}) - End Sub + End Function - Public Sub TestXmlEndConstructNotApplied() - VerifyEndConstructNotAppliedAfterChar( + Public Async Function TestXmlEndConstructNotApplied() As Task + Await VerifyEndConstructNotAppliedAfterCharAsync( before:= .NormalizedValue, typedChar:=">"c, endCaretPos:={3, 14}) - End Sub + End Function - Public Sub TestXmlCommentEndConstructApplied() - VerifyEndConstructAppliedAfterChar( + Public Async Function TestXmlCommentEndConstructApplied() As Task + Await VerifyEndConstructAppliedAfterCharAsync( before:= .NormalizedValue, typedChar:="-"c, endCaretPos:={3, 25}) - End Sub + End Function - Public Sub TestXmlCommentEndConstructNotApplied() - VerifyEndConstructNotAppliedAfterChar( + Public Async Function TestXmlCommentEndConstructNotApplied() As Task + Await VerifyEndConstructNotAppliedAfterCharAsync( before:= .NormalizedValue, typedChar:="-"c, endCaretPos:={3, 19}) - End Sub + End Function - Public Sub TestXmlEmbeddedExpressionEndConstructApplied() - VerifyEndConstructAppliedAfterChar( + Public Async Function TestXmlEmbeddedExpressionEndConstructApplied() As Task + Await VerifyEndConstructAppliedAfterCharAsync( before:= .NormalizedValue, typedChar:="="c, endCaretPos:={3, 30}) - End Sub + End Function - Public Sub TestXmlEmbeddedExpressionEndConstructNotApplied() - VerifyEndConstructNotAppliedAfterChar( + Public Async Function TestXmlEmbeddedExpressionEndConstructNotApplied() As Task + Await VerifyEndConstructNotAppliedAfterCharAsync( before:= .NormalizedValue, typedChar:="="c, endCaretPos:={3, 15}) - End Sub + End Function - Public Sub TestXmlCDataEndConstructApplied() - VerifyEndConstructAppliedAfterChar( + Public Async Function TestXmlCDataEndConstructApplied() As Task + Await VerifyEndConstructAppliedAfterCharAsync( before:= .NormalizedValue, typedChar:="["c, endCaretPos:={3, 30}) - End Sub + End Function - Public Sub TestXmlCDataEndConstructNotApplied() - VerifyEndConstructNotAppliedAfterChar( + Public Async Function TestXmlCDataEndConstructNotApplied() As Task + Await VerifyEndConstructNotAppliedAfterCharAsync( before:= .NormalizedValue, typedChar:="["c, endCaretPos:={3, 18}) - End Sub + End Function - Public Sub TestXmlProcessingInstructionEndConstructApplied() - VerifyEndConstructAppliedAfterChar( + Public Async Function TestXmlProcessingInstructionEndConstructApplied() As Task + Await VerifyEndConstructAppliedAfterCharAsync( before:= .NormalizedValue, typedChar:="?"c, endCaretPos:={3, 18}) - End Sub + End Function - Public Sub TestXmlProcessingInstructionEndConstructNotApplied() - VerifyEndConstructNotAppliedAfterChar( + Public Async Function TestXmlProcessingInstructionEndConstructNotApplied() As Task + Await VerifyEndConstructNotAppliedAfterCharAsync( before:= .NormalizedValue, typedChar:="?"c, endCaretPos:={3, 18}) - End Sub - + End Function End Class End Namespace diff --git a/src/EditorFeatures/VisualBasicTest/EndConstructGeneration/CustomEventTests.vb b/src/EditorFeatures/VisualBasicTest/EndConstructGeneration/CustomEventTests.vb index 004afcb0be2cc..19ca00759e62f 100644 --- a/src/EditorFeatures/VisualBasicTest/EndConstructGeneration/CustomEventTests.vb +++ b/src/EditorFeatures/VisualBasicTest/EndConstructGeneration/CustomEventTests.vb @@ -7,8 +7,8 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.EndConstructGenera Public Class CustomEventTests - Public Sub TestApplyAfterCustomEvent() - VerifyStatementEndConstructApplied( + Public Async Function TestApplyAfterCustomEvent() As Task + Await VerifyStatementEndConstructAppliedAsync( before:="Class c1 Custom Event goo As System.EventHandler End Class", @@ -27,11 +27,11 @@ End Class", End Event End Class", afterCaret:={3, -1}) - End Sub + End Function - Public Sub TestApplyAfterCustomEventWithImportsStatement() - VerifyStatementEndConstructApplied( + Public Async Function TestApplyAfterCustomEventWithImportsStatement() As Task + Await VerifyStatementEndConstructAppliedAsync( before:="Imports System Class c1 Custom Event goo As EventHandler @@ -52,11 +52,11 @@ Class c1 End Event End Class", afterCaret:={4, -1}) - End Sub + End Function - Public Sub TestApplyAfterCustomEventWithMissingDelegateType() - VerifyStatementEndConstructApplied( + Public Async Function TestApplyAfterCustomEventWithMissingDelegateType() As Task + Await VerifyStatementEndConstructAppliedAsync( before:="Imports System Class c1 Custom Event goo As GooHandler @@ -77,11 +77,11 @@ Class c1 End Event End Class", afterCaret:={4, -1}) - End Sub + End Function - Public Sub TestApplyAfterCustomEventWithNonDelegateType() - VerifyStatementEndConstructApplied( + Public Async Function TestApplyAfterCustomEventWithNonDelegateType() As Task + Await VerifyStatementEndConstructAppliedAsync( before:="Imports System Class c1 Custom Event goo As Object @@ -102,11 +102,11 @@ Class c1 End Event End Class", afterCaret:={4, -1}) - End Sub + End Function - Public Sub TestApplyAfterCustomEventWithGenericType() - VerifyStatementEndConstructApplied( + Public Async Function TestApplyAfterCustomEventWithGenericType() As Task + Await VerifyStatementEndConstructAppliedAsync( before:="Imports System Class c1 Custom Event goo As EventHandler(Of ConsoleCancelEventArgs) @@ -127,11 +127,11 @@ Class c1 End Event End Class", afterCaret:={4, -1}) - End Sub + End Function - Public Sub DoNotApplyAfterCustomEventAlreadyTerminated() - VerifyStatementEndConstructNotApplied( + Public Async Function DoNotApplyAfterCustomEventAlreadyTerminated() As Task + Await VerifyStatementEndConstructNotAppliedAsync( text:="Imports System Class c1 Custom Event goo As EventHandler(Of ConsoleCancelEventArgs) @@ -147,6 +147,6 @@ Class c1 End Event End Class", caret:={2, -1}) - End Sub + End Function End Class End Namespace diff --git a/src/EditorFeatures/VisualBasicTest/EndConstructGeneration/DoLoopTests.vb b/src/EditorFeatures/VisualBasicTest/EndConstructGeneration/DoLoopTests.vb index dbedfb25e4364..82d1218b7f92e 100644 --- a/src/EditorFeatures/VisualBasicTest/EndConstructGeneration/DoLoopTests.vb +++ b/src/EditorFeatures/VisualBasicTest/EndConstructGeneration/DoLoopTests.vb @@ -7,8 +7,8 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.EndConstructGenera Public Class DoLoopTests - Public Sub TestApplyAfterUnmatchedDo() - VerifyStatementEndConstructApplied( + Public Async Function TestApplyAfterUnmatchedDo() As Task + Await VerifyStatementEndConstructAppliedAsync( before:="Class c1 Sub goo() Do @@ -23,11 +23,11 @@ End Class", End Sub End Class", afterCaret:={3, -1}) - End Sub + End Function - Public Sub TestVerifyNestedDo() - VerifyStatementEndConstructApplied( + Public Async Function TestVerifyNestedDo() As Task + Await VerifyStatementEndConstructAppliedAsync( before:="Class c1 Sub goo() Do @@ -46,39 +46,39 @@ End Class", End Sub End Class", afterCaret:={4, -1}) - End Sub + End Function - Public Sub DoNotApplyFromPairedDo() - VerifyStatementEndConstructNotApplied( + Public Async Function DoNotApplyFromPairedDo() As Task + Await VerifyStatementEndConstructNotAppliedAsync( text:="Class c1 Do Loop End Class", caret:={1, -1}) - End Sub + End Function - Public Sub DoNotApplyFromInsideDo() - VerifyStatementEndConstructNotApplied( + Public Async Function DoNotApplyFromInsideDo() As Task + Await VerifyStatementEndConstructNotAppliedAsync( text:="Class c1 Do End Class", caret:={1, 1}) - End Sub + End Function - Public Sub DoNotApplyFromDoOutsideMethod() - VerifyStatementEndConstructNotApplied( + Public Async Function DoNotApplyFromDoOutsideMethod() As Task + Await VerifyStatementEndConstructNotAppliedAsync( text:="Class c1 Do End Class", caret:={1, -1}) - End Sub + End Function - Public Sub TestVerifyDoWhile() - VerifyStatementEndConstructApplied( + Public Async Function TestVerifyDoWhile() As Task + Await VerifyStatementEndConstructAppliedAsync( before:="Class C Sub s Do While True @@ -94,11 +94,11 @@ End Sub End Class", afterCaret:={3, -1}) - End Sub + End Function - Public Sub TestVerifyNestedDoWhile() - VerifyStatementEndConstructApplied( + Public Async Function TestVerifyNestedDoWhile() As Task + Await VerifyStatementEndConstructAppliedAsync( before:="Class C Sub s do While True @@ -117,11 +117,11 @@ End Class", End Sub End Class", afterCaret:={4, -1}) - End Sub + End Function - Public Sub TestVerifyDoUntil() - VerifyStatementEndConstructApplied( + Public Async Function TestVerifyDoUntil() As Task + Await VerifyStatementEndConstructAppliedAsync( before:="Class C Sub s do Until true @@ -136,11 +136,11 @@ End Class", End Sub End Class", afterCaret:={3, -1}) - End Sub + End Function - Public Sub TestVerifyNestedDoUntil() - VerifyStatementEndConstructApplied( + Public Async Function TestVerifyNestedDoUntil() As Task + Await VerifyStatementEndConstructAppliedAsync( before:="Class C Sub s do Until True @@ -159,11 +159,11 @@ End Class", End Sub End Class", afterCaret:={4, -1}) - End Sub + End Function - Public Sub TestVerifyDoWhileInBrokenSub() - VerifyStatementEndConstructApplied( + Public Async Function TestVerifyDoWhileInBrokenSub() As Task + Await VerifyStatementEndConstructAppliedAsync( before:="Class C Sub s Do While True @@ -176,35 +176,35 @@ End Class", Loop End Class", afterCaret:={3, -1}) - End Sub + End Function - Public Sub VerifyDoUntilInvalidLocation01() - VerifyStatementEndConstructNotApplied( + Public Async Function VerifyDoUntilInvalidLocation01() As Task + Await VerifyStatementEndConstructNotAppliedAsync( text:="Class C Sub s End Sub do Until True End Class", caret:={3, -1}) - End Sub + End Function - Public Sub VerifyDoUntilInvalidLocation02() - VerifyStatementEndConstructNotApplied( + Public Async Function VerifyDoUntilInvalidLocation02() As Task + Await VerifyStatementEndConstructNotAppliedAsync( text:="Do", caret:={0, -1}) - End Sub + End Function - Public Sub VerifyDoUntilInvalidLocation03() - VerifyStatementEndConstructNotApplied( + Public Async Function VerifyDoUntilInvalidLocation03() As Task + Await VerifyStatementEndConstructNotAppliedAsync( text:="Class C Sub s End Sub do Until End Class", caret:={3, -1}) - End Sub + End Function End Class End Namespace diff --git a/src/EditorFeatures/VisualBasicTest/EndConstructGeneration/EndConstructCommandHandlerTests.vb b/src/EditorFeatures/VisualBasicTest/EndConstructGeneration/EndConstructCommandHandlerTests.vb index 583abaf9ac0ee..b7fcfe8135e32 100644 --- a/src/EditorFeatures/VisualBasicTest/EndConstructGeneration/EndConstructCommandHandlerTests.vb +++ b/src/EditorFeatures/VisualBasicTest/EndConstructGeneration/EndConstructCommandHandlerTests.vb @@ -16,35 +16,6 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.EndConstructGenera Private ReadOnly _textViewMock As New Mock(Of ITextView)(MockBehavior.Strict) Private ReadOnly _textBufferMock As New Mock(Of ITextBuffer)(MockBehavior.Strict) -#If False Then - Private ReadOnly _featureOptions As New Mock(Of ILegacyWorkspaceOptionService)(MockBehavior.Strict) - - ' TODO(jasonmal): Figure out how to enable these tests. - - Public Sub ServiceNotCompletingShouldCallNextHandler() - _endConstructServiceMock.Setup(Function(s) s.TryDo(It.IsAny(Of ITextView), It.IsAny(Of ITextBuffer), It.IsAny(Of Char))).Returns(False) - _featureOptions.Setup(Function(s) s.GetOption(FeatureOnOffOptions.EndConstruct)).Returns(True) - - Dim nextHandlerCalled = False - Dim handler As New EndConstructCommandHandler(_featureOptions.Object, _endConstructServiceMock.Object) - handler.ExecuteCommand_ReturnKeyCommandHandler(New ReturnKeyCommandArgs(_textViewMock.Object, _textBufferMock.Object), Sub() nextHandlerCalled = True) - - Assert.True(nextHandlerCalled) - End Sub - - - Public Sub ServiceCompletingShouldCallNextHandler() - _endConstructServiceMock.Setup(Function(s) s.TryDo(It.IsAny(Of ITextView), It.IsAny(Of ITextBuffer), It.IsAny(Of Char))).Returns(True) - _featureOptions.Setup(Function(s) s.GetOption(FeatureOnOffOptions.EndConstruct)).Returns(True) - - Dim nextHandlerCalled = False - Dim handler As New EndConstructCommandHandler(_featureOptions.Object, _endConstructServiceMock.Object) - handler.ExecuteCommand_ReturnKeyCommandHandler(New ReturnKeyCommandArgs(_textViewMock.Object, _textBufferMock.Object), Sub() nextHandlerCalled = True) - - Assert.False(nextHandlerCalled) - End Sub -#End If - Public Sub EndConstruct_AfterCodeCleanup() Dim code = Class C @@ -111,12 +82,12 @@ End Module.Value.Replace(vbLf, vbCrLf) End Sub - Public Sub EndConstruct_NotOnLineFollowingToken() - VerifyStatementEndConstructNotApplied( + Public Async Function EndConstruct_NotOnLineFollowingToken() As Task + Await VerifyStatementEndConstructNotAppliedAsync( text:="Class C ", caret:={2, 0}) - End Sub + End Function End Class End Namespace diff --git a/src/EditorFeatures/VisualBasicTest/EndConstructGeneration/EndConstructTestingHelpers.vb b/src/EditorFeatures/VisualBasicTest/EndConstructGeneration/EndConstructTestingHelpers.vb index 099577ac198b9..75dc3eb375333 100644 --- a/src/EditorFeatures/VisualBasicTest/EndConstructGeneration/EndConstructTestingHelpers.vb +++ b/src/EditorFeatures/VisualBasicTest/EndConstructGeneration/EndConstructTestingHelpers.vb @@ -4,9 +4,9 @@ Imports System.Threading Imports Microsoft.CodeAnalysis +Imports Microsoft.CodeAnalysis.Editor.[Shared].Utilities Imports Microsoft.CodeAnalysis.Editor.UnitTests Imports Microsoft.CodeAnalysis.Editor.UnitTests.Utilities -Imports Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces Imports Microsoft.CodeAnalysis.Editor.VisualBasic.EndConstructGeneration Imports Microsoft.CodeAnalysis.Editor.VisualBasic.LineCommit Imports Microsoft.CodeAnalysis.Options @@ -26,11 +26,12 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.EndConstructGenera Return mock.Object End Function - Private Sub VerifyTypedCharApplied(doFunc As Func(Of VisualBasicEndConstructService, ITextView, ITextBuffer, Boolean), - before As String, - after As String, - typedChar As Char, - endCaretPos As Integer()) + Private Async Function VerifyTypedCharAppliedAsync( + doFunc As Func(Of VisualBasicEndConstructService, ITextView, ITextBuffer, Task(Of Boolean)), + before As String, + after As String, + typedChar As Char, + endCaretPos As Integer()) As Task Dim caretPos = before.IndexOf("$$", StringComparison.Ordinal) Dim beforeText = before.Replace("$$", "") Using workspace = EditorTestWorkspace.CreateVisualBasic(beforeText, composition:=EditorTestCompositions.EditorFeatures) @@ -47,7 +48,7 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.EndConstructGenera workspace.GetService(Of IEditorOptionsFactoryService)) view.TextBuffer.Replace(New Span(caretPos, 0), typedChar.ToString()) - Assert.True(doFunc(endConstructService, view, view.TextBuffer)) + Assert.True(Await doFunc(endConstructService, view, view.TextBuffer)) Assert.Equal(after, view.TextSnapshot.GetText()) Dim actualLine As Integer @@ -56,13 +57,14 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.EndConstructGenera Assert.Equal(endCaretPos(0), actualLine) Assert.Equal(endCaretPos(1), actualChar) End Using - End Sub + End Function - Private Sub VerifyApplied(doFunc As Func(Of VisualBasicEndConstructService, ITextView, ITextBuffer, Boolean), - before As String, - beforeCaret As Integer(), - after As String, - afterCaret As Integer()) + Private Async Function VerifyAppliedAsync( + doFunc As Func(Of VisualBasicEndConstructService, ITextView, ITextBuffer, Task(Of Boolean)), + before As String, + beforeCaret As Integer(), + after As String, + afterCaret As Integer()) As Task Using workspace = EditorTestWorkspace.CreateVisualBasic(before, composition:=EditorTestCompositions.EditorFeatures) Dim globalOptions = workspace.GetService(Of IGlobalOptionService) globalOptions.SetGlobalOption(LineCommitOptionsStorage.PrettyListing, LanguageNames.VisualBasic, False) @@ -86,7 +88,7 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.EndConstructGenera workspace.GetService(Of IEditorOperationsFactoryService), workspace.GetService(Of IEditorOptionsFactoryService)) - Assert.True(doFunc(endConstructService, textView, textView.TextSnapshot.TextBuffer)) + Assert.True(Await doFunc(endConstructService, textView, textView.TextSnapshot.TextBuffer)) Assert.Equal(EditorFactory.LinesToFullText(after), textView.TextSnapshot.GetText()) Dim afterLine = textView.TextSnapshot.GetLineFromLineNumber(afterCaret(0)) @@ -99,7 +101,7 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.EndConstructGenera Assert.Equal(Of Integer)(afterCaretPoint, textView.GetCaretPoint(subjectBuffer).Value.Position) End Using - End Sub + End Function Private Function GetSnapshotPointFromArray(view As ITextView, caret As Integer(), startIndex As Integer) As SnapshotPoint Dim line = view.TextSnapshot.GetLineFromLineNumber(caret(startIndex)) @@ -111,9 +113,10 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.EndConstructGenera End If End Function - Private Sub VerifyNotApplied(doFunc As Func(Of VisualBasicEndConstructService, ITextView, ITextBuffer, Boolean), - text As String, - caret As Integer()) + Private Async Function VerifyNotAppliedAsync( + doFunc As Func(Of VisualBasicEndConstructService, ITextView, ITextBuffer, Task(Of Boolean)), + text As String, + caret As Integer()) As Task Using workspace = EditorTestWorkspace.CreateVisualBasic(text) Dim textView = workspace.Documents.First().GetTextView() Dim subjectBuffer = workspace.Documents.First().GetTextBuffer() @@ -134,7 +137,7 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.EndConstructGenera workspace.GetService(Of IEditorOperationsFactoryService), workspace.GetService(Of IEditorOptionsFactoryService)) - Assert.False(doFunc(endConstructService, textView, textView.TextSnapshot.TextBuffer), "End Construct should not have generated anything.") + Assert.False(Await doFunc(endConstructService, textView, textView.TextSnapshot.TextBuffer), "End Construct should not have generated anything.") ' The text should not have changed Assert.Equal(EditorFactory.LinesToFullText(text), textView.TextSnapshot.GetText()) @@ -142,63 +145,65 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.EndConstructGenera ' The caret should not have moved Assert.Equal(Of Integer)(caretPosition, textView.GetCaretPoint(subjectBuffer).Value.Position) End Using - End Sub + End Function - Public Sub VerifyStatementEndConstructApplied(before As String, beforeCaret As Integer(), after As String, afterCaret As Integer()) - VerifyApplied(Function(s, v, b) s.TryDoEndConstructForEnterKey(v, b, CancellationToken.None), before, beforeCaret, after, afterCaret) - End Sub + Public Function VerifyStatementEndConstructAppliedAsync(before As String, beforeCaret As Integer(), after As String, afterCaret As Integer()) As Task + Return VerifyAppliedAsync(Function(s, v, b) s.TryDoEndConstructForEnterKeyAsync(v, b, CancellationToken.None), before, beforeCaret, after, afterCaret) + End Function - Public Sub VerifyStatementEndConstructNotApplied(text As String, caret As Integer()) - VerifyNotApplied(Function(s, v, b) s.TryDoEndConstructForEnterKey(v, b, CancellationToken.None), text, caret) - End Sub + Public Function VerifyStatementEndConstructNotAppliedAsync(text As String, caret As Integer()) As Task + Return VerifyNotAppliedAsync(Function(s, v, b) s.TryDoEndConstructForEnterKeyAsync(v, b, CancellationToken.None), text, caret) + End Function - Public Sub VerifyXmlElementEndConstructApplied(before As String, beforeCaret As Integer(), after As String, afterCaret As Integer()) - VerifyApplied(Function(s, v, b) s.TryDoXmlElementEndConstruct(v, b, Nothing), before, beforeCaret, after, afterCaret) - End Sub +#Disable Warning BC42356 ' This async method lacks 'Await' operators and so will run synchronously + Public Function VerifyXmlElementEndConstructAppliedAsync(before As String, beforeCaret As Integer(), after As String, afterCaret As Integer()) As Task + Return VerifyAppliedAsync(Async Function(s, v, b) s.TryDoXmlElementEndConstruct(v, b, Nothing), before, beforeCaret, after, afterCaret) + End Function - Public Sub VerifyXmlElementEndConstructNotApplied(text As String, caret As Integer()) - VerifyNotApplied(Function(s, v, b) s.TryDoXmlElementEndConstruct(v, b, Nothing), text, caret) - End Sub + Public Function VerifyXmlElementEndConstructNotAppliedAsync(text As String, caret As Integer()) As Task + Return VerifyNotAppliedAsync(Async Function(s, v, b) s.TryDoXmlElementEndConstruct(v, b, Nothing), text, caret) + End Function - Public Sub VerifyXmlCommentEndConstructApplied(before As String, beforeCaret As Integer(), after As String, afterCaret As Integer()) - VerifyApplied(Function(s, v, b) s.TryDoXmlCommentEndConstruct(v, b, Nothing), before, beforeCaret, after, afterCaret) - End Sub + Public Function VerifyXmlCommentEndConstructAppliedAsync(before As String, beforeCaret As Integer(), after As String, afterCaret As Integer()) As Task + Return VerifyAppliedAsync(Async Function(s, v, b) s.TryDoXmlCommentEndConstruct(v, b, Nothing), before, beforeCaret, after, afterCaret) + End Function - Public Sub VerifyXmlCommentEndConstructNotApplied(text As String, caret As Integer()) - VerifyNotApplied(Function(s, v, b) s.TryDoXmlCommentEndConstruct(v, b, Nothing), text, caret) - End Sub + Public Function VerifyXmlCommentEndConstructNotAppliedAsync(text As String, caret As Integer()) As Task + Return VerifyNotAppliedAsync(Async Function(s, v, b) s.TryDoXmlCommentEndConstruct(v, b, Nothing), text, caret) + End Function - Public Sub VerifyXmlCDataEndConstructApplied(before As String, beforeCaret As Integer(), after As String, afterCaret As Integer()) - VerifyApplied(Function(s, v, b) s.TryDoXmlCDataEndConstruct(v, b, Nothing), before, beforeCaret, after, afterCaret) - End Sub + Public Function VerifyXmlCDataEndConstructAppliedAsync(before As String, beforeCaret As Integer(), after As String, afterCaret As Integer()) As Task + Return VerifyAppliedAsync(Async Function(s, v, b) s.TryDoXmlCDataEndConstruct(v, b, Nothing), before, beforeCaret, after, afterCaret) + End Function - Public Sub VerifyXmlCDataEndConstructNotApplied(text As String, caret As Integer()) - VerifyNotApplied(Function(s, v, b) s.TryDoXmlCDataEndConstruct(v, b, Nothing), text, caret) - End Sub + Public Function VerifyXmlCDataEndConstructNotAppliedAsync(text As String, caret As Integer()) As Task + Return VerifyNotAppliedAsync(Async Function(s, v, b) s.TryDoXmlCDataEndConstruct(v, b, Nothing), text, caret) + End Function - Public Sub VerifyXmlEmbeddedExpressionEndConstructApplied(before As String, beforeCaret As Integer(), after As String, afterCaret As Integer()) - VerifyApplied(Function(s, v, b) s.TryDoXmlEmbeddedExpressionEndConstruct(v, b, Nothing), before, beforeCaret, after, afterCaret) - End Sub + Public Function VerifyXmlEmbeddedExpressionEndConstructAppliedAsync(before As String, beforeCaret As Integer(), after As String, afterCaret As Integer()) As Task + Return VerifyAppliedAsync(Async Function(s, v, b) s.TryDoXmlEmbeddedExpressionEndConstruct(v, b, Nothing), before, beforeCaret, after, afterCaret) + End Function - Public Sub VerifyXmlEmbeddedExpressionEndConstructNotApplied(text As String, caret As Integer()) - VerifyNotApplied(Function(s, v, b) s.TryDoXmlEmbeddedExpressionEndConstruct(v, b, Nothing), text, caret) - End Sub + Public Function VerifyXmlEmbeddedExpressionEndConstructNotAppliedAsync(text As String, caret As Integer()) As Task + Return VerifyNotAppliedAsync(Async Function(s, v, b) s.TryDoXmlEmbeddedExpressionEndConstruct(v, b, Nothing), text, caret) + End Function - Public Sub VerifyXmlProcessingInstructionEndConstructApplied(before As String, beforeCaret As Integer(), after As String, afterCaret As Integer()) - VerifyApplied(Function(s, v, b) s.TryDoXmlProcessingInstructionEndConstruct(v, b, Nothing), before, beforeCaret, after, afterCaret) - End Sub + Public Function VerifyXmlProcessingInstructionEndConstructAppliedAsync(before As String, beforeCaret As Integer(), after As String, afterCaret As Integer()) As Task + Return VerifyAppliedAsync(Async Function(s, v, b) s.TryDoXmlProcessingInstructionEndConstruct(v, b, Nothing), before, beforeCaret, after, afterCaret) + End Function - Public Sub VerifyXmlProcessingInstructionNotApplied(text As String, caret As Integer()) - VerifyNotApplied(Function(s, v, b) s.TryDoXmlProcessingInstructionEndConstruct(v, b, Nothing), text, caret) - End Sub + Public Function VerifyXmlProcessingInstructionNotAppliedAsync(text As String, caret As Integer()) As Task + Return VerifyNotAppliedAsync(Async Function(s, v, b) s.TryDoXmlProcessingInstructionEndConstruct(v, b, Nothing), text, caret) + End Function +#Enable Warning BC42356 ' This async method lacks 'Await' operators and so will run synchronously - Public Sub VerifyEndConstructAppliedAfterChar(before As String, after As String, typedChar As Char, endCaretPos As Integer()) - VerifyTypedCharApplied(Function(s, v, b) s.TryDo(v, b, typedChar, Nothing), before, after, typedChar, endCaretPos) - End Sub + Public Function VerifyEndConstructAppliedAfterCharAsync(before As String, after As String, typedChar As Char, endCaretPos As Integer()) As Task + Return VerifyTypedCharAppliedAsync(Function(s, v, b) s.TryDoAsync(v, b, typedChar, Nothing), before, after, typedChar, endCaretPos) + End Function - Public Sub VerifyEndConstructNotAppliedAfterChar(before As String, after As String, typedChar As Char, endCaretPos As Integer()) - VerifyTypedCharApplied(Function(s, v, b) Not s.TryDo(v, b, typedChar, Nothing), before, after, typedChar, endCaretPos) - End Sub + Public Function VerifyEndConstructNotAppliedAfterCharAsync(before As String, after As String, typedChar As Char, endCaretPos As Integer()) As Task + Return VerifyTypedCharAppliedAsync(Async Function(s, v, b) Not Await s.TryDoAsync(v, b, typedChar, Nothing), before, after, typedChar, endCaretPos) + End Function Public Sub VerifyAppliedAfterReturnUsingCommandHandler( before As String, @@ -223,6 +228,7 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.EndConstructGenera Dim factory = workspace.GetService(Of IEditorOperationsFactoryService)() Dim endConstructor = New EndConstructCommandHandler( + workspace.GetService(Of IThreadingContext), factory, workspace.GetService(Of ITextUndoHistoryRegistry), workspace.GetService(Of EditorOptionsService)) diff --git a/src/EditorFeatures/VisualBasicTest/EndConstructGeneration/ForLoopTests.vb b/src/EditorFeatures/VisualBasicTest/EndConstructGeneration/ForLoopTests.vb index d1c1e129ee287..e51898d0f835f 100644 --- a/src/EditorFeatures/VisualBasicTest/EndConstructGeneration/ForLoopTests.vb +++ b/src/EditorFeatures/VisualBasicTest/EndConstructGeneration/ForLoopTests.vb @@ -7,8 +7,8 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.EndConstructGenera Public Class ForLoopTests - Public Sub TestVerifyForWithIndex() - VerifyStatementEndConstructApplied( + Public Async Function TestVerifyForWithIndex() As Task + Await VerifyStatementEndConstructAppliedAsync( before:="Class c1 Sub goo() For i = 1 To 10 @@ -23,11 +23,11 @@ End Class", End Sub End Class", afterCaret:={3, -1}) - End Sub + End Function - Public Sub TestVerifyForEach() - VerifyStatementEndConstructApplied( + Public Async Function TestVerifyForEach() As Task + Await VerifyStatementEndConstructAppliedAsync( before:="Class c1 Sub goo() For Each i In collection @@ -42,11 +42,11 @@ End Class", End Sub End Class", afterCaret:={3, -1}) - End Sub + End Function - Public Sub VerifyIndexMatchedInner1() - VerifyStatementEndConstructNotApplied( + Public Async Function VerifyIndexMatchedInner1() As Task + Await VerifyStatementEndConstructNotAppliedAsync( text:="Class c1 Sub goo() For i = 1 To 10 @@ -55,11 +55,11 @@ End Class", End Sub End Class", caret:={3, -1}) - End Sub + End Function - Public Sub TestVerifyIndexMatchedInner2() - VerifyStatementEndConstructApplied( + Public Async Function TestVerifyIndexMatchedInner2() As Task + Await VerifyStatementEndConstructAppliedAsync( before:="Class c1 Sub goo() For i = 1 To 10 @@ -78,11 +78,11 @@ End Class", End Sub End Class", afterCaret:={3, -1}) - End Sub + End Function - Public Sub VerifyIndexSharedNext() - VerifyStatementEndConstructNotApplied( + Public Async Function VerifyIndexSharedNext() As Task + Await VerifyStatementEndConstructNotAppliedAsync( text:="Class c1 Sub goo() For i = 1 To 10 @@ -91,11 +91,11 @@ End Class", End Sub End Class", caret:={3, -1}) - End Sub + End Function - Public Sub TestVerifyNestedFor() - VerifyStatementEndConstructApplied( + Public Async Function TestVerifyNestedFor() As Task + Await VerifyStatementEndConstructAppliedAsync( before:="' NestedFor Class C Sub s @@ -116,11 +116,11 @@ Class C End sub End Class", afterCaret:={5, -1}) - End Sub + End Function - Public Sub TestVerifyNestedForEach() - VerifyStatementEndConstructApplied( + Public Async Function TestVerifyNestedForEach() As Task + Await VerifyStatementEndConstructAppliedAsync( before:="Class C function f(byval x as Integer, byref y as string) as string @@ -143,11 +143,11 @@ End Class", End Function End Class", afterCaret:={5, -1}) - End Sub + End Function - Public Sub VerifyReCommitForEach() - VerifyStatementEndConstructNotApplied( + Public Async Function VerifyReCommitForEach() As Task + Await VerifyStatementEndConstructNotAppliedAsync( text:="Class C Public Property p(byval x as Integer) as Integer for each i in {1,2,3} @@ -155,26 +155,25 @@ End Class", End Property End Class", caret:={2, -1}) - End Sub + End Function - Public Sub VerifyForAtIncorrectLocation() - VerifyStatementEndConstructNotApplied( + Public Async Function VerifyForAtIncorrectLocation() As Task + Await VerifyStatementEndConstructNotAppliedAsync( text:="Class C For i = 1 to 10", caret:={1, -1}) - End Sub + End Function - Public Sub VerifyInvalidForSyntax() - VerifyStatementEndConstructNotApplied( + Public Async Function VerifyInvalidForSyntax() As Task + Await VerifyStatementEndConstructNotAppliedAsync( text:="Class C Sub s for For End Sub End Class", caret:={2, -1}) - End Sub - + End Function End Class End Namespace diff --git a/src/EditorFeatures/VisualBasicTest/EndConstructGeneration/ITextSnapshotExtensionsTests.vb b/src/EditorFeatures/VisualBasicTest/EndConstructGeneration/ITextSnapshotExtensionsTests.vb index 77e704798a831..130d4c68faa5f 100644 --- a/src/EditorFeatures/VisualBasicTest/EndConstructGeneration/ITextSnapshotExtensionsTests.vb +++ b/src/EditorFeatures/VisualBasicTest/EndConstructGeneration/ITextSnapshotExtensionsTests.vb @@ -8,9 +8,7 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.EndConstructGenera Public Class ITextSnapshotExtensionsTests Public Sub ThrowsWithNullSnapshot() - Assert.Throws(Of ArgumentNullException)(Sub() - EndConstructExtensions.GetAligningWhitespace(Nothing, 0) - End Sub) + Assert.Throws(Of ArgumentNullException)(Sub() EndConstructExtensions.GetAligningWhitespace(Nothing, 0)) End Sub End Class End Namespace diff --git a/src/EditorFeatures/VisualBasicTest/EndConstructGeneration/IfBlockTests.vb b/src/EditorFeatures/VisualBasicTest/EndConstructGeneration/IfBlockTests.vb index aa38593306930..361ee5f84de92 100644 --- a/src/EditorFeatures/VisualBasicTest/EndConstructGeneration/IfBlockTests.vb +++ b/src/EditorFeatures/VisualBasicTest/EndConstructGeneration/IfBlockTests.vb @@ -7,8 +7,8 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.EndConstructGenera Public Class IfBlockTests - Public Sub TestApplyAfterSimpleIfThen() - VerifyStatementEndConstructApplied( + Public Async Function TestApplyAfterSimpleIfThen() As Task + Await VerifyStatementEndConstructAppliedAsync( before:="Class c1 Sub goo() If True Then @@ -23,11 +23,11 @@ End Class", End Sub End Class", afterCaret:={3, -1}) - End Sub + End Function - Public Sub TestApplyAfterLineIfNextToThen() - VerifyStatementEndConstructApplied( + Public Async Function TestApplyAfterLineIfNextToThen() As Task + Await VerifyStatementEndConstructAppliedAsync( before:="Class c1 Sub goo() If True Then goo() @@ -42,11 +42,11 @@ End Class", End Sub End Class", afterCaret:={3, 12}) - End Sub + End Function - Public Sub TestApplyAfterLineIfWithMultipleStatements() - VerifyStatementEndConstructApplied( + Public Async Function TestApplyAfterLineIfWithMultipleStatements() As Task + Await VerifyStatementEndConstructAppliedAsync( before:="Class c1 Sub goo() If True Then goo() : goo() @@ -62,11 +62,11 @@ End Class", End Sub End Class", afterCaret:={3, 12}) - End Sub + End Function - Public Sub TestApplyAfterLineIfNextToStatement() - VerifyStatementEndConstructApplied( + Public Async Function TestApplyAfterLineIfNextToStatement() As Task + Await VerifyStatementEndConstructAppliedAsync( before:="Class c1 Sub goo() If True Then goo() @@ -81,11 +81,11 @@ End Class", End Sub End Class", afterCaret:={3, 12}) - End Sub + End Function - Public Sub TestVerifySingleLineIfWithMultiLineLambda() - VerifyStatementEndConstructApplied( + Public Async Function TestVerifySingleLineIfWithMultiLineLambda() As Task + Await VerifyStatementEndConstructAppliedAsync( before:="Class C Sub S If True Then Dim x = Function(x As Integer) @@ -110,11 +110,11 @@ End Class", End Sub End Class", afterCaret:={3, 12}) - End Sub + End Function - Public Sub TestVerifySingleLineIfThenElse() - VerifyStatementEndConstructApplied( + Public Async Function TestVerifySingleLineIfThenElse() As Task + Await VerifyStatementEndConstructAppliedAsync( before:="Class C Sub S If True Then dim x = 1 Else y = 6 @@ -131,11 +131,11 @@ End Class", End Sub End Class", afterCaret:={3, 12}) - End Sub + End Function - Public Sub TestVerifyNestedIf() - VerifyStatementEndConstructApplied( + Public Async Function TestVerifyNestedIf() As Task + Await VerifyStatementEndConstructAppliedAsync( before:="Class C Sub S If True Then @@ -157,11 +157,11 @@ End Class", End Class", afterCaret:={4, -1}) - End Sub + End Function - Public Sub TestVerifyNestedSingleLineIf() - VerifyStatementEndConstructApplied( + Public Async Function TestVerifyNestedSingleLineIf() As Task + Await VerifyStatementEndConstructAppliedAsync( before:="Class C Sub S If True Then If True Then X = 1 Else X = 2 @@ -176,11 +176,11 @@ End Class", End Sub End Class", afterCaret:={3, 12}) - End Sub + End Function - Public Sub VerifyAddingElseIf() - VerifyStatementEndConstructNotApplied( + Public Async Function VerifyAddingElseIf() As Task + Await VerifyStatementEndConstructNotAppliedAsync( text:="Class C Sub S If true Then @@ -189,11 +189,11 @@ End Class", End Sub End Class", caret:={3, -1}) - End Sub + End Function - Public Sub TestVerifyIfWithImplicitLC() - VerifyStatementEndConstructApplied( + Public Async Function TestVerifyIfWithImplicitLC() As Task + Await VerifyStatementEndConstructAppliedAsync( before:="Class C Sub S If True And @@ -210,11 +210,11 @@ End Class", End Sub End Class", afterCaret:={4, -1}) - End Sub + End Function - Public Sub VerifyReCommitWithCode() - VerifyStatementEndConstructNotApplied( + Public Async Function VerifyReCommitWithCode() As Task + Await VerifyStatementEndConstructNotAppliedAsync( text:="Class C Sub S If True Then @@ -224,11 +224,11 @@ End Class", End Sub End Class", caret:={2, -1}) - End Sub + End Function - Public Sub VerifyReCommitWithoutCode() - VerifyStatementEndConstructNotApplied( + Public Async Function VerifyReCommitWithoutCode() As Task + Await VerifyStatementEndConstructNotAppliedAsync( text:="Class C Sub S If True Then @@ -236,22 +236,22 @@ End Class", End Sub End Class", caret:={2, -1}) - End Sub + End Function - Public Sub VerifyWithMultiLineChar() - VerifyStatementEndConstructNotApplied( + Public Async Function VerifyWithMultiLineChar() As Task + Await VerifyStatementEndConstructNotAppliedAsync( text:="Class C Sub S If True Then : Elseif true then: End If End Sub End Class", caret:={2, -1}) - End Sub + End Function - Public Sub TestVerifyWithSkippedTokens() - VerifyStatementEndConstructApplied( + Public Async Function TestVerifyWithSkippedTokens() As Task + Await VerifyStatementEndConstructAppliedAsync( before:="Class C Sub S If True Then #Const goo = 2 ' x = 42 @@ -266,11 +266,11 @@ End Class", End Sub End Class", afterCaret:={3, 12}) - End Sub + End Function - Public Sub VerifyInvalidMissingEndIf() - VerifyStatementEndConstructNotApplied( + Public Async Function VerifyInvalidMissingEndIf() As Task + Await VerifyStatementEndConstructNotAppliedAsync( text:="Class C Sub S If True Then @@ -278,20 +278,20 @@ End Class", End Sub End Class", caret:={3, -1}) - End Sub + End Function - Public Sub VerifyIfInInvalidCode() - VerifyStatementEndConstructNotApplied( + Public Async Function VerifyIfInInvalidCode() As Task + Await VerifyStatementEndConstructNotAppliedAsync( text:="If True Then if True then End If", caret:={1, -1}) - End Sub + End Function - Public Sub TestVerifyInternationalCharacter() - VerifyStatementEndConstructApplied( + Public Async Function TestVerifyInternationalCharacter() As Task + Await VerifyStatementEndConstructAppliedAsync( before:="Class c1 Sub goo() If True Then Dim xæ大% = 1 @@ -306,12 +306,12 @@ End Class", End Sub End Class", afterCaret:={3, 12}) - End Sub + End Function - Public Sub TestBugFix6380() - VerifyStatementEndConstructApplied( + Public Async Function TestBugFix6380() As Task + Await VerifyStatementEndConstructAppliedAsync( before:="Imports System Imports System.Collections.Generic Imports System.Linq @@ -337,11 +337,11 @@ Module Program End Sub End Module", afterCaret:={8, 12}) - End Sub + End Function - Public Sub TestVerifyRewriteOfIfWithColons() - VerifyStatementEndConstructApplied( + Public Async Function TestVerifyRewriteOfIfWithColons() As Task + Await VerifyStatementEndConstructAppliedAsync( before:="Class C Sub Goo() If True Then : Return : End If @@ -356,14 +356,14 @@ End Class", End Sub End Class", afterCaret:={3, 12}) - End Sub + End Function - Public Sub TestVerifyRewriteOfIfWithEmptyStatement() + Public Async Function TestVerifyRewriteOfIfWithEmptyStatement() As Task ' Verify the caret is at the beginning of line 3 here. In VS, it will be moved to the ' correct virtual offset as part of the edit. This is an edge case that we really just ' need to avoid crashing. - VerifyStatementEndConstructApplied( + Await VerifyStatementEndConstructAppliedAsync( before:="Class C Sub Goo() If True Then Else ' asdf @@ -380,6 +380,6 @@ End Class", End Sub End Class", afterCaret:={3, 0}) - End Sub + End Function End Class End Namespace diff --git a/src/EditorFeatures/VisualBasicTest/EndConstructGeneration/MethodBlockTests.vb b/src/EditorFeatures/VisualBasicTest/EndConstructGeneration/MethodBlockTests.vb index 02407969683d2..af9db1065a055 100644 --- a/src/EditorFeatures/VisualBasicTest/EndConstructGeneration/MethodBlockTests.vb +++ b/src/EditorFeatures/VisualBasicTest/EndConstructGeneration/MethodBlockTests.vb @@ -7,8 +7,8 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.EndConstructGenera Public Class MethodBlockTests - Public Sub TestApplyAfterSimpleSubDeclarationWithTrailingComment() - VerifyStatementEndConstructApplied( + Public Async Function TestApplyAfterSimpleSubDeclarationWithTrailingComment() As Task + Await VerifyStatementEndConstructAppliedAsync( before:="Class c1 Sub goo() 'Extra Comment End Class", @@ -19,11 +19,11 @@ End Class", End Sub End Class", afterCaret:={2, -1}) - End Sub + End Function - Public Sub TestApplyAfterConstructorDeclaration() - VerifyStatementEndConstructApplied( + Public Async Function TestApplyAfterConstructorDeclaration() As Task + Await VerifyStatementEndConstructAppliedAsync( before:="Class c1 Sub New() End Class", @@ -34,11 +34,11 @@ End Class", End Sub End Class", afterCaret:={2, -1}) - End Sub + End Function - Public Sub TestApplyAfterConstructorDeclarationForDesignerGeneratedClass() - VerifyStatementEndConstructApplied( + Public Async Function TestApplyAfterConstructorDeclarationForDesignerGeneratedClass() As Task + Await VerifyStatementEndConstructAppliedAsync( before:=" Class c1 Sub New() @@ -62,11 +62,11 @@ Class c1 End Sub End Class", afterCaret:={3, -1}) - End Sub + End Function - Public Sub TestApplyAfterConstructorDeclarationWithTrailingComment() - VerifyStatementEndConstructApplied( + Public Async Function TestApplyAfterConstructorDeclarationWithTrailingComment() As Task + Await VerifyStatementEndConstructAppliedAsync( before:="Class c1 Sub New() 'Extra Comment End Class", @@ -77,11 +77,11 @@ End Class", End Sub End Class", afterCaret:={2, -1}) - End Sub + End Function - Public Sub TestApplyAfterSimpleFunctionDeclarationWithTrailingComment() - VerifyStatementEndConstructApplied( + Public Async Function TestApplyAfterSimpleFunctionDeclarationWithTrailingComment() As Task + Await VerifyStatementEndConstructAppliedAsync( before:="Class c1 Function goo() As Integer 'Extra Comment End Class", @@ -92,20 +92,20 @@ End Class", End Function End Class", afterCaret:={2, -1}) - End Sub + End Function - Public Sub DoNotApplyForInterfaceFunction() - VerifyStatementEndConstructNotApplied( + Public Async Function DoNotApplyForInterfaceFunction() As Task + Await VerifyStatementEndConstructNotAppliedAsync( text:="Interface IGoo Function Goo() as Integer End Interface", caret:={1, -1}) - End Sub + End Function - Public Sub TestVerifySubInAModule() - VerifyStatementEndConstructApplied( + Public Async Function TestVerifySubInAModule() As Task + Await VerifyStatementEndConstructAppliedAsync( before:="Module C Public Sub s End Module", @@ -116,11 +116,11 @@ Public Sub s End Sub End Module", afterCaret:={2, -1}) - End Sub + End Function - Public Sub TestVerifySubWithParameters() - VerifyStatementEndConstructApplied( + Public Async Function TestVerifySubWithParameters() As Task + Await VerifyStatementEndConstructAppliedAsync( before:="Module C Private Sub s1(byval x as Integer, Optional y as Integer = 5) End Module", @@ -131,11 +131,11 @@ End Module", End Sub End Module", afterCaret:={2, -1}) - End Sub + End Function - Public Sub TestVerifyFuncWithParameters() - VerifyStatementEndConstructApplied( + Public Async Function TestVerifyFuncWithParameters() As Task + Await VerifyStatementEndConstructAppliedAsync( before:="Module C Public function f(byval x as Integer, byref y as string) as string @@ -148,11 +148,11 @@ End Module", End function End Module", afterCaret:={3, -1}) - End Sub + End Function - Public Sub TestVerifyFuncNamedWithKeyWord() - VerifyStatementEndConstructApplied( + Public Async Function TestVerifyFuncNamedWithKeyWord() As Task + Await VerifyStatementEndConstructAppliedAsync( before:="Class C private funCtion f1(Optional x as integer = 5) as [if] End Class", @@ -163,11 +163,11 @@ End Class", End funCtion End Class", afterCaret:={2, -1}) - End Sub + End Function - Public Sub TestVerifySharedOperator() - VerifyStatementEndConstructApplied( + Public Async Function TestVerifySharedOperator() As Task + Await VerifyStatementEndConstructAppliedAsync( before:="Class C Public Shared Operator +(ByVal a As bar, ByVal b As bar) As bar End Class", @@ -178,39 +178,38 @@ End Class", End Operator End Class", afterCaret:={2, -1}) - End Sub + End Function - Public Sub VerifyRecommit() - VerifyStatementEndConstructNotApplied( + Public Async Function VerifyRecommit() As Task + Await VerifyStatementEndConstructNotAppliedAsync( text:="Class C Protected friend sub S End sub End Class", caret:={1, -1}) - End Sub + End Function - Public Sub VerifyInvalidLocation01() - VerifyStatementEndConstructNotApplied( + Public Async Function VerifyInvalidLocation01() As Task + Await VerifyStatementEndConstructNotAppliedAsync( text:="Class C Sub S Sub P End Sub End Class", caret:={2, -1}) - End Sub + End Function - Public Sub TestVerifyInvalidLocation02() - VerifyStatementEndConstructApplied( + Public Async Function TestVerifyInvalidLocation02() As Task + Await VerifyStatementEndConstructAppliedAsync( before:="Sub S", beforeCaret:={0, -1}, after:="Sub S End Sub", afterCaret:={1, -1}) - End Sub - + End Function End Class End Namespace diff --git a/src/EditorFeatures/VisualBasicTest/EndConstructGeneration/MiscellaneousTests.vb b/src/EditorFeatures/VisualBasicTest/EndConstructGeneration/MiscellaneousTests.vb index 133bddbca95fb..422a2a7084333 100644 --- a/src/EditorFeatures/VisualBasicTest/EndConstructGeneration/MiscellaneousTests.vb +++ b/src/EditorFeatures/VisualBasicTest/EndConstructGeneration/MiscellaneousTests.vb @@ -15,23 +15,23 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.EndConstructGenera Public Class MiscellaneousTests - Public Sub DoesNothingOnEmptyFile() - VerifyStatementEndConstructNotApplied( + Public Async Function DoesNothingOnEmptyFile() As Task + Await VerifyStatementEndConstructNotAppliedAsync( text:="", caret:={0, -1}) - End Sub + End Function - Public Sub DoesNothingOnFileWithNoStatement() - VerifyStatementEndConstructNotApplied( + Public Async Function DoesNothingOnFileWithNoStatement() As Task + Await VerifyStatementEndConstructNotAppliedAsync( text:="'Goo ", caret:={0, -1}) - End Sub + End Function - Public Sub VerifyLineContinuationMark() - VerifyStatementEndConstructNotApplied( + Public Async Function VerifyLineContinuationMark() As Task + Await VerifyStatementEndConstructNotAppliedAsync( text:="Class C function f(byval x as Integer, byref y as string) as string @@ -40,11 +40,11 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.EndConstructGenera End Function End Class", caret:={3, -1}) - End Sub + End Function - Public Sub VerifyImplicitLineContinuation() - VerifyStatementEndConstructNotApplied( + Public Async Function VerifyImplicitLineContinuation() As Task + Await VerifyStatementEndConstructNotAppliedAsync( text:="Class C function f() as string While 1 + @@ -52,11 +52,11 @@ End Class", End Function End Class", caret:={2, -1}) - End Sub + End Function - Public Sub TestVerifyNestedDo() - VerifyStatementEndConstructApplied( + Public Async Function TestVerifyNestedDo() As Task + Await VerifyStatementEndConstructAppliedAsync( before:="Class C function f() as string for i = 1 to 10", @@ -67,11 +67,11 @@ End Class", Next", afterCaret:={3, -1}) - End Sub + End Function - Public Sub TestVerifyMultilinesChar() - VerifyStatementEndConstructApplied( + Public Async Function TestVerifyMultilinesChar() As Task + Await VerifyStatementEndConstructAppliedAsync( before:="Class C sub s do :do @@ -88,11 +88,11 @@ End Class", End sub End Class", afterCaret:={3, -1}) - End Sub + End Function - Public Sub TestVerifyInlineComments() - VerifyStatementEndConstructApplied( + Public Async Function TestVerifyInlineComments() As Task + Await VerifyStatementEndConstructAppliedAsync( before:="Class C sub s If true then 'here @@ -107,27 +107,27 @@ End Class", End sub End Class", afterCaret:={3, -1}) - End Sub + End Function - Public Sub VerifyNotAppliedWithJunkAtEndOfLine() + Public Async Function VerifyNotAppliedWithJunkAtEndOfLine() As Task ' Try this without a newline at the end of the file - VerifyStatementEndConstructNotApplied( + Await VerifyStatementEndConstructNotAppliedAsync( text:="Class C End Class", caret:={0, "Class C".Length}) - End Sub + End Function - Public Sub VerifyNotAppliedWithJunkAtEndOfLine2() + Public Async Function VerifyNotAppliedWithJunkAtEndOfLine2() As Task ' Try this with a newline at the end of the file - VerifyStatementEndConstructNotApplied( + Await VerifyStatementEndConstructNotAppliedAsync( text:="Class C End Class ", caret:={0, "Class C".Length}) - End Sub + End Function - Public Sub DeletesSelectedText() + Public Async Function DeletesSelectedText() As Task Using workspace = EditorTestWorkspace.CreateVisualBasic("Interface IGoo ~~") Dim textView = workspace.Documents.Single().GetTextView() Dim subjectBuffer = workspace.Documents.First().GetTextBuffer() @@ -143,10 +143,11 @@ End Class", workspace.GetService(Of IEditorOperationsFactoryService), workspace.GetService(Of IEditorOptionsFactoryService)) - Assert.True(endConstructService.TryDoEndConstructForEnterKey(textView, textView.TextSnapshot.TextBuffer, CancellationToken.None)) + Assert.True(Await endConstructService.TryDoEndConstructForEnterKeyAsync( + textView, textView.TextSnapshot.TextBuffer, CancellationToken.None)) Assert.Equal("End Interface", textView.TextSnapshot.Lines.Last().GetText()) End Using - End Sub + End Function End Class End Namespace diff --git a/src/EditorFeatures/VisualBasicTest/EndConstructGeneration/MultiLineLambdaTests.vb b/src/EditorFeatures/VisualBasicTest/EndConstructGeneration/MultiLineLambdaTests.vb index cbab0b2f161ee..e9114af38da65 100644 --- a/src/EditorFeatures/VisualBasicTest/EndConstructGeneration/MultiLineLambdaTests.vb +++ b/src/EditorFeatures/VisualBasicTest/EndConstructGeneration/MultiLineLambdaTests.vb @@ -7,8 +7,8 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.EndConstructGenera Public Class MultiLineLambdaTests - Public Sub TestApplyWithFunctionLambda() - VerifyStatementEndConstructApplied( + Public Async Function TestApplyWithFunctionLambda() As Task + Await VerifyStatementEndConstructAppliedAsync( before:="Class c1 Sub goo() Dim x = Function() @@ -23,11 +23,11 @@ End Class", End Sub End Class", afterCaret:={3, -1}) - End Sub + End Function - Public Sub TestApplyWithFunctionLambdaWithMissingEndFunction() - VerifyStatementEndConstructApplied( + Public Async Function TestApplyWithFunctionLambdaWithMissingEndFunction() As Task + Await VerifyStatementEndConstructAppliedAsync( before:="Class c1 Function goo() Dim x = Function() @@ -40,11 +40,11 @@ End Class", End Function End Class", afterCaret:={3, -1}) - End Sub + End Function - Public Sub TestApplyWithSubLambda() - VerifyStatementEndConstructApplied( + Public Async Function TestApplyWithSubLambda() As Task + Await VerifyStatementEndConstructAppliedAsync( before:="Class c1 Function goo() Dim x = Sub() @@ -59,11 +59,11 @@ End Class", End Function End Class", afterCaret:={3, -1}) - End Sub + End Function - Public Sub TestApplyWithSubLambdaWithNoParameterParenthesis() - VerifyStatementEndConstructApplied( + Public Async Function TestApplyWithSubLambdaWithNoParameterParenthesis() As Task + Await VerifyStatementEndConstructAppliedAsync( before:="Class c1 Function goo() Dim x = Sub @@ -78,11 +78,11 @@ End Class", End Function End Class", afterCaret:={3, -1}) - End Sub + End Function - Public Sub TestApplyWithSubLambdaInsideMethodCall() - VerifyStatementEndConstructApplied( + Public Async Function TestApplyWithSubLambdaInsideMethodCall() As Task + Await VerifyStatementEndConstructAppliedAsync( before:="Class c1 Function goo() M(Sub()) @@ -97,11 +97,11 @@ End Class", End Function End Class", afterCaret:={3, -1}) - End Sub + End Function - Public Sub TestApplyWithSubLambdaAndStatementInsideMethodCall() - VerifyStatementEndConstructApplied( + Public Async Function TestApplyWithSubLambdaAndStatementInsideMethodCall() As Task + Await VerifyStatementEndConstructAppliedAsync( before:="Class c1 Function goo() M(Sub() Exit Sub) @@ -116,11 +116,11 @@ End Class", End Function End Class", afterCaret:={3, 10}) - End Sub + End Function - Public Sub TestApplyWithFunctionLambdaInsideMethodCall() - VerifyStatementEndConstructApplied( + Public Async Function TestApplyWithFunctionLambdaInsideMethodCall() As Task + Await VerifyStatementEndConstructAppliedAsync( before:="Class c1 Function goo() M(Function() 1) @@ -135,11 +135,11 @@ End Class", End Function End Class", afterCaret:={3, 17}) - End Sub + End Function - Public Sub TestVerifyAnonymousType() - VerifyStatementEndConstructApplied( + Public Async Function TestVerifyAnonymousType() As Task + Await VerifyStatementEndConstructAppliedAsync( before:="Class C Sub s() Dim x = New With {.x = Function(x) @@ -154,33 +154,33 @@ End Class", End Sub End Class", afterCaret:={3, -1}) - End Sub + End Function - Public Sub VerifySingleLineLambdaFunc() - VerifyStatementEndConstructNotApplied( + Public Async Function VerifySingleLineLambdaFunc() As Task + Await VerifyStatementEndConstructNotAppliedAsync( text:="Class C Sub s() Dim x = Function(x) x End Sub End Class", caret:={2, -1}) - End Sub + End Function - Public Sub VerifySingleLineLambdaSub() - VerifyStatementEndConstructNotApplied( + Public Async Function VerifySingleLineLambdaSub() As Task + Await VerifyStatementEndConstructNotAppliedAsync( text:="Class C Sub s() Dim y = Sub(x As Integer) x.ToString() End Sub End Class", caret:={2, -1}) - End Sub + End Function - Public Sub TestVerifyAsDefaultParameterValue() - VerifyStatementEndConstructApplied( + Public Async Function TestVerifyAsDefaultParameterValue() As Task + Await VerifyStatementEndConstructAppliedAsync( before:="Class C Sub s(Optional ByVal f As Func(Of String, String) = Function(x As String) End Class", @@ -191,11 +191,11 @@ End Class", End Function End Class", afterCaret:={2, -1}) - End Sub + End Function - Public Sub TestVerifyNestedLambda() - VerifyStatementEndConstructApplied( + Public Async Function TestVerifyNestedLambda() As Task + Await VerifyStatementEndConstructAppliedAsync( before:="Class C sub s Dim x = Function (x) @@ -214,11 +214,11 @@ End Class", End sub End Class", afterCaret:={4, -1}) - End Sub + End Function - Public Sub TestVerifyInField() - VerifyStatementEndConstructApplied( + Public Async Function TestVerifyInField() As Task + Await VerifyStatementEndConstructAppliedAsync( before:="Class C Dim x = Sub() End Class", @@ -229,55 +229,55 @@ End Class", End Sub End Class", afterCaret:={2, -1}) - End Sub + End Function - Public Sub VerifyInvalidLambdaSyntax() - VerifyStatementEndConstructNotApplied( + Public Async Function VerifyInvalidLambdaSyntax() As Task + Await VerifyStatementEndConstructNotAppliedAsync( text:="Class C Sub s() Sub(x) End Sub End Class", caret:={2, -1}) - End Sub + End Function - Public Sub VerifyNotAppliedIfSubLambdaContainsEndSub() - VerifyStatementEndConstructNotApplied( + Public Async Function VerifyNotAppliedIfSubLambdaContainsEndSub() As Task + Await VerifyStatementEndConstructNotAppliedAsync( text:="Class C Sub s() Dim x = Sub() End Sub End Sub End Class", caret:={2, 21}) - End Sub + End Function - Public Sub VerifyNotAppliedIfSyntaxIsFunctionLambdaContainsEndFunction() - VerifyStatementEndConstructNotApplied( + Public Async Function VerifyNotAppliedIfSyntaxIsFunctionLambdaContainsEndFunction() As Task + Await VerifyStatementEndConstructNotAppliedAsync( text:="Class C Sub s() Dim x = Function() End Function End Sub End Class", caret:={2, 26}) - End Sub + End Function - Public Sub VerifyLambdaWithImplicitLC() - VerifyStatementEndConstructNotApplied( + Public Async Function VerifyLambdaWithImplicitLC() As Task + Await VerifyStatementEndConstructNotAppliedAsync( text:="Class C Sub s() Dim x = Function(y As Integer) y + End Sub End Class", caret:={2, -1}) - End Sub + End Function - Public Sub TestVerifyLambdaWithMissingParenthesis() - VerifyStatementEndConstructApplied( + Public Async Function TestVerifyLambdaWithMissingParenthesis() As Task + Await VerifyStatementEndConstructAppliedAsync( before:="Class C Sub s() Dim x = Function @@ -292,11 +292,11 @@ End Class", End Sub End Class", afterCaret:={3, -1}) - End Sub + End Function - Public Sub TestVerifySingleLineSubLambdaToMultiLine() - VerifyStatementEndConstructApplied( + Public Async Function TestVerifySingleLineSubLambdaToMultiLine() As Task + Await VerifyStatementEndConstructAppliedAsync( before:="Class C Sub s() Dim x = Sub() f() @@ -311,11 +311,11 @@ End Class", End Sub End Class", afterCaret:={3, 20}) - End Sub + End Function - Public Sub TestVerifySingleLineSubLambdaToMultiLineWithTrailingTrivia() - VerifyStatementEndConstructApplied( + Public Async Function TestVerifySingleLineSubLambdaToMultiLineWithTrailingTrivia() As Task + Await VerifyStatementEndConstructAppliedAsync( before:="Class C Sub s() Dim x = Sub() f() ' Invokes f() @@ -330,11 +330,11 @@ End Class", End Sub End Class", afterCaret:={3, 20}) - End Sub + End Function - Public Sub TestVerifySingleLineFunctionLambdaToMultiLine() - VerifyStatementEndConstructApplied( + Public Async Function TestVerifySingleLineFunctionLambdaToMultiLine() As Task + Await VerifyStatementEndConstructAppliedAsync( before:="Class C Sub s() Dim x = Function() f() @@ -349,11 +349,11 @@ End Class", End Sub End Class", afterCaret:={3, 27}) - End Sub + End Function - Public Sub TestVerifySingleLineFunctionLambdaToMultiLineWithTrailingTrivia() - VerifyStatementEndConstructApplied( + Public Async Function TestVerifySingleLineFunctionLambdaToMultiLineWithTrailingTrivia() As Task + Await VerifyStatementEndConstructAppliedAsync( before:="Class C Sub s() Dim x = Function() 4 ' Returns Constant 4 @@ -368,12 +368,12 @@ End Class", End Sub End Class", afterCaret:={3, 27}) - End Sub + End Function - Public Sub TestVerifySingleLineFunctionLambdaToMultiLineInsideXMLTag() - VerifyStatementEndConstructApplied( + Public Async Function TestVerifySingleLineFunctionLambdaToMultiLineInsideXMLTag() As Task + Await VerifyStatementEndConstructAppliedAsync( before:="Class C Sub s() Dim x = <%= Function()%> @@ -388,12 +388,12 @@ End Class", End Sub End Class", afterCaret:={3, -1}) - End Sub + End Function - Public Sub TestVerifySingleLineSubLambdaToMultiLineInsideXMLTag() - VerifyStatementEndConstructApplied( + Public Async Function TestVerifySingleLineSubLambdaToMultiLineInsideXMLTag() As Task + Await VerifyStatementEndConstructAppliedAsync( before:="Class C Sub s() Dim x = <%= Sub()%> @@ -408,6 +408,6 @@ End Class", End Sub End Class", afterCaret:={3, -1}) - End Sub + End Function End Class End Namespace diff --git a/src/EditorFeatures/VisualBasicTest/EndConstructGeneration/NamespaceBlockTests.vb b/src/EditorFeatures/VisualBasicTest/EndConstructGeneration/NamespaceBlockTests.vb index b59d637829e12..ad34f791206b6 100644 --- a/src/EditorFeatures/VisualBasicTest/EndConstructGeneration/NamespaceBlockTests.vb +++ b/src/EditorFeatures/VisualBasicTest/EndConstructGeneration/NamespaceBlockTests.vb @@ -7,19 +7,19 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.EndConstructGenera Public Class NamespaceBlockTests - Public Sub TestApplyAfterNamespace() - VerifyStatementEndConstructApplied( + Public Async Function TestApplyAfterNamespace() As Task + Await VerifyStatementEndConstructAppliedAsync( before:="Namespace goo", beforeCaret:={0, -1}, after:="Namespace goo End Namespace", afterCaret:={1, -1}) - End Sub + End Function - Public Sub TestApplyAfterNestedNamespace() - VerifyStatementEndConstructApplied( + Public Async Function TestApplyAfterNestedNamespace() As Task + Await VerifyStatementEndConstructAppliedAsync( before:="Namespace goo Namespace bar End Namespace", @@ -30,34 +30,34 @@ Namespace bar End Namespace End Namespace", afterCaret:={2, -1}) - End Sub + End Function - Public Sub VerifyRecommit() - VerifyStatementEndConstructNotApplied( + Public Async Function VerifyRecommit() As Task + Await VerifyStatementEndConstructNotAppliedAsync( text:="NameSpace Bar End Namespace", caret:={0, -1}) - End Sub + End Function - Public Sub VerifyInvalidNSInMethod() - VerifyStatementEndConstructNotApplied( + Public Async Function VerifyInvalidNSInMethod() As Task + Await VerifyStatementEndConstructNotAppliedAsync( text:="Class C Sub S NameSpace T End Sub End Class", caret:={2, -1}) - End Sub + End Function - Public Sub VerifyInvalidNSInModule() - VerifyStatementEndConstructNotApplied( + Public Async Function VerifyInvalidNSInModule() As Task + Await VerifyStatementEndConstructNotAppliedAsync( text:="Module M Namespace n End Module", caret:={1, -1}) - End Sub + End Function End Class End Namespace diff --git a/src/EditorFeatures/VisualBasicTest/EndConstructGeneration/PreprocessorIfTests.vb b/src/EditorFeatures/VisualBasicTest/EndConstructGeneration/PreprocessorIfTests.vb index 1ea270f2e9f48..984acb9bc18f0 100644 --- a/src/EditorFeatures/VisualBasicTest/EndConstructGeneration/PreprocessorIfTests.vb +++ b/src/EditorFeatures/VisualBasicTest/EndConstructGeneration/PreprocessorIfTests.vb @@ -7,31 +7,31 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.EndConstructGenera Public Class PreprocessorIfTests - Public Sub ApplyAfterHashIf() - VerifyStatementEndConstructApplied( + Public Async Function ApplyAfterHashIf() As Task + Await VerifyStatementEndConstructAppliedAsync( before:="#If True Then", beforeCaret:={0, -1}, after:="#If True Then #End If", afterCaret:={1, -1}) - End Sub + End Function - Public Sub DoNotApplyAfterHashIfWhenEndIfExists() - VerifyStatementEndConstructNotApplied( + Public Async Function DoNotApplyAfterHashIfWhenEndIfExists() As Task + Await VerifyStatementEndConstructNotAppliedAsync( text:="#If True Then #End If", caret:={0, -1}) - End Sub + End Function - Public Sub DoNotApplyAfterHashElseIfWhenEndIfExists() - VerifyStatementEndConstructNotApplied( + Public Async Function DoNotApplyAfterHashElseIfWhenEndIfExists() As Task + Await VerifyStatementEndConstructNotAppliedAsync( text:="#If True Then #ElseIf True Then #End If", caret:={1, -1}) - End Sub + End Function End Class End Namespace diff --git a/src/EditorFeatures/VisualBasicTest/EndConstructGeneration/PreprocessorRegionsTests.vb b/src/EditorFeatures/VisualBasicTest/EndConstructGeneration/PreprocessorRegionsTests.vb index 59c85a5698e33..d4fda6639d87f 100644 --- a/src/EditorFeatures/VisualBasicTest/EndConstructGeneration/PreprocessorRegionsTests.vb +++ b/src/EditorFeatures/VisualBasicTest/EndConstructGeneration/PreprocessorRegionsTests.vb @@ -7,19 +7,19 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.EndConstructGenera Public Class PreprocessorRegionTests - Public Sub ApplyAfterHashRegion() - VerifyStatementEndConstructApplied( + Public Async Function ApplyAfterHashRegion() As Task + Await VerifyStatementEndConstructAppliedAsync( before:="#Region ""Goo""", beforeCaret:={0, -1}, after:="#Region ""Goo"" #End Region", afterCaret:={1, -1}) - End Sub + End Function - Public Sub ApplyAfterHashRegion1() - VerifyStatementEndConstructApplied( + Public Async Function ApplyAfterHashRegion1() As Task + Await VerifyStatementEndConstructAppliedAsync( before:="#Region ""Goo"" #Region ""Bar"" #End Region", @@ -30,41 +30,41 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.EndConstructGenera #End Region #End Region", afterCaret:={2, -1}) - End Sub + End Function - Public Sub DoNotApplyAfterHashRegionWithoutStringConstant() - VerifyStatementEndConstructNotApplied( + Public Async Function DoNotApplyAfterHashRegionWithoutStringConstant() As Task + Await VerifyStatementEndConstructNotAppliedAsync( text:="#Region", caret:={0, -1}) - End Sub + End Function - Public Sub DoNotApplyAfterHashRegionWhenEndRegionExists1() - VerifyStatementEndConstructNotApplied( + Public Async Function DoNotApplyAfterHashRegionWhenEndRegionExists1() As Task + Await VerifyStatementEndConstructNotAppliedAsync( text:="#Region ""Goo"" #End Region", caret:={0, -1}) - End Sub + End Function - Public Sub DoNotApplyAfterHashRegionWhenEndRegionExists2() - VerifyStatementEndConstructNotApplied( + Public Async Function DoNotApplyAfterHashRegionWhenEndRegionExists2() As Task + Await VerifyStatementEndConstructNotAppliedAsync( text:="#Region ""Goo"" #Region ""Bar"" #End Region #End Region", caret:={0, -1}) - End Sub + End Function - Public Sub DoNotApplyAfterHashRegionWhenEndRegionExists3() - VerifyStatementEndConstructNotApplied( + Public Async Function DoNotApplyAfterHashRegionWhenEndRegionExists3() As Task + Await VerifyStatementEndConstructNotAppliedAsync( text:="#Region ""Goo"" #Region ""Bar"" #End Region #End Region", caret:={1, -1}) - End Sub + End Function End Class End Namespace diff --git a/src/EditorFeatures/VisualBasicTest/EndConstructGeneration/PropertyBlockTests.vb b/src/EditorFeatures/VisualBasicTest/EndConstructGeneration/PropertyBlockTests.vb index d8db42f7098b1..90e39597af9fe 100644 --- a/src/EditorFeatures/VisualBasicTest/EndConstructGeneration/PropertyBlockTests.vb +++ b/src/EditorFeatures/VisualBasicTest/EndConstructGeneration/PropertyBlockTests.vb @@ -7,35 +7,35 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.EndConstructGenera Public Class PropertyBlockTests - Public Sub DoNotApplyForAutoProperty() - VerifyStatementEndConstructNotApplied( + Public Async Function DoNotApplyForAutoProperty() As Task + Await VerifyStatementEndConstructNotAppliedAsync( text:="Class c1 Property goo As Integer End Class", caret:={1, -1}) - End Sub + End Function - Public Sub DoNotApplyForAutoPropertyWithEmptyParens() - VerifyStatementEndConstructNotApplied( + Public Async Function DoNotApplyForAutoPropertyWithEmptyParens() As Task + Await VerifyStatementEndConstructNotAppliedAsync( text:="Class c1 Property goo() As Integer End Class", caret:={1, -1}) - End Sub + End Function - Public Sub DoNotApplyForMustInheritProperty() - VerifyStatementEndConstructNotApplied( + Public Async Function DoNotApplyForMustInheritProperty() As Task + Await VerifyStatementEndConstructNotAppliedAsync( text:="MustInherit Class C MustOverride Property goo(x as integer) As Integer End Class", caret:={1, -1}) - End Sub + End Function - Public Sub TestApplyForPropertyWithParameters() - VerifyStatementEndConstructApplied( + Public Async Function TestApplyForPropertyWithParameters() As Task + Await VerifyStatementEndConstructAppliedAsync( before:="Class c1 Property goo(i As Integer) As Integer End Class", @@ -51,20 +51,20 @@ End Class", End Property End Class", afterCaret:={3, -1}) - End Sub + End Function - Public Sub DoNotApplyForReadOnlyProperty() - VerifyStatementEndConstructNotApplied( + Public Async Function DoNotApplyForReadOnlyProperty() As Task + Await VerifyStatementEndConstructNotAppliedAsync( text:="Class c1 ReadOnly Property goo As Integer End Class", caret:={1, -1}) - End Sub + End Function - Public Sub DoNotApplyForReadOnlyPropertyAfterExistingGet() - VerifyStatementEndConstructNotApplied( + Public Async Function DoNotApplyForReadOnlyPropertyAfterExistingGet() As Task + Await VerifyStatementEndConstructNotAppliedAsync( text:="Class c1 ReadOnly Property goo As Integer Get @@ -73,11 +73,11 @@ End Class", End Property End Class", caret:={2, -1}) - End Sub + End Function - Public Sub DoNotApplyForReadOnlyWithSecondGetPropertyAfterExistingGet() - VerifyStatementEndConstructNotApplied( + Public Async Function DoNotApplyForReadOnlyWithSecondGetPropertyAfterExistingGet() As Task + Await VerifyStatementEndConstructNotAppliedAsync( text:="Class c1 ReadOnly Property goo As Integer Get @@ -88,20 +88,20 @@ End Class", End Property End Class", caret:={6, -1}) - End Sub + End Function - Public Sub DoNotApplyForWriteOnlyProperty() - VerifyStatementEndConstructNotApplied( + Public Async Function DoNotApplyForWriteOnlyProperty() As Task + Await VerifyStatementEndConstructNotAppliedAsync( text:="Class c1 WriteOnly Property goo As Integer End Class", caret:={1, -1}) - End Sub + End Function - Public Sub TestApplyOnGetForRegularProperty() - VerifyStatementEndConstructApplied( + Public Async Function TestApplyOnGetForRegularProperty() As Task + Await VerifyStatementEndConstructAppliedAsync( before:="Class c1 Property goo As Integer Get @@ -118,11 +118,11 @@ End Class", End Property End Class", afterCaret:={3, -1}) - End Sub + End Function - Public Sub TestApplyOnSetForRegularProperty() - VerifyStatementEndConstructApplied( + Public Async Function TestApplyOnSetForRegularProperty() As Task + Await VerifyStatementEndConstructAppliedAsync( before:="Class c1 Property goo As Integer Set @@ -139,21 +139,21 @@ End Class", End Property End Class", afterCaret:={3, -1}) - End Sub + End Function - Public Sub DoNotApplyForReadOnlyPropertyIfEndPropertyMissingWhenInvokedAfterProperty() - VerifyStatementEndConstructNotApplied( + Public Async Function DoNotApplyForReadOnlyPropertyIfEndPropertyMissingWhenInvokedAfterProperty() As Task + Await VerifyStatementEndConstructNotAppliedAsync( text:="Class c1 ReadOnly Property goo As Integer Get End Class", caret:={1, -1}) - End Sub + End Function - Public Sub TestApplyOnGetForRegularPropertyWithSetPresent() - VerifyStatementEndConstructApplied( + Public Async Function TestApplyOnGetForRegularPropertyWithSetPresent() As Task + Await VerifyStatementEndConstructAppliedAsync( before:="Class c1 Property goo As Integer Get @@ -176,20 +176,20 @@ End Class", End Property End Class", afterCaret:={3, -1}) - End Sub + End Function - Public Sub DoNotApplyForWriteOnlyPropertyWithTypeCharacter() - VerifyStatementEndConstructNotApplied( + Public Async Function DoNotApplyForWriteOnlyPropertyWithTypeCharacter() As Task + Await VerifyStatementEndConstructNotAppliedAsync( text:="Class c1 WriteOnly Property goo$ End Class", caret:={1, -1}) - End Sub + End Function - Public Sub TestApplyForPropertyWithIndexer() - VerifyStatementEndConstructApplied( + Public Async Function TestApplyForPropertyWithIndexer() As Task + Await VerifyStatementEndConstructAppliedAsync( before:="Class c1 Property goo(arg as Integer) As Integer End Class", @@ -205,11 +205,11 @@ End Class", End Property End Class", afterCaret:={3, -1}) - End Sub + End Function - Public Sub DoNotApplyForDuplicateGet() - VerifyStatementEndConstructNotApplied( + Public Async Function DoNotApplyForDuplicateGet() As Task + Await VerifyStatementEndConstructNotAppliedAsync( text:="Class c1 ReadOnly Property goo As Integer Get @@ -219,11 +219,11 @@ End Class", End Property End Class", caret:={5, -1}) - End Sub + End Function - Public Sub DoNotApplyForDuplicateSet() - VerifyStatementEndConstructNotApplied( + Public Async Function DoNotApplyForDuplicateSet() As Task + Await VerifyStatementEndConstructNotAppliedAsync( text:="Class c1 WriteOnly Property goo As Integer Set(ByVal value As Integer) @@ -233,51 +233,51 @@ End Class", End Property End Class", caret:={5, -1}) - End Sub + End Function - Public Sub DoNotApplyForSetInReadOnly() - VerifyStatementEndConstructNotApplied( + Public Async Function DoNotApplyForSetInReadOnly() As Task + Await VerifyStatementEndConstructNotAppliedAsync( text:="Class c1 ReadOnly Property goo As Integer Set End Property End Class", caret:={2, -1}) - End Sub + End Function - Public Sub DoNotApplyForGetInReadOnly() - VerifyStatementEndConstructNotApplied( + Public Async Function DoNotApplyForGetInReadOnly() As Task + Await VerifyStatementEndConstructNotAppliedAsync( text:="Class c1 WriteOnly Property goo As Integer Get End Property End Class", caret:={2, -1}) - End Sub + End Function - Public Sub VerifyInternationalCharacter() - VerifyStatementEndConstructNotApplied( + Public Async Function VerifyInternationalCharacter() As Task + Await VerifyStatementEndConstructNotAppliedAsync( text:="Class c1 WriteOnly Property gooæ End Class", caret:={1, -1}) - End Sub + End Function - Public Sub DoNotApplyInsideAnInterface() - VerifyStatementEndConstructNotApplied( + Public Async Function DoNotApplyInsideAnInterface() As Task + Await VerifyStatementEndConstructNotAppliedAsync( text:="Interface IGoo Property Goo(x As Integer) As String End Interface", caret:={1, -1}) - End Sub + End Function - Public Sub TestDoNotGenerateSetForReadonlyProperty() - VerifyStatementEndConstructApplied( + Public Async Function TestDoNotGenerateSetForReadonlyProperty() As Task + Await VerifyStatementEndConstructAppliedAsync( before:="Class c1 Readonly Property goo(arg as Integer) As Integer End Class", @@ -290,11 +290,11 @@ End Class", End Property End Class", afterCaret:={3, -1}) - End Sub + End Function - Public Sub TestDoNotGenerateGetForWriteonlyProperty() - VerifyStatementEndConstructApplied( + Public Async Function TestDoNotGenerateGetForWriteonlyProperty() As Task + Await VerifyStatementEndConstructAppliedAsync( before:="Class c1 Writeonly Property goo(arg as Integer) As Integer End Class", @@ -307,6 +307,6 @@ End Class", End Property End Class", afterCaret:={3, -1}) - End Sub + End Function End Class End Namespace diff --git a/src/EditorFeatures/VisualBasicTest/EndConstructGeneration/SelectBlockTests.vb b/src/EditorFeatures/VisualBasicTest/EndConstructGeneration/SelectBlockTests.vb index d08f41f44584c..93ece3a19bcc0 100644 --- a/src/EditorFeatures/VisualBasicTest/EndConstructGeneration/SelectBlockTests.vb +++ b/src/EditorFeatures/VisualBasicTest/EndConstructGeneration/SelectBlockTests.vb @@ -7,8 +7,8 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.EndConstructGenera Public Class SelectBlockTests - Public Sub TestApplyAfterSelectKeyword() - VerifyStatementEndConstructApplied( + Public Async Function TestApplyAfterSelectKeyword() As Task + Await VerifyStatementEndConstructAppliedAsync( before:="Class c1 Sub goo() Select goo @@ -23,11 +23,11 @@ End Select End Sub End Class", afterCaret:={3, -1}) - End Sub + End Function - Public Sub TestApplyAfterSelectCaseKeyword() - VerifyStatementEndConstructApplied( + Public Async Function TestApplyAfterSelectCaseKeyword() As Task + Await VerifyStatementEndConstructAppliedAsync( before:="Class c1 Sub goo() Select Case goo @@ -42,11 +42,11 @@ End Select End Sub End Class", afterCaret:={3, -1}) - End Sub + End Function - Public Sub VerifyNestedDo() - VerifyStatementEndConstructApplied( + Public Async Function VerifyNestedDo() As Task + Await VerifyStatementEndConstructAppliedAsync( before:="Class C Sub S Select Case 1 @@ -67,22 +67,22 @@ End Class", End Sub End Class", afterCaret:={5, -1}) - End Sub + End Function - Public Sub VerifyInvalidSelectBlock() - VerifyStatementEndConstructNotApplied( + Public Async Function VerifyInvalidSelectBlock() As Task + Await VerifyStatementEndConstructNotAppliedAsync( text:="Class C Sub S dim x = Select 1 End Sub End Class", caret:={2, -1}) - End Sub + End Function - Public Sub VerifyInvalidSelectBlock01() - VerifyStatementEndConstructNotApplied( + Public Async Function VerifyInvalidSelectBlock01() As Task + Await VerifyStatementEndConstructNotAppliedAsync( text:="Class EC Sub T Select 1 @@ -90,20 +90,20 @@ End Class", End Sub End Class", caret:={3, -1}) - End Sub + End Function - Public Sub VerifyInvalidSelectBlock02() - VerifyStatementEndConstructNotApplied( + Public Async Function VerifyInvalidSelectBlock02() As Task + Await VerifyStatementEndConstructNotAppliedAsync( text:="Class EC Select 1 End Class", caret:={1, -1}) - End Sub + End Function - Public Sub VerifyReCommitSelectBlock() - VerifyStatementEndConstructNotApplied( + Public Async Function VerifyReCommitSelectBlock() As Task + Await VerifyStatementEndConstructNotAppliedAsync( text:="Class C Sub S Select Case 1 @@ -112,6 +112,6 @@ End Class", End Sub End Class", caret:={2, -1}) - End Sub + End Function End Class End Namespace diff --git a/src/EditorFeatures/VisualBasicTest/EndConstructGeneration/SyncLockBlockTests.vb b/src/EditorFeatures/VisualBasicTest/EndConstructGeneration/SyncLockBlockTests.vb index 88f14a8a1e49e..74050194336fb 100644 --- a/src/EditorFeatures/VisualBasicTest/EndConstructGeneration/SyncLockBlockTests.vb +++ b/src/EditorFeatures/VisualBasicTest/EndConstructGeneration/SyncLockBlockTests.vb @@ -7,8 +7,8 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.EndConstructGenera Public Class SyncLockBlockTests - Public Sub ApplyAfterSyncLockStatement() - VerifyStatementEndConstructApplied( + Public Async Function ApplyAfterSyncLockStatement() As Task + Await VerifyStatementEndConstructAppliedAsync( before:="Class c1 Sub goo() SyncLock variable @@ -23,11 +23,11 @@ End SyncLock End Sub End Class", afterCaret:={3, -1}) - End Sub + End Function - Public Sub DoNotApplyForMatchedUsing() - VerifyStatementEndConstructNotApplied( + Public Async Function DoNotApplyForMatchedUsing() As Task + Await VerifyStatementEndConstructNotAppliedAsync( text:="Class c1 Sub goo() SyncLock variable @@ -35,11 +35,11 @@ End SyncLock End Sub End Class", caret:={2, -1}) - End Sub + End Function - Public Sub VerifyNestedSyncBlock() - VerifyStatementEndConstructApplied( + Public Async Function VerifyNestedSyncBlock() As Task + Await VerifyStatementEndConstructAppliedAsync( before:="Class C Sub S SyncLock x @@ -58,26 +58,26 @@ End Class", End Sub End Class", afterCaret:={4, -1}) - End Sub + End Function - Public Sub VerifyInvalidSyntax() - VerifyStatementEndConstructNotApplied( + Public Async Function VerifyInvalidSyntax() As Task + Await VerifyStatementEndConstructNotAppliedAsync( text:="Class C Sub S Using (SyncLock 1) End Sub End Class", caret:={2, -1}) - End Sub + End Function - Public Sub VerifyInvalidLocation() - VerifyStatementEndConstructNotApplied( + Public Async Function VerifyInvalidLocation() As Task + Await VerifyStatementEndConstructNotAppliedAsync( text:="Class EC Synclock 1 End Class", caret:={1, -1}) - End Sub + End Function End Class End Namespace diff --git a/src/EditorFeatures/VisualBasicTest/EndConstructGeneration/TryBlockTests.vb b/src/EditorFeatures/VisualBasicTest/EndConstructGeneration/TryBlockTests.vb index e2518511aab8f..71cb45072dc76 100644 --- a/src/EditorFeatures/VisualBasicTest/EndConstructGeneration/TryBlockTests.vb +++ b/src/EditorFeatures/VisualBasicTest/EndConstructGeneration/TryBlockTests.vb @@ -7,8 +7,8 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.EndConstructGenera Public Class TryBlockTests - Public Sub ApplyAfterTryStatement() - VerifyStatementEndConstructApplied( + Public Async Function ApplyAfterTryStatement() As Task + Await VerifyStatementEndConstructAppliedAsync( before:="Class c1 Sub goo() Try @@ -25,11 +25,11 @@ End Try End Sub End Class", afterCaret:={3, -1}) - End Sub + End Function - Public Sub DoNotApplyForMatchedTryWithCatch() - VerifyStatementEndConstructNotApplied( + Public Async Function DoNotApplyForMatchedTryWithCatch() As Task + Await VerifyStatementEndConstructNotAppliedAsync( text:="Class c1 Sub goo() Try @@ -38,11 +38,11 @@ End Try End Sub End Class", caret:={2, -1}) - End Sub + End Function - Public Sub DoNotApplyForMatchedTryWithoutCatch() - VerifyStatementEndConstructNotApplied( + Public Async Function DoNotApplyForMatchedTryWithoutCatch() As Task + Await VerifyStatementEndConstructNotAppliedAsync( text:="Class c1 Sub goo() Try @@ -50,11 +50,11 @@ End Try End Sub End Class", caret:={2, -1}) - End Sub + End Function - Public Sub VerifyNestedTryBlock() - VerifyStatementEndConstructApplied( + Public Async Function VerifyNestedTryBlock() As Task + Await VerifyStatementEndConstructAppliedAsync( before:="Class C Sub S Try @@ -79,11 +79,11 @@ End Class", End Sub End Class", afterCaret:={6, -1}) - End Sub + End Function - Public Sub VerifyNestedTryBlockWithCode() - VerifyStatementEndConstructApplied( + Public Async Function VerifyNestedTryBlockWithCode() As Task + Await VerifyStatementEndConstructAppliedAsync( before:="Class C Sub S Try @@ -104,11 +104,11 @@ End Class", End Sub End Class", afterCaret:={3, -1}) - End Sub + End Function - Public Sub VerifyMissingCatchInTryBlock() - VerifyStatementEndConstructNotApplied( + Public Async Function VerifyMissingCatchInTryBlock() As Task + Await VerifyStatementEndConstructNotAppliedAsync( text:="Class C Sub S dim x = function(x) @@ -119,27 +119,26 @@ End Class", End Sub End Class", caret:={3, -1}) - End Sub + End Function - Public Sub VerifyInvalidSyntax() - VerifyStatementEndConstructNotApplied( + Public Async Function VerifyInvalidSyntax() As Task + Await VerifyStatementEndConstructNotAppliedAsync( text:="Class EC Sub S Dim x = try End Sub End Class", caret:={2, -1}) - End Sub + End Function - Public Sub VerifyInvalidLocation() - VerifyStatementEndConstructNotApplied( + Public Async Function VerifyInvalidLocation() As Task + Await VerifyStatementEndConstructNotAppliedAsync( text:="Class EC Sub Try End Class", caret:={1, -1}) - End Sub - + End Function End Class End Namespace diff --git a/src/EditorFeatures/VisualBasicTest/EndConstructGeneration/TypeBlockTests.vb b/src/EditorFeatures/VisualBasicTest/EndConstructGeneration/TypeBlockTests.vb index 7899d0278b956..04202526cc4ce 100644 --- a/src/EditorFeatures/VisualBasicTest/EndConstructGeneration/TypeBlockTests.vb +++ b/src/EditorFeatures/VisualBasicTest/EndConstructGeneration/TypeBlockTests.vb @@ -7,71 +7,71 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.EndConstructGenera Public Class TypeBlockTests - Public Sub TestApplyAfterClassStatement() - VerifyStatementEndConstructApplied( + Public Async Function TestApplyAfterClassStatement() As Task + Await VerifyStatementEndConstructAppliedAsync( before:="Class c1", beforeCaret:={0, -1}, after:="Class c1 End Class", afterCaret:={1, -1}) - End Sub + End Function - Public Sub TestApplyAfterModuleStatement() - VerifyStatementEndConstructApplied( + Public Async Function TestApplyAfterModuleStatement() As Task + Await VerifyStatementEndConstructAppliedAsync( before:="Module m1", beforeCaret:={0, -1}, after:="Module m1 End Module", afterCaret:={1, -1}) - End Sub + End Function - Public Sub DoNotApplyForMatchedClass() - VerifyStatementEndConstructNotApplied( + Public Async Function DoNotApplyForMatchedClass() As Task + Await VerifyStatementEndConstructNotAppliedAsync( text:="Class c1 End Class", caret:={0, -1}) - End Sub + End Function - Public Sub TestApplyAfterInterfaceStatement() - VerifyStatementEndConstructApplied( + Public Async Function TestApplyAfterInterfaceStatement() As Task + Await VerifyStatementEndConstructAppliedAsync( before:="Interface IGoo", beforeCaret:={0, -1}, after:="Interface IGoo End Interface", afterCaret:={1, -1}) - End Sub + End Function - Public Sub TestApplyAfterStructureStatement() - VerifyStatementEndConstructApplied( + Public Async Function TestApplyAfterStructureStatement() As Task + Await VerifyStatementEndConstructAppliedAsync( before:="Structure Goo", beforeCaret:={0, -1}, after:="Structure Goo End Structure", afterCaret:={1, -1}) - End Sub + End Function - Public Sub TestApplyAfterEnumStatement() - VerifyStatementEndConstructApplied( + Public Async Function TestApplyAfterEnumStatement() As Task + Await VerifyStatementEndConstructAppliedAsync( before:="Enum Goo", beforeCaret:={0, -1}, after:="Enum Goo End Enum", afterCaret:={1, -1}) - End Sub + End Function - Public Sub TestVerifyGenericClass() - VerifyStatementEndConstructApplied( + Public Async Function TestVerifyGenericClass() As Task + Await VerifyStatementEndConstructAppliedAsync( before:="NameSpace X Class C(of T)", beforeCaret:={1, -1}, @@ -80,11 +80,11 @@ End Enum", End Class", afterCaret:={2, -1}) - End Sub + End Function - Public Sub TestVerifyStructInAClass() - VerifyStatementEndConstructApplied( + Public Async Function TestVerifyStructInAClass() As Task + Await VerifyStatementEndConstructAppliedAsync( before:="Class C Structure s End Class", @@ -95,11 +95,11 @@ End Class", End Structure End Class", afterCaret:={2, -1}) - End Sub + End Function - Public Sub TestVerifyClassInAModule() - VerifyStatementEndConstructApplied( + Public Async Function TestVerifyClassInAModule() As Task + Await VerifyStatementEndConstructAppliedAsync( before:="Module M Class C End Module", @@ -110,22 +110,22 @@ End Module", End Class End Module", afterCaret:={2, -1}) - End Sub + End Function - Public Sub TestVerifyClassDeclaration() - VerifyStatementEndConstructApplied( + Public Async Function TestVerifyClassDeclaration() As Task + Await VerifyStatementEndConstructAppliedAsync( before:="Partial Friend MustInherit Class C", beforeCaret:={0, -1}, after:="Partial Friend MustInherit Class C End Class", afterCaret:={1, -1}) - End Sub + End Function - Public Sub TestVerifyEnumInAClass() - VerifyStatementEndConstructApplied( + Public Async Function TestVerifyEnumInAClass() As Task + Await VerifyStatementEndConstructAppliedAsync( before:="Class C Public Enum e End Class", @@ -136,69 +136,69 @@ End Class", End Enum End Class", afterCaret:={2, -1}) - End Sub + End Function - Public Sub VerifyInvalidSyntax() - VerifyStatementEndConstructNotApplied( + Public Async Function VerifyInvalidSyntax() As Task + Await VerifyStatementEndConstructNotAppliedAsync( text:="Class EC Sub S Class B End Sub End Class", caret:={2, -1}) - End Sub + End Function - Public Sub VerifyInvalidSyntax01() - VerifyStatementEndConstructNotApplied( + Public Async Function VerifyInvalidSyntax01() As Task + Await VerifyStatementEndConstructNotAppliedAsync( text:="Enum e(Of T)", caret:={0, -1}) - End Sub + End Function - Public Sub VerifyInvalidSyntax02() - VerifyStatementEndConstructNotApplied( + Public Async Function VerifyInvalidSyntax02() As Task + Await VerifyStatementEndConstructNotAppliedAsync( text:="Class C Class", caret:={0, -1}) - End Sub + End Function - Public Sub TestVerifyInheritsDecl() - VerifyStatementEndConstructApplied( + Public Async Function TestVerifyInheritsDecl() As Task + Await VerifyStatementEndConstructAppliedAsync( before:="Class C : Inherits B", beforeCaret:={0, -1}, after:="Class C : Inherits B End Class", afterCaret:={1, -1}) - End Sub + End Function - Public Sub VerifyInheritsDeclNotApplied() - VerifyStatementEndConstructNotApplied( + Public Async Function VerifyInheritsDeclNotApplied() As Task + Await VerifyStatementEndConstructNotAppliedAsync( text:="Class C : Inherits B End Class", caret:={0, -1}) - End Sub + End Function - Public Sub TestVerifyImplementsDecl() - VerifyStatementEndConstructApplied( + Public Async Function TestVerifyImplementsDecl() As Task + Await VerifyStatementEndConstructAppliedAsync( before:="Class C : Implements IB", beforeCaret:={0, -1}, after:="Class C : Implements IB End Class", afterCaret:={1, -1}) - End Sub + End Function - Public Sub VerifyImplementsDeclNotApplied() - VerifyStatementEndConstructNotApplied( + Public Async Function VerifyImplementsDeclNotApplied() As Task + Await VerifyStatementEndConstructNotAppliedAsync( text:="Class C : Implements IB End Class", caret:={0, -1}) - End Sub + End Function End Class End Namespace diff --git a/src/EditorFeatures/VisualBasicTest/EndConstructGeneration/UsingBlockTests.vb b/src/EditorFeatures/VisualBasicTest/EndConstructGeneration/UsingBlockTests.vb index 44ec4f54998db..38d27a5da39af 100644 --- a/src/EditorFeatures/VisualBasicTest/EndConstructGeneration/UsingBlockTests.vb +++ b/src/EditorFeatures/VisualBasicTest/EndConstructGeneration/UsingBlockTests.vb @@ -7,8 +7,8 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.EndConstructGenera Public Class UsingBlockTests - Public Sub ApplyAfterUsingStatement() - VerifyStatementEndConstructApplied( + Public Async Function ApplyAfterUsingStatement() As Task + Await VerifyStatementEndConstructAppliedAsync( before:="Class c1 Sub goo() Using variable @@ -23,11 +23,11 @@ End Using End Sub End Class", afterCaret:={3, -1}) - End Sub + End Function - Public Sub DoNotApplyForMatchedUsing() - VerifyStatementEndConstructNotApplied( + Public Async Function DoNotApplyForMatchedUsing() As Task + Await VerifyStatementEndConstructNotAppliedAsync( text:="Class c1 Sub goo() Using variable @@ -35,11 +35,11 @@ End Using End Sub End Class", caret:={2, -1}) - End Sub + End Function - Public Sub VerifyNestedUsing() - VerifyStatementEndConstructApplied( + Public Async Function VerifyNestedUsing() As Task + Await VerifyStatementEndConstructAppliedAsync( before:="Class C Sub S Using y @@ -58,11 +58,11 @@ End Class", End Sub End Class", afterCaret:={4, -1}) - End Sub + End Function - Public Sub VerifyUsingWithDelegate() - VerifyStatementEndConstructApplied( + Public Async Function VerifyUsingWithDelegate() As Task + Await VerifyStatementEndConstructAppliedAsync( before:="Class C Sub S Using Func(of String, String) @@ -77,26 +77,26 @@ End Class", End Sub End Class", afterCaret:={3, -1}) - End Sub + End Function - Public Sub VerifyUsingAtInvalidSyntax() - VerifyStatementEndConstructNotApplied( + Public Async Function VerifyUsingAtInvalidSyntax() As Task + Await VerifyStatementEndConstructNotAppliedAsync( text:="Class EC Sub S Using x asf asdf End Sub End Class", caret:={2, -1}) - End Sub + End Function - Public Sub VerifyUsingAtInvalidLocation() - VerifyStatementEndConstructNotApplied( + Public Async Function VerifyUsingAtInvalidLocation() As Task + Await VerifyStatementEndConstructNotAppliedAsync( text:="Class EC Using x End Class", caret:={1, -1}) - End Sub + End Function End Class End Namespace diff --git a/src/EditorFeatures/VisualBasicTest/EndConstructGeneration/WhileLoopTests.vb b/src/EditorFeatures/VisualBasicTest/EndConstructGeneration/WhileLoopTests.vb index 0dc9b3a2484ea..5dfa92cf9cf6a 100644 --- a/src/EditorFeatures/VisualBasicTest/EndConstructGeneration/WhileLoopTests.vb +++ b/src/EditorFeatures/VisualBasicTest/EndConstructGeneration/WhileLoopTests.vb @@ -7,8 +7,8 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.EndConstructGenera Public Class WhileLoopTests - Public Sub ApplyAfterWithStatement() - VerifyStatementEndConstructApplied( + Public Async Function ApplyAfterWithStatement() As Task + Await VerifyStatementEndConstructAppliedAsync( before:="Class c1 Sub goo() While variable @@ -23,11 +23,11 @@ End While End Sub End Class", afterCaret:={3, -1}) - End Sub + End Function - Public Sub DoNotApplyForMatchedWith() - VerifyStatementEndConstructNotApplied( + Public Async Function DoNotApplyForMatchedWith() As Task + Await VerifyStatementEndConstructNotAppliedAsync( text:="Class c1 Sub goo() While variable @@ -35,11 +35,11 @@ End While End Sub End Class", caret:={2, -1}) - End Sub + End Function - Public Sub VerifyNestedWhileBlock() - VerifyStatementEndConstructApplied( + Public Async Function VerifyNestedWhileBlock() As Task + Await VerifyStatementEndConstructAppliedAsync( before:="Class C Sub S While True @@ -60,11 +60,11 @@ End Class", End Sub End Class", afterCaret:={4, -1}) - End Sub + End Function - Public Sub VerifyRecommitWhileBlock() - VerifyStatementEndConstructNotApplied( + Public Async Function VerifyRecommitWhileBlock() As Task + Await VerifyStatementEndConstructNotAppliedAsync( text:="Class C Sub S While [while] = [while] @@ -72,26 +72,26 @@ End Class", End Sub End Class", caret:={2, -1}) - End Sub + End Function - Public Sub VerifyInvalidWhileSyntax() - VerifyStatementEndConstructNotApplied( + Public Async Function VerifyInvalidWhileSyntax() As Task + Await VerifyStatementEndConstructNotAppliedAsync( text:="Class EC Sub S While asdf asdf asd End Sub End Class", caret:={2, -1}) - End Sub + End Function - Public Sub VerifyInvalidWhileLocation() - VerifyStatementEndConstructNotApplied( + Public Async Function VerifyInvalidWhileLocation() As Task + Await VerifyStatementEndConstructNotAppliedAsync( text:="Class EC While True End Class", caret:={1, -1}) - End Sub + End Function End Class End Namespace diff --git a/src/EditorFeatures/VisualBasicTest/EndConstructGeneration/WhiteSpacesInsertTests.vb b/src/EditorFeatures/VisualBasicTest/EndConstructGeneration/WhiteSpacesInsertTests.vb index aa0d902427e3b..0d913f04ee8cd 100644 --- a/src/EditorFeatures/VisualBasicTest/EndConstructGeneration/WhiteSpacesInsertTests.vb +++ b/src/EditorFeatures/VisualBasicTest/EndConstructGeneration/WhiteSpacesInsertTests.vb @@ -7,8 +7,8 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.EndConstructGenera Public Class WhiteSpacesInsertTests - Public Sub VerifyInsertWhiteSpace() - VerifyStatementEndConstructApplied( + Public Async Function VerifyInsertWhiteSpace() As Task + Await VerifyStatementEndConstructAppliedAsync( before:="Class X Sub y() End Class", @@ -19,11 +19,11 @@ End Class", End Sub End Class", afterCaret:={2, -1}) - End Sub + End Function - Public Sub VerifyInsertTabSpace() - VerifyStatementEndConstructApplied( + Public Async Function VerifyInsertTabSpace() As Task + Await VerifyStatementEndConstructAppliedAsync( before:="Class X Sub y() End Class", @@ -34,11 +34,11 @@ End Class", End Sub End Class", afterCaret:={2, -1}) - End Sub + End Function - Public Sub VerifyInsertDoubleWideWhiteSpace() - VerifyStatementEndConstructApplied( + Public Async Function VerifyInsertDoubleWideWhiteSpace() As Task + Await VerifyStatementEndConstructAppliedAsync( before:="Class X Sub y() End Class", @@ -50,6 +50,6 @@ End Class", End Class", afterCaret:={2, -1}) - End Sub + End Function End Class End Namespace diff --git a/src/EditorFeatures/VisualBasicTest/EndConstructGeneration/WithBlockTests.vb b/src/EditorFeatures/VisualBasicTest/EndConstructGeneration/WithBlockTests.vb index 2459fdab98daf..8a0f5700a937d 100644 --- a/src/EditorFeatures/VisualBasicTest/EndConstructGeneration/WithBlockTests.vb +++ b/src/EditorFeatures/VisualBasicTest/EndConstructGeneration/WithBlockTests.vb @@ -7,8 +7,8 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.EndConstructGenera Public Class WithBlockTests - Public Sub ApplyAfterWithStatement() - VerifyStatementEndConstructApplied( + Public Async Function ApplyAfterWithStatement() As Task + Await VerifyStatementEndConstructAppliedAsync( before:="Class c1 Sub goo() With variable @@ -23,11 +23,11 @@ End With End Sub End Class", afterCaret:={3, -1}) - End Sub + End Function - Public Sub DoNotApplyForMatchedWith() - VerifyStatementEndConstructNotApplied( + Public Async Function DoNotApplyForMatchedWith() As Task + Await VerifyStatementEndConstructNotAppliedAsync( text:="Class c1 Sub goo() With variable @@ -35,11 +35,11 @@ End With End Sub End Class", caret:={2, -1}) - End Sub + End Function - Public Sub VerifyNestedWith() - VerifyStatementEndConstructApplied( + Public Async Function VerifyNestedWith() As Task + Await VerifyStatementEndConstructAppliedAsync( before:="Class C Sub S With K @@ -58,11 +58,11 @@ End Class", End Sub End Class", afterCaret:={4, -1}) - End Sub + End Function - Public Sub VerifyWithFollowsCode() - VerifyStatementEndConstructApplied( + Public Async Function VerifyWithFollowsCode() As Task + Await VerifyStatementEndConstructAppliedAsync( before:="Class C Sub S With K @@ -79,26 +79,26 @@ End Class", End Sub End Class", afterCaret:={3, -1}) - End Sub + End Function - Public Sub VerifyInvalidWithSyntax() - VerifyStatementEndConstructNotApplied( + Public Async Function VerifyInvalidWithSyntax() As Task + Await VerifyStatementEndConstructNotAppliedAsync( text:="Class EC Sub S With using End Sub End Class", caret:={2, -1}) - End Sub + End Function - Public Sub VerifyInvalidWithLocation() - VerifyStatementEndConstructNotApplied( + Public Async Function VerifyInvalidWithLocation() As Task + Await VerifyStatementEndConstructNotAppliedAsync( text:="Class EC With True End Class", caret:={1, -1}) - End Sub + End Function End Class End Namespace diff --git a/src/EditorFeatures/VisualBasicTest/EndConstructGeneration/XmlLiteralTests.vb b/src/EditorFeatures/VisualBasicTest/EndConstructGeneration/XmlLiteralTests.vb index 18a5ad08c5358..d9e0b6bf92c0f 100644 --- a/src/EditorFeatures/VisualBasicTest/EndConstructGeneration/XmlLiteralTests.vb +++ b/src/EditorFeatures/VisualBasicTest/EndConstructGeneration/XmlLiteralTests.vb @@ -7,8 +7,8 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.EndConstructGenera Public Class XmlLiteralTests - Public Sub TestApplyAfterXmlStartElement() - VerifyXmlElementEndConstructApplied( + Public Async Function TestApplyAfterXmlStartElement() As Task + Await VerifyXmlElementEndConstructAppliedAsync( before:="Class C1 Sub M1() Dim x = @@ -21,11 +21,11 @@ End Class", End Sub End Class", afterCaret:={2, 21}) - End Sub + End Function - Public Sub TestApplyAfterXmlStartElementSplitAcrossLines() - VerifyXmlElementEndConstructApplied( + Public Async Function TestApplyAfterXmlStartElementSplitAcrossLines() As Task + Await VerifyXmlElementEndConstructAppliedAsync( before:="Class C1 Sub M1() Dim x = - Public Sub TestApplyAfterXmlStartElementWithNamespace() - VerifyXmlElementEndConstructApplied( + Public Async Function TestApplyAfterXmlStartElementWithNamespace() As Task + Await VerifyXmlElementEndConstructAppliedAsync( before:="Class C1 Sub M1() Dim x = @@ -57,76 +57,76 @@ End Class", End Sub End Class", afterCaret:={2, 21}) - End Sub + End Function - Public Sub DoNotApplyInParameterDeclaration1() - VerifyXmlElementEndConstructNotApplied( + Public Async Function DoNotApplyInParameterDeclaration1() As Task + Await VerifyXmlElementEndConstructNotAppliedAsync( text:="Class C1 Sub M1() End Sub End Class", caret:={1, 16}) - End Sub + End Function - Public Sub DoNotApplyInParameterDeclaration2() - VerifyXmlElementEndConstructNotApplied( + Public Async Function DoNotApplyInParameterDeclaration2() As Task + Await VerifyXmlElementEndConstructNotAppliedAsync( text:="Class C1 Sub M1(i As Integer, ) End Sub End Class", caret:={2, 16}) - End Sub + End Function - Public Sub DoNotApplyAfterXmlStartElementWithEndElement() - VerifyXmlElementEndConstructNotApplied( + Public Async Function DoNotApplyAfterXmlStartElementWithEndElement() As Task + Await VerifyXmlElementEndConstructNotAppliedAsync( text:="Class C1 Sub M1() Dim x = End Sub End Class", caret:={2, 23}) - End Sub + End Function - Public Sub DoNotApplyAfterXmlEndElement() - VerifyXmlElementEndConstructNotApplied( + Public Async Function DoNotApplyAfterXmlEndElement() As Task + Await VerifyXmlElementEndConstructNotAppliedAsync( text:="Class C1 Sub M1() Dim x = End Sub End Class", caret:={2, -1}) - End Sub + End Function - Public Sub DoNotApplyAfterSingleXmlTag() - VerifyXmlElementEndConstructNotApplied( + Public Async Function DoNotApplyAfterSingleXmlTag() As Task + Await VerifyXmlElementEndConstructNotAppliedAsync( text:="Class C1 Sub M1() Dim x = End Sub End Class", caret:={2, -1}) - End Sub + End Function - Public Sub DoNotApplyAfterProcessingInstruction() - VerifyXmlElementEndConstructNotApplied( + Public Async Function DoNotApplyAfterProcessingInstruction() As Task + Await VerifyXmlElementEndConstructNotAppliedAsync( text:="Class C1 Sub M1() Dim x = End Sub End Class", caret:={2, -1}) - End Sub + End Function - Public Sub TestApplyAfterXmlStartElementWhenPassedAsParameter1() - VerifyXmlElementEndConstructApplied( + Public Async Function TestApplyAfterXmlStartElementWhenPassedAsParameter1() As Task + Await VerifyXmlElementEndConstructAppliedAsync( before:="Class C1 Sub M1() M2( @@ -139,11 +139,11 @@ End Class", End Sub End Class", afterCaret:={2, 16}) - End Sub + End Function - Public Sub TestApplyAfterXmlStartElementWhenPassedAsParameter2() - VerifyXmlElementEndConstructApplied( + Public Async Function TestApplyAfterXmlStartElementWhenPassedAsParameter2() As Task + Await VerifyXmlElementEndConstructAppliedAsync( before:="Class C1 Sub M1() M2() @@ -156,11 +156,11 @@ End Class", End Sub End Class", afterCaret:={2, 16}) - End Sub + End Function - Public Sub TestApplyAfterXmlComment() - VerifyXmlCommentEndConstructApplied( + Public Async Function TestApplyAfterXmlComment() As Task + Await VerifyXmlCommentEndConstructAppliedAsync( before:="Class C1 Sub M1() Dim x = + diff --git a/src/Features/ExternalAccess/OmniSharp/Notification/IOmniSharpNotificationService.cs b/src/Features/ExternalAccess/OmniSharp/Notification/IOmniSharpNotificationService.cs new file mode 100644 index 0000000000000..bf9d18bc189f9 --- /dev/null +++ b/src/Features/ExternalAccess/OmniSharp/Notification/IOmniSharpNotificationService.cs @@ -0,0 +1,31 @@ +// 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.ExternalAccess.OmniSharp.Notification; + +internal interface IOmniSharpNotificationService +{ + /// + /// Displays a message box with an OK button to the user. + /// + /// The message shown within the message box. + /// The title bar to be shown in the message box. May be ignored by some implementations. + /// The severity of the message. + void SendNotification( + string message, + string? title = null, + OmniSharpNotificationSeverity severity = OmniSharpNotificationSeverity.Warning); + + /// + /// Displays a message box with a yes/no question to the user. + /// + /// The message shown within the message box. + /// The title bar to be shown in the message box. May be ignored by some implementations. + /// The severity of the message. + /// true if yes was clicked, false otherwise. + bool ConfirmMessageBox( + string message, + string? title = null, + OmniSharpNotificationSeverity severity = OmniSharpNotificationSeverity.Warning); +} diff --git a/src/Features/ExternalAccess/OmniSharp/Notification/OmniSharpNotificationSeverity.cs b/src/Features/ExternalAccess/OmniSharp/Notification/OmniSharpNotificationSeverity.cs new file mode 100644 index 0000000000000..5effd1e9bf5b3 --- /dev/null +++ b/src/Features/ExternalAccess/OmniSharp/Notification/OmniSharpNotificationSeverity.cs @@ -0,0 +1,14 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Microsoft.CodeAnalysis.Notification; + +namespace Microsoft.CodeAnalysis.ExternalAccess.OmniSharp.Notification; + +internal enum OmniSharpNotificationSeverity +{ + Information = NotificationSeverity.Information, + Warning = NotificationSeverity.Warning, + Error = NotificationSeverity.Error +} diff --git a/src/Features/ExternalAccess/OmniSharp/Options/OmniSharpEditorConfigOptions.cs b/src/Features/ExternalAccess/OmniSharp/Options/OmniSharpEditorConfigOptions.cs new file mode 100644 index 0000000000000..066123be77edf --- /dev/null +++ b/src/Features/ExternalAccess/OmniSharp/Options/OmniSharpEditorConfigOptions.cs @@ -0,0 +1,13 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Microsoft.CodeAnalysis.ExternalAccess.OmniSharp.ImplementType; + +namespace Microsoft.CodeAnalysis.ExternalAccess.OmniSharp.Options; + +internal sealed record class OmniSharpEditorConfigOptions +{ + public required OmniSharpLineFormattingOptions LineFormattingOptions { get; init; } + public OmniSharpImplementTypeOptions ImplementTypeOptions { get; init; } +} diff --git a/src/Features/ExternalAccess/OmniSharp/Options/OmniSharpSolutionAnalyzerConfigOptionsUpdater.cs b/src/Features/ExternalAccess/OmniSharp/Options/OmniSharpSolutionAnalyzerConfigOptionsUpdater.cs new file mode 100644 index 0000000000000..dd1209b916f32 --- /dev/null +++ b/src/Features/ExternalAccess/OmniSharp/Options/OmniSharpSolutionAnalyzerConfigOptionsUpdater.cs @@ -0,0 +1,73 @@ +// 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 Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.ErrorReporting; +using Microsoft.CodeAnalysis.Formatting; +using Microsoft.CodeAnalysis.ImplementType; +using Microsoft.CodeAnalysis.Options; +using Roslyn.Utilities; + +namespace Microsoft.CodeAnalysis.ExternalAccess.OmniSharp.Options; + +using Workspace = CodeAnalysis.Workspace; + +internal static class OmniSharpSolutionAnalyzerConfigOptionsUpdater +{ + internal static bool UpdateOptions(Workspace workspace, OmniSharpEditorConfigOptions editorConfigOptions) + { + try + { + var oldSolution = workspace.CurrentSolution; + var oldFallbackOptions = oldSolution.FallbackAnalyzerOptions; + oldFallbackOptions.TryGetValue(LanguageNames.CSharp, out var csharpFallbackOptions); + + var builder = ImmutableDictionary.CreateBuilder(AnalyzerConfigOptions.KeyComparer); + if (csharpFallbackOptions is not null) + { + // copy existing option values: + foreach (var oldKey in csharpFallbackOptions.Keys) + { + if (csharpFallbackOptions.TryGetValue(oldKey, out var oldValue)) + { + builder.Add(oldKey, oldValue); + } + } + } + + // add o# option values: + var lineFormattingOptions = editorConfigOptions.LineFormattingOptions; + AddOption(FormattingOptions2.UseTabs, lineFormattingOptions.UseTabs); + AddOption(FormattingOptions2.TabSize, lineFormattingOptions.TabSize); + AddOption(FormattingOptions2.IndentationSize, lineFormattingOptions.IndentationSize); + AddOption(FormattingOptions2.NewLine, lineFormattingOptions.NewLine); + + var implementTypeOptions = editorConfigOptions.ImplementTypeOptions; + AddOption(ImplementTypeOptionsStorage.InsertionBehavior, (ImplementTypeInsertionBehavior)implementTypeOptions.InsertionBehavior); + AddOption(ImplementTypeOptionsStorage.PropertyGenerationBehavior, (ImplementTypePropertyGenerationBehavior)implementTypeOptions.PropertyGenerationBehavior); + + var newFallbackOptions = oldFallbackOptions.SetItem( + LanguageNames.CSharp, + StructuredAnalyzerConfigOptions.Create(new DictionaryAnalyzerConfigOptions(builder.ToImmutable()))); + + var newSolution = oldSolution.WithFallbackAnalyzerOptions(newFallbackOptions); + return workspace.TryApplyChanges(newSolution); + + void AddOption( + PerLanguageOption2 option, + T value) + { + var configName = option.Definition.ConfigName; + var configValue = option.Definition.Serializer.Serialize(value); + builder[configName] = configValue; + } + } + catch (Exception e) when (FatalError.ReportAndPropagate(e, ErrorSeverity.Diagnostic)) + { + throw ExceptionUtilities.Unreachable(); + } + } +} diff --git a/src/Features/Lsif/Generator/Generator.cs b/src/Features/Lsif/Generator/Generator.cs index a4b485bd593e0..354e412cf2d71 100644 --- a/src/Features/Lsif/Generator/Generator.cs +++ b/src/Features/Lsif/Generator/Generator.cs @@ -317,7 +317,7 @@ SymbolKind.RangeVariable or ISymbol? referencedSymbol = null; - if (syntaxFactsService.IsBindableToken(syntaxToken)) + if (syntaxFactsService.IsBindableToken(semanticModel, syntaxToken)) { var bindableParent = syntaxFactsService.TryGetBindableParent(syntaxToken); diff --git a/src/Features/RulesMissingDocumentation.md b/src/Features/RulesMissingDocumentation.md index 0e66ef5c49bf1..4828131b75ff9 100644 --- a/src/Features/RulesMissingDocumentation.md +++ b/src/Features/RulesMissingDocumentation.md @@ -4,6 +4,7 @@ Rule ID | Missing Help Link | Title | --------|-------------------|-------| IDE0005_gen | | Imports statement is unnecessary. | IDE0043 | | Invalid format string | +IDE0121 | | Simplify LINQ expression | IDE0290 | | Use primary constructor | IDE0300 | | Simplify collection initialization | IDE0301 | | Simplify collection initialization | diff --git a/src/Features/Test/EditAndContinue/ActiveStatementsMapTests.cs b/src/Features/Test/EditAndContinue/ActiveStatementsMapTests.cs index d8599d06b4fd2..e677d352e9164 100644 --- a/src/Features/Test/EditAndContinue/ActiveStatementsMapTests.cs +++ b/src/Features/Test/EditAndContinue/ActiveStatementsMapTests.cs @@ -256,7 +256,7 @@ ManagedActiveStatementDebugInfo CreateInfo(int startLine, int startColumn, int e ], map.DocumentPathMap["a.cs"].OrderBy(s => s.Span.Start.Line).Select(s => $"{s.Span}")); void CreateRegion(int ordinal, SourceFileSpan oldSpan, SourceFileSpan newSpan) - => remapping.Add(debugInfos[ordinal].ActiveInstruction.Method, ImmutableArray.Create(new NonRemappableRegion(oldSpan, newSpan, isExceptionRegion: false))); + => remapping.Add(debugInfos[ordinal].ActiveInstruction.Method, [new NonRemappableRegion(oldSpan, newSpan, isExceptionRegion: false)]); SourceFileSpan Span(int startLine, int startColumn, int endLine, int endColumn) => new("a.cs", new(new(startLine, startColumn), new(endLine, endColumn))); @@ -301,7 +301,7 @@ static void M() // The order should not matter. var remapping = ImmutableDictionary>.Empty.Add( debugInfos[0].ActiveInstruction.Method, - reverse ? ImmutableArray.Create(mapping1, mapping2) : ImmutableArray.Create(mapping2, mapping1)); + reverse ? [mapping1, mapping2] : [mapping2, mapping1]); var map = ActiveStatementsMap.Create(debugInfos, remapping); @@ -339,7 +339,7 @@ static void M() // The order should not matter. var remapping = ImmutableDictionary>.Empty.Add( debugInfos[0].ActiveInstruction.Method, - reverse ? ImmutableArray.Create(mapping1, mapping2) : ImmutableArray.Create(mapping2, mapping1)); + reverse ? [mapping1, mapping2] : [mapping2, mapping1]); var map = ActiveStatementsMap.Create(debugInfos, remapping); diff --git a/src/Features/Test/EditAndContinue/EditAndContinueWorkspaceServiceTests.cs b/src/Features/Test/EditAndContinue/EditAndContinueWorkspaceServiceTests.cs index f5928559c4d59..89d5cb4e66699 100644 --- a/src/Features/Test/EditAndContinue/EditAndContinueWorkspaceServiceTests.cs +++ b/src/Features/Test/EditAndContinue/EditAndContinueWorkspaceServiceTests.cs @@ -13,6 +13,7 @@ using System.Text; using System.Threading; using System.Threading.Tasks; +using Microsoft.CodeAnalysis.CodeRefactorings.MoveType; using Microsoft.CodeAnalysis.Contracts.EditAndContinue; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Test.Utilities; @@ -132,7 +133,7 @@ public async Task StartDebuggingSession_CapturingDocuments(bool captureAllDocume filePath: sourceFileD.Path)); var captureMatchingDocuments = captureAllDocuments - ? ImmutableArray.Empty + ? [] : (from project in solution.Projects from documentId in project.DocumentIds select documentId).ToImmutableArray(); var sessionId = await service.StartDebuggingSessionAsync(solution, _debuggerService, NullPdbMatchingSourceTextProvider.Instance, captureMatchingDocuments, captureAllDocuments, reportDiagnostics: true, CancellationToken.None); @@ -416,9 +417,9 @@ public async Task DesignTimeOnlyDocument_Wpf([CombinatorialValues(LanguageNames. } // make sure renames are not supported: - _debuggerService.GetCapabilitiesImpl = () => ImmutableArray.Create("Baseline"); + _debuggerService.GetCapabilitiesImpl = () => ["Baseline"]; - var openDocumentIds = open ? ImmutableArray.Create(designTimeOnlyDocumentId) : ImmutableArray.Empty; + var openDocumentIds = open ? ImmutableArray.Create(designTimeOnlyDocumentId) : []; var sessionId = await service.StartDebuggingSessionAsync(solution, _debuggerService, NullPdbMatchingSourceTextProvider.Instance, captureMatchingDocuments: openDocumentIds, captureAllMatchingDocuments: false, reportDiagnostics: true, CancellationToken.None); var debuggingSession = service.GetTestAccessor().GetDebuggingSession(sessionId); @@ -449,7 +450,7 @@ public async Task DesignTimeOnlyDocument_Wpf([CombinatorialValues(LanguageNames. Assert.NotEmpty(activeStatementMap.DocumentPathMap); // Active statements in design-time documents should be left unchanged. - var asSpans = await debuggingSession.GetBaseActiveStatementSpansAsync(solution, ImmutableArray.Create(designTimeOnlyDocumentId), CancellationToken.None); + var asSpans = await debuggingSession.GetBaseActiveStatementSpansAsync(solution, [designTimeOnlyDocumentId], CancellationToken.None); Assert.Empty(asSpans.Single()); // no Rude Edits reported: @@ -1899,7 +1900,7 @@ public async Task Project_Add() // TODO: https://github.com/dotnet/roslyn/issues/1204 // Should return span in document B since the document content matches the PDB. - var baseSpans = await debuggingSession.GetBaseActiveStatementSpansAsync(solution, ImmutableArray.Create(documentA1.Id, documentB2.Id), CancellationToken.None); + var baseSpans = await debuggingSession.GetBaseActiveStatementSpansAsync(solution, [documentA1.Id, documentB2.Id], CancellationToken.None); AssertEx.Equal( [ "", @@ -1949,7 +1950,7 @@ public async Task Capabilities(bool breakState) EmitAndLoadLibraryToDebuggee(source1); // attached to processes that allow updating custom attributes: - _debuggerService.GetCapabilitiesImpl = () => ImmutableArray.Create("Baseline", "ChangeCustomAttributes"); + _debuggerService.GetCapabilitiesImpl = () => ["Baseline", "ChangeCustomAttributes"]; // F5 var debuggingSession = await StartDebuggingSessionAsync(service, solution); @@ -1974,7 +1975,7 @@ public async Task Capabilities(bool breakState) ExitBreakState(debuggingSession); } - _debuggerService.GetCapabilitiesImpl = () => ImmutableArray.Create("Baseline"); + _debuggerService.GetCapabilitiesImpl = () => ["Baseline"]; if (breakState) { @@ -1999,7 +2000,7 @@ public async Task Capabilities(bool breakState) diagnostics.Select(d => $"{d.Id}: {d.GetMessage()}")); // detach from processes that do not allow updating custom attributes: - _debuggerService.GetCapabilitiesImpl = () => ImmutableArray.Create("Baseline", "ChangeCustomAttributes"); + _debuggerService.GetCapabilitiesImpl = () => ["Baseline", "ChangeCustomAttributes"]; if (breakState) { @@ -2062,7 +2063,7 @@ int M() LoadLibraryToDebuggee(moduleId); // attached to processes that doesn't allow creating new types - _debuggerService.GetCapabilitiesImpl = () => ImmutableArray.Create("Baseline"); + _debuggerService.GetCapabilitiesImpl = () => ["Baseline"]; var debuggingSession = await StartDebuggingSessionAsync(service, solution); @@ -2097,7 +2098,7 @@ public async Task Capabilities_SynthesizedNewType() EmitAndLoadLibraryToDebuggee(source1); // attached to processes that doesn't allow creating new types - _debuggerService.GetCapabilitiesImpl = () => ImmutableArray.Create("Baseline"); + _debuggerService.GetCapabilitiesImpl = () => ["Baseline"]; // F5 var debuggingSession = await StartDebuggingSessionAsync(service, solution); @@ -2531,7 +2532,7 @@ void ValidateDelta(ManagedHotReloadUpdate delta) Assert.Same(readers[1], baselineReaders[1]); // verify that baseline is added: - Assert.Same(newBaseline.EmitBaseline, debuggingSession.GetTestAccessor().GetProjectEmitBaseline(document2.Project.Id)); + Assert.Same(newBaseline.EmitBaseline, debuggingSession.GetTestAccessor().GetProjectBaselines(document2.Project.Id).Single().EmitBaseline); // solution update status after committing an update: (updates, emitDiagnostics) = await EmitSolutionUpdateAsync(debuggingSession, solution); @@ -2659,7 +2660,7 @@ public async Task ValidSignificantChange_EmitSuccessful_UpdateDeferred(bool comm Assert.Empty(debuggingSession.EditSession.NonRemappableRegions); // verify that baseline is added: - Assert.Same(newBaseline.EmitBaseline, debuggingSession.GetTestAccessor().GetProjectEmitBaseline(document2.Project.Id)); + Assert.Same(newBaseline.EmitBaseline, debuggingSession.GetTestAccessor().GetProjectBaselines(document2.Project.Id).Single().EmitBaseline); // solution update status after committing an update: ExitBreakState(debuggingSession); @@ -3129,7 +3130,7 @@ public async Task RudeEdit() EmitAndLoadLibraryToDebuggee(source1); // attached to processes that doesn't allow creating new types - _debuggerService.GetCapabilitiesImpl = () => ImmutableArray.Create("Baseline"); + _debuggerService.GetCapabilitiesImpl = () => ["Baseline"]; // F5 var debuggingSession = await StartDebuggingSessionAsync(service, solution); @@ -3239,8 +3240,8 @@ public async Task TwoUpdatesWithLoadedAndUnloadedModule() Assert.Empty(debuggingSession.EditSession.NonRemappableRegions); // verify that baseline is added for both modules: - Assert.Same(newBaselineA1, debuggingSession.GetTestAccessor().GetProjectEmitBaseline(projectA.Id)); - Assert.Same(newBaselineB1, debuggingSession.GetTestAccessor().GetProjectEmitBaseline(projectB.Id)); + Assert.Same(newBaselineA1, debuggingSession.GetTestAccessor().GetProjectBaselines(projectA.Id).Single().EmitBaseline); + Assert.Same(newBaselineB1, debuggingSession.GetTestAccessor().GetProjectBaselines(projectB.Id).Single().EmitBaseline); // solution update status after committing an update:(updates, emitDiagnostics) = await EmitSolutionUpdateAsync(debuggingSession, solution); Assert.Empty(emitDiagnostics); @@ -3292,8 +3293,8 @@ public async Task TwoUpdatesWithLoadedAndUnloadedModule() AssertEx.Equal(readers, baselineReaders); // verify that baseline is updated for both modules: - Assert.Same(newBaselineA2, debuggingSession.GetTestAccessor().GetProjectEmitBaseline(projectA.Id)); - Assert.Same(newBaselineB2, debuggingSession.GetTestAccessor().GetProjectEmitBaseline(projectB.Id)); + Assert.Same(newBaselineA2, debuggingSession.GetTestAccessor().GetProjectBaselines(projectA.Id).Single().EmitBaseline); + Assert.Same(newBaselineB2, debuggingSession.GetTestAccessor().GetProjectBaselines(projectB.Id).Single().EmitBaseline); // solution update status after committing an update: (updates, emitDiagnostics) = await EmitSolutionUpdateAsync(debuggingSession, solution); @@ -3406,7 +3407,7 @@ public async Task ActiveStatements() var debuggingSession = await StartDebuggingSessionAsync(service, solution); // default if not called in a break state - Assert.True((await debuggingSession.GetBaseActiveStatementSpansAsync(solution, ImmutableArray.Create(document1.Id), CancellationToken.None)).IsDefault); + Assert.True((await debuggingSession.GetBaseActiveStatementSpansAsync(solution, [document1.Id], CancellationToken.None)).IsDefault); var moduleId = Guid.NewGuid(); var activeInstruction1 = new ManagedInstructionId(new ManagedMethodId(moduleId, token: 0x06000001, version: 1), ilOffset: 1); @@ -3429,7 +3430,7 @@ public async Task ActiveStatements() var activeStatementSpan11 = new ActiveStatementSpan(new ActiveStatementId(0), activeLineSpan11, ActiveStatementFlags.MethodUpToDate | ActiveStatementFlags.NonLeafFrame); var activeStatementSpan12 = new ActiveStatementSpan(new ActiveStatementId(1), activeLineSpan12, ActiveStatementFlags.MethodUpToDate | ActiveStatementFlags.LeafFrame); - var baseSpans = await debuggingSession.GetBaseActiveStatementSpansAsync(solution, ImmutableArray.Create(document1.Id), CancellationToken.None); + var baseSpans = await debuggingSession.GetBaseActiveStatementSpansAsync(solution, [document1.Id], CancellationToken.None); AssertEx.Equal( [ activeStatementSpan11, @@ -3502,7 +3503,7 @@ public async Task ActiveStatements_SyntaxErrorOrOutOfSyncDocument(bool isOutOfSy EnterBreakState(debuggingSession, activeStatements); - var baseSpans = (await debuggingSession.GetBaseActiveStatementSpansAsync(solution, ImmutableArray.Create(documentId), CancellationToken.None)).Single(); + var baseSpans = (await debuggingSession.GetBaseActiveStatementSpansAsync(solution, [documentId], CancellationToken.None)).Single(); AssertEx.Equal( [ new ActiveStatementSpan(new ActiveStatementId(0), activeLineSpan11, ActiveStatementFlags.MethodUpToDate | ActiveStatementFlags.NonLeafFrame), @@ -3553,13 +3554,13 @@ public async Task ActiveStatements_ForeignDocument(bool withPath, bool designTim var currentSpans = await debuggingSession.GetAdjustedActiveStatementSpansAsync(document, s_noActiveSpans, CancellationToken.None); Assert.Empty(currentSpans); - var baseSpans = await debuggingSession.GetBaseActiveStatementSpansAsync(solution, ImmutableArray.Create(document.Id), CancellationToken.None); + var baseSpans = await debuggingSession.GetBaseActiveStatementSpansAsync(solution, [document.Id], CancellationToken.None); Assert.Empty(baseSpans.Single()); // update solution: solution = solution.WithDocumentText(document.Id, CreateText("dummy2")); - baseSpans = await debuggingSession.GetBaseActiveStatementSpansAsync(solution, ImmutableArray.Create(document.Id), CancellationToken.None); + baseSpans = await debuggingSession.GetBaseActiveStatementSpansAsync(solution, [document.Id], CancellationToken.None); Assert.Empty(baseSpans.Single()); } @@ -3738,14 +3739,14 @@ static void M() Assert.True(activeStatement1.IsLeaf); // Active statement reported as unchanged as the containing document is out-of-sync: - var baseSpans = await debuggingSession.GetBaseActiveStatementSpansAsync(solution, ImmutableArray.Create(document.Id), CancellationToken.None); + var baseSpans = await debuggingSession.GetBaseActiveStatementSpansAsync(solution, [document.Id], CancellationToken.None); AssertEx.Equal([$"(9,18)-(9,22)"], baseSpans.Single().Select(s => s.LineSpan.ToString())); // Document got synchronized: debuggingSession.LastCommittedSolution.Test_SetDocumentState(document.Id, CommittedSolution.DocumentState.MatchesBuildOutput); // New location of the active statement reported: - baseSpans = await debuggingSession.GetBaseActiveStatementSpansAsync(solution, ImmutableArray.Create(document.Id), CancellationToken.None); + baseSpans = await debuggingSession.GetBaseActiveStatementSpansAsync(solution, [document.Id], CancellationToken.None); AssertEx.Equal([$"(10,12)-(10,16)"], baseSpans.Single().Select(s => s.LineSpan.ToString())); } @@ -4027,7 +4028,7 @@ static void F() ActiveStatementFlags.Stale | ActiveStatementFlags.NonLeafFrame, // F - not up-to-date anymore and since F v1 is followed by F v3 (hot-reload) it is now stale ])); - var spans = (await debuggingSession.GetBaseActiveStatementSpansAsync(solution, ImmutableArray.Create(documentId), CancellationToken.None)).Single(); + var spans = (await debuggingSession.GetBaseActiveStatementSpansAsync(solution, [documentId], CancellationToken.None)).Single(); AssertEx.Equal( [ new ActiveStatementSpan(new ActiveStatementId(0), new LinePositionSpan(new(4, 41), new(4, 42)), ActiveStatementFlags.MethodUpToDate | ActiveStatementFlags.LeafFrame), @@ -4130,7 +4131,7 @@ static void F() var expectedSpanG1 = new LinePositionSpan(new LinePosition(3, 41), new LinePosition(3, 42)); var expectedSpanF1 = new LinePositionSpan(new LinePosition(8, 14), new LinePosition(8, 18)); - var spans = (await debuggingSession.GetBaseActiveStatementSpansAsync(solution, ImmutableArray.Create(documentId), CancellationToken.None)).Single(); + var spans = (await debuggingSession.GetBaseActiveStatementSpansAsync(solution, [documentId], CancellationToken.None)).Single(); AssertEx.Equal( [ new ActiveStatementSpan(new ActiveStatementId(0), expectedSpanG1, ActiveStatementFlags.MethodUpToDate | ActiveStatementFlags.LeafFrame, documentId), @@ -4143,7 +4144,7 @@ static void F() var expectedSpanG2 = new LinePositionSpan(new LinePosition(3, 41), new LinePosition(3, 42)); var expectedSpanF2 = new LinePositionSpan(new LinePosition(9, 14), new LinePosition(9, 18)); - spans = (await debuggingSession.GetBaseActiveStatementSpansAsync(solution, ImmutableArray.Create(documentId), CancellationToken.None)).Single(); + spans = (await debuggingSession.GetBaseActiveStatementSpansAsync(solution, [documentId], CancellationToken.None)).Single(); AssertEx.Equal( [ new ActiveStatementSpan(new ActiveStatementId(0), expectedSpanG2, ActiveStatementFlags.MethodUpToDate | ActiveStatementFlags.LeafFrame, documentId), @@ -4240,7 +4241,7 @@ static void F() // check that the active statement is mapped correctly to snapshot v2: var expectedSpanG1 = new LinePositionSpan(new LinePosition(3, 41), new LinePosition(3, 42)); - var spans = (await debuggingSession.GetBaseActiveStatementSpansAsync(solution, ImmutableArray.Create(documentId), CancellationToken.None)).Single(); + var spans = (await debuggingSession.GetBaseActiveStatementSpansAsync(solution, [documentId], CancellationToken.None)).Single(); AssertEx.Equal( [ new ActiveStatementSpan(new ActiveStatementId(0), expectedSpanG1, ActiveStatementFlags.MethodUpToDate | ActiveStatementFlags.LeafFrame) @@ -4251,6 +4252,90 @@ static void F() EndDebuggingSession(debuggingSession); } + /// + /// Scenario: + /// - F5 + /// - edit source and apply code fix to move type to file XYZ.cs + /// - continue execution + /// + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/72984")] + public async Task EditAndContinueAfterApplyingMoveTypeToFileCodeFix() + { + const string movedType = "AnotherClass"; + + const string source = $$""" + class {{movedType}} + { + public const bool True = true; + } + + class Test + { + static bool B() => {{movedType}}.True; + static void G() { while (B()); } + + static void F() + { + G(); + } + } + """; + + const string modifiedSource = $$""" + class Test + { + static bool A() => {{movedType}}.True; + static bool B() => A(); + static void G() { while (B()); } + + static void F() + { + H(); + } + + static void H() + { + G(); + } + } + """; + + var moduleId = EmitAndLoadLibraryToDebuggee(source); + + using var workspace = CreateWorkspace(out var solution, out var service); + (solution, var document) = AddDefaultTestProject(solution, source); + var documentId = document.Id; + var oldProject = document.Project; + + var debuggingSession = await StartDebuggingSessionAsync(service, solution); + + // Apply code fix: Move type to AnotherClass.cs + + var moveTypeService = document.GetLanguageService(); + var root = await document.GetSyntaxRootAsync(); + var span = root.DescendantTokens() + .Where(s => s.Text is movedType) + .FirstOrDefault() + .Span; + var modifiedSolution = await moveTypeService.GetModifiedSolutionAsync(document, span, MoveTypeOperationKind.MoveType, cancellationToken: default); + + // Apply edit on remaining document: source after code fix -> modifiedSource + + modifiedSolution = modifiedSolution.WithDocumentText(document.Id, CreateText(modifiedSource)); + + var newProject = modifiedSolution.GetProject(oldProject.Id); + Assert.Equal(1, oldProject.DocumentIds.Count); + Assert.Equal(2, newProject.DocumentIds.Count); + + var (updates, emitDiagnostics) = await EmitSolutionUpdateAsync(debuggingSession, modifiedSolution); + Assert.Empty(emitDiagnostics); + Assert.False(updates.Updates.IsEmpty); + Assert.Equal(ModuleUpdateStatus.Ready, updates.Status); + + CommitSolutionUpdate(debuggingSession); + EndDebuggingSession(debuggingSession); + } + [Fact] public async Task MultiSession() { @@ -4282,7 +4367,7 @@ public async Task MultiSession() solution, _debuggerService, NullPdbMatchingSourceTextProvider.Instance, - captureMatchingDocuments: ImmutableArray.Empty, + captureMatchingDocuments: [], captureAllMatchingDocuments: true, reportDiagnostics: true, CancellationToken.None); @@ -4328,6 +4413,114 @@ public async Task Disposal() // The following methods can be called at any point in time, so we must handle race with dispose gracefully. Assert.Empty(await debuggingSession.GetDocumentDiagnosticsAsync(document, s_noActiveSpans, CancellationToken.None)); Assert.Empty(await debuggingSession.GetAdjustedActiveStatementSpansAsync(document, s_noActiveSpans, CancellationToken.None)); - Assert.True((await debuggingSession.GetBaseActiveStatementSpansAsync(solution, ImmutableArray.Empty, CancellationToken.None)).IsDefault); + Assert.True((await debuggingSession.GetBaseActiveStatementSpansAsync(solution, [], CancellationToken.None)).IsDefault); + } + + [Fact] + public async Task MultipleSharedLibraryBaselines() + { + var libSource1 = """ + public class C + { + public int F() => 1; + } + """; + + var libSource2 = """ + public class C + { + public int F() => 2; + } + """; + + var libSource3 = """ + public class C + { + public int F() => 3; + } + """; + + using var workspace = CreateWorkspace(out var solution, out var service); + + (solution, var document) = AddDefaultTestProject(solution, libSource1); + var documentId = document.Id; + var oldProject = document.Project; + + var debuggingSession = await StartDebuggingSessionAsync(service, solution); + + // Build and load two versions of the libary. + // This happens when projects A and B both reference Lib project and copy the assembly to their respective output directories and + // 1) A is built and launched + // 2) an update is made to the library + // 3) B is built and launched + // + // At this point we have two baselines for the Lib project (two mvids). + // + // The update to the library source also produces delta to be applied to V1 of the library. + + var libMvid1 = EmitAndLoadLibraryToDebuggee(libSource1); + + // lib source is updated: + solution = solution.WithDocumentText(documentId, CreateText(libSource2)); + + var (updates, emitDiagnostics) = await EmitSolutionUpdateAsync(debuggingSession, solution); + Assert.Empty(emitDiagnostics); + Assert.Equal(ModuleUpdateStatus.Ready, updates.Status); + + var update = updates.Updates.Single(); + GetModuleIds(update.MetadataDelta, out var updateModuleId, out var baseId, out var genId, out var gen); + Assert.Equal(libMvid1, updateModuleId); + Assert.Equal(1, gen); + Assert.Equal(default, baseId); + Assert.NotEqual(default, genId); + + CommitSolutionUpdate(debuggingSession); + + // B is launched: + var libMvid2 = EmitAndLoadLibraryToDebuggee(libSource2); + + // lib source is updated: + solution = solution.WithDocumentText(documentId, CreateText(libSource3)); + + (updates, emitDiagnostics) = await EmitSolutionUpdateAsync(debuggingSession, solution); + Assert.Empty(emitDiagnostics); + Assert.Equal(ModuleUpdateStatus.Ready, updates.Status); + + Assert.Equal(2, updates.Updates.Length); + var libUpdate1 = updates.Updates.Single(u => u.Module == libMvid1); + var libUpdate2 = updates.Updates.Single(u => u.Module == libMvid2); + + // update of the original library should chain to its previous delta: + GetModuleIds(libUpdate1.MetadataDelta, out var updateModuleId1, out var baseId1, out var genId1, out var gen1); + Assert.Equal(libMvid1, updateModuleId1); + Assert.Equal(genId, baseId1); + Assert.Equal(2, gen1); + Assert.NotEqual(default, genId1); + + // update of the rebuilt library should be the first in the new chain: + GetModuleIds(libUpdate2.MetadataDelta, out var updateModuleId2, out var baseId2, out var genId2, out var gen2); + Assert.Equal(libMvid2, updateModuleId2); + Assert.Equal(default, baseId2); + Assert.Equal(1, gen2); + Assert.NotEqual(default, genId2); + + CommitSolutionUpdate(debuggingSession); + EndDebuggingSession(debuggingSession); + + static void GetModuleIds( + ImmutableArray metadataDelta, + out Guid mvid, + out Guid baseId, + out Guid generationId, + out int generation) + { + using var readerProvider = MetadataReaderProvider.FromMetadataImage(metadataDelta); + var reader = readerProvider.GetMetadataReader(); + var moduleDef = reader.GetModuleDefinition(); + baseId = reader.GetGuid(moduleDef.BaseGenerationId); + generationId = reader.GetGuid(moduleDef.GenerationId); + mvid = reader.GetGuid(moduleDef.Mvid); + generation = moduleDef.Generation; + } } } diff --git a/src/Features/Test/EditAndContinue/EditSessionActiveStatementsTests.cs b/src/Features/Test/EditAndContinue/EditSessionActiveStatementsTests.cs index 7f29f64aeebba..a34b189667323 100644 --- a/src/Features/Test/EditAndContinue/EditSessionActiveStatementsTests.cs +++ b/src/Features/Test/EditAndContinue/EditSessionActiveStatementsTests.cs @@ -250,19 +250,23 @@ static void Main() var newActiveStatementsInChangedDocuments = ImmutableArray.Create( new DocumentActiveStatementChanges( oldSpans: oldActiveStatements2, - newStatements: ImmutableArray.Create( + newStatements: + [ statements[3].WithFileSpan(statements[3].FileSpan.AddLineDelta(+1)), statements[2].WithFileSpan(statements[2].FileSpan.AddLineDelta(+2)), - statements[4]), - newExceptionRegions: ImmutableArray.Create( + statements[4], + ], + newExceptionRegions: + [ oldActiveStatements2[0].ExceptionRegions.Spans.SelectAsArray(es => es.AddLineDelta(+1)), oldActiveStatements2[1].ExceptionRegions.Spans, - oldActiveStatements2[2].ExceptionRegions.Spans))); + oldActiveStatements2[2].ExceptionRegions.Spans, + ])); EditSession.GetActiveStatementAndExceptionRegionSpans( module2, baseActiveStatementsMap, - updatedMethodTokens: ImmutableArray.Create(0x06000004), // contains only recompiled methods in the project we are interested in (module2) + updatedMethodTokens: [0x06000004], // contains only recompiled methods in the project we are interested in (module2) previousNonRemappableRegions: ImmutableDictionary>.Empty, newActiveStatementsInChangedDocuments, out var activeStatementsInUpdatedMethods, @@ -366,18 +370,14 @@ static void F2() var newActiveStatementsInChangedDocuments = ImmutableArray.Create( new DocumentActiveStatementChanges( oldSpans: oldActiveStatements, - newStatements: ImmutableArray.Create( - baseActiveStatements[0], - baseActiveStatements[1].WithFileSpan(baseActiveStatements[1].FileSpan.AddLineDelta(+1))), - newExceptionRegions: ImmutableArray.Create( - oldActiveStatements[0].ExceptionRegions.Spans, - oldActiveStatements[1].ExceptionRegions.Spans)) + newStatements: [baseActiveStatements[0], baseActiveStatements[1].WithFileSpan(baseActiveStatements[1].FileSpan.AddLineDelta(+1))], + newExceptionRegions: [oldActiveStatements[0].ExceptionRegions.Spans, oldActiveStatements[1].ExceptionRegions.Spans]) ); EditSession.GetActiveStatementAndExceptionRegionSpans( module1, baseActiveStatementMap, - updatedMethodTokens: ImmutableArray.Create(0x06000001), // F1 + updatedMethodTokens: [0x06000001], // F1 previousNonRemappableRegions: ImmutableDictionary>.Empty, newActiveStatementsInChangedDocuments, out var activeStatementsInUpdatedMethods, @@ -556,21 +556,25 @@ static void F4() var newActiveStatementsInChangedDocuments = ImmutableArray.Create( new DocumentActiveStatementChanges( oldSpans: oldActiveStatements, - newStatements: ImmutableArray.Create( + newStatements: + [ baseActiveStatements[0], baseActiveStatements[1].WithFileSpan(baseActiveStatements[1].FileSpan.AddLineDelta(-1)), baseActiveStatements[2], - baseActiveStatements[3].WithFileSpan(baseActiveStatements[3].FileSpan.AddLineDelta(+2))), - newExceptionRegions: ImmutableArray.Create( + baseActiveStatements[3].WithFileSpan(baseActiveStatements[3].FileSpan.AddLineDelta(+2)), + ], + newExceptionRegions: + [ oldActiveStatements[0].ExceptionRegions.Spans, oldActiveStatements[1].ExceptionRegions.Spans.SelectAsArray(es => es.AddLineDelta(-1)), oldActiveStatements[2].ExceptionRegions.Spans, - oldActiveStatements[3].ExceptionRegions.Spans.SelectAsArray(es => es.AddLineDelta(+2))))); + oldActiveStatements[3].ExceptionRegions.Spans.SelectAsArray(es => es.AddLineDelta(+2)), + ])); EditSession.GetActiveStatementAndExceptionRegionSpans( module1, baseActiveStatementMap, - updatedMethodTokens: ImmutableArray.Create(0x06000002, 0x06000004), // F2, F4 + updatedMethodTokens: [0x06000002, 0x06000004], // F2, F4 initialNonRemappableRegions, newActiveStatementsInChangedDocuments, out var activeStatementsInUpdatedMethods, diff --git a/src/Features/Test/EditAndContinue/EmitSolutionUpdateResultsTests.cs b/src/Features/Test/EditAndContinue/EmitSolutionUpdateResultsTests.cs index 9f52adbc0541c..1b4aec81d413d 100644 --- a/src/Features/Test/EditAndContinue/EmitSolutionUpdateResultsTests.cs +++ b/src/Features/Test/EditAndContinue/EmitSolutionUpdateResultsTests.cs @@ -84,7 +84,7 @@ public async Task GetHotReloadDiagnostics() defaultSeverity: DiagnosticSeverity.Warning, isEnabledByDefault: true, warningLevel: 0, - customTags: ImmutableArray.Create("Test2"), + customTags: ["Test2"], properties: ImmutableDictionary.Empty, document.Project.Id, DiagnosticDataLocation.TestAccessor.Create(new(sourcePath, new(0, 0), new(0, 5)), document.Id, new("a.razor", new(10, 10), new(10, 15)), forceMappedPath: true), @@ -100,7 +100,7 @@ public async Task GetHotReloadDiagnostics() defaultSeverity: DiagnosticSeverity.Warning, isEnabledByDefault: true, warningLevel: 0, - customTags: ImmutableArray.Create("Test2"), + customTags: ["Test2"], properties: ImmutableDictionary.Empty, document.Project.Id, DiagnosticDataLocation.TestAccessor.Create(new(sourcePath, new(0, 0), new(0, 5)), document.Id, new(@"..\a.razor", new(10, 10), new(10, 15)), forceMappedPath: true), @@ -117,7 +117,7 @@ public async Task GetHotReloadDiagnostics() defaultSeverity: DiagnosticSeverity.Error, isEnabledByDefault: true, warningLevel: 0, - customTags: ImmutableArray.Create("Test3"), + customTags: ["Test3"], properties: ImmutableDictionary.Empty, document.Project.Id, new DiagnosticDataLocation(new(sourcePath, new(0, 1), new(0, 5)), document.Id), diff --git a/src/Features/Test/EditAndContinue/RemoteEditAndContinueServiceTests.cs b/src/Features/Test/EditAndContinue/RemoteEditAndContinueServiceTests.cs index ab25d52016512..f994595ca3c2f 100644 --- a/src/Features/Test/EditAndContinue/RemoteEditAndContinueServiceTests.cs +++ b/src/Features/Test/EditAndContinue/RemoteEditAndContinueServiceTests.cs @@ -142,10 +142,10 @@ await localWorkspace.ChangeSolutionAsync(localWorkspace.CurrentSolution debuggerService: new MockManagedEditAndContinueDebuggerService() { IsEditAndContinueAvailable = _ => new ManagedHotReloadAvailability(ManagedHotReloadAvailabilityStatus.NotAllowedForModule, "can't do enc"), - GetActiveStatementsImpl = () => ImmutableArray.Create(as1) + GetActiveStatementsImpl = () => [as1] }, sourceTextProvider: NullPdbMatchingSourceTextProvider.Instance, - captureMatchingDocuments: ImmutableArray.Create(documentId), + captureMatchingDocuments: [documentId], captureAllMatchingDocuments: false, reportDiagnostics: true, CancellationToken.None); @@ -184,14 +184,14 @@ await localWorkspace.ChangeSolutionAsync(localWorkspace.CurrentSolution module: moduleId1, moduleName: "mod", projectId: projectId, - ilDelta: ImmutableArray.Create(1, 2), - metadataDelta: ImmutableArray.Create(3, 4), - pdbDelta: ImmutableArray.Create(5, 6), - updatedMethods: ImmutableArray.Create(0x06000001), - updatedTypes: ImmutableArray.Create(0x02000001), - sequencePoints: ImmutableArray.Create(new SequencePointUpdates("file.cs", ImmutableArray.Create(new SourceLineUpdate(1, 2)))), - activeStatements: ImmutableArray.Create(new ManagedActiveStatementUpdate(instructionId1.Method.Method, instructionId1.ILOffset, span1.ToSourceSpan())), - exceptionRegions: ImmutableArray.Create(exceptionRegionUpdate1), + ilDelta: [1, 2], + metadataDelta: [3, 4], + pdbDelta: [5, 6], + updatedMethods: [0x06000001], + updatedTypes: [0x02000001], + sequencePoints: [new SequencePointUpdates("file.cs", [new SourceLineUpdate(1, 2)])], + activeStatements: [new ManagedActiveStatementUpdate(instructionId1.Method.Method, instructionId1.ILOffset, span1.ToSourceSpan())], + exceptionRegions: [exceptionRegionUpdate1], requiredCapabilities: EditAndContinueCapabilities.Baseline.ToStringArray())); var syntaxTree = solution.GetRequiredDocument(documentId).GetSyntaxTreeSynchronously(CancellationToken.None)!; @@ -257,10 +257,10 @@ await localWorkspace.ChangeSolutionAsync(localWorkspace.CurrentSolution mockEncService.GetBaseActiveStatementSpansImpl = (solution, documentIds) => { AssertEx.Equal(new[] { documentId, inProcOnlyDocumentId }, documentIds); - return ImmutableArray.Create(ImmutableArray.Create(activeStatementSpan1)); + return [ImmutableArray.Create(activeStatementSpan1)]; }; - var baseActiveSpans = await sessionProxy.GetBaseActiveStatementSpansAsync(localWorkspace.CurrentSolution, ImmutableArray.Create(documentId, inProcOnlyDocumentId), CancellationToken.None); + var baseActiveSpans = await sessionProxy.GetBaseActiveStatementSpansAsync(localWorkspace.CurrentSolution, [documentId, inProcOnlyDocumentId], CancellationToken.None); Assert.Equal(activeStatementSpan1, baseActiveSpans.Single().Single()); // GetDocumentActiveStatementSpans @@ -269,7 +269,7 @@ await localWorkspace.ChangeSolutionAsync(localWorkspace.CurrentSolution { Assert.Equal("test.cs", document.Name); AssertEx.Equal(activeSpans1, activeStatementSpanProvider(documentId, "test.cs", CancellationToken.None).AsTask().Result); - return ImmutableArray.Create(activeStatementSpan1); + return [activeStatementSpan1]; }; Assert.Empty(await sessionProxy.GetAdjustedActiveStatementSpansAsync(inProcOnlyDocument, activeStatementSpanProvider, CancellationToken.None)); @@ -286,7 +286,7 @@ await localWorkspace.ChangeSolutionAsync(localWorkspace.CurrentSolution // GetDocumentDiagnosticsAsync - mockEncService.GetDocumentDiagnosticsImpl = (document, activeStatementProvider) => ImmutableArray.Create(diagnostic); + mockEncService.GetDocumentDiagnosticsImpl = (document, activeStatementProvider) => [diagnostic]; Assert.Empty(await proxy.GetDocumentDiagnosticsAsync(inProcOnlyDocument, activeStatementSpanProvider, CancellationToken.None)); Assert.Equal(diagnostic.GetMessage(), (await proxy.GetDocumentDiagnosticsAsync(document, activeStatementSpanProvider, CancellationToken.None)).Single().Message); diff --git a/src/Features/TestUtilities/EditAndContinue/EditAndContinueWorkspaceTestBase.cs b/src/Features/TestUtilities/EditAndContinue/EditAndContinueWorkspaceTestBase.cs index eb6e9ac492dc2..7efd6ae56f794 100644 --- a/src/Features/TestUtilities/EditAndContinue/EditAndContinueWorkspaceTestBase.cs +++ b/src/Features/TestUtilities/EditAndContinue/EditAndContinueWorkspaceTestBase.cs @@ -38,7 +38,7 @@ public abstract class EditAndContinueWorkspaceTestBase : TestBase, IDisposable private protected static readonly Regex s_timePropertiesRegex = new("[|](EmitDifferenceMilliseconds|TotalAnalysisMilliseconds)=[0-9]+"); private protected static readonly ActiveStatementSpanProvider s_noActiveSpans = - (_, _, _) => new(ImmutableArray.Empty); + (_, _, _) => new([]); private protected const TargetFramework DefaultTargetFramework = TargetFramework.NetStandard20; @@ -162,7 +162,7 @@ internal async Task StartDebuggingSessionAsync( solution, _debuggerService, sourceTextProvider: sourceTextProvider ?? NullPdbMatchingSourceTextProvider.Instance, - captureMatchingDocuments: ImmutableArray.Empty, + captureMatchingDocuments: [], captureAllMatchingDocuments: false, reportDiagnostics: true, CancellationToken.None); @@ -190,7 +190,7 @@ internal void EnterBreakState( internal void ExitBreakState( DebuggingSession session) { - _debuggerService.GetActiveStatementsImpl = () => ImmutableArray.Empty; + _debuggerService.GetActiveStatementsImpl = () => []; session.BreakStateOrCapabilitiesChanged(inBreakState: false); } diff --git a/src/Features/TestUtilities/EditAndContinue/MatchingPair.cs b/src/Features/TestUtilities/EditAndContinue/MatchingPair.cs index a9b0346bc561d..6b266d515fe13 100644 --- a/src/Features/TestUtilities/EditAndContinue/MatchingPair.cs +++ b/src/Features/TestUtilities/EditAndContinue/MatchingPair.cs @@ -28,7 +28,7 @@ public MatchingPairs() => Pairs = []; public MatchingPairs(IEnumerable pairs) - => Pairs = pairs.ToList(); + => Pairs = [.. pairs]; public void Add(string old, string @new) => Pairs.Add(new MatchingPair { Old = old, New = @new }); diff --git a/src/Features/TestUtilities/EditAndContinue/MockManagedEditAndContinueDebuggerService.cs b/src/Features/TestUtilities/EditAndContinue/MockManagedEditAndContinueDebuggerService.cs index c14217d372cfa..c0f1c1a99f80a 100644 --- a/src/Features/TestUtilities/EditAndContinue/MockManagedEditAndContinueDebuggerService.cs +++ b/src/Features/TestUtilities/EditAndContinue/MockManagedEditAndContinueDebuggerService.cs @@ -38,7 +38,7 @@ public ValueTask GetAvailabilityAsync(Guid mvid, C } public ValueTask> GetCapabilitiesAsync(CancellationToken cancellationToken) - => ValueTaskFactory.FromResult(GetCapabilitiesImpl?.Invoke() ?? ImmutableArray.Create("Baseline", "AddDefinitionToExistingType", "NewTypeDefinition")); + => ValueTaskFactory.FromResult(GetCapabilitiesImpl?.Invoke() ?? ["Baseline", "AddDefinitionToExistingType", "NewTypeDefinition"]); public ValueTask PrepareModuleForUpdateAsync(Guid mvid, CancellationToken cancellationToken) => ValueTaskFactory.CompletedTask; diff --git a/src/Features/TestUtilities/EditAndContinue/SourceMarkers.cs b/src/Features/TestUtilities/EditAndContinue/SourceMarkers.cs index fb8ca73810f85..531d2c714271d 100644 --- a/src/Features/TestUtilities/EditAndContinue/SourceMarkers.cs +++ b/src/Features/TestUtilities/EditAndContinue/SourceMarkers.cs @@ -35,10 +35,10 @@ internal static string Clear(string source) => s_tags.Replace(source, m => new string(' ', m.Length)); internal static string[] Clear(string[] sources) - => sources.Select(Clear).ToArray(); + => [.. sources.Select(Clear)]; private static IEnumerable<(int, int)> ParseIds(Match match) - => from ids in match.Groups["Id"].Value.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries) + => from ids in match.Groups["Id"].Value.Split([','], StringSplitOptions.RemoveEmptyEntries) let parts = ids.Split('.') select (int.Parse(parts[0]), (parts.Length > 1) ? int.Parse(parts[1]) : -1); @@ -134,7 +134,7 @@ public static ImmutableArray> GetExceptionRegions(strin } } - return result.Select(r => r.AsImmutableOrEmpty()).ToImmutableArray(); + return [.. result.Select(r => r.AsImmutableOrEmpty())]; } public static ImmutableArray> GetNodeSpans(string markedSource) @@ -151,7 +151,7 @@ public static ImmutableArray> GetNodeSpans(string marke result[i][j] = span; } - return result.Select(r => r.AsImmutableOrEmpty()).ToImmutableArray(); + return [.. result.Select(r => r.AsImmutableOrEmpty())]; } public static ImmutableArray GetSpans(string markedSource, string tagName) @@ -165,7 +165,7 @@ public static ImmutableArray GetSpans(string markedSource, string tagN result[major] = span; } - return result.ToImmutableArray(); + return [.. result]; } public static int IndexOfDifferent(ReadOnlySpan span, char c) diff --git a/src/Features/VisualBasic/Portable/AddFileBanner/VisualBasicAddFileBannerCodeRefactoringProvider.vb b/src/Features/VisualBasic/Portable/AddFileBanner/VisualBasicAddFileBannerCodeRefactoringProvider.vb index c987b3c15c998..976b0e06a1faa 100644 --- a/src/Features/VisualBasic/Portable/AddFileBanner/VisualBasicAddFileBannerCodeRefactoringProvider.vb +++ b/src/Features/VisualBasic/Portable/AddFileBanner/VisualBasicAddFileBannerCodeRefactoringProvider.vb @@ -10,7 +10,7 @@ Imports Microsoft.CodeAnalysis.CodeRefactorings Namespace Microsoft.CodeAnalysis.VisualBasic.AddFileBanner - Friend Class VisualBasicAddFileBannerCodeRefactoringProvider + Friend NotInheritable Class VisualBasicAddFileBannerCodeRefactoringProvider Inherits AbstractAddFileBannerCodeRefactoringProvider @@ -21,11 +21,5 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.AddFileBanner Protected Overrides Function IsCommentStartCharacter(ch As Char) As Boolean Return ch = "'"c End Function - - Protected Overrides Function CreateTrivia(trivia As SyntaxTrivia, text As String) As SyntaxTrivia - Return If(trivia.Kind() = SyntaxKind.CommentTrivia OrElse trivia.Kind() = SyntaxKind.DocumentationCommentTrivia, - SyntaxFactory.CommentTrivia(text), - trivia) - End Function End Class End Namespace diff --git a/src/Features/VisualBasic/Portable/AddImport/VisualBasicAddImportFeatureService.vb b/src/Features/VisualBasic/Portable/AddImport/VisualBasicAddImportFeatureService.vb index 842b1d149bfbe..e54c887c98445 100644 --- a/src/Features/VisualBasic/Portable/AddImport/VisualBasicAddImportFeatureService.vb +++ b/src/Features/VisualBasic/Portable/AddImport/VisualBasicAddImportFeatureService.vb @@ -6,7 +6,6 @@ Imports System.Composition Imports System.Threading Imports Microsoft.CodeAnalysis.AddImport Imports Microsoft.CodeAnalysis.CaseCorrection -Imports Microsoft.CodeAnalysis.CodeGeneration Imports Microsoft.CodeAnalysis.Diagnostics Imports Microsoft.CodeAnalysis.Editing Imports Microsoft.CodeAnalysis.Formatting @@ -17,7 +16,7 @@ Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Namespace Microsoft.CodeAnalysis.VisualBasic.AddImport - Friend Class VisualBasicAddImportFeatureService + Friend NotInheritable Class VisualBasicAddImportFeatureService Inherits AbstractAddImportFeatureService(Of SimpleNameSyntax) @@ -25,8 +24,11 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.AddImport Public Sub New() End Sub + Protected Overrides Function IsWithinImport(node As SyntaxNode) As Boolean + Return node.GetAncestor(Of ImportsStatementSyntax)() IsNot Nothing + End Function + Protected Overrides Function CanAddImport(node As SyntaxNode, allowInHiddenRegions As Boolean, cancellationToken As CancellationToken) As Boolean - cancellationToken.ThrowIfCancellationRequested() Return node.CanAddImportsStatements(allowInHiddenRegions, cancellationToken) End Function @@ -129,7 +131,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.AddImport node.GetAncestor(Of QueryExpressionSyntax)() IsNot Nothing End Function - Protected Overrides Function CanAddImportForType( + Protected Overrides Function CanAddImportForTypeOrNamespace( diagnosticId As String, node As SyntaxNode, ByRef nameNode As SimpleNameSyntax) As Boolean Select Case diagnosticId Case AddImportDiagnosticIds.BC30002, diff --git a/src/Features/VisualBasic/Portable/BraceCompletion/BracketBraceCompletionService.vb b/src/Features/VisualBasic/Portable/BraceCompletion/BracketBraceCompletionService.vb index 3ee4ea728879d..c9bcb1127b1fc 100644 --- a/src/Features/VisualBasic/Portable/BraceCompletion/BracketBraceCompletionService.vb +++ b/src/Features/VisualBasic/Portable/BraceCompletion/BracketBraceCompletionService.vb @@ -7,15 +7,13 @@ Imports System.Threading Imports Microsoft.CodeAnalysis Imports Microsoft.CodeAnalysis.BraceCompletion Imports Microsoft.CodeAnalysis.Host.Mef -Imports Microsoft.CodeAnalysis.LanguageService Imports Microsoft.CodeAnalysis.Text Imports Microsoft.CodeAnalysis.VisualBasic -Imports Microsoft.CodeAnalysis.VisualBasic.LanguageService Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Namespace Microsoft.CodeAnalysis.VisualBasic.BraceCompletion - Friend Class BracketBraceCompletionService + Friend NotInheritable Class BracketBraceCompletionService Inherits AbstractVisualBasicBraceCompletionService diff --git a/src/Features/VisualBasic/Portable/BraceCompletion/CurlyBraceCompletionService.vb b/src/Features/VisualBasic/Portable/BraceCompletion/CurlyBraceCompletionService.vb index 2f8b7ccef2be4..6a804285d2a76 100644 --- a/src/Features/VisualBasic/Portable/BraceCompletion/CurlyBraceCompletionService.vb +++ b/src/Features/VisualBasic/Portable/BraceCompletion/CurlyBraceCompletionService.vb @@ -7,11 +7,10 @@ Imports System.Threading Imports Microsoft.CodeAnalysis Imports Microsoft.CodeAnalysis.BraceCompletion Imports Microsoft.CodeAnalysis.Host.Mef -Imports Microsoft.CodeAnalysis.VisualBasic Namespace Microsoft.CodeAnalysis.VisualBasic.BraceCompletion - Friend Class CurlyBraceCompletionService + Friend NotInheritable Class CurlyBraceCompletionService Inherits AbstractVisualBasicBraceCompletionService diff --git a/src/Features/VisualBasic/Portable/BraceCompletion/InterpolatedStringBraceCompletionService.vb b/src/Features/VisualBasic/Portable/BraceCompletion/InterpolatedStringBraceCompletionService.vb index bb8d519199db3..39a1a8f7fc1df 100644 --- a/src/Features/VisualBasic/Portable/BraceCompletion/InterpolatedStringBraceCompletionService.vb +++ b/src/Features/VisualBasic/Portable/BraceCompletion/InterpolatedStringBraceCompletionService.vb @@ -8,12 +8,10 @@ Imports Microsoft.CodeAnalysis Imports Microsoft.CodeAnalysis.BraceCompletion Imports Microsoft.CodeAnalysis.Host.Mef Imports Microsoft.CodeAnalysis.Text -Imports Microsoft.CodeAnalysis.VisualBasic -Imports Microsoft.CodeAnalysis.VisualBasic.Extensions.ContextQuery Namespace Microsoft.CodeAnalysis.VisualBasic.BraceCompletion - Friend Class InterpolatedStringBraceCompletionService + Friend NotInheritable Class InterpolatedStringBraceCompletionService Inherits AbstractVisualBasicBraceCompletionService diff --git a/src/Features/VisualBasic/Portable/BraceCompletion/InterpolationBraceCompletionService.vb b/src/Features/VisualBasic/Portable/BraceCompletion/InterpolationBraceCompletionService.vb index 0d9071527ee49..12ef3ed4b9141 100644 --- a/src/Features/VisualBasic/Portable/BraceCompletion/InterpolationBraceCompletionService.vb +++ b/src/Features/VisualBasic/Portable/BraceCompletion/InterpolationBraceCompletionService.vb @@ -8,11 +8,10 @@ Imports Microsoft.CodeAnalysis Imports Microsoft.CodeAnalysis.BraceCompletion Imports Microsoft.CodeAnalysis.Host.Mef Imports Microsoft.CodeAnalysis.Text -Imports Microsoft.CodeAnalysis.VisualBasic Namespace Microsoft.CodeAnalysis.VisualBasic.BraceCompletion - Friend Class InterpolationBraceCompletionService + Friend NotInheritable Class InterpolationBraceCompletionService Inherits AbstractVisualBasicBraceCompletionService diff --git a/src/Features/VisualBasic/Portable/BraceCompletion/LessAndGreaterThanCompletionService.vb b/src/Features/VisualBasic/Portable/BraceCompletion/LessAndGreaterThanCompletionService.vb index a5469d4b63238..5d2f647c4bfa6 100644 --- a/src/Features/VisualBasic/Portable/BraceCompletion/LessAndGreaterThanCompletionService.vb +++ b/src/Features/VisualBasic/Portable/BraceCompletion/LessAndGreaterThanCompletionService.vb @@ -8,12 +8,11 @@ Imports Microsoft.CodeAnalysis Imports Microsoft.CodeAnalysis.BraceCompletion Imports Microsoft.CodeAnalysis.Host.Mef Imports Microsoft.CodeAnalysis.Text -Imports Microsoft.CodeAnalysis.VisualBasic Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Namespace Microsoft.CodeAnalysis.VisualBasic.BraceCompletion - Friend Class LessAndGreaterThanCompletionService + Friend NotInheritable Class LessAndGreaterThanCompletionService Inherits AbstractVisualBasicBraceCompletionService diff --git a/src/Features/VisualBasic/Portable/BraceCompletion/ParenthesisBraceCompletionService.vb b/src/Features/VisualBasic/Portable/BraceCompletion/ParenthesisBraceCompletionService.vb index c358d2de1cfad..a7f1c2e2bbef6 100644 --- a/src/Features/VisualBasic/Portable/BraceCompletion/ParenthesisBraceCompletionService.vb +++ b/src/Features/VisualBasic/Portable/BraceCompletion/ParenthesisBraceCompletionService.vb @@ -13,7 +13,7 @@ Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Namespace Microsoft.CodeAnalysis.VisualBasic.BraceCompletion - Friend Class ParenthesisBraceCompletionService + Friend NotInheritable Class ParenthesisBraceCompletionService Inherits AbstractVisualBasicBraceCompletionService @@ -43,7 +43,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.BraceCompletion If skippedTriviaNode IsNot Nothing Then Dim skippedToken = skippedTriviaNode.ParentTrivia.Token ' These checks don't make any sense. Leaving them in place to avoid breaking something as part of this move. - If skippedToken.Kind <> SyntaxKind.CloseParenToken OrElse Not TypeOf skippedToken.Parent Is BinaryConditionalExpressionSyntax Then + If skippedToken.Kind <> SyntaxKind.CloseParenToken OrElse TypeOf skippedToken.Parent IsNot BinaryConditionalExpressionSyntax Then Return False End If End If diff --git a/src/Features/VisualBasic/Portable/BraceCompletion/StringLiteralBraceCompletionService.vb b/src/Features/VisualBasic/Portable/BraceCompletion/StringLiteralBraceCompletionService.vb index f0f3f44ae6f98..a83f0307d8464 100644 --- a/src/Features/VisualBasic/Portable/BraceCompletion/StringLiteralBraceCompletionService.vb +++ b/src/Features/VisualBasic/Portable/BraceCompletion/StringLiteralBraceCompletionService.vb @@ -7,11 +7,10 @@ Imports System.Threading Imports Microsoft.CodeAnalysis Imports Microsoft.CodeAnalysis.BraceCompletion Imports Microsoft.CodeAnalysis.Host.Mef -Imports Microsoft.CodeAnalysis.VisualBasic Namespace Microsoft.CodeAnalysis.VisualBasic.BraceCompletion - Friend Class StringLiteralBraceCompletionService + Friend NotInheritable Class StringLiteralBraceCompletionService Inherits AbstractVisualBasicBraceCompletionService diff --git a/src/Features/VisualBasic/Portable/ChangeSignature/VisualBasicChangeSignatureService.vb b/src/Features/VisualBasic/Portable/ChangeSignature/VisualBasicChangeSignatureService.vb index 45fc7e1c99aaa..fdbc52e418eaa 100644 --- a/src/Features/VisualBasic/Portable/ChangeSignature/VisualBasicChangeSignatureService.vb +++ b/src/Features/VisualBasic/Portable/ChangeSignature/VisualBasicChangeSignatureService.vb @@ -271,13 +271,14 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ChangeSignature Return matchingNode End Function - Public Overrides Async Function ChangeSignatureAsync( - document As Document, + Public Overrides Function ChangeSignature( + document As SemanticDocument, declarationSymbol As ISymbol, potentiallyUpdatedNode As SyntaxNode, originalNode As SyntaxNode, updatedSignature As SignatureChange, - cancellationToken As CancellationToken) As Task(Of SyntaxNode) + lineFormattingOptions As LineFormattingOptions, + cancellationToken As CancellationToken) As SyntaxNode Dim vbnode = DirectCast(potentiallyUpdatedNode, VisualBasicSyntaxNode) If vbnode.IsKind(SyntaxKind.SubStatement) OrElse @@ -290,14 +291,15 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ChangeSignature vbnode.IsKind(SyntaxKind.EventBlock) OrElse vbnode.IsKind(SyntaxKind.EventStatement) Then - Dim updatedLeadingTrivia = Await UpdateParamNodesInLeadingTriviaAsync(document, vbnode, declarationSymbol, updatedSignature, cancellationToken).ConfigureAwait(False) + Dim updatedLeadingTrivia = UpdateParamNodesInLeadingTrivia( + document.Document, vbnode, declarationSymbol, updatedSignature, lineFormattingOptions) vbnode = vbnode.WithLeadingTrivia(updatedLeadingTrivia) End If If vbnode.IsKind(SyntaxKind.SubStatement) OrElse vbnode.IsKind(SyntaxKind.FunctionStatement) Then Dim method = DirectCast(vbnode, MethodStatementSyntax) Dim updatedParameters = UpdateDeclaration(method.ParameterList.Parameters, updatedSignature, s_createNewParameterSyntaxDelegate) - Return method.WithParameterList(method.ParameterList.WithParameters(updatedParameters).WithAdditionalAnnotations(changeSignatureFormattingAnnotation)) + Return method.WithParameterList(method.ParameterList.WithParameters(updatedParameters).WithAdditionalAnnotations(ChangeSignatureFormattingAnnotation)) End If If vbnode.IsKind(SyntaxKind.EventStatement) Then @@ -305,7 +307,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ChangeSignature If eventStatement.ParameterList IsNot Nothing Then Dim updatedParameters = UpdateDeclaration(eventStatement.ParameterList.Parameters, updatedSignature, s_createNewParameterSyntaxDelegate) - eventStatement = eventStatement.WithParameterList(eventStatement.ParameterList.WithParameters(updatedParameters).WithAdditionalAnnotations(changeSignatureFormattingAnnotation)) + eventStatement = eventStatement.WithParameterList(eventStatement.ParameterList.WithParameters(updatedParameters).WithAdditionalAnnotations(ChangeSignatureFormattingAnnotation)) End If Return eventStatement @@ -316,14 +318,14 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ChangeSignature If eventBlock.EventStatement.ParameterList IsNot Nothing Then Dim updatedParameters = UpdateDeclaration(eventBlock.EventStatement.ParameterList.Parameters, updatedSignature, s_createNewParameterSyntaxDelegate) - Return eventBlock.WithEventStatement(eventBlock.EventStatement.WithParameterList(eventBlock.EventStatement.ParameterList.WithParameters(updatedParameters).WithAdditionalAnnotations(changeSignatureFormattingAnnotation))) + Return eventBlock.WithEventStatement(eventBlock.EventStatement.WithParameterList(eventBlock.EventStatement.ParameterList.WithParameters(updatedParameters).WithAdditionalAnnotations(ChangeSignatureFormattingAnnotation))) End If Dim raiseEventAccessor = eventBlock.Accessors.FirstOrDefault(Function(a) a.IsKind(SyntaxKind.RaiseEventAccessorBlock)) If raiseEventAccessor IsNot Nothing Then If raiseEventAccessor.BlockStatement.ParameterList IsNot Nothing Then Dim updatedParameters = UpdateDeclaration(raiseEventAccessor.BlockStatement.ParameterList.Parameters, updatedSignature, s_createNewParameterSyntaxDelegate) - Dim updatedRaiseEventAccessor = raiseEventAccessor.WithAccessorStatement(raiseEventAccessor.AccessorStatement.WithParameterList(raiseEventAccessor.AccessorStatement.ParameterList.WithParameters(updatedParameters).WithAdditionalAnnotations(changeSignatureFormattingAnnotation))) + Dim updatedRaiseEventAccessor = raiseEventAccessor.WithAccessorStatement(raiseEventAccessor.AccessorStatement.WithParameterList(raiseEventAccessor.AccessorStatement.ParameterList.WithParameters(updatedParameters).WithAdditionalAnnotations(ChangeSignatureFormattingAnnotation))) eventBlock = eventBlock.WithAccessors(eventBlock.Accessors.Remove(raiseEventAccessor).Add(updatedRaiseEventAccessor)) End If End If @@ -333,24 +335,24 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ChangeSignature If vbnode.IsKind(SyntaxKind.RaiseEventStatement) Then Dim raiseEventStatement = DirectCast(vbnode, RaiseEventStatementSyntax) - Dim semanticModel = Await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(False) + Dim semanticModel = document.SemanticModel Dim delegateInvokeMethod = DirectCast(DirectCast(semanticModel.GetSymbolInfo(raiseEventStatement.Name, cancellationToken).Symbol, IEventSymbol).Type, INamedTypeSymbol).DelegateInvokeMethod - Return raiseEventStatement.WithArgumentList(Await UpdateArgumentListAsync( + Return raiseEventStatement.WithArgumentList(UpdateArgumentList( + document, delegateInvokeMethod, updatedSignature, raiseEventStatement.ArgumentList, isReducedExtensionMethod:=False, isParamsArrayExpanded:=False, generateAttributeArguments:=False, - document, originalNode.SpanStart, - cancellationToken).ConfigureAwait(False)) + cancellationToken)) End If If vbnode.IsKind(SyntaxKind.InvocationExpression) Then Dim invocation = DirectCast(vbnode, InvocationExpressionSyntax) - Dim semanticModel = Await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(False) + Dim semanticModel = document.SemanticModel Dim isReducedExtensionMethod = False Dim symbolInfo = semanticModel.GetSymbolInfo(DirectCast(originalNode, InvocationExpressionSyntax), cancellationToken) @@ -371,68 +373,68 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ChangeSignature End If End If - Return invocation.WithArgumentList(Await UpdateArgumentListAsync( + Return invocation.WithArgumentList(UpdateArgumentList( + document, declarationSymbol, updatedSignature, invocation.ArgumentList, isReducedExtensionMethod, IsParamsArrayExpanded(semanticModel, invocation, symbolInfo, cancellationToken), generateAttributeArguments:=False, - document, originalNode.SpanStart, - cancellationToken).ConfigureAwait(False)) + cancellationToken)) End If If vbnode.IsKind(SyntaxKind.SubNewStatement) Then Dim constructor = DirectCast(vbnode, SubNewStatementSyntax) Dim newParameters = UpdateDeclaration(constructor.ParameterList.Parameters, updatedSignature, s_createNewParameterSyntaxDelegate) - Return constructor.WithParameterList(constructor.ParameterList.WithParameters(newParameters).WithAdditionalAnnotations(changeSignatureFormattingAnnotation)) + Return constructor.WithParameterList(constructor.ParameterList.WithParameters(newParameters).WithAdditionalAnnotations(ChangeSignatureFormattingAnnotation)) End If If vbnode.IsKind(SyntaxKind.Attribute) Then Dim attribute = DirectCast(vbnode, AttributeSyntax) - Dim semanticModel = Await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(False) + Dim semanticModel = document.SemanticModel Dim symbolInfo = semanticModel.GetSymbolInfo(DirectCast(originalNode, AttributeSyntax), cancellationToken) Dim methodSymbol = TryCast(symbolInfo.Symbol, IMethodSymbol) - Return attribute.WithArgumentList(Await UpdateArgumentListAsync( + Return attribute.WithArgumentList(UpdateArgumentList( + document, declarationSymbol, updatedSignature, attribute.ArgumentList, isReducedExtensionMethod:=False, isParamsArrayExpanded:=False, generateAttributeArguments:=True, - document, originalNode.SpanStart, - cancellationToken).ConfigureAwait(False)) + cancellationToken)) End If If vbnode.IsKind(SyntaxKind.ObjectCreationExpression) Then Dim objectCreation = DirectCast(vbnode, ObjectCreationExpressionSyntax) - Dim semanticModel = Await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(False) + Dim semanticModel = document.SemanticModel Dim symbolInfo = semanticModel.GetSymbolInfo(DirectCast(originalNode, ObjectCreationExpressionSyntax), cancellationToken) Dim methodSymbol = TryCast(symbolInfo.Symbol, IMethodSymbol) Dim paramsArrayExpanded = IsParamsArrayExpanded(semanticModel, objectCreation, symbolInfo, cancellationToken) - Return objectCreation.WithArgumentList(Await UpdateArgumentListAsync( + Return objectCreation.WithArgumentList(UpdateArgumentList( + document, declarationSymbol, updatedSignature, objectCreation.ArgumentList, isReducedExtensionMethod:=False, IsParamsArrayExpanded(semanticModel, objectCreation, symbolInfo, cancellationToken), generateAttributeArguments:=False, - document, originalNode.SpanStart, - cancellationToken).ConfigureAwait(False)) + cancellationToken)) End If If vbnode.IsKind(SyntaxKind.PropertyStatement) Then Dim propertyStatement = DirectCast(vbnode, PropertyStatementSyntax) Dim newParameters = UpdateDeclaration(propertyStatement.ParameterList.Parameters, updatedSignature, s_createNewParameterSyntaxDelegate) - Return propertyStatement.WithParameterList(propertyStatement.ParameterList.WithParameters(newParameters).WithAdditionalAnnotations(changeSignatureFormattingAnnotation)) + Return propertyStatement.WithParameterList(propertyStatement.ParameterList.WithParameters(newParameters).WithAdditionalAnnotations(ChangeSignatureFormattingAnnotation)) End If If vbnode.IsKind(SyntaxKind.CrefReference) Then @@ -457,7 +459,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ChangeSignature End If Dim newParameters = UpdateDeclaration(lambda.SubOrFunctionHeader.ParameterList.Parameters, updatedSignature, s_createNewParameterSyntaxDelegate) - Dim newBegin = lambda.SubOrFunctionHeader.WithParameterList(lambda.SubOrFunctionHeader.ParameterList.WithParameters(newParameters).WithAdditionalAnnotations(changeSignatureFormattingAnnotation)) + Dim newBegin = lambda.SubOrFunctionHeader.WithParameterList(lambda.SubOrFunctionHeader.ParameterList.WithParameters(newParameters).WithAdditionalAnnotations(ChangeSignatureFormattingAnnotation)) Return lambda.WithSubOrFunctionHeader(newBegin) End If @@ -471,7 +473,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ChangeSignature End If Dim newParameters = UpdateDeclaration(lambda.SubOrFunctionHeader.ParameterList.Parameters, updatedSignature, s_createNewParameterSyntaxDelegate) - Dim newBegin = lambda.SubOrFunctionHeader.WithParameterList(lambda.SubOrFunctionHeader.ParameterList.WithParameters(newParameters).WithAdditionalAnnotations(changeSignatureFormattingAnnotation)) + Dim newBegin = lambda.SubOrFunctionHeader.WithParameterList(lambda.SubOrFunctionHeader.ParameterList.WithParameters(newParameters).WithAdditionalAnnotations(ChangeSignatureFormattingAnnotation)) Return lambda.WithSubOrFunctionHeader(newBegin) End If @@ -479,22 +481,22 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ChangeSignature vbnode.IsKind(SyntaxKind.DelegateFunctionStatement) Then Dim delegateStatement = DirectCast(vbnode, DelegateStatementSyntax) Dim newParameters = UpdateDeclaration(delegateStatement.ParameterList.Parameters, updatedSignature, s_createNewParameterSyntaxDelegate) - Return delegateStatement.WithParameterList(delegateStatement.ParameterList.WithParameters(newParameters).WithAdditionalAnnotations(changeSignatureFormattingAnnotation)) + Return delegateStatement.WithParameterList(delegateStatement.ParameterList.WithParameters(newParameters).WithAdditionalAnnotations(ChangeSignatureFormattingAnnotation)) End If Return vbnode End Function - Private Async Function UpdateArgumentListAsync( + Private Function UpdateArgumentList( + document As SemanticDocument, declarationSymbol As ISymbol, signaturePermutation As SignatureChange, argumentList As ArgumentListSyntax, isReducedExtensionMethod As Boolean, isParamsArrayExpanded As Boolean, generateAttributeArguments As Boolean, - document As Document, position As Integer, - cancellationToken As CancellationToken) As Task(Of ArgumentListSyntax) + cancellationToken As CancellationToken) As ArgumentListSyntax Dim newArguments = PermuteArgumentList( argumentList.Arguments, @@ -502,20 +504,20 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ChangeSignature declarationSymbol, isReducedExtensionMethod) - newArguments = Await AddNewArgumentsToListAsync( + newArguments = AddNewArgumentsToList( + document, declarationSymbol, newArguments, signaturePermutation, isReducedExtensionMethod, isParamsArrayExpanded, generateAttributeArguments, - document, position, - cancellationToken).ConfigureAwait(False) + cancellationToken) Return argumentList. WithArguments(newArguments). - WithAdditionalAnnotations(changeSignatureFormattingAnnotation) + WithAdditionalAnnotations(ChangeSignatureFormattingAnnotation) End Function Private Shared Function IsParamsArrayExpanded(semanticModel As SemanticModel, node As SyntaxNode, symbolInfo As SymbolInfo, cancellationToken As CancellationToken) As Boolean @@ -602,12 +604,12 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ChangeSignature type:=addedParameter.Type.GenerateTypeSyntax()) End Function - Private Async Function UpdateParamNodesInLeadingTriviaAsync( + Private Function UpdateParamNodesInLeadingTrivia( document As Document, node As VisualBasicSyntaxNode, declarationSymbol As ISymbol, updatedSignature As SignatureChange, - cancellationToken As CancellationToken) As Task(Of ImmutableArray(Of SyntaxTrivia)) + lineFormattingOption As LineFormattingOptions) As ImmutableArray(Of SyntaxTrivia) If Not node.HasLeadingTrivia Then Return ImmutableArray(Of SyntaxTrivia).Empty @@ -625,8 +627,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ChangeSignature Return node.GetLeadingTrivia().ToImmutableArray() End If - Dim options = Await document.GetLineFormattingOptionsAsync(cancellationToken).ConfigureAwait(False) - Return GetPermutedDocCommentTrivia(node, permutedParamNodes, document.Project.Services, options) + Return GetPermutedDocCommentTrivia(node, permutedParamNodes, document.Project.Services, lineFormattingOption) End Function Private Function VerifyAndPermuteParamNodes(paramNodes As ImmutableArray(Of XmlElementSyntax), declarationSymbol As ISymbol, updatedSignature As SignatureChange) As ImmutableArray(Of SyntaxNode) @@ -701,7 +702,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ChangeSignature End If If convertedType IsNot Nothing Then - convertedType = If(Await SymbolFinder.FindSourceDefinitionAsync(convertedType, document.Project.Solution, cancellationToken).ConfigureAwait(False), convertedType) + convertedType = If(SymbolFinder.FindSourceDefinition(convertedType, document.Project.Solution, cancellationToken), convertedType) End If If Equals(convertedType, symbol.ContainingType) Then @@ -720,7 +721,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ChangeSignature End If If nodeType IsNot Nothing Then - nodeType = If(Await SymbolFinder.FindSourceDefinitionAsync(nodeType, document.Project.Solution, cancellationToken).ConfigureAwait(False), nodeType) + nodeType = If(SymbolFinder.FindSourceDefinition(nodeType, document.Project.Solution, cancellationToken), nodeType) End If If Equals(nodeType, symbol.ContainingType) Then diff --git a/src/Features/VisualBasic/Portable/CodeFixes/GenerateEvent/GenerateEventCodeFixProvider.vb b/src/Features/VisualBasic/Portable/CodeFixes/GenerateEvent/GenerateEventCodeFixProvider.vb index 6d1792578115f..458b0d27fea5a 100644 --- a/src/Features/VisualBasic/Portable/CodeFixes/GenerateEvent/GenerateEventCodeFixProvider.vb +++ b/src/Features/VisualBasic/Portable/CodeFixes/GenerateEvent/GenerateEventCodeFixProvider.vb @@ -105,7 +105,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeFixes.GenerateEvent End If ' Target type may be in other project so we need to find its source definition - Dim sourceDefinition = Await SymbolFinder.FindSourceDefinitionAsync(targetType, document.Project.Solution, cancellationToken).ConfigureAwait(False) + Dim sourceDefinition = SymbolFinder.FindSourceDefinition(targetType, document.Project.Solution, cancellationToken) targetType = TryCast(sourceDefinition, INamedTypeSymbol) @@ -256,7 +256,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeFixes.GenerateEvent Return Nothing End If - Dim targetType = TryCast(Await SymbolFinder.FindSourceDefinitionAsync(semanticModel.GetSymbolInfo(node.Left, cancellationToken).Symbol, document.Project.Solution, cancellationToken).ConfigureAwait(False), INamedTypeSymbol) + Dim targetType = TryCast(SymbolFinder.FindSourceDefinition(semanticModel.GetSymbolInfo(node.Left, cancellationToken).Symbol, document.Project.Solution, cancellationToken), INamedTypeSymbol) If targetType Is Nothing OrElse (targetType.TypeKind <> TypeKind.Interface AndAlso targetType.TypeKind <> TypeKind.Class) Then Return Nothing End If @@ -347,11 +347,11 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeFixes.GenerateEvent Return Nothing End If - targetType = TryCast(Await SymbolFinder.FindSourceDefinitionAsync(withEventsProperty.Type, document.Project.Solution, cancellationToken).ConfigureAwait(False), INamedTypeSymbol) + targetType = TryCast(SymbolFinder.FindSourceDefinition(withEventsProperty.Type, document.Project.Solution, cancellationToken), INamedTypeSymbol) End If - targetType = TryCast(Await SymbolFinder.FindSourceDefinitionAsync(targetType, document.Project.Solution, cancellationToken).ConfigureAwait(False), INamedTypeSymbol) + targetType = TryCast(SymbolFinder.FindSourceDefinition(targetType, document.Project.Solution, cancellationToken), INamedTypeSymbol) If targetType Is Nothing OrElse Not (targetType.TypeKind = TypeKind.Class OrElse targetType.TypeKind = TypeKind.Interface) OrElse targetType.IsAnonymousType Then diff --git a/src/Features/VisualBasic/Portable/CodeRefactorings/InlineTemporary/VisualBasicInlineTemporaryCodeRefactoringProvider.ReferenceRewriter.vb b/src/Features/VisualBasic/Portable/CodeRefactorings/InlineTemporary/VisualBasicInlineTemporaryCodeRefactoringProvider.ReferenceRewriter.vb index b1de5001d4c71..c9896b3c8a989 100644 --- a/src/Features/VisualBasic/Portable/CodeRefactorings/InlineTemporary/VisualBasicInlineTemporaryCodeRefactoringProvider.ReferenceRewriter.vb +++ b/src/Features/VisualBasic/Portable/CodeRefactorings/InlineTemporary/VisualBasicInlineTemporaryCodeRefactoringProvider.ReferenceRewriter.vb @@ -50,7 +50,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeRefactorings.InlineTemporary If IsReference(node) Then If HasConflict(node, _definition, _expressionToInline, _semanticModel) Then Return node.Update(node.Identifier.WithAdditionalAnnotations( - ConflictAnnotation.Create(VBFeaturesResources.Conflict_s_detected))) + ConflictAnnotation.Create(FeaturesResources.Conflict_s_detected))) End If ' Make sure we attach any trailing trivia from the identifier node we're replacing diff --git a/src/Features/VisualBasic/Portable/CodeRefactorings/InlineTemporary/VisualBasicInlineTemporaryCodeRefactoringProvider.vb b/src/Features/VisualBasic/Portable/CodeRefactorings/InlineTemporary/VisualBasicInlineTemporaryCodeRefactoringProvider.vb index 874f041c8bc7c..2d0d7cf1d82f4 100644 --- a/src/Features/VisualBasic/Portable/CodeRefactorings/InlineTemporary/VisualBasicInlineTemporaryCodeRefactoringProvider.vb +++ b/src/Features/VisualBasic/Portable/CodeRefactorings/InlineTemporary/VisualBasicInlineTemporaryCodeRefactoringProvider.vb @@ -463,7 +463,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeRefactorings.InlineTemporary ' Replace the conflicting inlined nodes with the original nodes annotated with conflict annotation. Dim conflictAnnotationAdder = Function(oldNode As SyntaxNode, newNode As SyntaxNode) As SyntaxNode Return newNode _ - .WithAdditionalAnnotations(ConflictAnnotation.Create(VBFeaturesResources.Conflict_s_detected)) + .WithAdditionalAnnotations(ConflictAnnotation.Create(FeaturesResources.Conflict_s_detected)) End Function Return Await inlinedDocument.ReplaceNodesAsync(replacementNodesWithChangedSemantics.Keys, conflictAnnotationAdder, cancellationToken).ConfigureAwait(False) diff --git a/src/Features/VisualBasic/Portable/CodeRefactorings/MoveType/VisualBasicMoveTypeService.vb b/src/Features/VisualBasic/Portable/CodeRefactorings/MoveType/VisualBasicMoveTypeService.vb index 51bb3107165c4..6c2b0e8efd6a6 100644 --- a/src/Features/VisualBasic/Portable/CodeRefactorings/MoveType/VisualBasicMoveTypeService.vb +++ b/src/Features/VisualBasic/Portable/CodeRefactorings/MoveType/VisualBasicMoveTypeService.vb @@ -12,14 +12,18 @@ Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Namespace Microsoft.CodeAnalysis.VisualBasic.CodeRefactorings.MoveType - Friend Class VisualBasicMoveTypeService - Inherits AbstractMoveTypeService(Of VisualBasicMoveTypeService, TypeBlockSyntax, NamespaceBlockSyntax, MethodBaseSyntax, CompilationUnitSyntax) + Friend NotInheritable Class VisualBasicMoveTypeService + Inherits AbstractMoveTypeService(Of VisualBasicMoveTypeService, TypeBlockSyntax, NamespaceBlockSyntax, CompilationUnitSyntax) Public Sub New() End Sub + Protected Overrides Function IsMemberDeclaration(syntaxNode As SyntaxNode) As Boolean + Return TypeOf syntaxNode Is MethodBaseSyntax OrElse TypeOf syntaxNode Is MethodBlockBaseSyntax + End Function + Protected Overrides Async Function GetRelevantNodeAsync(document As Document, textSpan As TextSpan, cancellationToken As CancellationToken) As Task(Of TypeBlockSyntax) Dim typeStatement As TypeStatementSyntax = Await document.TryGetRelevantNodeAsync(Of TypeStatementSyntax)(textSpan, cancellationToken).ConfigureAwait(False) Return TryCast(typeStatement?.Parent, TypeBlockSyntax) diff --git a/src/Features/VisualBasic/Portable/Completion/CompletionProviders/AwaitCompletionProvider.vb b/src/Features/VisualBasic/Portable/Completion/CompletionProviders/AwaitCompletionProvider.vb index 1dcbe488a34bc..f26ee8e2e49ea 100644 --- a/src/Features/VisualBasic/Portable/Completion/CompletionProviders/AwaitCompletionProvider.vb +++ b/src/Features/VisualBasic/Portable/Completion/CompletionProviders/AwaitCompletionProvider.vb @@ -8,6 +8,7 @@ Imports System.Threading Imports Microsoft.CodeAnalysis.Completion Imports Microsoft.CodeAnalysis.Completion.Providers Imports Microsoft.CodeAnalysis.Host.Mef +Imports Microsoft.CodeAnalysis.Text Imports Microsoft.CodeAnalysis.VisualBasic.LanguageService Imports Microsoft.CodeAnalysis.VisualBasic.Syntax @@ -23,15 +24,11 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Completion.Providers MyBase.New(VisualBasicSyntaxFacts.Instance) End Sub - Friend Overrides ReadOnly Property Language As String - Get - Return LanguageNames.VisualBasic - End Get - End Property + Friend Overrides ReadOnly Property Language As String = LanguageNames.VisualBasic Public Overrides ReadOnly Property TriggerCharacters As ImmutableHashSet(Of Char) = CommonTriggerChars - Protected Overrides Function GetSpanStart(declaration As SyntaxNode) As Integer + Protected Overrides Function GetAsyncKeywordInsertionPosition(declaration As SyntaxNode) As Integer Select Case declaration.Kind() Case SyntaxKind.FunctionBlock, SyntaxKind.SubBlock @@ -46,6 +43,11 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Completion.Providers Throw ExceptionUtilities.Unreachable End Function + Protected Overrides Function GetReturnTypeChange(semanticModel As SemanticModel, declaration As SyntaxNode, cancellationToken As CancellationToken) As TextChange? + ' Todo: Add support if desired. + Return Nothing + End Function + Protected Overrides Function GetAsyncSupportingDeclaration(targetToken As SyntaxToken, position As Integer) As SyntaxNode Return targetToken.GetAncestor(Function(node) node.IsAsyncSupportedFunctionSyntax()) End Function diff --git a/src/Features/VisualBasic/Portable/Completion/CompletionProviders/InternalsVisibleToCompletionProvider.vb b/src/Features/VisualBasic/Portable/Completion/CompletionProviders/InternalsVisibleToCompletionProvider.vb index e351d7cb2ac3f..258fd572acd04 100644 --- a/src/Features/VisualBasic/Portable/Completion/CompletionProviders/InternalsVisibleToCompletionProvider.vb +++ b/src/Features/VisualBasic/Portable/Completion/CompletionProviders/InternalsVisibleToCompletionProvider.vb @@ -32,7 +32,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Completion.Providers Protected Overrides Function GetAssemblyScopedAttributeSyntaxNodesOfDocument(documentRoot As SyntaxNode) As IImmutableList(Of SyntaxNode) Dim builder As ImmutableList(Of SyntaxNode).Builder = Nothing Dim compilationUnit = TryCast(documentRoot, CompilationUnitSyntax) - If Not compilationUnit Is Nothing Then + If compilationUnit IsNot Nothing Then For Each attributeStatement In compilationUnit.Attributes For Each attributeList In attributeStatement.AttributeLists builder = If(builder, ImmutableList.CreateBuilder(Of SyntaxNode)()) diff --git a/src/Features/VisualBasic/Portable/Completion/CompletionProviders/ObjectInitializerCompletionProvider.vb b/src/Features/VisualBasic/Portable/Completion/CompletionProviders/ObjectInitializerCompletionProvider.vb index e6a7054e39a87..34c8e093d7a24 100644 --- a/src/Features/VisualBasic/Portable/Completion/CompletionProviders/ObjectInitializerCompletionProvider.vb +++ b/src/Features/VisualBasic/Portable/Completion/CompletionProviders/ObjectInitializerCompletionProvider.vb @@ -9,15 +9,13 @@ Imports Microsoft.CodeAnalysis Imports Microsoft.CodeAnalysis.Completion Imports Microsoft.CodeAnalysis.Completion.Providers Imports Microsoft.CodeAnalysis.Host.Mef -Imports Microsoft.CodeAnalysis.Options Imports Microsoft.CodeAnalysis.Text Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Namespace Microsoft.CodeAnalysis.VisualBasic.Completion.Providers - + - <[Shared]> - Friend Class ObjectInitializerCompletionProvider + Friend NotInheritable Class ObjectInitializerCompletionProvider Inherits AbstractObjectInitializerCompletionProvider @@ -52,10 +50,11 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Completion.Providers Return New HashSet(Of String)(initializer.Initializers.OfType(Of NamedFieldInitializerSyntax)().Select(Function(i) i.Name.Identifier.ValueText)) End Function - Protected Overrides Function GetInitializedType(document As Document, - semanticModel As SemanticModel, - position As Integer, - cancellationToken As CancellationToken) As Tuple(Of ITypeSymbol, Location) + Protected Overrides Function GetInitializedType( + document As Document, + semanticModel As SemanticModel, + position As Integer, + cancellationToken As CancellationToken) As Tuple(Of ITypeSymbol, Location) Dim tree = semanticModel.SyntaxTree If tree.IsInNonUserCode(position, cancellationToken) Then Return Nothing @@ -107,12 +106,11 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Completion.Providers Return SpecializedTasks.True End Function - Protected Overrides Function IsInitializable(member As ISymbol, containingType As INamedTypeSymbol) As Boolean + Protected Overrides Function IsInitializableFieldOrProperty(fieldOrProperty As ISymbol, containingType As INamedTypeSymbol) As Boolean ' Unlike CSharp, we don't want to suggest readonly members, even if they are Collections - Return member.IsWriteableFieldOrProperty() AndAlso - IsValidProperty(member) AndAlso - Not member.IsStatic AndAlso - member.IsAccessibleWithin(containingType) + Return MyBase.IsInitializableFieldOrProperty(fieldOrProperty, containingType) AndAlso + fieldOrProperty.IsWriteableFieldOrProperty() AndAlso + IsValidProperty(fieldOrProperty) End Function Protected Overrides Function EscapeIdentifier(symbol As ISymbol) As String @@ -127,6 +125,5 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Completion.Providers Return True End Function - End Class End Namespace diff --git a/src/Features/VisualBasic/Portable/Completion/CompletionProviders/VisualBasicSuggestionModeCompletionProvider.vb b/src/Features/VisualBasic/Portable/Completion/CompletionProviders/VisualBasicSuggestionModeCompletionProvider.vb index db41b1195422e..7f86fa54be673 100644 --- a/src/Features/VisualBasic/Portable/Completion/CompletionProviders/VisualBasicSuggestionModeCompletionProvider.vb +++ b/src/Features/VisualBasic/Portable/Completion/CompletionProviders/VisualBasicSuggestionModeCompletionProvider.vb @@ -116,7 +116,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Completion.Providers description = VBFeaturesResources.Type_a_name_here_to_declare_a_namespace & vbCrLf & VBFeaturesResources.Note_colon_Space_completion_is_disabled_to_avoid_potential_interference_To_insert_a_name_from_the_list_use_tab - Return CreateSuggestionModeItem(VBFeaturesResources.namespace_name, description) + Return CreateSuggestionModeItem(FeaturesResources.namespace_name, description) End If Dim statementSyntax As TypeStatementSyntax = Nothing @@ -127,13 +127,13 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Completion.Providers Select Case statementSyntax.DeclarationKeyword.Kind() Case SyntaxKind.ClassKeyword Return CreateSuggestionModeItem( - VBFeaturesResources.class_name, + FeaturesResources.class_name, VBFeaturesResources.Type_a_name_here_to_declare_a_partial_class & vbCrLf & VBFeaturesResources.Note_colon_Space_completion_is_disabled_to_avoid_potential_interference_To_insert_a_name_from_the_list_use_tab) Case SyntaxKind.InterfaceKeyword Return CreateSuggestionModeItem( - VBFeaturesResources.interface_name, + FeaturesResources.interface_name, VBFeaturesResources.Type_a_name_here_to_declare_a_partial_interface & vbCrLf & VBFeaturesResources.Note_colon_Space_completion_is_disabled_to_avoid_potential_interference_To_insert_a_name_from_the_list_use_tab) diff --git a/src/Features/VisualBasic/Portable/Completion/KeywordRecommenders/Declarations/ParameterModifiersKeywordRecommender.vb b/src/Features/VisualBasic/Portable/Completion/KeywordRecommenders/Declarations/ParameterModifiersKeywordRecommender.vb index 7ffab05a85afe..5bf3c2535c462 100644 --- a/src/Features/VisualBasic/Portable/Completion/KeywordRecommenders/Declarations/ParameterModifiersKeywordRecommender.vb +++ b/src/Features/VisualBasic/Portable/Completion/KeywordRecommenders/Declarations/ParameterModifiersKeywordRecommender.vb @@ -33,13 +33,13 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Completion.KeywordRecommenders.Decl End If ' Compute some basic properties of what is allowed at all in this context - Dim byRefAllowed = Not TypeOf methodDeclaration Is AccessorStatementSyntax AndAlso + Dim byRefAllowed = TypeOf methodDeclaration IsNot AccessorStatementSyntax AndAlso methodDeclaration.Kind <> SyntaxKind.PropertyStatement AndAlso methodDeclaration.Kind <> SyntaxKind.OperatorStatement - Dim optionalAndParamArrayAllowed = Not TypeOf methodDeclaration Is DelegateStatementSyntax AndAlso - Not TypeOf methodDeclaration Is LambdaHeaderSyntax AndAlso - Not TypeOf methodDeclaration Is AccessorStatementSyntax AndAlso + Dim optionalAndParamArrayAllowed = TypeOf methodDeclaration IsNot DelegateStatementSyntax AndAlso + TypeOf methodDeclaration IsNot LambdaHeaderSyntax AndAlso + TypeOf methodDeclaration IsNot AccessorStatementSyntax AndAlso methodDeclaration.Kind <> SyntaxKind.EventStatement AndAlso methodDeclaration.Kind <> SyntaxKind.OperatorStatement diff --git a/src/Features/VisualBasic/Portable/ConvertAutoPropertyToFullProperty/VisualBasicConvertAutoPropertyToFullProperty.vb b/src/Features/VisualBasic/Portable/ConvertAutoPropertyToFullProperty/VisualBasicConvertAutoPropertyToFullProperty.vb index 5c6c307ee0f81..3572c389d45f7 100644 --- a/src/Features/VisualBasic/Portable/ConvertAutoPropertyToFullProperty/VisualBasicConvertAutoPropertyToFullProperty.vb +++ b/src/Features/VisualBasic/Portable/ConvertAutoPropertyToFullProperty/VisualBasicConvertAutoPropertyToFullProperty.vb @@ -5,12 +5,9 @@ Imports System.Composition Imports System.Diagnostics.CodeAnalysis Imports System.Threading -Imports Microsoft.CodeAnalysis.CodeGeneration Imports Microsoft.CodeAnalysis.CodeRefactorings -Imports Microsoft.CodeAnalysis.CodeStyle Imports Microsoft.CodeAnalysis.ConvertAutoPropertyToFullProperty Imports Microsoft.CodeAnalysis.Editing -Imports Microsoft.CodeAnalysis.Options Imports Microsoft.CodeAnalysis.VisualBasic.CodeGeneration Imports Microsoft.CodeAnalysis.VisualBasic.Syntax @@ -37,7 +34,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ConvertAutoPropertyToFullProperty Protected Overrides Function GetNewAccessors( info As VisualBasicCodeGenerationContextInfo, - propertyNode As SyntaxNode, + propertySyntax As PropertyStatementSyntax, fieldName As String, generator As SyntaxGenerator, cancellationToken As CancellationToken) As (newGetAccessor As SyntaxNode, newSetAccessor As SyntaxNode) @@ -48,8 +45,6 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ConvertAutoPropertyToFullProperty SyntaxFactory.GetAccessorStatement(), returnStatement) - Dim propertySyntax = DirectCast(propertyNode, PropertyStatementSyntax) - Dim setAccessor As SyntaxNode If IsReadOnly(propertySyntax) Then setAccessor = Nothing diff --git a/src/Features/VisualBasic/Portable/Debugging/DataTipInfoGetter.vb b/src/Features/VisualBasic/Portable/Debugging/DataTipInfoGetter.vb index a1c0ad09bc0e0..9df8e8df27c1a 100644 --- a/src/Features/VisualBasic/Portable/Debugging/DataTipInfoGetter.vb +++ b/src/Features/VisualBasic/Portable/Debugging/DataTipInfoGetter.vb @@ -10,52 +10,61 @@ Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Namespace Microsoft.CodeAnalysis.VisualBasic.Debugging ' TODO: Make this class static when we add that functionality to VB. - Namespace DataTipInfoGetter - Friend Module DataTipInfoGetterModule - Friend Async Function GetInfoAsync(document As Document, position As Integer, cancellationToken As CancellationToken) As Task(Of DebugDataTipInfo) - Dim root = Await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(False) - Dim token = root.FindToken(position) - - If token.IsKind(SyntaxKind.CommaToken) Then - ' The commas in a separated syntax list consider the list's parent - ' to be their parent, which leads to false positives below. - Return Nothing - End If - - If token.Parent.IsKind(SyntaxKind.ModifiedIdentifier) Then - Return New DebugDataTipInfo(token.Span, text:=Nothing) - End If - - Dim expression = TryCast(token.Parent, ExpressionSyntax) - If expression Is Nothing Then - Return If(token.IsKind(SyntaxKind.IdentifierToken), - New DebugDataTipInfo(token.Span, text:=Nothing), - Nothing) - End If - - If expression.IsAnyLiteralExpression() Then - Return Nothing - End If - - Dim conditionalAccess As ExpressionSyntax = Nothing - If expression.IsRightSideOfDotOrBang() Then - expression = DirectCast(expression.Parent, ExpressionSyntax) - conditionalAccess = If(expression.GetRootConditionalAccessExpression(), expression) - End If - - If expression.Parent.IsKind(SyntaxKind.InvocationExpression) Then - expression = DirectCast(expression.Parent, ExpressionSyntax) - End If - - Dim span = expression.Span - If conditionalAccess IsNot Nothing Then - ' There may not be an ExpressionSyntax corresponding to the range we want. - ' For example, for input a?.$$B?.C we want span [|a?.B|].C. - span = TextSpan.FromBounds(conditionalAccess.SpanStart, span.End) - End If - - Return New DebugDataTipInfo(span, text:=Nothing) - End Function - End Module - End Namespace + Friend NotInheritable Class DataTipInfoGetter + Inherits AbstractDataTipInfoGetter(Of + ExpressionSyntax, + MemberAccessExpressionSyntax, + InvocationExpressionSyntax) + + Public Shared Async Function GetInfoAsync( + document As Document, + position As Integer, + includeKind As Boolean, + cancellationToken As CancellationToken) As Task(Of DebugDataTipInfo) + Dim root = Await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(False) + Dim token = root.FindToken(position) + + If token.IsKind(SyntaxKind.CommaToken) Then + ' The commas in a separated syntax list consider the list's parent + ' to be their parent, which leads to false positives below. + Return Nothing + End If + + If token.Parent.IsKind(SyntaxKind.ModifiedIdentifier) Then + Return New DebugDataTipInfo(token.Span, Text:=Nothing) + End If + + Dim expression = TryCast(token.Parent, ExpressionSyntax) + If expression Is Nothing Then + Return If(token.IsKind(SyntaxKind.IdentifierToken), + New DebugDataTipInfo(token.Span, Text:=Nothing), + Nothing) + End If + + If expression.IsAnyLiteralExpression() Then + Return Nothing + End If + + Dim kindAndExpressionSpan = Await ComputeKindAsync(document, expression, includeKind, cancellationToken).ConfigureAwait(False) + + Dim conditionalAccess As ExpressionSyntax = Nothing + If expression.IsRightSideOfDotOrBang() Then + expression = DirectCast(expression.Parent, ExpressionSyntax) + conditionalAccess = If(expression.GetRootConditionalAccessExpression(), expression) + End If + + If expression.Parent.IsKind(SyntaxKind.InvocationExpression) Then + expression = DirectCast(expression.Parent, ExpressionSyntax) + End If + + Dim span = expression.Span + If conditionalAccess IsNot Nothing Then + ' There may not be an ExpressionSyntax corresponding to the range we want. + ' For example, for input a?.$$B?.C we want span [|a?.B|].C. + span = TextSpan.FromBounds(conditionalAccess.SpanStart, span.End) + End If + + Return New DebugDataTipInfo(span, If(kindAndExpressionSpan.expressionSpan, span), Text:=Nothing, kindAndExpressionSpan.kind) + End Function + End Class End Namespace diff --git a/src/Features/VisualBasic/Portable/Debugging/VisualBasicLanguageDebugInfoService.vb b/src/Features/VisualBasic/Portable/Debugging/VisualBasicLanguageDebugInfoService.vb index b1355287f3f3f..ed8e0da15bf43 100644 --- a/src/Features/VisualBasic/Portable/Debugging/VisualBasicLanguageDebugInfoService.vb +++ b/src/Features/VisualBasic/Portable/Debugging/VisualBasicLanguageDebugInfoService.vb @@ -22,8 +22,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Debugging Return LocationInfoGetter.GetInfoAsync(document, position, cancellationToken) End Function - Public Function GetDataTipInfoAsync(document As Document, position As Integer, cancellationToken As CancellationToken) As Task(Of DebugDataTipInfo) Implements ILanguageDebugInfoService.GetDataTipInfoAsync - Return DataTipInfoGetter.GetInfoAsync(document, position, cancellationToken) + Public Function GetDataTipInfoAsync(document As Document, position As Integer, includeKind As Boolean, cancellationToken As CancellationToken) As Task(Of DebugDataTipInfo) Implements ILanguageDebugInfoService.GetDataTipInfoAsync + Return DataTipInfoGetter.GetInfoAsync(document, position, includeKind, cancellationToken) End Function End Class End Namespace diff --git a/src/Features/VisualBasic/Portable/ExtractMethod/VisualBasicExtractMethodService.vb b/src/Features/VisualBasic/Portable/ExtractMethod/VisualBasicExtractMethodService.vb index 46be28488cb77..4ba1388ccf1c2 100644 --- a/src/Features/VisualBasic/Portable/ExtractMethod/VisualBasicExtractMethodService.vb +++ b/src/Features/VisualBasic/Portable/ExtractMethod/VisualBasicExtractMethodService.vb @@ -10,11 +10,9 @@ Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Namespace Microsoft.CodeAnalysis.VisualBasic.ExtractMethod - Friend NotInheritable Class VisualBasicExtractMethodService + Partial Friend NotInheritable Class VisualBasicExtractMethodService Inherits AbstractExtractMethodService(Of - VisualBasicSelectionValidator, - VisualBasicMethodExtractor, - VisualBasicSelectionResult, + StatementSyntax, ExecutableStatementSyntax, ExpressionSyntax) @@ -23,13 +21,11 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ExtractMethod Public Sub New() End Sub - Protected Overrides Function CreateSelectionValidator(document As SemanticDocument, - textSpan As TextSpan, - localFunction As Boolean) As VisualBasicSelectionValidator + Protected Overrides Function CreateSelectionValidator(document As SemanticDocument, textSpan As TextSpan, localFunction As Boolean) As SelectionValidator Return New VisualBasicSelectionValidator(document, textSpan) End Function - Protected Overrides Function CreateMethodExtractor(selectionResult As VisualBasicSelectionResult, options As ExtractMethodGenerationOptions, localFunction As Boolean) As VisualBasicMethodExtractor + Protected Overrides Function CreateMethodExtractor(selectionResult As SelectionResult, options As ExtractMethodGenerationOptions, localFunction As Boolean) As MethodExtractor Return New VisualBasicMethodExtractor(selectionResult, options) End Function End Class diff --git a/src/Features/VisualBasic/Portable/ExtractMethod/VisualBasicMethodExtractor.Analyzer.vb b/src/Features/VisualBasic/Portable/ExtractMethod/VisualBasicMethodExtractor.Analyzer.vb index cb2eaa30938b7..141269b7903f1 100644 --- a/src/Features/VisualBasic/Portable/ExtractMethod/VisualBasicMethodExtractor.Analyzer.vb +++ b/src/Features/VisualBasic/Portable/ExtractMethod/VisualBasicMethodExtractor.Analyzer.vb @@ -2,62 +2,50 @@ ' The .NET Foundation licenses this file to you under the MIT license. ' See the LICENSE file in the project root for more information. +Imports System.Collections.Immutable Imports System.Threading Imports Microsoft.CodeAnalysis -Imports Microsoft.CodeAnalysis.ExtractMethod Imports Microsoft.CodeAnalysis.VisualBasic.Symbols Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Namespace Microsoft.CodeAnalysis.VisualBasic.ExtractMethod - Partial Friend Class VisualBasicMethodExtractor - Private Class VisualBasicAnalyzer - Inherits Analyzer - - Private Shared ReadOnly s_nonNoisySyntaxKindSet As HashSet(Of Integer) = New HashSet(Of Integer) From {SyntaxKind.WhitespaceTrivia, SyntaxKind.EndOfLineTrivia} - - Public Shared Function AnalyzeResult(currentSelectionResult As VisualBasicSelectionResult, cancellationToken As CancellationToken) As AnalyzerResult - Dim analyzer = New VisualBasicAnalyzer(currentSelectionResult, cancellationToken) - Return analyzer.Analyze() - End Function - - Public Sub New(currentSelectionResult As VisualBasicSelectionResult, cancellationToken As CancellationToken) - MyBase.New(currentSelectionResult, localFunction:=False, cancellationToken) - End Sub - - Protected Overrides ReadOnly Property TreatOutAsRef As Boolean = True - - Protected Overrides Function CreateFromSymbol( - compilation As Compilation, symbol As ISymbol, - type As ITypeSymbol, style As VariableStyle, requiresDeclarationExpressionRewrite As Boolean) As VariableInfo - If symbol.IsFunctionValue() AndAlso style.ParameterStyle.DeclarationBehavior <> DeclarationBehavior.None Then - Contract.ThrowIfFalse(style.ParameterStyle.DeclarationBehavior = DeclarationBehavior.MoveIn OrElse style.ParameterStyle.DeclarationBehavior = DeclarationBehavior.SplitIn) - style = AlwaysReturn(style) - End If - - Return CreateFromSymbolCommon(Of LocalDeclarationStatementSyntax)(compilation, symbol, type, style, s_nonNoisySyntaxKindSet) - End Function - - Protected Overrides Function GetRangeVariableType(semanticModel As SemanticModel, symbol As IRangeVariableSymbol) As ITypeSymbol - Dim info = semanticModel.GetSpeculativeTypeInfo(Me.SelectionResult.FinalSpan.Start, SyntaxFactory.ParseName(symbol.Name), SpeculativeBindingOption.BindAsExpression) - If info.Type.IsErrorType() Then - Return Nothing - End If - - Return If(info.ConvertedType.IsObjectType(), info.ConvertedType, info.Type) - End Function - - Protected Overrides Function ContainsReturnStatementInSelectedCode(jumpOutOfRegionStatements As IEnumerable(Of SyntaxNode)) As Boolean - Return jumpOutOfRegionStatements.Where(Function(n) TypeOf n Is ReturnStatementSyntax OrElse TypeOf n Is ExitStatementSyntax).Any() - End Function - - Protected Overrides Function ReadOnlyFieldAllowed() As Boolean - Dim methodBlock = Me.SelectionResult.GetContainingScopeOf(Of MethodBlockBaseSyntax)() - If methodBlock Is Nothing Then - Return True - End If - - Return Not TypeOf methodBlock.BlockStatement Is SubNewStatementSyntax - End Function + Partial Friend NotInheritable Class VisualBasicExtractMethodService + Partial Friend Class VisualBasicMethodExtractor + Private Class VisualBasicAnalyzer + Inherits Analyzer + + Public Sub New(currentSelectionResult As SelectionResult, cancellationToken As CancellationToken) + MyBase.New(currentSelectionResult, localFunction:=False, cancellationToken) + End Sub + + Protected Overrides ReadOnly Property TreatOutAsRef As Boolean = True + + Protected Overrides Function IsInPrimaryConstructorBaseType() As Boolean + Return False + End Function + + Protected Overrides Function GetRangeVariableType(symbol As IRangeVariableSymbol) As ITypeSymbol + Dim info = Me.SemanticModel.GetSpeculativeTypeInfo(Me.SelectionResult.FinalSpan.Start, SyntaxFactory.ParseName(symbol.Name), SpeculativeBindingOption.BindAsExpression) + If info.Type.IsErrorType() Then + Return Nothing + End If + + Return If(info.ConvertedType.IsObjectType(), info.ConvertedType, info.Type) + End Function + + Protected Overrides Function ContainsReturnStatementInSelectedCode(exitPoints As ImmutableArray(Of SyntaxNode)) As Boolean + Return exitPoints.Any(Function(n) TypeOf n Is ReturnStatementSyntax OrElse TypeOf n Is ExitStatementSyntax) + End Function + + Protected Overrides Function ReadOnlyFieldAllowed() As Boolean + Dim methodBlock = Me.SelectionResult.GetContainingScopeOf(Of MethodBlockBaseSyntax)() + If methodBlock Is Nothing Then + Return True + End If + + Return TypeOf methodBlock.BlockStatement IsNot SubNewStatementSyntax + End Function + End Class End Class End Class End Namespace diff --git a/src/Features/VisualBasic/Portable/ExtractMethod/VisualBasicMethodExtractor.PostProcessor.vb b/src/Features/VisualBasic/Portable/ExtractMethod/VisualBasicMethodExtractor.PostProcessor.vb index 07ba4e387b4c9..fd326978e6a6f 100644 --- a/src/Features/VisualBasic/Portable/ExtractMethod/VisualBasicMethodExtractor.PostProcessor.vb +++ b/src/Features/VisualBasic/Portable/ExtractMethod/VisualBasicMethodExtractor.PostProcessor.vb @@ -8,242 +8,244 @@ Imports Microsoft.CodeAnalysis.VisualBasic Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Namespace Microsoft.CodeAnalysis.VisualBasic.ExtractMethod - Partial Friend Class VisualBasicMethodExtractor - Private Class PostProcessor - Private ReadOnly _semanticModel As SemanticModel - Private ReadOnly _contextPosition As Integer + Partial Friend NotInheritable Class VisualBasicExtractMethodService + Partial Friend Class VisualBasicMethodExtractor + Private Class PostProcessor + Private ReadOnly _semanticModel As SemanticModel + Private ReadOnly _contextPosition As Integer + + Public Sub New(semanticModel As SemanticModel, contextPosition As Integer) + Contract.ThrowIfNull(semanticModel) + + Me._semanticModel = semanticModel + Me._contextPosition = contextPosition + End Sub + + Public Function MergeDeclarationStatements(statements As ImmutableArray(Of StatementSyntax)) As ImmutableArray(Of StatementSyntax) + If statements.FirstOrDefault() Is Nothing Then + Return statements + End If - Public Sub New(semanticModel As SemanticModel, contextPosition As Integer) - Contract.ThrowIfNull(semanticModel) + Return MergeDeclarationStatementsWorker(statements) + End Function - Me._semanticModel = semanticModel - Me._contextPosition = contextPosition - End Sub + Private Function MergeDeclarationStatementsWorker(statements As ImmutableArray(Of StatementSyntax)) As ImmutableArray(Of StatementSyntax) + Dim declarationStatements = New List(Of StatementSyntax)() - Public Function MergeDeclarationStatements(statements As ImmutableArray(Of StatementSyntax)) As ImmutableArray(Of StatementSyntax) - If statements.FirstOrDefault() Is Nothing Then - Return statements - End If + Dim map = New Dictionary(Of ITypeSymbol, List(Of LocalDeclarationStatementSyntax))() + For Each statement In statements + If Not IsDeclarationMergable(statement) Then + For Each declStatement In GetMergedDeclarationStatements(map) + declarationStatements.Add(declStatement) + Next declStatement - Return MergeDeclarationStatementsWorker(statements) - End Function + declarationStatements.Add(statement) + Continue For + End If - Private Function MergeDeclarationStatementsWorker(statements As ImmutableArray(Of StatementSyntax)) As ImmutableArray(Of StatementSyntax) - Dim declarationStatements = New List(Of StatementSyntax)() + AppendDeclarationStatementToMap(TryCast(statement, LocalDeclarationStatementSyntax), map) + Next statement - Dim map = New Dictionary(Of ITypeSymbol, List(Of LocalDeclarationStatementSyntax))() - For Each statement In statements - If Not IsDeclarationMergable(statement) Then + ' merge leftover + If map.Count > 0 Then For Each declStatement In GetMergedDeclarationStatements(map) declarationStatements.Add(declStatement) Next declStatement - - declarationStatements.Add(statement) - Continue For End If - AppendDeclarationStatementToMap(TryCast(statement, LocalDeclarationStatementSyntax), map) - Next statement - - ' merge leftover - If map.Count > 0 Then - For Each declStatement In GetMergedDeclarationStatements(map) - declarationStatements.Add(declStatement) - Next declStatement - End If - - Return declarationStatements.ToImmutableArray() - End Function - - Private Sub AppendDeclarationStatementToMap(statement As LocalDeclarationStatementSyntax, map As Dictionary(Of ITypeSymbol, List(Of LocalDeclarationStatementSyntax))) - Contract.ThrowIfNull(statement) - Contract.ThrowIfFalse(statement.Declarators.Count = 1) - - Dim declarator = statement.Declarators(0) - Dim symbolInfo = Me._semanticModel.GetSpeculativeSymbolInfo(Me._contextPosition, declarator.AsClause.Type, SpeculativeBindingOption.BindAsTypeOrNamespace) - Dim type = TryCast(symbolInfo.Symbol, ITypeSymbol) - Contract.ThrowIfNull(type) - - map.GetOrAdd(type, Function() New List(Of LocalDeclarationStatementSyntax)()).Add(statement) - End Sub + Return declarationStatements.ToImmutableArray() + End Function + + Private Sub AppendDeclarationStatementToMap(statement As LocalDeclarationStatementSyntax, map As Dictionary(Of ITypeSymbol, List(Of LocalDeclarationStatementSyntax))) + Contract.ThrowIfNull(statement) + Contract.ThrowIfFalse(statement.Declarators.Count = 1) + + Dim declarator = statement.Declarators(0) + Dim symbolInfo = Me._semanticModel.GetSpeculativeSymbolInfo(Me._contextPosition, declarator.AsClause.Type, SpeculativeBindingOption.BindAsTypeOrNamespace) + Dim type = TryCast(symbolInfo.Symbol, ITypeSymbol) + Contract.ThrowIfNull(type) + + map.GetOrAdd(type, Function() New List(Of LocalDeclarationStatementSyntax)()).Add(statement) + End Sub + + Private Shared Function GetMergedDeclarationStatements(map As Dictionary(Of ITypeSymbol, List(Of LocalDeclarationStatementSyntax))) As IEnumerable(Of LocalDeclarationStatementSyntax) + Dim declarationStatements = New List(Of LocalDeclarationStatementSyntax)() + + For Each keyValuePair In map + Contract.ThrowIfFalse(keyValuePair.Value.Count > 0) + + ' merge all variable decl for current type + Dim variables = New List(Of ModifiedIdentifierSyntax)() + For Each statement In keyValuePair.Value + For Each variable In statement.Declarators(0).Names + variables.Add(variable) + Next variable + Next statement + + ' and create one decl statement + ' use type name from the first decl statement + Dim firstDeclaration = keyValuePair.Value.First() + declarationStatements.Add( + SyntaxFactory.LocalDeclarationStatement(firstDeclaration.Modifiers, + SyntaxFactory.SingletonSeparatedList( + SyntaxFactory.VariableDeclarator(SyntaxFactory.SeparatedList(variables)).WithAsClause(firstDeclaration.Declarators(0).AsClause)) + )) + Next keyValuePair + + map.Clear() + + Return declarationStatements + End Function + + Private Function IsDeclarationMergable(statement As StatementSyntax) As Boolean + Contract.ThrowIfNull(statement) + + ' to be mergable, statement must be + ' 1. decl statement without any extra info + ' 2. no initialization on any of its decls + ' 3. no trivia except whitespace + ' 4. type must be known + + Dim declarationStatement = TryCast(statement, LocalDeclarationStatementSyntax) + If declarationStatement Is Nothing Then + Return False + End If - Private Shared Function GetMergedDeclarationStatements(map As Dictionary(Of ITypeSymbol, List(Of LocalDeclarationStatementSyntax))) As IEnumerable(Of LocalDeclarationStatementSyntax) - Dim declarationStatements = New List(Of LocalDeclarationStatementSyntax)() + If declarationStatement.Modifiers.Any(SyntaxKind.ConstKeyword) OrElse + declarationStatement.IsMissing Then + Return False + End If - For Each keyValuePair In map - Contract.ThrowIfFalse(keyValuePair.Value.Count > 0) + If ContainsAnyInitialization(declarationStatement) Then + Return False + End If - ' merge all variable decl for current type - Dim variables = New List(Of ModifiedIdentifierSyntax)() - For Each statement In keyValuePair.Value - For Each variable In statement.Declarators(0).Names - variables.Add(variable) - Next variable - Next statement + If Not ContainsOnlyWhitespaceTrivia(declarationStatement) Then + Return False + End If - ' and create one decl statement - ' use type name from the first decl statement - Dim firstDeclaration = keyValuePair.Value.First() - declarationStatements.Add( - SyntaxFactory.LocalDeclarationStatement(firstDeclaration.Modifiers, - SyntaxFactory.SingletonSeparatedList( - SyntaxFactory.VariableDeclarator(SyntaxFactory.SeparatedList(variables)).WithAsClause(firstDeclaration.Declarators(0).AsClause)) - )) - Next keyValuePair + If declarationStatement.Declarators.Count <> 1 Then + Return False + End If - map.Clear() + If declarationStatement.Declarators(0).AsClause Is Nothing Then + Return False + End If - Return declarationStatements - End Function + Dim symbolInfo = Me._semanticModel.GetSpeculativeSymbolInfo(Me._contextPosition, declarationStatement.Declarators(0).AsClause.Type, SpeculativeBindingOption.BindAsTypeOrNamespace) + Dim type = TryCast(symbolInfo.Symbol, ITypeSymbol) + If type Is Nothing OrElse + type.TypeKind = TypeKind.Error OrElse + type.TypeKind = TypeKind.Unknown Then + Return False + End If - Private Function IsDeclarationMergable(statement As StatementSyntax) As Boolean - Contract.ThrowIfNull(statement) + Return True + End Function - ' to be mergable, statement must be - ' 1. decl statement without any extra info - ' 2. no initialization on any of its decls - ' 3. no trivia except whitespace - ' 4. type must be known + Private Shared Function ContainsAnyInitialization(statement As LocalDeclarationStatementSyntax) As Boolean + For Each variable In statement.Declarators + If variable.Initializer IsNot Nothing Then + Return True + End If + Next variable - Dim declarationStatement = TryCast(statement, LocalDeclarationStatementSyntax) - If declarationStatement Is Nothing Then Return False - End If + End Function + + Private Shared Function ContainsOnlyWhitespaceTrivia(statement As StatementSyntax) As Boolean + For Each token In statement.DescendantTokens() + If Not ContainsOnlyWhitespaceTrivia(token) Then + Return False + End If + Next token + + Return True + End Function + + Private Shared Function ContainsOnlyWhitespaceTrivia(token As SyntaxToken) As Boolean + For Each trivia In token.LeadingTrivia.Concat(token.TrailingTrivia) + If trivia.Kind <> SyntaxKind.WhitespaceTrivia AndAlso trivia.Kind <> SyntaxKind.EndOfLineTrivia Then + Return False + End If + Next trivia + + Return True + End Function + + Public Shared Function RemoveDeclarationAssignmentPattern(statements As ImmutableArray(Of StatementSyntax)) As ImmutableArray(Of StatementSyntax) + If statements.Count() < 2 Then + Return statements + End If - If declarationStatement.Modifiers.Any(SyntaxKind.ConstKeyword) OrElse - declarationStatement.IsMissing Then - Return False - End If + ' if we have inline temp variable as service, we could just use that service here. + ' since it is not a service right now, do very simple clean up + Dim declaration = TryCast(statements(0), LocalDeclarationStatementSyntax) + Dim assignment = TryCast(statements(1), AssignmentStatementSyntax) + If declaration Is Nothing OrElse assignment Is Nothing Then + Return statements + End If - If ContainsAnyInitialization(declarationStatement) Then - Return False - End If + If ContainsAnyInitialization(declaration) OrElse + declaration.Modifiers.Any(Function(m) m.Kind <> SyntaxKind.DimKeyword) OrElse + declaration.Declarators.Count <> 1 OrElse + declaration.Declarators(0).Names.Count <> 1 OrElse + assignment.Left Is Nothing OrElse + assignment.Right Is Nothing Then + Return statements + End If - If Not ContainsOnlyWhitespaceTrivia(declarationStatement) Then - Return False - End If + If Not ContainsOnlyWhitespaceTrivia(declaration) OrElse + Not ContainsOnlyWhitespaceTrivia(assignment) Then + Return statements + End If - If declarationStatement.Declarators.Count <> 1 Then - Return False - End If + Dim variableName = declaration.Declarators(0).Names(0).ToString() - If declarationStatement.Declarators(0).AsClause Is Nothing Then - Return False - End If + If assignment.Left.ToString() <> variableName Then + Return statements + End If - Dim symbolInfo = Me._semanticModel.GetSpeculativeSymbolInfo(Me._contextPosition, declarationStatement.Declarators(0).AsClause.Type, SpeculativeBindingOption.BindAsTypeOrNamespace) - Dim type = TryCast(symbolInfo.Symbol, ITypeSymbol) - If type Is Nothing OrElse - type.TypeKind = TypeKind.Error OrElse - type.TypeKind = TypeKind.Unknown Then - Return False - End If + Dim variable = declaration.Declarators(0).WithoutTrailingTrivia().WithInitializer(SyntaxFactory.EqualsValue(assignment.Right)) + Dim newDeclaration = declaration.WithDeclarators(SyntaxFactory.SingletonSeparatedList(variable)) - Return True - End Function + Return SpecializedCollections.SingletonEnumerable(Of StatementSyntax)(newDeclaration).Concat(statements.Skip(2)).ToImmutableArray() + End Function - Private Shared Function ContainsAnyInitialization(statement As LocalDeclarationStatementSyntax) As Boolean - For Each variable In statement.Declarators - If variable.Initializer IsNot Nothing Then - Return True + Public Shared Function RemoveInitializedDeclarationAndReturnPattern(statements As ImmutableArray(Of StatementSyntax)) As ImmutableArray(Of StatementSyntax) + ' if we have inline temp variable as service, we could just use that service here. + ' since it is not a service right now, do very simple clean up + If statements.Count() <> 2 Then + Return statements End If - Next variable - Return False - End Function + Dim declaration = TryCast(statements.ElementAtOrDefault(0), LocalDeclarationStatementSyntax) + Dim returnStatement = TryCast(statements.ElementAtOrDefault(1), ReturnStatementSyntax) + If declaration Is Nothing OrElse returnStatement Is Nothing Then + Return statements + End If - Private Shared Function ContainsOnlyWhitespaceTrivia(statement As StatementSyntax) As Boolean - For Each token In statement.DescendantTokens() - If Not ContainsOnlyWhitespaceTrivia(token) Then - Return False + If declaration.Declarators.Count <> 1 OrElse + declaration.Declarators(0).Names.Count <> 1 OrElse + declaration.Declarators(0).Initializer Is Nothing OrElse + returnStatement.Expression Is Nothing Then + Return statements End If - Next token - Return True - End Function + If Not ContainsOnlyWhitespaceTrivia(declaration) OrElse + Not ContainsOnlyWhitespaceTrivia(returnStatement) Then + Return statements + End If - Private Shared Function ContainsOnlyWhitespaceTrivia(token As SyntaxToken) As Boolean - For Each trivia In token.LeadingTrivia.Concat(token.TrailingTrivia) - If trivia.Kind <> SyntaxKind.WhitespaceTrivia AndAlso trivia.Kind <> SyntaxKind.EndOfLineTrivia Then - Return False + Dim variableName = declaration.Declarators(0).Names(0).ToString() + If returnStatement.Expression.ToString() <> variableName Then + Return statements End If - Next trivia - - Return True - End Function - - Public Shared Function RemoveDeclarationAssignmentPattern(statements As ImmutableArray(Of StatementSyntax)) As ImmutableArray(Of StatementSyntax) - If statements.Count() < 2 Then - Return statements - End If - - ' if we have inline temp variable as service, we could just use that service here. - ' since it is not a service right now, do very simple clean up - Dim declaration = TryCast(statements(0), LocalDeclarationStatementSyntax) - Dim assignment = TryCast(statements(1), AssignmentStatementSyntax) - If declaration Is Nothing OrElse assignment Is Nothing Then - Return statements - End If - - If ContainsAnyInitialization(declaration) OrElse - declaration.Modifiers.Any(Function(m) m.Kind <> SyntaxKind.DimKeyword) OrElse - declaration.Declarators.Count <> 1 OrElse - declaration.Declarators(0).Names.Count <> 1 OrElse - assignment.Left Is Nothing OrElse - assignment.Right Is Nothing Then - Return statements - End If - - If Not ContainsOnlyWhitespaceTrivia(declaration) OrElse - Not ContainsOnlyWhitespaceTrivia(assignment) Then - Return statements - End If - - Dim variableName = declaration.Declarators(0).Names(0).ToString() - - If assignment.Left.ToString() <> variableName Then - Return statements - End If - - Dim variable = declaration.Declarators(0).WithoutTrailingTrivia().WithInitializer(SyntaxFactory.EqualsValue(assignment.Right)) - Dim newDeclaration = declaration.WithDeclarators(SyntaxFactory.SingletonSeparatedList(variable)) - - Return SpecializedCollections.SingletonEnumerable(Of StatementSyntax)(newDeclaration).Concat(statements.Skip(2)).ToImmutableArray() - End Function - - Public Shared Function RemoveInitializedDeclarationAndReturnPattern(statements As ImmutableArray(Of StatementSyntax)) As ImmutableArray(Of StatementSyntax) - ' if we have inline temp variable as service, we could just use that service here. - ' since it is not a service right now, do very simple clean up - If statements.Count() <> 2 Then - Return statements - End If - - Dim declaration = TryCast(statements.ElementAtOrDefault(0), LocalDeclarationStatementSyntax) - Dim returnStatement = TryCast(statements.ElementAtOrDefault(1), ReturnStatementSyntax) - If declaration Is Nothing OrElse returnStatement Is Nothing Then - Return statements - End If - - If declaration.Declarators.Count <> 1 OrElse - declaration.Declarators(0).Names.Count <> 1 OrElse - declaration.Declarators(0).Initializer Is Nothing OrElse - returnStatement.Expression Is Nothing Then - Return statements - End If - - If Not ContainsOnlyWhitespaceTrivia(declaration) OrElse - Not ContainsOnlyWhitespaceTrivia(returnStatement) Then - Return statements - End If - - Dim variableName = declaration.Declarators(0).Names(0).ToString() - If returnStatement.Expression.ToString() <> variableName Then - Return statements - End If - - Return SpecializedCollections.SingletonEnumerable(Of StatementSyntax)( - SyntaxFactory.ReturnStatement(declaration.Declarators(0).Initializer.Value)).Concat(statements.Skip(2)).ToImmutableArray() - End Function + + Return SpecializedCollections.SingletonEnumerable(Of StatementSyntax)( + SyntaxFactory.ReturnStatement(declaration.Declarators(0).Initializer.Value)).Concat(statements.Skip(2)).ToImmutableArray() + End Function + End Class End Class End Class End Namespace diff --git a/src/Features/VisualBasic/Portable/ExtractMethod/VisualBasicMethodExtractor.TriviaResult.vb b/src/Features/VisualBasic/Portable/ExtractMethod/VisualBasicMethodExtractor.TriviaResult.vb index 7b0a3b0b0dcec..c6368e296b332 100644 --- a/src/Features/VisualBasic/Portable/ExtractMethod/VisualBasicMethodExtractor.TriviaResult.vb +++ b/src/Features/VisualBasic/Portable/ExtractMethod/VisualBasicMethodExtractor.TriviaResult.vb @@ -8,197 +8,189 @@ Imports Microsoft.CodeAnalysis.ExtractMethod Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Namespace Microsoft.CodeAnalysis.VisualBasic.ExtractMethod - Partial Friend Class VisualBasicMethodExtractor - Private Class VisualBasicTriviaResult - Inherits TriviaResult - - Public Shared Async Function ProcessAsync(selectionResult As VisualBasicSelectionResult, cancellationToken As CancellationToken) As Task(Of VisualBasicTriviaResult) - Dim preservationService = selectionResult.SemanticDocument.Document.Project.Services.GetService(Of ISyntaxTriviaService)() - Dim root = selectionResult.SemanticDocument.Root - Dim result = preservationService.SaveTriviaAroundSelection(root, selectionResult.FinalSpan) - - Return New VisualBasicTriviaResult( - Await selectionResult.SemanticDocument.WithSyntaxRootAsync(result.Root, cancellationToken).ConfigureAwait(False), - result) - End Function - - Private Sub New(document As SemanticDocument, result As ITriviaSavedResult) - MyBase.New(document, result, SyntaxKind.EndOfLineTrivia, SyntaxKind.WhitespaceTrivia) - End Sub - - Protected Overrides Function GetAnnotationResolver(callsite As SyntaxNode, method As SyntaxNode) As AnnotationResolver - Dim methodDefinition = TryCast(method, MethodBlockBaseSyntax) - If callsite Is Nothing OrElse methodDefinition Is Nothing Then - Return Nothing - End If - - Return Function(node, location, annotation) AnnotationResolver(node, location, annotation, callsite, methodDefinition) - End Function - - Protected Overrides Function GetTriviaResolver(method As SyntaxNode) As TriviaResolver - Dim methodDefinition = TryCast(method, MethodBlockBaseSyntax) - If methodDefinition Is Nothing Then - Return Nothing - End If - - Return Function(location, tokenPair, triviaMap) TriviaResolver(location, tokenPair, triviaMap, methodDefinition) - End Function - - Private Shared Function AnnotationResolver( - node As SyntaxNode, - location As TriviaLocation, - annotation As SyntaxAnnotation, - callsite As SyntaxNode, - method As MethodBlockBaseSyntax) As SyntaxToken - - Dim token = node.GetAnnotatedNodesAndTokens(annotation).FirstOrDefault().AsToken() - If token.Kind <> 0 Then - Return token - End If - - Select Case location - Case TriviaLocation.BeforeBeginningOfSpan - Return callsite.GetFirstToken(includeZeroWidth:=True).GetPreviousToken(includeZeroWidth:=True) - Case TriviaLocation.AfterEndOfSpan - Return callsite.GetLastToken(includeZeroWidth:=True).GetNextToken(includeZeroWidth:=True) - Case TriviaLocation.AfterBeginningOfSpan - Return method.BlockStatement.GetLastToken(includeZeroWidth:=True).GetNextToken(includeZeroWidth:=True) - Case TriviaLocation.BeforeEndOfSpan - Return method.EndBlockStatement.GetFirstToken(includeZeroWidth:=True).GetPreviousToken(includeZeroWidth:=True) - End Select - - throw ExceptionUtilities.UnexpectedValue(location) - End Function - - Private Function TriviaResolver( - location As TriviaLocation, - tokenPair As PreviousNextTokenPair, - triviaMap As Dictionary(Of SyntaxToken, LeadingTrailingTriviaPair), - method As MethodBlockBaseSyntax) As IEnumerable(Of SyntaxTrivia) - - ' Resolve trivia at the edge of the selection. simple case is easy to deal with, but complex cases where - ' elastic trivia and user trivia are mixed (hybrid case) and we want to preserve some part of user coding style - ' but not others can be dealt with here. - - ' method has no statement in them. so basically two trivia list now pointing to same thing. - If tokenPair.PreviousToken = method.BlockStatement.GetLastToken(includeZeroWidth:=True) AndAlso - tokenPair.NextToken = method.EndBlockStatement.GetFirstToken(includeZeroWidth:=True) Then - Return If(location = TriviaLocation.AfterBeginningOfSpan, - SpecializedCollections.SingletonEnumerable(Of SyntaxTrivia)(SyntaxFactory.ElasticMarker), - SpecializedCollections.EmptyEnumerable(Of SyntaxTrivia)()) - End If - - Dim previousTriviaPair As LeadingTrailingTriviaPair = Nothing - Dim trailingTrivia = If(triviaMap.TryGetValue(tokenPair.PreviousToken, previousTriviaPair), - previousTriviaPair.TrailingTrivia, SpecializedCollections.EmptyEnumerable(Of SyntaxTrivia)()) - - Dim nextTriviaPair As LeadingTrailingTriviaPair = Nothing - Dim leadingTrivia = If(triviaMap.TryGetValue(tokenPair.NextToken, nextTriviaPair), - nextTriviaPair.LeadingTrivia, SpecializedCollections.EmptyEnumerable(Of SyntaxTrivia)()) - - Dim list = trailingTrivia.Concat(leadingTrivia) - - Select Case location - Case TriviaLocation.BeforeBeginningOfSpan - Return FilterTriviaList(RemoveTrailingElasticTrivia(tokenPair.PreviousToken, list, tokenPair.NextToken)) - Case TriviaLocation.AfterEndOfSpan - Return FilterTriviaList(RemoveLeadingElasticTrivia(RemoveLeadingElasticTrivia(tokenPair.PreviousToken, list, tokenPair.NextToken))) - Case TriviaLocation.AfterBeginningOfSpan - Return FilterTriviaList(RemoveLeadingElasticTrivia(tokenPair.PreviousToken, list, tokenPair.NextToken)) - Case TriviaLocation.BeforeEndOfSpan - Return FilterTriviaList(RemoveTrailingElasticTrivia(tokenPair.PreviousToken, list, tokenPair.NextToken)) - End Select - - throw ExceptionUtilities.UnexpectedValue(location) - End Function - - Private Shared Function RemoveTrailingElasticTrivia( - token1 As SyntaxToken, list As IEnumerable(Of SyntaxTrivia), token2 As SyntaxToken) As IEnumerable(Of SyntaxTrivia) - - ' special case for skipped token trivia - ' formatter doesn't touch tokens that have skipped tokens in-between. so, we need to take care of such case ourselves - If list.Any(Function(t) t.RawKind = SyntaxKind.SkippedTokensTrivia) Then - Return RemoveElasticAfterColon( - token1.TrailingTrivia.Concat(list).Concat(ReplaceElasticToEndOfLine(token2.LeadingTrivia))) - End If - - If token1.IsLastTokenOfStatement() Then - Return RemoveElasticAfterColon(token1.TrailingTrivia.Concat(list).Concat(token2.LeadingTrivia)) - End If - - Return token1.TrailingTrivia.Concat(list) - End Function - - Private Shared Function RemoveLeadingElasticTrivia( - token1 As SyntaxToken, list As IEnumerable(Of SyntaxTrivia), token2 As SyntaxToken) As IEnumerable(Of SyntaxTrivia) - - If token1.IsLastTokenOfStatement() Then - If SingleLineStatement(token1) Then - Return list.Concat(token2.LeadingTrivia) + Partial Friend NotInheritable Class VisualBasicExtractMethodService + Partial Friend Class VisualBasicMethodExtractor + Private Class VisualBasicTriviaResult + Inherits TriviaResult + + Public Sub New(document As SemanticDocument, result As ITriviaSavedResult) + MyBase.New(document, result, SyntaxKind.EndOfLineTrivia, SyntaxKind.WhitespaceTrivia) + End Sub + + Protected Overrides Function GetAnnotationResolver(callsite As SyntaxNode, method As SyntaxNode) As AnnotationResolver + Dim methodDefinition = TryCast(method, MethodBlockBaseSyntax) + If callsite Is Nothing OrElse methodDefinition Is Nothing Then + Return Nothing End If - Return RemoveElasticAfterColon(token1.TrailingTrivia.Concat(list).Concat(token2.LeadingTrivia)) - End If + Return Function(node, location, annotation) AnnotationResolver(node, location, annotation, callsite, methodDefinition) + End Function - Return list.Concat(token2.LeadingTrivia) - End Function + Protected Overrides Function GetTriviaResolver(method As SyntaxNode) As TriviaResolver + Dim methodDefinition = TryCast(method, MethodBlockBaseSyntax) + If methodDefinition Is Nothing Then + Return Nothing + End If - Private Shared Function RemoveLeadingElasticTrivia(list As IEnumerable(Of SyntaxTrivia)) As IEnumerable(Of SyntaxTrivia) - ' remove leading elastic trivia if it is followed by noisy trivia - Dim trivia = list.FirstOrDefault() - If Not trivia.IsElastic() Then - Return list - End If + Return Function(location, tokenPair, triviaMap) TriviaResolver(location, tokenPair, triviaMap, methodDefinition) + End Function + + Private Shared Function AnnotationResolver( + node As SyntaxNode, + location As TriviaLocation, + annotation As SyntaxAnnotation, + callsite As SyntaxNode, + method As MethodBlockBaseSyntax) As SyntaxToken + + Dim token = node.GetAnnotatedNodesAndTokens(annotation).FirstOrDefault().AsToken() + If token.Kind <> 0 Then + Return token + End If + + Select Case location + Case TriviaLocation.BeforeBeginningOfSpan + Return callsite.GetFirstToken(includeZeroWidth:=True).GetPreviousToken(includeZeroWidth:=True) + Case TriviaLocation.AfterEndOfSpan + Return callsite.GetLastToken(includeZeroWidth:=True).GetNextToken(includeZeroWidth:=True) + Case TriviaLocation.AfterBeginningOfSpan + Return method.BlockStatement.GetLastToken(includeZeroWidth:=True).GetNextToken(includeZeroWidth:=True) + Case TriviaLocation.BeforeEndOfSpan + Return method.EndBlockStatement.GetFirstToken(includeZeroWidth:=True).GetPreviousToken(includeZeroWidth:=True) + End Select + + Throw ExceptionUtilities.UnexpectedValue(location) + End Function + + Private Function TriviaResolver( + location As TriviaLocation, + tokenPair As PreviousNextTokenPair, + triviaMap As Dictionary(Of SyntaxToken, LeadingTrailingTriviaPair), + method As MethodBlockBaseSyntax) As IEnumerable(Of SyntaxTrivia) + + ' Resolve trivia at the edge of the selection. simple case is easy to deal with, but complex cases where + ' elastic trivia and user trivia are mixed (hybrid case) and we want to preserve some part of user coding style + ' but not others can be dealt with here. + + ' method has no statement in them. so basically two trivia list now pointing to same thing. + If tokenPair.PreviousToken = method.BlockStatement.GetLastToken(includeZeroWidth:=True) AndAlso + tokenPair.NextToken = method.EndBlockStatement.GetFirstToken(includeZeroWidth:=True) Then + Return If(location = TriviaLocation.AfterBeginningOfSpan, + SpecializedCollections.SingletonEnumerable(Of SyntaxTrivia)(SyntaxFactory.ElasticMarker), + SpecializedCollections.EmptyEnumerable(Of SyntaxTrivia)()) + End If + + Dim previousTriviaPair As LeadingTrailingTriviaPair = Nothing + Dim trailingTrivia = If(triviaMap.TryGetValue(tokenPair.PreviousToken, previousTriviaPair), + previousTriviaPair.TrailingTrivia, SpecializedCollections.EmptyEnumerable(Of SyntaxTrivia)()) + + Dim nextTriviaPair As LeadingTrailingTriviaPair = Nothing + Dim leadingTrivia = If(triviaMap.TryGetValue(tokenPair.NextToken, nextTriviaPair), + nextTriviaPair.LeadingTrivia, SpecializedCollections.EmptyEnumerable(Of SyntaxTrivia)()) + + Dim list = trailingTrivia.Concat(leadingTrivia) + + Select Case location + Case TriviaLocation.BeforeBeginningOfSpan + Return FilterTriviaList(RemoveTrailingElasticTrivia(tokenPair.PreviousToken, list, tokenPair.NextToken)) + Case TriviaLocation.AfterEndOfSpan + Return FilterTriviaList(RemoveLeadingElasticTrivia(RemoveLeadingElasticTrivia(tokenPair.PreviousToken, list, tokenPair.NextToken))) + Case TriviaLocation.AfterBeginningOfSpan + Return FilterTriviaList(RemoveLeadingElasticTrivia(tokenPair.PreviousToken, list, tokenPair.NextToken)) + Case TriviaLocation.BeforeEndOfSpan + Return FilterTriviaList(RemoveTrailingElasticTrivia(tokenPair.PreviousToken, list, tokenPair.NextToken)) + End Select + + Throw ExceptionUtilities.UnexpectedValue(location) + End Function + + Private Shared Function RemoveTrailingElasticTrivia( + token1 As SyntaxToken, list As IEnumerable(Of SyntaxTrivia), token2 As SyntaxToken) As IEnumerable(Of SyntaxTrivia) + + ' special case for skipped token trivia + ' formatter doesn't touch tokens that have skipped tokens in-between. so, we need to take care of such case ourselves + If list.Any(Function(t) t.RawKind = SyntaxKind.SkippedTokensTrivia) Then + Return RemoveElasticAfterColon( + token1.TrailingTrivia.Concat(list).Concat(ReplaceElasticToEndOfLine(token2.LeadingTrivia))) + End If + + If token1.IsLastTokenOfStatement() Then + Return RemoveElasticAfterColon(token1.TrailingTrivia.Concat(list).Concat(token2.LeadingTrivia)) + End If + + Return token1.TrailingTrivia.Concat(list) + End Function + + Private Shared Function RemoveLeadingElasticTrivia( + token1 As SyntaxToken, list As IEnumerable(Of SyntaxTrivia), token2 As SyntaxToken) As IEnumerable(Of SyntaxTrivia) - For Each trivia In list.Skip(1) - If trivia.Kind = SyntaxKind.EndOfLineTrivia OrElse trivia.IsElastic() Then + If token1.IsLastTokenOfStatement() Then + If SingleLineStatement(token1) Then + Return list.Concat(token2.LeadingTrivia) + End If + + Return RemoveElasticAfterColon(token1.TrailingTrivia.Concat(list).Concat(token2.LeadingTrivia)) + End If + + Return list.Concat(token2.LeadingTrivia) + End Function + + Private Shared Function RemoveLeadingElasticTrivia(list As IEnumerable(Of SyntaxTrivia)) As IEnumerable(Of SyntaxTrivia) + ' remove leading elastic trivia if it is followed by noisy trivia + Dim trivia = list.FirstOrDefault() + If Not trivia.IsElastic() Then Return list - ElseIf trivia.Kind <> SyntaxKind.EndOfLineTrivia And trivia.Kind <> SyntaxKind.WhitespaceTrivia Then - Return list.Skip(1) End If - Next - - Return list - End Function - - Private Shared Function ReplaceElasticToEndOfLine(list As IEnumerable(Of SyntaxTrivia)) As IEnumerable(Of SyntaxTrivia) - Return list.Select(Function(t) If(t.IsElastic, SyntaxFactory.CarriageReturnLineFeed, t)) - End Function - - Private Shared Function SingleLineStatement(token As SyntaxToken) As Boolean - ' check whether given token is the last token of a single line statement - Dim singleLineIf = token.Parent.GetAncestor(Of SingleLineIfStatementSyntax)() - If singleLineIf IsNot Nothing Then - Return True - End If - - Dim singleLineLambda = token.Parent.GetAncestor(Of SingleLineLambdaExpressionSyntax)() - If singleLineLambda IsNot Nothing Then - Return True - End If - - Return False - End Function - - Private Shared Function RemoveElasticAfterColon(list As IEnumerable(Of SyntaxTrivia)) As IEnumerable(Of SyntaxTrivia) - ' make sure we don't have elastic trivia after colon trivia - Dim colon = False - Dim result = New List(Of SyntaxTrivia)() - - For Each trivia In list - If trivia.RawKind = SyntaxKind.ColonTrivia Then - colon = True + + For Each trivia In list.Skip(1) + If trivia.Kind = SyntaxKind.EndOfLineTrivia OrElse trivia.IsElastic() Then + Return list + ElseIf trivia.Kind <> SyntaxKind.EndOfLineTrivia And trivia.Kind <> SyntaxKind.WhitespaceTrivia Then + Return list.Skip(1) + End If + Next + + Return list + End Function + + Private Shared Function ReplaceElasticToEndOfLine(list As IEnumerable(Of SyntaxTrivia)) As IEnumerable(Of SyntaxTrivia) + Return list.Select(Function(t) If(t.IsElastic, SyntaxFactory.CarriageReturnLineFeed, t)) + End Function + + Private Shared Function SingleLineStatement(token As SyntaxToken) As Boolean + ' check whether given token is the last token of a single line statement + Dim singleLineIf = token.Parent.GetAncestor(Of SingleLineIfStatementSyntax)() + If singleLineIf IsNot Nothing Then + Return True End If - If colon AndAlso trivia.IsElastic() Then - Continue For + Dim singleLineLambda = token.Parent.GetAncestor(Of SingleLineLambdaExpressionSyntax)() + If singleLineLambda IsNot Nothing Then + Return True End If - result.Add(trivia) - Next + Return False + End Function + + Private Shared Function RemoveElasticAfterColon(list As IEnumerable(Of SyntaxTrivia)) As IEnumerable(Of SyntaxTrivia) + ' make sure we don't have elastic trivia after colon trivia + Dim colon = False + Dim result = New List(Of SyntaxTrivia)() + + For Each trivia In list + If trivia.RawKind = SyntaxKind.ColonTrivia Then + colon = True + End If + + If colon AndAlso trivia.IsElastic() Then + Continue For + End If + + result.Add(trivia) + Next - Return result - End Function + Return result + End Function + End Class End Class End Class End Namespace diff --git a/src/Features/VisualBasic/Portable/ExtractMethod/VisualBasicMethodExtractor.VisualBasicCodeGenerator.CallSiteContainerRewriter.vb b/src/Features/VisualBasic/Portable/ExtractMethod/VisualBasicMethodExtractor.VisualBasicCodeGenerator.CallSiteContainerRewriter.vb index 81f9a65062dcf..9a4ec7a0d9db6 100644 --- a/src/Features/VisualBasic/Portable/ExtractMethod/VisualBasicMethodExtractor.VisualBasicCodeGenerator.CallSiteContainerRewriter.vb +++ b/src/Features/VisualBasic/Portable/ExtractMethod/VisualBasicMethodExtractor.VisualBasicCodeGenerator.CallSiteContainerRewriter.vb @@ -7,402 +7,404 @@ Imports Microsoft.CodeAnalysis.VisualBasic Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Namespace Microsoft.CodeAnalysis.VisualBasic.ExtractMethod - Partial Friend Class VisualBasicMethodExtractor - Partial Private MustInherit Class VisualBasicCodeGenerator - Private Class CallSiteContainerRewriter - Inherits VisualBasicSyntaxRewriter - Private ReadOnly _outmostCallSiteContainer As SyntaxNode - Private ReadOnly _statementsOrFieldToInsert As IEnumerable(Of StatementSyntax) - Private ReadOnly _variableToRemoveMap As HashSet(Of SyntaxAnnotation) - Private ReadOnly _firstStatementOrFieldToReplace As StatementSyntax - Private ReadOnly _lastStatementOrFieldToReplace As StatementSyntax - - Private Shared ReadOnly s_removeAnnotation As SyntaxAnnotation = New SyntaxAnnotation() - - Public Sub New(outmostCallSiteContainer As SyntaxNode, - variableToRemoveMap As HashSet(Of SyntaxAnnotation), - firstStatementOrFieldToReplace As StatementSyntax, - lastStatementOrFieldToReplace As StatementSyntax, - statementsOrFieldToInsert As IEnumerable(Of StatementSyntax)) - Contract.ThrowIfNull(outmostCallSiteContainer) - Contract.ThrowIfNull(variableToRemoveMap) - Contract.ThrowIfNull(firstStatementOrFieldToReplace) - Contract.ThrowIfNull(lastStatementOrFieldToReplace) - Contract.ThrowIfTrue(statementsOrFieldToInsert.IsEmpty()) - - Me._outmostCallSiteContainer = outmostCallSiteContainer - - Me._variableToRemoveMap = variableToRemoveMap - Me._statementsOrFieldToInsert = statementsOrFieldToInsert - - Me._firstStatementOrFieldToReplace = firstStatementOrFieldToReplace - Me._lastStatementOrFieldToReplace = lastStatementOrFieldToReplace - - Contract.ThrowIfFalse(Me._firstStatementOrFieldToReplace.Parent Is Me._lastStatementOrFieldToReplace.Parent) - End Sub - - Public Function Generate() As SyntaxNode - Dim result = Visit(Me._outmostCallSiteContainer) - - ' remove any nodes annotated for removal - If result.ContainsAnnotations Then - Dim nodesToRemove = result.DescendantNodes(Function(n) n.ContainsAnnotations).Where(Function(n) n.HasAnnotation(s_removeAnnotation)) - result = result.RemoveNodes(nodesToRemove, SyntaxRemoveOptions.KeepNoTrivia) - End If - - Return result - End Function - - Private ReadOnly Property ContainerOfStatementsOrFieldToReplace() As SyntaxNode - Get - Return Me._firstStatementOrFieldToReplace.Parent - End Get - End Property - - Public Overrides Function VisitLocalDeclarationStatement(node As LocalDeclarationStatementSyntax) As SyntaxNode - node = CType(MyBase.VisitLocalDeclarationStatement(node), LocalDeclarationStatementSyntax) - - Dim expressionStatements = New List(Of StatementSyntax)() - Dim variableDeclarators = New List(Of VariableDeclaratorSyntax)() - Dim triviaList = New List(Of SyntaxTrivia)() - - If Not Me._variableToRemoveMap.ProcessLocalDeclarationStatement(node, expressionStatements, variableDeclarators, triviaList) Then + Partial Friend NotInheritable Class VisualBasicExtractMethodService + Partial Friend Class VisualBasicMethodExtractor + Partial Private MustInherit Class VisualBasicCodeGenerator + Private Class CallSiteContainerRewriter + Inherits VisualBasicSyntaxRewriter + Private ReadOnly _outmostCallSiteContainer As SyntaxNode + Private ReadOnly _statementsOrFieldToInsert As IEnumerable(Of StatementSyntax) + Private ReadOnly _variableToRemoveMap As HashSet(Of SyntaxAnnotation) + Private ReadOnly _firstStatementOrFieldToReplace As StatementSyntax + Private ReadOnly _lastStatementOrFieldToReplace As StatementSyntax + + Private Shared ReadOnly s_removeAnnotation As SyntaxAnnotation = New SyntaxAnnotation() + + Public Sub New(outmostCallSiteContainer As SyntaxNode, + variableToRemoveMap As HashSet(Of SyntaxAnnotation), + firstStatementOrFieldToReplace As StatementSyntax, + lastStatementOrFieldToReplace As StatementSyntax, + statementsOrFieldToInsert As IEnumerable(Of StatementSyntax)) + Contract.ThrowIfNull(outmostCallSiteContainer) + Contract.ThrowIfNull(variableToRemoveMap) + Contract.ThrowIfNull(firstStatementOrFieldToReplace) + Contract.ThrowIfNull(lastStatementOrFieldToReplace) + Contract.ThrowIfTrue(statementsOrFieldToInsert.IsEmpty()) + + Me._outmostCallSiteContainer = outmostCallSiteContainer + + Me._variableToRemoveMap = variableToRemoveMap + Me._statementsOrFieldToInsert = statementsOrFieldToInsert + + Me._firstStatementOrFieldToReplace = firstStatementOrFieldToReplace + Me._lastStatementOrFieldToReplace = lastStatementOrFieldToReplace + + Contract.ThrowIfFalse(Me._firstStatementOrFieldToReplace.Parent Is Me._lastStatementOrFieldToReplace.Parent) + End Sub + + Public Function Generate() As SyntaxNode + Dim result = Visit(Me._outmostCallSiteContainer) + + ' remove any nodes annotated for removal + If result.ContainsAnnotations Then + Dim nodesToRemove = result.DescendantNodes(Function(n) n.ContainsAnnotations).Where(Function(n) n.HasAnnotation(s_removeAnnotation)) + result = result.RemoveNodes(nodesToRemove, SyntaxRemoveOptions.KeepNoTrivia) + End If + + Return result + End Function + + Private ReadOnly Property ContainerOfStatementsOrFieldToReplace() As SyntaxNode + Get + Return Me._firstStatementOrFieldToReplace.Parent + End Get + End Property + + Public Overrides Function VisitLocalDeclarationStatement(node As LocalDeclarationStatementSyntax) As SyntaxNode + node = CType(MyBase.VisitLocalDeclarationStatement(node), LocalDeclarationStatementSyntax) + + Dim expressionStatements = New List(Of StatementSyntax)() + Dim variableDeclarators = New List(Of VariableDeclaratorSyntax)() + Dim triviaList = New List(Of SyntaxTrivia)() + + If Not Me._variableToRemoveMap.ProcessLocalDeclarationStatement(node, expressionStatements, variableDeclarators, triviaList) Then + Contract.ThrowIfFalse(expressionStatements.Count = 0) + Return node + End If + Contract.ThrowIfFalse(expressionStatements.Count = 0) - Return node - End If - - Contract.ThrowIfFalse(expressionStatements.Count = 0) - - If variableDeclarators.Count = 0 AndAlso - triviaList.Any(Function(t) t.Kind <> SyntaxKind.WhitespaceTrivia AndAlso t.Kind <> SyntaxKind.EndOfLineTrivia) Then - ' well, there are trivia associated with the node. - ' we can't just delete the node since then, we will lose - ' the trivia. unfortunately, it is not easy to attach the trivia - ' to next token. for now, create an empty statement and associate the - ' trivia to the statement - - ' TODO : think about a way to trivia attached to next token - Return SyntaxFactory.EmptyStatement(SyntaxFactory.Token(SyntaxKind.EmptyToken).WithLeadingTrivia(SyntaxFactory.TriviaList(triviaList))) - End If - - ' return survived var decls - If variableDeclarators.Count > 0 Then - Return SyntaxFactory.LocalDeclarationStatement( - node.Modifiers, - SyntaxFactory.SeparatedList(variableDeclarators)).WithPrependedLeadingTrivia(triviaList) - End If - - Return node.WithAdditionalAnnotations(s_removeAnnotation) - End Function - - Public Overrides Function VisitMethodBlock(node As MethodBlockSyntax) As SyntaxNode - If node IsNot Me.ContainerOfStatementsOrFieldToReplace Then - ' make sure we visit nodes under the block - Return MyBase.VisitMethodBlock(node) - End If - - Return node.WithSubOrFunctionStatement(ReplaceStatementIfNeeded(node.SubOrFunctionStatement)). - WithStatements(VisitList(ReplaceStatementsIfNeeded(node.Statements))) - End Function - - Public Overrides Function VisitConstructorBlock(node As ConstructorBlockSyntax) As SyntaxNode - If node IsNot Me.ContainerOfStatementsOrFieldToReplace Then - ' make sure we visit nodes under the block - Return MyBase.VisitConstructorBlock(node) - End If - - Return node.WithSubNewStatement(ReplaceStatementIfNeeded(node.SubNewStatement)). - WithStatements(VisitList(ReplaceStatementsIfNeeded(node.Statements))) - End Function - - Public Overrides Function VisitOperatorBlock(node As OperatorBlockSyntax) As SyntaxNode - If node IsNot Me.ContainerOfStatementsOrFieldToReplace Then - ' make sure we visit nodes under the block - Return MyBase.VisitOperatorBlock(node) - End If - - Return node.WithOperatorStatement(ReplaceStatementIfNeeded(node.OperatorStatement)). - WithStatements(VisitList(ReplaceStatementsIfNeeded(node.Statements))) - End Function - - Public Overrides Function VisitAccessorBlock(node As AccessorBlockSyntax) As SyntaxNode - If node IsNot Me.ContainerOfStatementsOrFieldToReplace Then - ' make sure we visit nodes under the block - Return MyBase.VisitAccessorBlock(node) - End If - - Return node.WithAccessorStatement(ReplaceStatementIfNeeded(node.AccessorStatement)). - WithStatements(VisitList(ReplaceStatementsIfNeeded(node.Statements))) - End Function - - Public Overrides Function VisitWhileBlock(node As WhileBlockSyntax) As SyntaxNode - If node IsNot Me.ContainerOfStatementsOrFieldToReplace Then - ' make sure we visit nodes under the switch section - Return MyBase.VisitWhileBlock(node) - End If - - Return node.WithWhileStatement(ReplaceStatementIfNeeded(node.WhileStatement)). - WithStatements(VisitList(ReplaceStatementsIfNeeded(node.Statements))) - End Function - - Public Overrides Function VisitUsingBlock(node As UsingBlockSyntax) As SyntaxNode - If node IsNot Me.ContainerOfStatementsOrFieldToReplace Then - Return MyBase.VisitUsingBlock(node) - End If - - Return node.WithUsingStatement(ReplaceStatementIfNeeded(node.UsingStatement)). - WithStatements(VisitList(ReplaceStatementsIfNeeded(node.Statements))) - End Function - - Public Overrides Function VisitSyncLockBlock(node As SyncLockBlockSyntax) As SyntaxNode - If node IsNot Me.ContainerOfStatementsOrFieldToReplace Then - Return MyBase.VisitSyncLockBlock(node) - End If - - Return node.WithSyncLockStatement(ReplaceStatementIfNeeded(node.SyncLockStatement)). - WithStatements(VisitList(ReplaceStatementsIfNeeded(node.Statements))) - End Function - - Public Overrides Function VisitWithBlock(node As WithBlockSyntax) As SyntaxNode - If node IsNot Me.ContainerOfStatementsOrFieldToReplace Then - Return MyBase.VisitWithBlock(node) - End If - - Return node.WithWithStatement(ReplaceStatementIfNeeded(node.WithStatement)). - WithStatements(ReplaceStatementsIfNeeded(node.Statements)) - End Function - - Public Overrides Function VisitSingleLineIfStatement(node As SingleLineIfStatementSyntax) As SyntaxNode - If node IsNot Me.ContainerOfStatementsOrFieldToReplace Then - Return MyBase.VisitSingleLineIfStatement(node) - End If - - Return SyntaxFactory.SingleLineIfStatement(node.IfKeyword, - node.Condition, - node.ThenKeyword, - VisitList(ReplaceStatementsIfNeeded(node.Statements, colon:=True)), - node.ElseClause) - - End Function - - Public Overrides Function VisitSingleLineElseClause(node As SingleLineElseClauseSyntax) As SyntaxNode - If node IsNot Me.ContainerOfStatementsOrFieldToReplace Then - Return MyBase.VisitSingleLineElseClause(node) - End If - - Return SyntaxFactory.SingleLineElseClause(node.ElseKeyword, VisitList(ReplaceStatementsIfNeeded(node.Statements, colon:=True))) - End Function - - Public Overrides Function VisitMultiLineIfBlock(node As MultiLineIfBlockSyntax) As SyntaxNode - If node IsNot Me.ContainerOfStatementsOrFieldToReplace Then - Return MyBase.VisitMultiLineIfBlock(node) - End If - - Return node.WithIfStatement(ReplaceStatementIfNeeded(node.IfStatement)). - WithStatements(VisitList(ReplaceStatementsIfNeeded(node.Statements))) - End Function - - Public Overrides Function VisitElseBlock(node As ElseBlockSyntax) As SyntaxNode - If node IsNot Me.ContainerOfStatementsOrFieldToReplace Then - Return MyBase.VisitElseBlock(node) - End If - - Return node.WithElseStatement(ReplaceStatementIfNeeded(node.ElseStatement)). - WithStatements(VisitList(ReplaceStatementsIfNeeded(node.Statements))) - End Function - - Public Overrides Function VisitTryBlock(node As TryBlockSyntax) As SyntaxNode - If node IsNot Me.ContainerOfStatementsOrFieldToReplace Then - Return MyBase.VisitTryBlock(node) - End If - - Return node.WithTryStatement(ReplaceStatementIfNeeded(node.TryStatement)). - WithStatements(VisitList(ReplaceStatementsIfNeeded(node.Statements))) - End Function - - Public Overrides Function VisitCatchBlock(node As CatchBlockSyntax) As SyntaxNode - If node IsNot Me.ContainerOfStatementsOrFieldToReplace Then - Return MyBase.VisitCatchBlock(node) - End If - - Return node.WithCatchStatement(ReplaceStatementIfNeeded(node.CatchStatement)). - WithStatements(VisitList(ReplaceStatementsIfNeeded(node.Statements))) - End Function - - Public Overrides Function VisitFinallyBlock(node As FinallyBlockSyntax) As SyntaxNode - If node IsNot Me.ContainerOfStatementsOrFieldToReplace Then - Return MyBase.VisitFinallyBlock(node) - End If - - Return node.WithFinallyStatement(ReplaceStatementIfNeeded(node.FinallyStatement)). - WithStatements(VisitList(ReplaceStatementsIfNeeded(node.Statements))) - End Function - - Public Overrides Function VisitSelectBlock(node As SelectBlockSyntax) As SyntaxNode - If node IsNot Me.ContainerOfStatementsOrFieldToReplace Then - Return MyBase.VisitSelectBlock(node) - End If - - Return node.WithSelectStatement(ReplaceStatementIfNeeded(node.SelectStatement)). - WithCaseBlocks(VisitList(node.CaseBlocks)). - WithEndSelectStatement(ReplaceStatementIfNeeded(node.EndSelectStatement)) - End Function - - Public Overrides Function VisitCaseBlock(node As CaseBlockSyntax) As SyntaxNode - If node IsNot Me.ContainerOfStatementsOrFieldToReplace Then - Return MyBase.VisitCaseBlock(node) - End If - - Return node.WithCaseStatement(ReplaceStatementIfNeeded(node.CaseStatement)). - WithStatements(VisitList(ReplaceStatementsIfNeeded(node.Statements))) - End Function - - Public Overrides Function VisitDoLoopBlock(node As DoLoopBlockSyntax) As SyntaxNode - If node IsNot Me.ContainerOfStatementsOrFieldToReplace Then - Return MyBase.VisitDoLoopBlock(node) - End If - - Return node.WithDoStatement(ReplaceStatementIfNeeded(node.DoStatement)). - WithStatements(VisitList(ReplaceStatementsIfNeeded(node.Statements))). - WithLoopStatement(ReplaceStatementIfNeeded(node.LoopStatement)) - End Function - - Public Overrides Function VisitForBlock(node As ForBlockSyntax) As SyntaxNode - If node IsNot Me.ContainerOfStatementsOrFieldToReplace Then - Return MyBase.VisitForBlock(node) - End If - - Return node.WithForStatement(ReplaceStatementIfNeeded(node.ForStatement)). - WithStatements(VisitList(ReplaceStatementsIfNeeded(node.Statements))). - WithNextStatement(ReplaceStatementIfNeeded(node.NextStatement)) - End Function - - Public Overrides Function VisitForEachBlock(node As ForEachBlockSyntax) As SyntaxNode - If node IsNot Me.ContainerOfStatementsOrFieldToReplace Then - Return MyBase.VisitForEachBlock(node) - End If - - Return node.WithForEachStatement(ReplaceStatementIfNeeded(node.ForEachStatement)). - WithStatements(VisitList(ReplaceStatementsIfNeeded(node.Statements))). - WithNextStatement(ReplaceStatementIfNeeded(node.NextStatement)) - End Function - - Public Overrides Function VisitSingleLineLambdaExpression(node As SingleLineLambdaExpressionSyntax) As SyntaxNode - If node IsNot Me.ContainerOfStatementsOrFieldToReplace Then - Return MyBase.VisitSingleLineLambdaExpression(node) - End If - - Dim body = SyntaxFactory.SingletonList(DirectCast(node.Body, StatementSyntax)) - Return node.WithBody(VisitList(ReplaceStatementsIfNeeded(body, colon:=True)).First()). - WithSubOrFunctionHeader(ReplaceStatementIfNeeded(node.SubOrFunctionHeader)) - End Function - - Public Overrides Function VisitMultiLineLambdaExpression(node As MultiLineLambdaExpressionSyntax) As SyntaxNode - If node IsNot Me.ContainerOfStatementsOrFieldToReplace Then - Return MyBase.VisitMultiLineLambdaExpression(node) - End If - - Return node.WithStatements(VisitList(ReplaceStatementsIfNeeded(node.Statements))). - WithSubOrFunctionHeader(ReplaceStatementIfNeeded(node.SubOrFunctionHeader)) - End Function - - Private Function ReplaceStatementIfNeeded(Of T As StatementSyntax)(statement As T) As T - Contract.ThrowIfNull(statement) - - ' if all three same - If (statement IsNot _firstStatementOrFieldToReplace) OrElse (Me._firstStatementOrFieldToReplace IsNot Me._lastStatementOrFieldToReplace) Then - Return statement - End If - - Contract.ThrowIfFalse(Me._statementsOrFieldToInsert.Count() = 1) - Return CType(Me._statementsOrFieldToInsert.Single(), T) - End Function - - Private Function ReplaceStatementsIfNeeded(statements As SyntaxList(Of StatementSyntax), Optional colon As Boolean = False) As SyntaxList(Of StatementSyntax) - Dim newStatements = New List(Of StatementSyntax)(statements) - Dim firstStatementIndex = newStatements.FindIndex(Function(s) s Is Me._firstStatementOrFieldToReplace) - - ' looks like statements belong to parent's Begin statement. there is nothing we need to do here. - If firstStatementIndex < 0 Then - Contract.ThrowIfFalse(Me._firstStatementOrFieldToReplace Is Me._lastStatementOrFieldToReplace) - Return statements - End If - - Dim lastStatementIndex = newStatements.FindIndex(Function(s) s Is Me._lastStatementOrFieldToReplace) - Contract.ThrowIfFalse(lastStatementIndex >= 0) - - Contract.ThrowIfFalse(firstStatementIndex <= lastStatementIndex) - - ' okay, this visit contains the statement - - ' remove statement that must be removed - statements = statements.RemoveRange(firstStatementIndex, lastStatementIndex - firstStatementIndex + 1) - - ' insert new statements - Return statements.InsertRange(firstStatementIndex, Join(Me._statementsOrFieldToInsert, colon).ToArray()) - End Function - - Private Shared Function Join(statements As IEnumerable(Of StatementSyntax), colon As Boolean) As IEnumerable(Of StatementSyntax) - If Not colon Then - Return statements - End If - - Dim removeEndOfLine = Function(t As SyntaxTrivia) Not t.IsElastic() AndAlso t.Kind <> SyntaxKind.EndOfLineTrivia - - Dim i = 0 - Dim count = statements.Count() - Dim trivia = SyntaxFactory.ColonTrivia(SyntaxFacts.GetText(SyntaxKind.ColonTrivia)) - Dim newStatements = New List(Of StatementSyntax) - For Each statement In statements - statement = statement.WithLeadingTrivia(statement.GetLeadingTrivia().Where(removeEndOfLine)) + If variableDeclarators.Count = 0 AndAlso + triviaList.Any(Function(t) t.Kind <> SyntaxKind.WhitespaceTrivia AndAlso t.Kind <> SyntaxKind.EndOfLineTrivia) Then + ' well, there are trivia associated with the node. + ' we can't just delete the node since then, we will lose + ' the trivia. unfortunately, it is not easy to attach the trivia + ' to next token. for now, create an empty statement and associate the + ' trivia to the statement + + ' TODO : think about a way to trivia attached to next token + Return SyntaxFactory.EmptyStatement(SyntaxFactory.Token(SyntaxKind.EmptyToken).WithLeadingTrivia(SyntaxFactory.TriviaList(triviaList))) + End If + + ' return survived var decls + If variableDeclarators.Count > 0 Then + Return SyntaxFactory.LocalDeclarationStatement( + node.Modifiers, + SyntaxFactory.SeparatedList(variableDeclarators)).WithPrependedLeadingTrivia(triviaList) + End If + + Return node.WithAdditionalAnnotations(s_removeAnnotation) + End Function + + Public Overrides Function VisitMethodBlock(node As MethodBlockSyntax) As SyntaxNode + If node IsNot Me.ContainerOfStatementsOrFieldToReplace Then + ' make sure we visit nodes under the block + Return MyBase.VisitMethodBlock(node) + End If + + Return node.WithSubOrFunctionStatement(ReplaceStatementIfNeeded(node.SubOrFunctionStatement)). + WithStatements(VisitList(ReplaceStatementsIfNeeded(node.Statements))) + End Function + + Public Overrides Function VisitConstructorBlock(node As ConstructorBlockSyntax) As SyntaxNode + If node IsNot Me.ContainerOfStatementsOrFieldToReplace Then + ' make sure we visit nodes under the block + Return MyBase.VisitConstructorBlock(node) + End If + + Return node.WithSubNewStatement(ReplaceStatementIfNeeded(node.SubNewStatement)). + WithStatements(VisitList(ReplaceStatementsIfNeeded(node.Statements))) + End Function + + Public Overrides Function VisitOperatorBlock(node As OperatorBlockSyntax) As SyntaxNode + If node IsNot Me.ContainerOfStatementsOrFieldToReplace Then + ' make sure we visit nodes under the block + Return MyBase.VisitOperatorBlock(node) + End If + + Return node.WithOperatorStatement(ReplaceStatementIfNeeded(node.OperatorStatement)). + WithStatements(VisitList(ReplaceStatementsIfNeeded(node.Statements))) + End Function + + Public Overrides Function VisitAccessorBlock(node As AccessorBlockSyntax) As SyntaxNode + If node IsNot Me.ContainerOfStatementsOrFieldToReplace Then + ' make sure we visit nodes under the block + Return MyBase.VisitAccessorBlock(node) + End If + + Return node.WithAccessorStatement(ReplaceStatementIfNeeded(node.AccessorStatement)). + WithStatements(VisitList(ReplaceStatementsIfNeeded(node.Statements))) + End Function + + Public Overrides Function VisitWhileBlock(node As WhileBlockSyntax) As SyntaxNode + If node IsNot Me.ContainerOfStatementsOrFieldToReplace Then + ' make sure we visit nodes under the switch section + Return MyBase.VisitWhileBlock(node) + End If + + Return node.WithWhileStatement(ReplaceStatementIfNeeded(node.WhileStatement)). + WithStatements(VisitList(ReplaceStatementsIfNeeded(node.Statements))) + End Function + + Public Overrides Function VisitUsingBlock(node As UsingBlockSyntax) As SyntaxNode + If node IsNot Me.ContainerOfStatementsOrFieldToReplace Then + Return MyBase.VisitUsingBlock(node) + End If + + Return node.WithUsingStatement(ReplaceStatementIfNeeded(node.UsingStatement)). + WithStatements(VisitList(ReplaceStatementsIfNeeded(node.Statements))) + End Function + + Public Overrides Function VisitSyncLockBlock(node As SyncLockBlockSyntax) As SyntaxNode + If node IsNot Me.ContainerOfStatementsOrFieldToReplace Then + Return MyBase.VisitSyncLockBlock(node) + End If + + Return node.WithSyncLockStatement(ReplaceStatementIfNeeded(node.SyncLockStatement)). + WithStatements(VisitList(ReplaceStatementsIfNeeded(node.Statements))) + End Function + + Public Overrides Function VisitWithBlock(node As WithBlockSyntax) As SyntaxNode + If node IsNot Me.ContainerOfStatementsOrFieldToReplace Then + Return MyBase.VisitWithBlock(node) + End If + + Return node.WithWithStatement(ReplaceStatementIfNeeded(node.WithStatement)). + WithStatements(ReplaceStatementsIfNeeded(node.Statements)) + End Function + + Public Overrides Function VisitSingleLineIfStatement(node As SingleLineIfStatementSyntax) As SyntaxNode + If node IsNot Me.ContainerOfStatementsOrFieldToReplace Then + Return MyBase.VisitSingleLineIfStatement(node) + End If + + Return SyntaxFactory.SingleLineIfStatement(node.IfKeyword, + node.Condition, + node.ThenKeyword, + VisitList(ReplaceStatementsIfNeeded(node.Statements, colon:=True)), + node.ElseClause) + + End Function + + Public Overrides Function VisitSingleLineElseClause(node As SingleLineElseClauseSyntax) As SyntaxNode + If node IsNot Me.ContainerOfStatementsOrFieldToReplace Then + Return MyBase.VisitSingleLineElseClause(node) + End If + + Return SyntaxFactory.SingleLineElseClause(node.ElseKeyword, VisitList(ReplaceStatementsIfNeeded(node.Statements, colon:=True))) + End Function + + Public Overrides Function VisitMultiLineIfBlock(node As MultiLineIfBlockSyntax) As SyntaxNode + If node IsNot Me.ContainerOfStatementsOrFieldToReplace Then + Return MyBase.VisitMultiLineIfBlock(node) + End If + + Return node.WithIfStatement(ReplaceStatementIfNeeded(node.IfStatement)). + WithStatements(VisitList(ReplaceStatementsIfNeeded(node.Statements))) + End Function + + Public Overrides Function VisitElseBlock(node As ElseBlockSyntax) As SyntaxNode + If node IsNot Me.ContainerOfStatementsOrFieldToReplace Then + Return MyBase.VisitElseBlock(node) + End If + + Return node.WithElseStatement(ReplaceStatementIfNeeded(node.ElseStatement)). + WithStatements(VisitList(ReplaceStatementsIfNeeded(node.Statements))) + End Function + + Public Overrides Function VisitTryBlock(node As TryBlockSyntax) As SyntaxNode + If node IsNot Me.ContainerOfStatementsOrFieldToReplace Then + Return MyBase.VisitTryBlock(node) + End If + + Return node.WithTryStatement(ReplaceStatementIfNeeded(node.TryStatement)). + WithStatements(VisitList(ReplaceStatementsIfNeeded(node.Statements))) + End Function + + Public Overrides Function VisitCatchBlock(node As CatchBlockSyntax) As SyntaxNode + If node IsNot Me.ContainerOfStatementsOrFieldToReplace Then + Return MyBase.VisitCatchBlock(node) + End If + + Return node.WithCatchStatement(ReplaceStatementIfNeeded(node.CatchStatement)). + WithStatements(VisitList(ReplaceStatementsIfNeeded(node.Statements))) + End Function + + Public Overrides Function VisitFinallyBlock(node As FinallyBlockSyntax) As SyntaxNode + If node IsNot Me.ContainerOfStatementsOrFieldToReplace Then + Return MyBase.VisitFinallyBlock(node) + End If + + Return node.WithFinallyStatement(ReplaceStatementIfNeeded(node.FinallyStatement)). + WithStatements(VisitList(ReplaceStatementsIfNeeded(node.Statements))) + End Function + + Public Overrides Function VisitSelectBlock(node As SelectBlockSyntax) As SyntaxNode + If node IsNot Me.ContainerOfStatementsOrFieldToReplace Then + Return MyBase.VisitSelectBlock(node) + End If + + Return node.WithSelectStatement(ReplaceStatementIfNeeded(node.SelectStatement)). + WithCaseBlocks(VisitList(node.CaseBlocks)). + WithEndSelectStatement(ReplaceStatementIfNeeded(node.EndSelectStatement)) + End Function + + Public Overrides Function VisitCaseBlock(node As CaseBlockSyntax) As SyntaxNode + If node IsNot Me.ContainerOfStatementsOrFieldToReplace Then + Return MyBase.VisitCaseBlock(node) + End If - If i < count - 1 Then - statement = statement.WithTrailingTrivia(statement.GetTrailingTrivia().Where(removeEndOfLine).Concat(trivia)) - End If + Return node.WithCaseStatement(ReplaceStatementIfNeeded(node.CaseStatement)). + WithStatements(VisitList(ReplaceStatementsIfNeeded(node.Statements))) + End Function - newStatements.Add(statement) - i += 1 - Next + Public Overrides Function VisitDoLoopBlock(node As DoLoopBlockSyntax) As SyntaxNode + If node IsNot Me.ContainerOfStatementsOrFieldToReplace Then + Return MyBase.VisitDoLoopBlock(node) + End If + + Return node.WithDoStatement(ReplaceStatementIfNeeded(node.DoStatement)). + WithStatements(VisitList(ReplaceStatementsIfNeeded(node.Statements))). + WithLoopStatement(ReplaceStatementIfNeeded(node.LoopStatement)) + End Function - Return newStatements - End Function - - Public Overrides Function VisitModuleBlock(ByVal node As ModuleBlockSyntax) As SyntaxNode - If node IsNot Me.ContainerOfStatementsOrFieldToReplace Then - ' make sure we visit nodes under the block - Return MyBase.VisitModuleBlock(node) - End If + Public Overrides Function VisitForBlock(node As ForBlockSyntax) As SyntaxNode + If node IsNot Me.ContainerOfStatementsOrFieldToReplace Then + Return MyBase.VisitForBlock(node) + End If - Return node.WithMembers(VisitList(ReplaceStatementsIfNeeded(node.Members))) - End Function + Return node.WithForStatement(ReplaceStatementIfNeeded(node.ForStatement)). + WithStatements(VisitList(ReplaceStatementsIfNeeded(node.Statements))). + WithNextStatement(ReplaceStatementIfNeeded(node.NextStatement)) + End Function - Public Overrides Function VisitClassBlock(ByVal node As ClassBlockSyntax) As SyntaxNode - If node IsNot Me.ContainerOfStatementsOrFieldToReplace Then - ' make sure we visit nodes under the block - Return MyBase.VisitClassBlock(node) - End If + Public Overrides Function VisitForEachBlock(node As ForEachBlockSyntax) As SyntaxNode + If node IsNot Me.ContainerOfStatementsOrFieldToReplace Then + Return MyBase.VisitForEachBlock(node) + End If + + Return node.WithForEachStatement(ReplaceStatementIfNeeded(node.ForEachStatement)). + WithStatements(VisitList(ReplaceStatementsIfNeeded(node.Statements))). + WithNextStatement(ReplaceStatementIfNeeded(node.NextStatement)) + End Function + + Public Overrides Function VisitSingleLineLambdaExpression(node As SingleLineLambdaExpressionSyntax) As SyntaxNode + If node IsNot Me.ContainerOfStatementsOrFieldToReplace Then + Return MyBase.VisitSingleLineLambdaExpression(node) + End If - Return node.WithMembers(VisitList(ReplaceStatementsIfNeeded(node.Members))) - End Function + Dim body = SyntaxFactory.SingletonList(DirectCast(node.Body, StatementSyntax)) + Return node.WithBody(VisitList(ReplaceStatementsIfNeeded(body, colon:=True)).First()). + WithSubOrFunctionHeader(ReplaceStatementIfNeeded(node.SubOrFunctionHeader)) + End Function + + Public Overrides Function VisitMultiLineLambdaExpression(node As MultiLineLambdaExpressionSyntax) As SyntaxNode + If node IsNot Me.ContainerOfStatementsOrFieldToReplace Then + Return MyBase.VisitMultiLineLambdaExpression(node) + End If + + Return node.WithStatements(VisitList(ReplaceStatementsIfNeeded(node.Statements))). + WithSubOrFunctionHeader(ReplaceStatementIfNeeded(node.SubOrFunctionHeader)) + End Function + + Private Function ReplaceStatementIfNeeded(Of T As StatementSyntax)(statement As T) As T + Contract.ThrowIfNull(statement) + + ' if all three same + If (statement IsNot _firstStatementOrFieldToReplace) OrElse (Me._firstStatementOrFieldToReplace IsNot Me._lastStatementOrFieldToReplace) Then + Return statement + End If - Public Overrides Function VisitStructureBlock(ByVal node As StructureBlockSyntax) As SyntaxNode - If node IsNot Me.ContainerOfStatementsOrFieldToReplace Then - ' make sure we visit nodes under the block - Return MyBase.VisitStructureBlock(node) - End If + Contract.ThrowIfFalse(Me._statementsOrFieldToInsert.Count() = 1) + Return CType(Me._statementsOrFieldToInsert.Single(), T) + End Function - Return node.WithMembers(VisitList(ReplaceStatementsIfNeeded(node.Members))) - End Function + Private Function ReplaceStatementsIfNeeded(statements As SyntaxList(Of StatementSyntax), Optional colon As Boolean = False) As SyntaxList(Of StatementSyntax) + Dim newStatements = New List(Of StatementSyntax)(statements) + Dim firstStatementIndex = newStatements.FindIndex(Function(s) s Is Me._firstStatementOrFieldToReplace) - Public Overrides Function VisitCompilationUnit(node As CompilationUnitSyntax) As SyntaxNode - If node IsNot Me.ContainerOfStatementsOrFieldToReplace Then - ' make sure we visit nodes under the block - Return MyBase.VisitCompilationUnit(node) - End If + ' looks like statements belong to parent's Begin statement. there is nothing we need to do here. + If firstStatementIndex < 0 Then + Contract.ThrowIfFalse(Me._firstStatementOrFieldToReplace Is Me._lastStatementOrFieldToReplace) + Return statements + End If + + Dim lastStatementIndex = newStatements.FindIndex(Function(s) s Is Me._lastStatementOrFieldToReplace) + Contract.ThrowIfFalse(lastStatementIndex >= 0) + + Contract.ThrowIfFalse(firstStatementIndex <= lastStatementIndex) + + ' okay, this visit contains the statement + + ' remove statement that must be removed + statements = statements.RemoveRange(firstStatementIndex, lastStatementIndex - firstStatementIndex + 1) + + ' insert new statements + Return statements.InsertRange(firstStatementIndex, Join(Me._statementsOrFieldToInsert, colon).ToArray()) + End Function + + Private Shared Function Join(statements As IEnumerable(Of StatementSyntax), colon As Boolean) As IEnumerable(Of StatementSyntax) + If Not colon Then + Return statements + End If + + Dim removeEndOfLine = Function(t As SyntaxTrivia) Not t.IsElastic() AndAlso t.Kind <> SyntaxKind.EndOfLineTrivia + + Dim i = 0 + Dim count = statements.Count() + Dim trivia = SyntaxFactory.ColonTrivia(SyntaxFacts.GetText(SyntaxKind.ColonTrivia)) + + Dim newStatements = New List(Of StatementSyntax) + For Each statement In statements + statement = statement.WithLeadingTrivia(statement.GetLeadingTrivia().Where(removeEndOfLine)) + + If i < count - 1 Then + statement = statement.WithTrailingTrivia(statement.GetTrailingTrivia().Where(removeEndOfLine).Concat(trivia)) + End If + + newStatements.Add(statement) + i += 1 + Next + + Return newStatements + End Function + + Public Overrides Function VisitModuleBlock(ByVal node As ModuleBlockSyntax) As SyntaxNode + If node IsNot Me.ContainerOfStatementsOrFieldToReplace Then + ' make sure we visit nodes under the block + Return MyBase.VisitModuleBlock(node) + End If + + Return node.WithMembers(VisitList(ReplaceStatementsIfNeeded(node.Members))) + End Function + + Public Overrides Function VisitClassBlock(ByVal node As ClassBlockSyntax) As SyntaxNode + If node IsNot Me.ContainerOfStatementsOrFieldToReplace Then + ' make sure we visit nodes under the block + Return MyBase.VisitClassBlock(node) + End If + + Return node.WithMembers(VisitList(ReplaceStatementsIfNeeded(node.Members))) + End Function + + Public Overrides Function VisitStructureBlock(ByVal node As StructureBlockSyntax) As SyntaxNode + If node IsNot Me.ContainerOfStatementsOrFieldToReplace Then + ' make sure we visit nodes under the block + Return MyBase.VisitStructureBlock(node) + End If + + Return node.WithMembers(VisitList(ReplaceStatementsIfNeeded(node.Members))) + End Function + + Public Overrides Function VisitCompilationUnit(node As CompilationUnitSyntax) As SyntaxNode + If node IsNot Me.ContainerOfStatementsOrFieldToReplace Then + ' make sure we visit nodes under the block + Return MyBase.VisitCompilationUnit(node) + End If - Return node.WithMembers(VisitList(ReplaceStatementsIfNeeded(node.Members))) - End Function + Return node.WithMembers(VisitList(ReplaceStatementsIfNeeded(node.Members))) + End Function + End Class End Class End Class End Class diff --git a/src/Features/VisualBasic/Portable/ExtractMethod/VisualBasicMethodExtractor.VisualBasicCodeGenerator.ExpressionCodeGenerator.vb b/src/Features/VisualBasic/Portable/ExtractMethod/VisualBasicMethodExtractor.VisualBasicCodeGenerator.ExpressionCodeGenerator.vb index 402aaa4080b15..1d70eda65011d 100644 --- a/src/Features/VisualBasic/Portable/ExtractMethod/VisualBasicMethodExtractor.VisualBasicCodeGenerator.ExpressionCodeGenerator.vb +++ b/src/Features/VisualBasic/Portable/ExtractMethod/VisualBasicMethodExtractor.VisualBasicCodeGenerator.ExpressionCodeGenerator.vb @@ -6,130 +6,129 @@ Imports System.Collections.Immutable Imports System.Threading Imports Microsoft.CodeAnalysis Imports Microsoft.CodeAnalysis.ExtractMethod -Imports Microsoft.CodeAnalysis.VisualBasic -Imports Microsoft.CodeAnalysis.VisualBasic.CodeGeneration Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Namespace Microsoft.CodeAnalysis.VisualBasic.ExtractMethod - Partial Friend Class VisualBasicMethodExtractor - Partial Private Class VisualBasicCodeGenerator - Private Class ExpressionCodeGenerator - Inherits VisualBasicCodeGenerator - - Public Sub New(selectionResult As VisualBasicSelectionResult, analyzerResult As AnalyzerResult, options As VisualBasicCodeGenerationOptions) - MyBase.New(selectionResult, analyzerResult, options) - End Sub - - Public Shared Function IsExtractMethodOnExpression(code As VisualBasicSelectionResult) As Boolean - Return code.SelectionInExpression - End Function - - Protected Overrides Function CreateMethodName() As SyntaxToken - Dim methodName = "NewMethod" - Dim containingScope = Me.SelectionResult.GetContainingScope() - - methodName = GetMethodNameBasedOnExpression(methodName, containingScope) - - Dim semanticModel = SemanticDocument.SemanticModel - Dim nameGenerator = New UniqueNameGenerator(semanticModel) - Return SyntaxFactory.Identifier( - nameGenerator.CreateUniqueMethodName(containingScope, methodName)) - End Function - - Private Shared Function GetMethodNameBasedOnExpression(methodName As String, expression As SyntaxNode) As String - If expression.IsParentKind(SyntaxKind.EqualsValue) AndAlso - expression.Parent.IsParentKind(SyntaxKind.VariableDeclarator) Then - - Dim varDecl = DirectCast(expression.Parent.Parent, VariableDeclaratorSyntax) - If varDecl.Names.Count <> 1 Then - Return methodName + Partial Friend NotInheritable Class VisualBasicExtractMethodService + Partial Friend Class VisualBasicMethodExtractor + Partial Private Class VisualBasicCodeGenerator + Private Class ExpressionCodeGenerator + Inherits VisualBasicCodeGenerator + + Public Sub New( + selectionResult As SelectionResult, + analyzerResult As AnalyzerResult, + options As ExtractMethodGenerationOptions) + MyBase.New(selectionResult, analyzerResult, options) + End Sub + + Protected Overrides Function CreateMethodName() As SyntaxToken + Dim methodName = "NewMethod" + Dim containingScope = Me.SelectionResult.GetContainingScope() + + methodName = GetMethodNameBasedOnExpression(methodName, containingScope) + + Dim semanticModel = SemanticDocument.SemanticModel + Dim nameGenerator = New UniqueNameGenerator(semanticModel) + Return SyntaxFactory.Identifier( + nameGenerator.CreateUniqueMethodName(containingScope, methodName)) + End Function + + Private Shared Function GetMethodNameBasedOnExpression(methodName As String, expression As SyntaxNode) As String + If expression.IsParentKind(SyntaxKind.EqualsValue) AndAlso + expression.Parent.IsParentKind(SyntaxKind.VariableDeclarator) Then + + Dim varDecl = DirectCast(expression.Parent.Parent, VariableDeclaratorSyntax) + If varDecl.Names.Count <> 1 Then + Return methodName + End If + + Dim identifierNode = varDecl.Names(0) + If identifierNode Is Nothing Then + Return methodName + End If + + Dim name = identifierNode.Identifier.ValueText + Return If(name IsNot Nothing AndAlso name.Length > 0, MakeMethodName("Get", name, camelCase:=False), methodName) End If - Dim identifierNode = varDecl.Names(0) - If identifierNode Is Nothing Then - Return methodName + If TypeOf expression Is MemberAccessExpressionSyntax Then + expression = CType(expression, MemberAccessExpressionSyntax).Name End If - Dim name = identifierNode.Identifier.ValueText - Return If(name IsNot Nothing AndAlso name.Length > 0, MakeMethodName("Get", name, camelCase:=False), methodName) - End If - - If TypeOf expression Is MemberAccessExpressionSyntax Then - expression = CType(expression, MemberAccessExpressionSyntax).Name - End If - - If TypeOf expression Is NameSyntax Then - Dim lastDottedName = CType(expression, NameSyntax).GetLastDottedName() - Dim plainName = CType(lastDottedName, SimpleNameSyntax).Identifier.ValueText - Return If(plainName IsNot Nothing AndAlso plainName.Length > 0, MakeMethodName("Get", plainName, camelCase:=False), methodName) - End If - - Return methodName - End Function - - Protected Overrides Function GetInitialStatementsForMethodDefinitions() As ImmutableArray(Of StatementSyntax) - Contract.ThrowIfFalse(IsExtractMethodOnExpression(Me.SelectionResult)) - - Dim expression = DirectCast(Me.SelectionResult.GetContainingScope(), ExpressionSyntax) - - Dim statement As StatementSyntax - If Me.AnalyzerResult.HasReturnType Then - statement = SyntaxFactory.ReturnStatement(expression:=expression) - Else - ' we have expression for void method (Sub). make the expression as call - ' statement if possible we can create call statement only from invocation - ' and member access expression. otherwise, it is not a valid expression. - ' return error code - If expression.Kind <> SyntaxKind.InvocationExpression AndAlso - expression.Kind <> SyntaxKind.SimpleMemberAccessExpression Then - Return ImmutableArray(Of StatementSyntax).Empty + If TypeOf expression Is NameSyntax Then + Dim lastDottedName = CType(expression, NameSyntax).GetLastDottedName() + Dim plainName = CType(lastDottedName, SimpleNameSyntax).Identifier.ValueText + Return If(plainName IsNot Nothing AndAlso plainName.Length > 0, MakeMethodName("Get", plainName, camelCase:=False), methodName) End If - statement = SyntaxFactory.ExpressionStatement(expression:=expression) - End If + Return methodName + End Function - Return ImmutableArray.Create(statement) - End Function + Protected Overrides Function GetInitialStatementsForMethodDefinitions() As ImmutableArray(Of StatementSyntax) + Contract.ThrowIfFalse(Me.SelectionResult.IsExtractMethodOnExpression) - Protected Overrides Function GetFirstStatementOrInitializerSelectedAtCallSite() As StatementSyntax - Return Me.SelectionResult.GetContainingScopeOf(Of StatementSyntax)() - End Function + Dim expression = DirectCast(Me.SelectionResult.GetContainingScope(), ExpressionSyntax) - Protected Overrides Function GetLastStatementOrInitializerSelectedAtCallSite() As StatementSyntax - Return GetFirstStatementOrInitializerSelectedAtCallSite() - End Function + Dim statement As StatementSyntax + If Me.AnalyzerResult.HasReturnType Then + statement = SyntaxFactory.ReturnStatement(expression:=expression) + Else + ' we have expression for void method (Sub). make the expression as call + ' statement if possible we can create call statement only from invocation + ' and member access expression. otherwise, it is not a valid expression. + ' return error code + If expression.Kind <> SyntaxKind.InvocationExpression AndAlso + expression.Kind <> SyntaxKind.SimpleMemberAccessExpression Then + Return ImmutableArray(Of StatementSyntax).Empty + End If - Protected Overrides Async Function GetStatementOrInitializerContainingInvocationToExtractedMethodAsync(cancellationToken As CancellationToken) As Task(Of StatementSyntax) - Dim enclosingStatement = GetFirstStatementOrInitializerSelectedAtCallSite() - Dim callSignature = CreateCallSignature().WithAdditionalAnnotations(CallSiteAnnotation) - - Dim sourceNode = Me.SelectionResult.GetContainingScope() - Contract.ThrowIfTrue( - sourceNode.IsParentKind(SyntaxKind.SimpleMemberAccessExpression) AndAlso - DirectCast(sourceNode.Parent, MemberAccessExpressionSyntax).Name Is sourceNode, - "invalid scope. scope is not an expression") - - ' To lower the chances that replacing sourceNode with callSignature will break the user's - ' code, we make the enclosing statement semantically explicit. This ends up being a little - ' bit more work because we need to annotate the sourceNode so that we can get back to it - ' after rewriting the enclosing statement. - Dim sourceNodeAnnotation = New SyntaxAnnotation() - Dim enclosingStatementAnnotation = New SyntaxAnnotation() - Dim newEnclosingStatement = enclosingStatement _ - .ReplaceNode(sourceNode, sourceNode.WithAdditionalAnnotations(sourceNodeAnnotation)) _ - .WithAdditionalAnnotations(enclosingStatementAnnotation) - - Dim updatedDocument = Await Me.SemanticDocument.Document.ReplaceNodeAsync(enclosingStatement, newEnclosingStatement, cancellationToken).ConfigureAwait(False) - Dim updatedRoot = Await updatedDocument.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(False) - - newEnclosingStatement = DirectCast(updatedRoot.GetAnnotatedNodesAndTokens(enclosingStatementAnnotation).Single().AsNode(), StatementSyntax) - - ' because of the complexification we cannot guarantee that there is only one annotation. - ' however complexification of names is prepended, so the last annotation should be the original one. - sourceNode = updatedRoot.GetAnnotatedNodesAndTokens(sourceNodeAnnotation).Last().AsNode() + statement = SyntaxFactory.ExpressionStatement(expression:=expression) + End If - Return newEnclosingStatement.ReplaceNode(sourceNode, callSignature) - End Function + Return ImmutableArray.Create(statement) + End Function + + Protected Overrides Function GetFirstStatementOrInitializerSelectedAtCallSite() As StatementSyntax + Return Me.SelectionResult.GetContainingScopeOf(Of StatementSyntax)() + End Function + + Protected Overrides Function GetLastStatementOrInitializerSelectedAtCallSite() As StatementSyntax + Return GetFirstStatementOrInitializerSelectedAtCallSite() + End Function + + Protected Overrides Async Function GetStatementOrInitializerContainingInvocationToExtractedMethodAsync(cancellationToken As CancellationToken) As Task(Of StatementSyntax) + Dim enclosingStatement = GetFirstStatementOrInitializerSelectedAtCallSite() + Dim callSignature = CreateCallSignature().WithAdditionalAnnotations(CallSiteAnnotation) + + Dim sourceNode = Me.SelectionResult.GetContainingScope() + Contract.ThrowIfTrue( + sourceNode.IsParentKind(SyntaxKind.SimpleMemberAccessExpression) AndAlso + DirectCast(sourceNode.Parent, MemberAccessExpressionSyntax).Name Is sourceNode, + "invalid scope. scope is not an expression") + + ' To lower the chances that replacing sourceNode with callSignature will break the user's + ' code, we make the enclosing statement semantically explicit. This ends up being a little + ' bit more work because we need to annotate the sourceNode so that we can get back to it + ' after rewriting the enclosing statement. + Dim sourceNodeAnnotation = New SyntaxAnnotation() + Dim enclosingStatementAnnotation = New SyntaxAnnotation() + Dim newEnclosingStatement = enclosingStatement _ + .ReplaceNode(sourceNode, sourceNode.WithAdditionalAnnotations(sourceNodeAnnotation)) _ + .WithAdditionalAnnotations(enclosingStatementAnnotation) + + Dim updatedDocument = Await Me.SemanticDocument.Document.ReplaceNodeAsync(enclosingStatement, newEnclosingStatement, cancellationToken).ConfigureAwait(False) + Dim updatedRoot = Await updatedDocument.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(False) + + newEnclosingStatement = DirectCast(updatedRoot.GetAnnotatedNodesAndTokens(enclosingStatementAnnotation).Single().AsNode(), StatementSyntax) + + ' because of the complexification we cannot guarantee that there is only one annotation. + ' however complexification of names is prepended, so the last annotation should be the original one. + sourceNode = updatedRoot.GetAnnotatedNodesAndTokens(sourceNodeAnnotation).Last().AsNode() + + Return newEnclosingStatement.ReplaceNode(sourceNode, callSignature) + End Function + End Class End Class End Class End Class diff --git a/src/Features/VisualBasic/Portable/ExtractMethod/VisualBasicMethodExtractor.VisualBasicCodeGenerator.MultipleStatementsCodeGenerator.vb b/src/Features/VisualBasic/Portable/ExtractMethod/VisualBasicMethodExtractor.VisualBasicCodeGenerator.MultipleStatementsCodeGenerator.vb index 2eb237d9619c4..db82b63ec0f33 100644 --- a/src/Features/VisualBasic/Portable/ExtractMethod/VisualBasicMethodExtractor.VisualBasicCodeGenerator.MultipleStatementsCodeGenerator.vb +++ b/src/Features/VisualBasic/Portable/ExtractMethod/VisualBasicMethodExtractor.VisualBasicCodeGenerator.MultipleStatementsCodeGenerator.vb @@ -6,57 +6,61 @@ Imports System.Collections.Immutable Imports System.Threading Imports Microsoft.CodeAnalysis Imports Microsoft.CodeAnalysis.ExtractMethod -Imports Microsoft.CodeAnalysis.VisualBasic.CodeGeneration Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Namespace Microsoft.CodeAnalysis.VisualBasic.ExtractMethod - Partial Friend Class VisualBasicMethodExtractor - Partial Private Class VisualBasicCodeGenerator - Private Class MultipleStatementsCodeGenerator - Inherits VisualBasicCodeGenerator + Partial Friend NotInheritable Class VisualBasicExtractMethodService + Partial Friend Class VisualBasicMethodExtractor + Partial Private Class VisualBasicCodeGenerator + Private Class MultipleStatementsCodeGenerator + Inherits VisualBasicCodeGenerator - Public Sub New(selectionResult As VisualBasicSelectionResult, analyzerResult As AnalyzerResult, options As VisualBasicCodeGenerationOptions) - MyBase.New(selectionResult, analyzerResult, options) - End Sub + Public Sub New( + selectionResult As SelectionResult, + analyzerResult As AnalyzerResult, + options As ExtractMethodGenerationOptions) + MyBase.New(selectionResult, analyzerResult, options) + End Sub - Protected Overrides Function CreateMethodName() As SyntaxToken - ' change this to more smarter one. - Dim semanticModel = SemanticDocument.SemanticModel - Dim nameGenerator = New UniqueNameGenerator(semanticModel) - Dim containingScope = Me.SelectionResult.GetContainingScope() - Return SyntaxFactory.Identifier(nameGenerator.CreateUniqueMethodName(containingScope, "NewMethod")) - End Function + Protected Overrides Function CreateMethodName() As SyntaxToken + ' change this to more smarter one. + Dim semanticModel = SemanticDocument.SemanticModel + Dim nameGenerator = New UniqueNameGenerator(semanticModel) + Dim containingScope = Me.SelectionResult.GetContainingScope() + Return SyntaxFactory.Identifier(nameGenerator.CreateUniqueMethodName(containingScope, "NewMethod")) + End Function - Protected Overrides Function GetInitialStatementsForMethodDefinitions() As ImmutableArray(Of StatementSyntax) - Dim firstStatementUnderContainer = Me.SelectionResult.GetFirstStatementUnderContainer() - Dim lastStatementUnderContainer = Me.SelectionResult.GetLastStatementUnderContainer() + Protected Overrides Function GetInitialStatementsForMethodDefinitions() As ImmutableArray(Of StatementSyntax) + Dim firstStatementUnderContainer = Me.SelectionResult.GetFirstStatementUnderContainer() + Dim lastStatementUnderContainer = Me.SelectionResult.GetLastStatementUnderContainer() - Dim statements = firstStatementUnderContainer.Parent.GetStatements() + Dim statements = firstStatementUnderContainer.Parent.GetStatements() - Dim firstStatementIndex = statements.IndexOf(firstStatementUnderContainer) - Contract.ThrowIfFalse(firstStatementIndex >= 0) + Dim firstStatementIndex = statements.IndexOf(firstStatementUnderContainer) + Contract.ThrowIfFalse(firstStatementIndex >= 0) - Dim lastStatementIndex = statements.IndexOf(lastStatementUnderContainer) - Contract.ThrowIfFalse(lastStatementIndex >= 0) + Dim lastStatementIndex = statements.IndexOf(lastStatementUnderContainer) + Contract.ThrowIfFalse(lastStatementIndex >= 0) - Dim nodes = statements. - Skip(firstStatementIndex). - Take(lastStatementIndex - firstStatementIndex + 1) + Dim nodes = statements. + Skip(firstStatementIndex). + Take(lastStatementIndex - firstStatementIndex + 1) - Return nodes.ToImmutableArray() - End Function + Return nodes.ToImmutableArray() + End Function - Protected Overrides Function GetFirstStatementOrInitializerSelectedAtCallSite() As StatementSyntax - Return Me.SelectionResult.GetFirstStatementUnderContainer() - End Function + Protected Overrides Function GetFirstStatementOrInitializerSelectedAtCallSite() As StatementSyntax + Return Me.SelectionResult.GetFirstStatementUnderContainer() + End Function - Protected Overrides Function GetLastStatementOrInitializerSelectedAtCallSite() As StatementSyntax - Return Me.SelectionResult.GetLastStatementUnderContainer() - End Function + Protected Overrides Function GetLastStatementOrInitializerSelectedAtCallSite() As StatementSyntax + Return Me.SelectionResult.GetLastStatementUnderContainer() + End Function - Protected Overrides Function GetStatementOrInitializerContainingInvocationToExtractedMethodAsync(cancellationToken As CancellationToken) As Task(Of StatementSyntax) - Return Task.FromResult(GetStatementContainingInvocationToExtractedMethodWorker().WithAdditionalAnnotations(CallSiteAnnotation)) - End Function + Protected Overrides Function GetStatementOrInitializerContainingInvocationToExtractedMethodAsync(cancellationToken As CancellationToken) As Task(Of StatementSyntax) + Return Task.FromResult(GetStatementContainingInvocationToExtractedMethodWorker().WithAdditionalAnnotations(CallSiteAnnotation)) + End Function + End Class End Class End Class End Class diff --git a/src/Features/VisualBasic/Portable/ExtractMethod/VisualBasicMethodExtractor.VisualBasicCodeGenerator.SingleStatementCodeGenerator.vb b/src/Features/VisualBasic/Portable/ExtractMethod/VisualBasicMethodExtractor.VisualBasicCodeGenerator.SingleStatementCodeGenerator.vb index f01087e809803..387906ee8cb90 100644 --- a/src/Features/VisualBasic/Portable/ExtractMethod/VisualBasicMethodExtractor.VisualBasicCodeGenerator.SingleStatementCodeGenerator.vb +++ b/src/Features/VisualBasic/Portable/ExtractMethod/VisualBasicMethodExtractor.VisualBasicCodeGenerator.SingleStatementCodeGenerator.vb @@ -6,47 +6,51 @@ Imports System.Collections.Immutable Imports System.Threading Imports Microsoft.CodeAnalysis Imports Microsoft.CodeAnalysis.ExtractMethod -Imports Microsoft.CodeAnalysis.VisualBasic.CodeGeneration Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Namespace Microsoft.CodeAnalysis.VisualBasic.ExtractMethod - Partial Friend Class VisualBasicMethodExtractor - Partial Private Class VisualBasicCodeGenerator - Private Class SingleStatementCodeGenerator - Inherits VisualBasicCodeGenerator - - Public Sub New(selectionResult As VisualBasicSelectionResult, analyzerResult As AnalyzerResult, options As VisualBasicCodeGenerationOptions) - MyBase.New(selectionResult, analyzerResult, options) - End Sub - - Protected Overrides Function CreateMethodName() As SyntaxToken - ' change this to more smarter one. - Dim semanticModel = CType(SemanticDocument.SemanticModel, SemanticModel) - Dim nameGenerator = New UniqueNameGenerator(semanticModel) - Dim containingScope = Me.SelectionResult.GetContainingScope() - Return SyntaxFactory.Identifier( - nameGenerator.CreateUniqueMethodName(containingScope, "NewMethod")) - End Function - - Protected Overrides Function GetInitialStatementsForMethodDefinitions() As ImmutableArray(Of StatementSyntax) - Contract.ThrowIfFalse(Me.SelectionResult.IsExtractMethodOnSingleStatement()) - - Return ImmutableArray.Create(Of StatementSyntax)(Me.SelectionResult.GetFirstStatement()) - End Function - - Protected Overrides Function GetFirstStatementOrInitializerSelectedAtCallSite() As StatementSyntax - Return Me.SelectionResult.GetFirstStatement() - End Function - - Protected Overrides Function GetLastStatementOrInitializerSelectedAtCallSite() As StatementSyntax - ' it is a single statement case. either first statement is same as last statement or - ' last statement belongs (embedded statement) to the first statement. - Return Me.SelectionResult.GetFirstStatement() - End Function - - Protected Overrides Function GetStatementOrInitializerContainingInvocationToExtractedMethodAsync(cancellationToken As CancellationToken) As Task(Of StatementSyntax) - Return Task.FromResult(GetStatementContainingInvocationToExtractedMethodWorker().WithAdditionalAnnotations(CallSiteAnnotation)) - End Function + Partial Friend NotInheritable Class VisualBasicExtractMethodService + Partial Friend Class VisualBasicMethodExtractor + Partial Private Class VisualBasicCodeGenerator + Private Class SingleStatementCodeGenerator + Inherits VisualBasicCodeGenerator + + Public Sub New( + selectionResult As SelectionResult, + analyzerResult As AnalyzerResult, + options As ExtractMethodGenerationOptions) + MyBase.New(selectionResult, analyzerResult, options) + End Sub + + Protected Overrides Function CreateMethodName() As SyntaxToken + ' change this to more smarter one. + Dim semanticModel = CType(SemanticDocument.SemanticModel, SemanticModel) + Dim nameGenerator = New UniqueNameGenerator(semanticModel) + Dim containingScope = Me.SelectionResult.GetContainingScope() + Return SyntaxFactory.Identifier( + nameGenerator.CreateUniqueMethodName(containingScope, "NewMethod")) + End Function + + Protected Overrides Function GetInitialStatementsForMethodDefinitions() As ImmutableArray(Of StatementSyntax) + Contract.ThrowIfFalse(Me.SelectionResult.IsExtractMethodOnSingleStatement()) + + Return ImmutableArray.Create(Of StatementSyntax)(Me.SelectionResult.GetFirstStatement()) + End Function + + Protected Overrides Function GetFirstStatementOrInitializerSelectedAtCallSite() As StatementSyntax + Return Me.SelectionResult.GetFirstStatement() + End Function + + Protected Overrides Function GetLastStatementOrInitializerSelectedAtCallSite() As StatementSyntax + ' it is a single statement case. either first statement is same as last statement or + ' last statement belongs (embedded statement) to the first statement. + Return Me.SelectionResult.GetFirstStatement() + End Function + + Protected Overrides Function GetStatementOrInitializerContainingInvocationToExtractedMethodAsync(cancellationToken As CancellationToken) As Task(Of StatementSyntax) + Return Task.FromResult(GetStatementContainingInvocationToExtractedMethodWorker().WithAdditionalAnnotations(CallSiteAnnotation)) + End Function + End Class End Class End Class End Class diff --git a/src/Features/VisualBasic/Portable/ExtractMethod/VisualBasicMethodExtractor.VisualBasicCodeGenerator.vb b/src/Features/VisualBasic/Portable/ExtractMethod/VisualBasicMethodExtractor.VisualBasicCodeGenerator.vb index abd9607ef8a17..b5087f356061d 100644 --- a/src/Features/VisualBasic/Portable/ExtractMethod/VisualBasicMethodExtractor.VisualBasicCodeGenerator.vb +++ b/src/Features/VisualBasic/Portable/ExtractMethod/VisualBasicMethodExtractor.VisualBasicCodeGenerator.vb @@ -10,435 +10,455 @@ Imports Microsoft.CodeAnalysis.Editing Imports Microsoft.CodeAnalysis.ExtractMethod Imports Microsoft.CodeAnalysis.Formatting Imports Microsoft.CodeAnalysis.Simplification +Imports Microsoft.CodeAnalysis.Text Imports Microsoft.CodeAnalysis.VisualBasic Imports Microsoft.CodeAnalysis.VisualBasic.CodeGeneration Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Namespace Microsoft.CodeAnalysis.VisualBasic.ExtractMethod - Partial Friend Class VisualBasicMethodExtractor - Partial Private MustInherit Class VisualBasicCodeGenerator - Inherits CodeGenerator(Of StatementSyntax, StatementSyntax, VisualBasicCodeGenerationOptions) - - Private ReadOnly _methodName As SyntaxToken - - Public Shared Async Function GenerateResultAsync(insertionPoint As InsertionPoint, selectionResult As VisualBasicSelectionResult, analyzerResult As AnalyzerResult, options As VisualBasicCodeGenerationOptions, cancellationToken As CancellationToken) As Task(Of GeneratedCode) - Dim generator = Create(selectionResult, analyzerResult, options) - Return Await generator.GenerateAsync(insertionPoint, cancellationToken).ConfigureAwait(False) - End Function - - Public Shared Function Create(selectionResult As VisualBasicSelectionResult, analyzerResult As AnalyzerResult, options As VisualBasicCodeGenerationOptions) As VisualBasicCodeGenerator - If selectionResult.SelectionInExpression Then - Return New ExpressionCodeGenerator(selectionResult, analyzerResult, options) - End If - - If selectionResult.IsExtractMethodOnSingleStatement() Then - Return New SingleStatementCodeGenerator(selectionResult, analyzerResult, options) - End If - - If selectionResult.IsExtractMethodOnMultipleStatements() Then - Return New MultipleStatementsCodeGenerator(selectionResult, analyzerResult, options) - End If - - Throw ExceptionUtilities.UnexpectedValue(selectionResult) - End Function - - Protected Sub New(selectionResult As VisualBasicSelectionResult, analyzerResult As AnalyzerResult, options As VisualBasicCodeGenerationOptions) - MyBase.New(selectionResult, analyzerResult, options, localFunction:=False) - Contract.ThrowIfFalse(Me.SemanticDocument Is selectionResult.SemanticDocument) - - Me._methodName = CreateMethodName().WithAdditionalAnnotations(MethodNameAnnotation) - End Sub - - Protected Overrides Function UpdateMethodAfterGenerationAsync(originalDocument As SemanticDocument, methodSymbol As IMethodSymbol, cancellationToken As CancellationToken) As Task(Of SemanticDocument) - Return Task.FromResult(originalDocument) - End Function - - Protected Overrides Function ShouldLocalFunctionCaptureParameter(node As SyntaxNode) As Boolean - Return False - End Function - - Protected Overrides Function GenerateMethodDefinition(insertionPointNode As SyntaxNode, cancellationToken As CancellationToken) As IMethodSymbol - Dim statements = CreateMethodBody(insertionPointNode, cancellationToken) - - Dim methodSymbol = CodeGenerationSymbolFactory.CreateMethodSymbol( - attributes:=ImmutableArray(Of AttributeData).Empty, - accessibility:=Accessibility.Private, - modifiers:=CreateMethodModifiers(), - returnType:=Me.AnalyzerResult.ReturnType, - refKind:=RefKind.None, - explicitInterfaceImplementations:=Nothing, - name:=_methodName.ToString(), - typeParameters:=CreateMethodTypeParameters(), - parameters:=CreateMethodParameters(), - statements:=statements.CastArray(Of SyntaxNode)) - - Return Me.MethodDefinitionAnnotation.AddAnnotationToSymbol( - Formatter.Annotation.AddAnnotationToSymbol(methodSymbol)) - End Function - - Protected Overrides Async Function GenerateBodyForCallSiteContainerAsync( - insertionPointNode As SyntaxNode, - container As SyntaxNode, - cancellationToken As CancellationToken) As Task(Of SyntaxNode) - Dim variableMapToRemove = CreateVariableDeclarationToRemoveMap(AnalyzerResult.GetVariablesToMoveIntoMethodDefinition(cancellationToken), cancellationToken) - Dim firstStatementToRemove = GetFirstStatementOrInitializerSelectedAtCallSite() - Dim lastStatementToRemove = GetLastStatementOrInitializerSelectedAtCallSite() - - Contract.ThrowIfFalse(firstStatementToRemove.Parent Is lastStatementToRemove.Parent) - - Dim statementsToInsert = Await CreateStatementsToInsertAtCallSiteAsync( - insertionPointNode, cancellationToken).ConfigureAwait(False) - - Dim callSiteGenerator = New CallSiteContainerRewriter( - container, - variableMapToRemove, - firstStatementToRemove, - lastStatementToRemove, - statementsToInsert) - - Return container.CopyAnnotationsTo(callSiteGenerator.Generate()).WithAdditionalAnnotations(Formatter.Annotation) - End Function - - Private Async Function CreateStatementsToInsertAtCallSiteAsync( - insertionPointNode As SyntaxNode, cancellationToken As CancellationToken) As Task(Of IEnumerable(Of StatementSyntax)) - Dim semanticModel = SemanticDocument.SemanticModel - Dim postProcessor = New PostProcessor(semanticModel, insertionPointNode.SpanStart) - - Dim statements = AddSplitOrMoveDeclarationOutStatementsToCallSite(cancellationToken) - statements = postProcessor.MergeDeclarationStatements(statements) - statements = AddAssignmentStatementToCallSite(statements, cancellationToken) - statements = Await AddInvocationAtCallSiteAsync(statements, cancellationToken).ConfigureAwait(False) - statements = AddReturnIfUnreachable(statements) - - Return statements - End Function - - Private Function CreateMethodNameForInvocation() As ExpressionSyntax - If AnalyzerResult.MethodTypeParametersInDeclaration.Count = 0 Then - Return SyntaxFactory.IdentifierName(_methodName) - End If + Partial Friend NotInheritable Class VisualBasicExtractMethodService + Partial Friend Class VisualBasicMethodExtractor + Partial Private MustInherit Class VisualBasicCodeGenerator + Inherits CodeGenerator(Of StatementSyntax, VisualBasicCodeGenerationOptions) + + Private ReadOnly _methodName As SyntaxToken + + Public Shared Function Create( + selectionResult As SelectionResult, + analyzerResult As AnalyzerResult, + options As ExtractMethodGenerationOptions) As VisualBasicCodeGenerator + If selectionResult.IsExtractMethodOnExpression Then + Return New ExpressionCodeGenerator(selectionResult, analyzerResult, options) + End If - Return SyntaxFactory.GenericName(_methodName, SyntaxFactory.TypeArgumentList(arguments:=CreateMethodCallTypeVariables())) - End Function - - Private Function CreateMethodCallTypeVariables() As SeparatedSyntaxList(Of TypeSyntax) - Contract.ThrowIfTrue(AnalyzerResult.MethodTypeParametersInDeclaration.Count = 0) - - ' propagate any type variable used in extracted code - Dim typeVariables = (From methodTypeParameter In AnalyzerResult.MethodTypeParametersInDeclaration - Select SyntaxFactory.ParseTypeName(methodTypeParameter.Name)).ToList() - - Return SyntaxFactory.SeparatedList(typeVariables) - End Function + If selectionResult.IsExtractMethodOnSingleStatement() Then + Return New SingleStatementCodeGenerator(selectionResult, analyzerResult, options) + End If - Protected Overrides Function GetCallSiteContainerFromOutermostMoveInVariable(cancellationToken As CancellationToken) As SyntaxNode - Dim outmostVariable = GetOutermostVariableToMoveIntoMethodDefinition(cancellationToken) - If outmostVariable Is Nothing Then - Return Nothing - End If - - Dim idToken = outmostVariable.GetIdentifierTokenAtDeclaration(SemanticDocument) - Dim declStatement = idToken.GetAncestor(Of LocalDeclarationStatementSyntax)() - - Contract.ThrowIfNull(declStatement) - Contract.ThrowIfFalse(declStatement.Parent.IsStatementContainerNode()) - - Return declStatement.Parent - End Function + If selectionResult.IsExtractMethodOnMultipleStatements() Then + Return New MultipleStatementsCodeGenerator(selectionResult, analyzerResult, options) + End If - Private Function CreateMethodModifiers() As DeclarationModifiers - Dim isShared = False - - If Not Me.AnalyzerResult.UseInstanceMember AndAlso - Not Me.SelectionResult.IsUnderModuleBlock() AndAlso - Not Me.SelectionResult.ContainsInstanceExpression() Then - isShared = True - End If - - Dim isAsync = Me.SelectionResult.ShouldPutAsyncModifier() - - Return New DeclarationModifiers(isStatic:=isShared, isAsync:=isAsync) - End Function - - Public Overrides Function GetNewMethodStatements( - insertionPointNode As SyntaxNode, cancellationToken As CancellationToken) As OperationStatus(Of ImmutableArray(Of SyntaxNode)) - Dim statements = CreateMethodBody(insertionPointNode, cancellationToken) - Dim status = CheckActiveStatements(statements) - Return status.With(statements.CastArray(Of SyntaxNode)) - End Function + Throw ExceptionUtilities.UnexpectedValue(selectionResult) + End Function - Private Function CreateMethodBody(insertionPointNode As SyntaxNode, cancellationToken As CancellationToken) As ImmutableArray(Of StatementSyntax) - Dim statements = GetInitialStatementsForMethodDefinitions() - statements = SplitOrMoveDeclarationIntoMethodDefinition(insertionPointNode, statements, cancellationToken) - statements = MoveDeclarationOutFromMethodDefinition(statements, cancellationToken) + Protected Sub New( + selectionResult As SelectionResult, + analyzerResult As AnalyzerResult, + options As ExtractMethodGenerationOptions) + MyBase.New(selectionResult, analyzerResult, options, localFunction:=False) + Contract.ThrowIfFalse(Me.SemanticDocument Is selectionResult.SemanticDocument) - Dim emptyStatements = ImmutableArray(Of StatementSyntax).Empty - Dim returnStatements = AppendReturnStatementIfNeeded(emptyStatements) + Me._methodName = CreateMethodName().WithAdditionalAnnotations(MethodNameAnnotation) + End Sub - statements = statements.Concat(returnStatements) + Protected Overrides Function UpdateMethodAfterGenerationAsync(originalDocument As SemanticDocument, methodSymbol As IMethodSymbol, cancellationToken As CancellationToken) As Task(Of SemanticDocument) + Return Task.FromResult(originalDocument) + End Function - Dim semanticModel = SemanticDocument.SemanticModel + Protected Overrides Function ShouldLocalFunctionCaptureParameter(node As SyntaxNode) As Boolean + Return False + End Function + + Protected Overrides Function GenerateMethodDefinition(insertionPointNode As SyntaxNode, cancellationToken As CancellationToken) As IMethodSymbol + Dim statements = CreateMethodBody(insertionPointNode, cancellationToken) + + Dim methodSymbol = CodeGenerationSymbolFactory.CreateMethodSymbol( + attributes:=ImmutableArray(Of AttributeData).Empty, + accessibility:=Accessibility.Private, + modifiers:=CreateMethodModifiers(), + returnType:=Me.AnalyzerResult.ReturnType, + refKind:=RefKind.None, + explicitInterfaceImplementations:=Nothing, + name:=_methodName.ToString(), + typeParameters:=CreateMethodTypeParameters(), + parameters:=CreateMethodParameters(), + statements:=statements.CastArray(Of SyntaxNode)) + + Return MethodDefinitionAnnotation.AddAnnotationToSymbol( + Formatter.Annotation.AddAnnotationToSymbol(methodSymbol)) + End Function + + Protected Overrides Async Function GenerateBodyForCallSiteContainerAsync( + insertionPointNode As SyntaxNode, + container As SyntaxNode, + cancellationToken As CancellationToken) As Task(Of SyntaxNode) + Dim variableMapToRemove = CreateVariableDeclarationToRemoveMap(AnalyzerResult.GetVariablesToMoveIntoMethodDefinition(), cancellationToken) + Dim firstStatementToRemove = GetFirstStatementOrInitializerSelectedAtCallSite() + Dim lastStatementToRemove = GetLastStatementOrInitializerSelectedAtCallSite() + + Contract.ThrowIfFalse(firstStatementToRemove.Parent Is lastStatementToRemove.Parent) + + Dim statementsToInsert = Await CreateStatementsToInsertAtCallSiteAsync( + insertionPointNode, cancellationToken).ConfigureAwait(False) + + Dim callSiteGenerator = New CallSiteContainerRewriter( + container, + variableMapToRemove, + firstStatementToRemove, + lastStatementToRemove, + statementsToInsert) + + Return container.CopyAnnotationsTo(callSiteGenerator.Generate()).WithAdditionalAnnotations(Formatter.Annotation) + End Function + + Private Async Function CreateStatementsToInsertAtCallSiteAsync( + insertionPointNode As SyntaxNode, cancellationToken As CancellationToken) As Task(Of IEnumerable(Of StatementSyntax)) + Dim semanticModel = SemanticDocument.SemanticModel + Dim postProcessor = New PostProcessor(semanticModel, insertionPointNode.SpanStart) + + Dim statements = AddSplitOrMoveDeclarationOutStatementsToCallSite(cancellationToken) + statements = postProcessor.MergeDeclarationStatements(statements) + statements = AddAssignmentStatementToCallSite(statements, cancellationToken) + statements = Await AddInvocationAtCallSiteAsync(statements, cancellationToken).ConfigureAwait(False) + statements = AddReturnIfUnreachable(statements, cancellationToken) + + Return statements + End Function + + Private Function CreateMethodNameForInvocation() As SimpleNameSyntax + If AnalyzerResult.MethodTypeParametersInDeclaration.Count = 0 Then + Return SyntaxFactory.IdentifierName(_methodName) + End If - statements = PostProcessor.RemoveDeclarationAssignmentPattern(statements) - statements = PostProcessor.RemoveInitializedDeclarationAndReturnPattern(statements) + Return SyntaxFactory.GenericName(_methodName, SyntaxFactory.TypeArgumentList(arguments:=CreateMethodCallTypeVariables())) + End Function - Return statements - End Function + Private Function CreateMethodCallTypeVariables() As SeparatedSyntaxList(Of TypeSyntax) + Contract.ThrowIfTrue(AnalyzerResult.MethodTypeParametersInDeclaration.Count = 0) - Private Shared Function CheckActiveStatements(statements As ImmutableArray(Of StatementSyntax)) As OperationStatus - Dim count = statements.Count() - If count = 0 Then - Return OperationStatus.NoActiveStatement - End If + ' propagate any type variable used in extracted code + Return SyntaxFactory.SeparatedList( + From methodTypeParameter In AnalyzerResult.MethodTypeParametersInDeclaration + Select SyntaxFactory.ParseTypeName(methodTypeParameter.Name)) + End Function - If count = 1 Then - Dim returnStatement = TryCast(statements(0), ReturnStatementSyntax) - If returnStatement IsNot Nothing AndAlso returnStatement.Expression Is Nothing Then - Return OperationStatus.NoActiveStatement + Protected Overrides Function GetCallSiteContainerFromOutermostMoveInVariable() As SyntaxNode + Dim outmostVariable = GetOutermostVariableToMoveIntoMethodDefinition() + If outmostVariable Is Nothing Then + Return Nothing End If - End If - For Each statement In statements - Dim localDeclStatement = TryCast(statement, LocalDeclarationStatementSyntax) - If localDeclStatement Is Nothing Then - 'found one - Return OperationStatus.SucceededStatus - End If + Dim idToken = outmostVariable.GetIdentifierTokenAtDeclaration(SemanticDocument) + Dim declStatement = idToken.GetAncestor(Of LocalDeclarationStatementSyntax)() - For Each variableDecl In localDeclStatement.Declarators - If variableDecl.Initializer IsNot Nothing Then - 'found one - Return OperationStatus.SucceededStatus - ElseIf TypeOf variableDecl.AsClause Is AsNewClauseSyntax Then - 'found one - Return OperationStatus.SucceededStatus - End If - Next - Next + Contract.ThrowIfNull(declStatement) + Contract.ThrowIfFalse(declStatement.Parent.IsStatementContainerNode()) - Return OperationStatus.NoActiveStatement - End Function + Return declStatement.Parent + End Function - Private Function MoveDeclarationOutFromMethodDefinition(statements As ImmutableArray(Of StatementSyntax), cancellationToken As CancellationToken) As ImmutableArray(Of StatementSyntax) - Dim variableToRemoveMap = CreateVariableDeclarationToRemoveMap( - Me.AnalyzerResult.GetVariablesToMoveOutToCallSiteOrDelete(cancellationToken), cancellationToken) + Private Function IsUnderModuleBlock() As Boolean + Dim currentScope = Me.SelectionResult.GetContainingScope() + Dim types = currentScope.GetAncestors(Of TypeBlockSyntax)() - Dim declarationStatements = New List(Of StatementSyntax)() + Return types.Any(Function(t) t.BlockStatement.Kind = SyntaxKind.ModuleStatement) + End Function - For Each statement In statements + Public Function ContainsInstanceExpression() As Boolean + Dim first = Me.SelectionResult.GetFirstTokenInSelection() + Dim last = Me.SelectionResult.GetLastTokenInSelection() + Dim node = first.GetCommonRoot(last) - Dim declarationStatement = TryCast(statement, LocalDeclarationStatementSyntax) - If declarationStatement Is Nothing Then - ' if given statement is not decl statement, do nothing. - declarationStatements.Add(statement) - Continue For - End If + Return node.DescendantNodesAndSelf(TextSpan.FromBounds(first.SpanStart, last.Span.End)). + Any(Function(n) TypeOf n Is InstanceExpressionSyntax) + End Function - Dim expressionStatements = New List(Of StatementSyntax)() - Dim variableDeclarators = New List(Of VariableDeclaratorSyntax)() - Dim triviaList = New List(Of SyntaxTrivia)() + Private Function CreateMethodModifiers() As DeclarationModifiers + Dim isShared = False - If Not variableToRemoveMap.ProcessLocalDeclarationStatement(declarationStatement, expressionStatements, variableDeclarators, triviaList) Then - declarationStatements.Add(statement) - Continue For + If Not Me.AnalyzerResult.UseInstanceMember AndAlso + Not IsUnderModuleBlock() AndAlso + Not ContainsInstanceExpression() Then + isShared = True End If - If variableDeclarators.Count = 0 AndAlso - triviaList.Any(Function(t) t.Kind <> SyntaxKind.WhitespaceTrivia AndAlso t.Kind <> SyntaxKind.EndOfLineTrivia) Then - ' well, there are trivia associated with the node. - ' we can't just delete the node since then, we will lose - ' the trivia. unfortunately, it is not easy to attach the trivia - ' to next token. for now, create an empty statement and associate the - ' trivia to the statement + Dim isAsync = Me.SelectionResult.CreateAsyncMethod() - ' TODO : think about a way to trivia attached to next token - Dim emptyStatement = SyntaxFactory.EmptyStatement(SyntaxFactory.Token(SyntaxKind.EmptyToken).WithLeadingTrivia(SyntaxFactory.TriviaList(triviaList))) - declarationStatements.Add(emptyStatement) + Return New DeclarationModifiers(isStatic:=isShared, isAsync:=isAsync) + End Function - triviaList.Clear() - End If + Public Overrides Function GetNewMethodStatements( + insertionPointNode As SyntaxNode, cancellationToken As CancellationToken) As OperationStatus(Of ImmutableArray(Of SyntaxNode)) + Dim statements = CreateMethodBody(insertionPointNode, cancellationToken) + Dim status = CheckActiveStatements(statements) + Return status.With(statements.CastArray(Of SyntaxNode)) + End Function + + Private Function CreateMethodBody(insertionPointNode As SyntaxNode, cancellationToken As CancellationToken) As ImmutableArray(Of StatementSyntax) + Dim statements = GetInitialStatementsForMethodDefinitions() + statements = SplitOrMoveDeclarationIntoMethodDefinition(insertionPointNode, statements, cancellationToken) + statements = MoveDeclarationOutFromMethodDefinition(statements, cancellationToken) + + Dim emptyStatements = ImmutableArray(Of StatementSyntax).Empty + Dim returnStatements = AppendReturnStatementIfNeeded(emptyStatements) + + statements = statements.Concat(returnStatements) + + Dim semanticModel = SemanticDocument.SemanticModel - ' return survived var decls - If variableDeclarators.Count > 0 Then - Dim localStatement = - SyntaxFactory.LocalDeclarationStatement( - declarationStatement.Modifiers, - SyntaxFactory.SeparatedList(variableDeclarators)).WithPrependedLeadingTrivia(triviaList) + statements = PostProcessor.RemoveDeclarationAssignmentPattern(statements) + statements = PostProcessor.RemoveInitializedDeclarationAndReturnPattern(statements) - declarationStatements.Add(localStatement) - triviaList.Clear() + Return statements + End Function + + Private Shared Function CheckActiveStatements(statements As ImmutableArray(Of StatementSyntax)) As OperationStatus + Dim count = statements.Count() + If count = 0 Then + Return OperationStatus.NoActiveStatement End If - ' return any expression statement if there was any - For Each expressionStatement In expressionStatements - declarationStatements.Add(expressionStatement) - Next expressionStatement - Next - - Return declarationStatements.ToImmutableArray() - End Function - - Private Function SplitOrMoveDeclarationIntoMethodDefinition( - insertionPointNode As SyntaxNode, - statements As ImmutableArray(Of StatementSyntax), - cancellationToken As CancellationToken) As ImmutableArray(Of StatementSyntax) - Dim semanticModel = Me.SemanticDocument.SemanticModel - Dim postProcessor = New PostProcessor(semanticModel, insertionPointNode.SpanStart) - - Dim declStatements = CreateDeclarationStatements(AnalyzerResult.GetVariablesToSplitOrMoveIntoMethodDefinition(cancellationToken), cancellationToken) - declStatements = postProcessor.MergeDeclarationStatements(declStatements) - - Return declStatements.Concat(statements) - End Function - - Protected Overrides Function CreateIdentifier(name As String) As SyntaxToken - Return SyntaxFactory.Identifier(name) - End Function - - Protected Overrides Function CreateReturnStatement(Optional identifierName As String = Nothing) As StatementSyntax - If String.IsNullOrEmpty(identifierName) Then - Return SyntaxFactory.ReturnStatement() - End If - - Return SyntaxFactory.ReturnStatement(expression:=SyntaxFactory.IdentifierName(identifierName)) - End Function - - Protected Overrides Function LastStatementOrHasReturnStatementInReturnableConstruct() As Boolean - Dim lastStatement = GetLastStatementOrInitializerSelectedAtCallSite() - Dim container = lastStatement.GetAncestorsOrThis(Of SyntaxNode).Where(Function(n) n.IsReturnableConstruct()).FirstOrDefault() - If container Is Nothing Then - ' case such as field initializer - Return False - End If + If count = 1 Then + Dim returnStatement = TryCast(statements(0), ReturnStatementSyntax) + If returnStatement IsNot Nothing AndAlso returnStatement.Expression Is Nothing Then + Return OperationStatus.NoActiveStatement + End If + End If - Dim statements = container.GetStatements() - If statements.Count = 0 Then - ' such as expression lambda - Return False - End If - - If statements.Last() Is lastStatement Then - Return True - End If - - Dim index = statements.IndexOf(lastStatement) - Return statements(index + 1).IsKind(SyntaxKind.ReturnStatement, SyntaxKind.ExitSubStatement) - End Function - - Protected Overrides Function CreateCallSignature() As ExpressionSyntax - Dim methodName As ExpressionSyntax = CreateMethodNameForInvocation().WithAdditionalAnnotations(Simplifier.Annotation) - - Dim arguments = New List(Of ArgumentSyntax)() - For Each argument In AnalyzerResult.MethodParameters - arguments.Add(SyntaxFactory.SimpleArgument(expression:=GetIdentifierName(argument.Name))) - Next argument - - Dim invocation = SyntaxFactory.InvocationExpression( - methodName, SyntaxFactory.ArgumentList(arguments:=SyntaxFactory.SeparatedList(arguments))) - - If Me.SelectionResult.ShouldPutAsyncModifier() Then - If Me.SelectionResult.ShouldCallConfigureAwaitFalse() Then - If AnalyzerResult.ReturnType.GetMembers().Any( - Function(x) - Dim method = TryCast(x, IMethodSymbol) - If method Is Nothing Then - Return False - End If + For Each statement In statements + Dim localDeclStatement = TryCast(statement, LocalDeclarationStatementSyntax) + If localDeclStatement Is Nothing Then + 'found one + Return OperationStatus.SucceededStatus + End If - If Not CaseInsensitiveComparison.Equals(method.Name, NameOf(Task.ConfigureAwait)) Then - Return False + For Each variableDecl In localDeclStatement.Declarators + If variableDecl.Initializer IsNot Nothing Then + 'found one + Return OperationStatus.SucceededStatus + ElseIf TypeOf variableDecl.AsClause Is AsNewClauseSyntax Then + 'found one + Return OperationStatus.SucceededStatus End If + Next + Next - If method.Parameters.Length <> 1 Then - Return False - End If + Return OperationStatus.NoActiveStatement + End Function + + Private Function MoveDeclarationOutFromMethodDefinition(statements As ImmutableArray(Of StatementSyntax), cancellationToken As CancellationToken) As ImmutableArray(Of StatementSyntax) + Dim variableToRemoveMap = CreateVariableDeclarationToRemoveMap( + Me.AnalyzerResult.GetVariablesToMoveOutToCallSiteOrDelete(), cancellationToken) - Return method.Parameters(0).Type.SpecialType = SpecialType.System_Boolean - End Function) Then - - invocation = SyntaxFactory.InvocationExpression( - SyntaxFactory.MemberAccessExpression( - SyntaxKind.SimpleMemberAccessExpression, - invocation, - SyntaxFactory.Token(SyntaxKind.DotToken), - SyntaxFactory.IdentifierName(NameOf(Task.ConfigureAwait))), - SyntaxFactory.ArgumentList(SyntaxFactory.SingletonSeparatedList(Of ArgumentSyntax)( - SyntaxFactory.SimpleArgument( - SyntaxFactory.LiteralExpression( - SyntaxKind.FalseLiteralExpression, - SyntaxFactory.Token(SyntaxKind.FalseKeyword)))))) + Dim declarationStatements = New List(Of StatementSyntax)() + + For Each statement In statements + + Dim declarationStatement = TryCast(statement, LocalDeclarationStatementSyntax) + If declarationStatement Is Nothing Then + ' if given statement is not decl statement, do nothing. + declarationStatements.Add(statement) + Continue For End If - End If - Return SyntaxFactory.AwaitExpression(invocation) - End If + Dim expressionStatements = New List(Of StatementSyntax)() + Dim variableDeclarators = New List(Of VariableDeclaratorSyntax)() + Dim triviaList = New List(Of SyntaxTrivia)() + + If Not variableToRemoveMap.ProcessLocalDeclarationStatement(declarationStatement, expressionStatements, variableDeclarators, triviaList) Then + declarationStatements.Add(statement) + Continue For + End If + + If variableDeclarators.Count = 0 AndAlso + triviaList.Any(Function(t) t.Kind <> SyntaxKind.WhitespaceTrivia AndAlso t.Kind <> SyntaxKind.EndOfLineTrivia) Then + ' well, there are trivia associated with the node. + ' we can't just delete the node since then, we will lose + ' the trivia. unfortunately, it is not easy to attach the trivia + ' to next token. for now, create an empty statement and associate the + ' trivia to the statement + + ' TODO : think about a way to trivia attached to next token + Dim emptyStatement = SyntaxFactory.EmptyStatement(SyntaxFactory.Token(SyntaxKind.EmptyToken).WithLeadingTrivia(SyntaxFactory.TriviaList(triviaList))) + declarationStatements.Add(emptyStatement) - Return invocation - End Function + triviaList.Clear() + End If + + ' return survived var decls + If variableDeclarators.Count > 0 Then + Dim localStatement = + SyntaxFactory.LocalDeclarationStatement( + declarationStatement.Modifiers, + SyntaxFactory.SeparatedList(variableDeclarators)).WithPrependedLeadingTrivia(triviaList) - Private Shared Function GetIdentifierName(name As String) As ExpressionSyntax - Dim bracket = SyntaxFacts.MakeHalfWidthIdentifier(name.First) = "[" AndAlso SyntaxFacts.MakeHalfWidthIdentifier(name.Last) = "]" - If bracket Then - Dim unescaped = name.Substring(1, name.Length() - 2) - Return SyntaxFactory.IdentifierName(SyntaxFactory.BracketedIdentifier(unescaped)) - End If + declarationStatements.Add(localStatement) + triviaList.Clear() + End If - Return SyntaxFactory.IdentifierName(name) - End Function + ' return any expression statement if there was any + For Each expressionStatement In expressionStatements + declarationStatements.Add(expressionStatement) + Next expressionStatement + Next - Protected Overrides Function CreateAssignmentExpressionStatement(identifier As SyntaxToken, rvalue As ExpressionSyntax) As StatementSyntax - Return identifier.CreateAssignmentExpressionStatementWithValue(rvalue) - End Function + Return declarationStatements.ToImmutableArray() + End Function - Protected Overrides Function CreateDeclarationStatement( - variable As VariableInfo, - givenInitializer As ExpressionSyntax, - cancellationToken As CancellationToken) As StatementSyntax + Private Function SplitOrMoveDeclarationIntoMethodDefinition( + insertionPointNode As SyntaxNode, + statements As ImmutableArray(Of StatementSyntax), + cancellationToken As CancellationToken) As ImmutableArray(Of StatementSyntax) + Dim semanticModel = Me.SemanticDocument.SemanticModel + Dim postProcessor = New PostProcessor(semanticModel, insertionPointNode.SpanStart) - Dim shouldInitializeWithNothing = (variable.GetDeclarationBehavior(cancellationToken) = DeclarationBehavior.MoveOut OrElse variable.GetDeclarationBehavior(cancellationToken) = DeclarationBehavior.SplitOut) AndAlso - (variable.ParameterModifier = ParameterBehavior.Out) + Dim declStatements = CreateDeclarationStatements(AnalyzerResult.GetVariablesToSplitOrMoveIntoMethodDefinition(), cancellationToken) + declStatements = postProcessor.MergeDeclarationStatements(declStatements) - Dim initializer = If(givenInitializer, If(shouldInitializeWithNothing, SyntaxFactory.NothingLiteralExpression(SyntaxFactory.Token(SyntaxKind.NothingKeyword)), Nothing)) + Return declStatements.Concat(statements) + End Function - Dim variableType = variable.GetVariableType() - Dim typeNode = variableType.GenerateTypeSyntax() + Protected Overrides Function CreateIdentifier(name As String) As SyntaxToken + Return name.ToIdentifierToken() + End Function + + Protected Overrides Function CreateReturnStatement(ParamArray identifierNames As String()) As StatementSyntax + Contract.ThrowIfTrue(identifierNames.Length > 1) + + If identifierNames.Length = 0 Then + Return SyntaxFactory.ReturnStatement() + End If - Dim names = SyntaxFactory.SingletonSeparatedList(SyntaxFactory.ModifiedIdentifier(SyntaxFactory.Identifier(variable.Name))) - Dim modifiers = SyntaxFactory.TokenList(SyntaxFactory.Token(SyntaxKind.DimKeyword)) - Dim equalsValue = If(initializer Is Nothing, Nothing, SyntaxFactory.EqualsValue(value:=initializer)) - Dim declarators = SyntaxFactory.SingletonSeparatedList(SyntaxFactory.VariableDeclarator(names, SyntaxFactory.SimpleAsClause(type:=typeNode), equalsValue)) + Return SyntaxFactory.ReturnStatement(identifierNames(0).ToIdentifierName()) + End Function - Return SyntaxFactory.LocalDeclarationStatement(modifiers, declarators) - End Function + Protected Overrides Function LastStatementOrHasReturnStatementInReturnableConstruct() As Boolean + Dim lastStatement = GetLastStatementOrInitializerSelectedAtCallSite() + Dim container = lastStatement.GetAncestorsOrThis(Of SyntaxNode).Where(Function(n) n.IsReturnableConstruct()).FirstOrDefault() + If container Is Nothing Then + ' case such as field initializer + Return False + End If - Protected Overrides Async Function CreateGeneratedCodeAsync(newDocument As SemanticDocument, cancellationToken As CancellationToken) As Task(Of GeneratedCode) - ' in hybrid code cases such as extract method, formatter will have some difficulties on where it breaks lines in two. - ' here, we explicitly insert newline at the end of auto generated method decl's begin statement so that anchor knows how to find out - ' indentation of inserted statements (from users code) with user code style preserved - Dim root = newDocument.Root - Dim methodDefinition = root.GetAnnotatedNodes(Of MethodBlockBaseSyntax)(Me.MethodDefinitionAnnotation).First() - Dim lastTokenOfBeginStatement = methodDefinition.BlockStatement.GetLastToken(includeZeroWidth:=True) + Dim statements = container.GetStatements() + If statements.Count = 0 Then + ' such as expression lambda + Return False + End If - Dim newMethodDefinition = methodDefinition.ReplaceToken( - lastTokenOfBeginStatement, - lastTokenOfBeginStatement.WithAppendedTrailingTrivia( - SpecializedCollections.SingletonEnumerable(SyntaxFactory.ElasticCarriageReturnLineFeed))) + If statements.Last() Is lastStatement Then + Return True + End If - newDocument = Await newDocument.WithSyntaxRootAsync(root.ReplaceNode(methodDefinition, newMethodDefinition), cancellationToken).ConfigureAwait(False) + Dim index = statements.IndexOf(lastStatement) + Return statements(index + 1).IsKind(SyntaxKind.ReturnStatement, SyntaxKind.ExitSubStatement) + End Function + + Protected Overrides Function CreateCallSignature() As ExpressionSyntax + Dim methodName = CreateMethodNameForInvocation().WithAdditionalAnnotations(Simplifier.Annotation) + + Dim methodExpression = + If(Me.AnalyzerResult.UseInstanceMember AndAlso Me.ExtractMethodGenerationOptions.SimplifierOptions.QualifyMethodAccess.Value, + SyntaxFactory.MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, SyntaxFactory.MeExpression(), SyntaxFactory.Token(SyntaxKind.DotToken), methodName), + DirectCast(methodName, ExpressionSyntax)) + + Dim arguments = New List(Of ArgumentSyntax)() + For Each argument In AnalyzerResult.MethodParameters + arguments.Add(SyntaxFactory.SimpleArgument(GetIdentifierName(argument.Name))) + Next argument + + Dim invocation = SyntaxFactory.InvocationExpression( + methodExpression, SyntaxFactory.ArgumentList(SyntaxFactory.SeparatedList(arguments))) + + If Me.SelectionResult.CreateAsyncMethod() Then + If Me.SelectionResult.ShouldCallConfigureAwaitFalse() Then + If AnalyzerResult.ReturnType.GetMembers().Any( + Function(x) + Dim method = TryCast(x, IMethodSymbol) + If method Is Nothing Then + Return False + End If + + If Not CaseInsensitiveComparison.Equals(method.Name, NameOf(Task.ConfigureAwait)) Then + Return False + End If + + If method.Parameters.Length <> 1 Then + Return False + End If + + Return method.Parameters(0).Type.SpecialType = SpecialType.System_Boolean + End Function) Then + + invocation = SyntaxFactory.InvocationExpression( + SyntaxFactory.MemberAccessExpression( + SyntaxKind.SimpleMemberAccessExpression, + invocation, + SyntaxFactory.Token(SyntaxKind.DotToken), + SyntaxFactory.IdentifierName(NameOf(Task.ConfigureAwait))), + SyntaxFactory.ArgumentList(SyntaxFactory.SingletonSeparatedList(Of ArgumentSyntax)( + SyntaxFactory.SimpleArgument( + SyntaxFactory.LiteralExpression( + SyntaxKind.FalseLiteralExpression, + SyntaxFactory.Token(SyntaxKind.FalseKeyword)))))) + End If + End If - Return Await MyBase.CreateGeneratedCodeAsync(newDocument, cancellationToken).ConfigureAwait(False) - End Function + Return SyntaxFactory.AwaitExpression(invocation) + End If - Protected Function GetStatementContainingInvocationToExtractedMethodWorker() As StatementSyntax - Dim callSignature = CreateCallSignature() + Return invocation + End Function - If Me.AnalyzerResult.HasReturnType Then - Contract.ThrowIfTrue(Me.AnalyzerResult.HasVariableToUseAsReturnValue) - Return SyntaxFactory.ReturnStatement(expression:=callSignature) - End If + Private Shared Function GetIdentifierName(name As String) As ExpressionSyntax + Dim bracket = SyntaxFacts.MakeHalfWidthIdentifier(name.First) = "[" AndAlso SyntaxFacts.MakeHalfWidthIdentifier(name.Last) = "]" + If bracket Then + Dim unescaped = name.Substring(1, name.Length() - 2) + Return SyntaxFactory.IdentifierName(SyntaxFactory.BracketedIdentifier(unescaped)) + End If - Return SyntaxFactory.ExpressionStatement(expression:=callSignature) - End Function + Return SyntaxFactory.IdentifierName(name) + End Function + + Protected Overrides Function CreateAssignmentExpressionStatement( + variables As ImmutableArray(Of VariableInfo), + rvalue As ExpressionSyntax) As StatementSyntax + Contract.ThrowIfTrue(variables.Length <> 1) + Dim identifier = variables(0).Name.ToIdentifierToken() + Return identifier.CreateAssignmentExpressionStatementWithValue(rvalue) + End Function + + Protected Overrides Function CreateDeclarationStatement( + variables As ImmutableArray(Of VariableInfo), + initialValue As ExpressionSyntax, + cancellationToken As CancellationToken) As StatementSyntax + Contract.ThrowIfTrue(variables.Length <> 1) + + Dim variable = variables(0) + Dim shouldInitializeWithNothing = (variable.GetDeclarationBehavior() = DeclarationBehavior.MoveOut OrElse variable.GetDeclarationBehavior() = DeclarationBehavior.SplitOut) AndAlso + (variable.ParameterModifier = ParameterBehavior.Out) + + Dim initializer = If(initialValue, If(shouldInitializeWithNothing, SyntaxFactory.NothingLiteralExpression(SyntaxFactory.Token(SyntaxKind.NothingKeyword)), Nothing)) + + Dim typeNode = variable.SymbolType.GenerateTypeSyntax() + + Dim names = SyntaxFactory.SingletonSeparatedList(SyntaxFactory.ModifiedIdentifier(SyntaxFactory.Identifier(variable.Name))) + Dim modifiers = SyntaxFactory.TokenList(SyntaxFactory.Token(SyntaxKind.DimKeyword)) + Dim equalsValue = If(initializer Is Nothing, Nothing, SyntaxFactory.EqualsValue(value:=initializer)) + Dim declarators = SyntaxFactory.SingletonSeparatedList(SyntaxFactory.VariableDeclarator(names, SyntaxFactory.SimpleAsClause(type:=typeNode), equalsValue)) + + Return SyntaxFactory.LocalDeclarationStatement(modifiers, declarators) + End Function + + Protected Overrides Async Function PerformFinalTriviaFixupAsync(newDocument As SemanticDocument, cancellationToken As CancellationToken) As Task(Of SemanticDocument) + ' in hybrid code cases such as extract method, formatter will have some difficulties on where it breaks lines in two. + ' here, we explicitly insert newline at the end of auto generated method decl's begin statement so that anchor knows how to find out + ' indentation of inserted statements (from users code) with user code style preserved + Dim root = newDocument.Root + Dim methodDefinition = root.GetAnnotatedNodes(Of MethodBlockBaseSyntax)(MethodDefinitionAnnotation).First() + Dim lastTokenOfBeginStatement = methodDefinition.BlockStatement.GetLastToken(includeZeroWidth:=True) + + Dim newMethodDefinition = methodDefinition.ReplaceToken( + lastTokenOfBeginStatement, + lastTokenOfBeginStatement.WithAppendedTrailingTrivia( + SpecializedCollections.SingletonEnumerable(SyntaxFactory.ElasticCarriageReturnLineFeed))) + + newDocument = Await newDocument.WithSyntaxRootAsync(root.ReplaceNode(methodDefinition, newMethodDefinition), cancellationToken).ConfigureAwait(False) + + Return newDocument + End Function + End Class End Class End Class End Namespace diff --git a/src/Features/VisualBasic/Portable/ExtractMethod/VisualBasicMethodExtractor.vb b/src/Features/VisualBasic/Portable/ExtractMethod/VisualBasicMethodExtractor.vb index b91e75d865b27..de8f167f9db7a 100644 --- a/src/Features/VisualBasic/Portable/ExtractMethod/VisualBasicMethodExtractor.vb +++ b/src/Features/VisualBasic/Portable/ExtractMethod/VisualBasicMethodExtractor.vb @@ -2,134 +2,125 @@ ' The .NET Foundation licenses this file to you under the MIT license. ' See the LICENSE file in the project root for more information. -Imports System.Collections.Immutable Imports System.Threading -Imports Microsoft.CodeAnalysis -Imports Microsoft.CodeAnalysis.CodeGeneration Imports Microsoft.CodeAnalysis.ExtractMethod Imports Microsoft.CodeAnalysis.Formatting.Rules -Imports Microsoft.CodeAnalysis.Simplification Imports Microsoft.CodeAnalysis.VisualBasic -Imports Microsoft.CodeAnalysis.VisualBasic.CodeGeneration Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Namespace Microsoft.CodeAnalysis.VisualBasic.ExtractMethod - Partial Friend Class VisualBasicMethodExtractor - Inherits MethodExtractor(Of VisualBasicSelectionResult, ExecutableStatementSyntax, ExpressionSyntax) + Partial Friend NotInheritable Class VisualBasicExtractMethodService + Partial Friend Class VisualBasicMethodExtractor + Inherits MethodExtractor - Public Sub New(result As VisualBasicSelectionResult, options As ExtractMethodGenerationOptions) - MyBase.New(result, options, localFunction:=False) - End Sub - - Protected Overrides Function CreateCodeGenerator(analyzerResult As AnalyzerResult) As CodeGenerator - Return VisualBasicCodeGenerator.Create(Me.OriginalSelectionResult, analyzerResult, DirectCast(Me.Options.CodeGenerationOptions, VisualBasicCodeGenerationOptions)) - End Function - - Protected Overrides Function Analyze(selectionResult As VisualBasicSelectionResult, localFunction As Boolean, cancellationToken As CancellationToken) As AnalyzerResult - Return VisualBasicAnalyzer.AnalyzeResult(selectionResult, cancellationToken) - End Function - - Protected Overrides Function GetInsertionPointNode( - analyzerResult As AnalyzerResult, cancellationToken As CancellationToken) As SyntaxNode - Dim document = Me.OriginalSelectionResult.SemanticDocument - Dim originalSpanStart = OriginalSelectionResult.OriginalSpan.Start - Contract.ThrowIfFalse(originalSpanStart >= 0) + Public Sub New(result As SelectionResult, options As ExtractMethodGenerationOptions) + MyBase.New(result, options, localFunction:=False) + End Sub - Dim root = document.Root - Dim basePosition = root.FindToken(originalSpanStart) + Protected Overrides Function CreateCodeGenerator(selectionResult As SelectionResult, analyzerResult As AnalyzerResult) As CodeGenerator + Return VisualBasicCodeGenerator.Create(selectionResult, analyzerResult, Me.Options) + End Function - Dim enclosingTopLevelNode As SyntaxNode = basePosition.GetAncestor(Of PropertyBlockSyntax)() - If enclosingTopLevelNode Is Nothing Then - enclosingTopLevelNode = basePosition.GetAncestor(Of EventBlockSyntax)() - End If + Protected Overrides Function Analyze(cancellationToken As CancellationToken) As AnalyzerResult + Dim analyzer = New VisualBasicAnalyzer(Me.OriginalSelectionResult, cancellationToken) + Return analyzer.Analyze() + End Function - If enclosingTopLevelNode Is Nothing Then - enclosingTopLevelNode = basePosition.GetAncestor(Of MethodBlockBaseSyntax)() - End If + Protected Overrides Function GetInsertionPointNode( + analyzerResult As AnalyzerResult, cancellationToken As CancellationToken) As SyntaxNode + Dim document = Me.OriginalSelectionResult.SemanticDocument + Dim spanStart = OriginalSelectionResult.FinalSpan.Start + Contract.ThrowIfFalse(spanStart >= 0) - If enclosingTopLevelNode Is Nothing Then - enclosingTopLevelNode = basePosition.GetAncestor(Of FieldDeclarationSyntax)() - End If + Dim root = document.Root + Dim basePosition = root.FindToken(spanStart) - If enclosingTopLevelNode Is Nothing Then - enclosingTopLevelNode = basePosition.GetAncestor(Of PropertyStatementSyntax)() - End If + Dim enclosingTopLevelNode As SyntaxNode = basePosition.GetAncestor(Of PropertyBlockSyntax)() - Contract.ThrowIfNull(enclosingTopLevelNode) - Return enclosingTopLevelNode - End Function + enclosingTopLevelNode = If(enclosingTopLevelNode, basePosition.GetAncestor(Of EventBlockSyntax)) + enclosingTopLevelNode = If(enclosingTopLevelNode, basePosition.GetAncestor(Of MethodBlockBaseSyntax)) + enclosingTopLevelNode = If(enclosingTopLevelNode, basePosition.GetAncestor(Of FieldDeclarationSyntax)) + enclosingTopLevelNode = If(enclosingTopLevelNode, basePosition.GetAncestor(Of PropertyStatementSyntax)) - Protected Overrides Async Function PreserveTriviaAsync(selectionResult As VisualBasicSelectionResult, cancellationToken As CancellationToken) As Task(Of TriviaResult) - Return Await VisualBasicTriviaResult.ProcessAsync(selectionResult, cancellationToken).ConfigureAwait(False) - End Function + Contract.ThrowIfNull(enclosingTopLevelNode) + Return enclosingTopLevelNode + End Function - Protected Overrides Function GenerateCodeAsync(insertionPoint As InsertionPoint, selectionResult As VisualBasicSelectionResult, analyzeResult As AnalyzerResult, options As CodeGenerationOptions, cancellationToken As CancellationToken) As Task(Of GeneratedCode) - Return VisualBasicCodeGenerator.GenerateResultAsync(insertionPoint, selectionResult, analyzeResult, DirectCast(options, VisualBasicCodeGenerationOptions), cancellationToken) - End Function + Protected Overrides Async Function PreserveTriviaAsync(root As SyntaxNode, cancellationToken As CancellationToken) As Task(Of TriviaResult) + Dim semanticDocument = Me.OriginalSelectionResult.SemanticDocument + Dim preservationService = semanticDocument.Document.Project.Services.GetService(Of ISyntaxTriviaService)() - Protected Overrides Function GetCustomFormattingRule(document As Document) As AbstractFormattingRule - Return FormattingRule.Instance - End Function + Dim result = preservationService.SaveTriviaAroundSelection(root, Me.OriginalSelectionResult.FinalSpan) - Protected Overrides Function GetInvocationNameToken(methodNames As IEnumerable(Of SyntaxToken)) As SyntaxToken? - Return methodNames.FirstOrNull(Function(t) t.Parent.Kind <> SyntaxKind.SubStatement AndAlso t.Parent.Kind <> SyntaxKind.FunctionStatement) - End Function + Return New VisualBasicTriviaResult( + Await semanticDocument.WithSyntaxRootAsync(result.Root, cancellationToken).ConfigureAwait(False), + result) + End Function - Protected Overrides Function ParseTypeName(name As String) As SyntaxNode - Return SyntaxFactory.ParseTypeName(name) - End Function + Protected Overrides Function GetCustomFormattingRule(document As Document) As AbstractFormattingRule + Return FormattingRule.Instance + End Function - Private NotInheritable Class FormattingRule - Inherits CompatAbstractFormattingRule + Protected Overrides Function GetInvocationNameToken(methodNames As IEnumerable(Of SyntaxToken)) As SyntaxToken? + Return methodNames.FirstOrNull(Function(t) t.Parent.Kind <> SyntaxKind.SubStatement AndAlso t.Parent.Kind <> SyntaxKind.FunctionStatement) + End Function - Public Shared ReadOnly Instance As New FormattingRule() + Protected Overrides Function ParseTypeName(name As String) As SyntaxNode + Return SyntaxFactory.ParseTypeName(name) + End Function - Private Sub New() - End Sub + Private NotInheritable Class FormattingRule + Inherits CompatAbstractFormattingRule - Public Overrides Function GetAdjustNewLinesOperationSlow(ByRef previousToken As SyntaxToken, ByRef currentToken As SyntaxToken, ByRef nextOperation As NextGetAdjustNewLinesOperation) As AdjustNewLinesOperation - If Not previousToken.IsLastTokenOfStatement() Then - Return nextOperation.Invoke(previousToken, currentToken) - End If + Public Shared ReadOnly Instance As New FormattingRule() - ' between [generated code] and [existing code] - If Not CommonFormattingHelpers.HasAnyWhitespaceElasticTrivia(previousToken, currentToken) Then - Return nextOperation.Invoke(previousToken, currentToken) - End If + Private Sub New() + End Sub - ' make sure attribute and previous statement has at least 1 blank lines between them - If IsLessThanInAttribute(currentToken) Then - Return FormattingOperations.CreateAdjustNewLinesOperation(2, AdjustNewLinesOption.ForceLines) - End If + Public Overrides Function GetAdjustNewLinesOperationSlow(ByRef previousToken As SyntaxToken, ByRef currentToken As SyntaxToken, ByRef nextOperation As NextGetAdjustNewLinesOperation) As AdjustNewLinesOperation + If Not previousToken.IsLastTokenOfStatement() Then + Return nextOperation.Invoke(previousToken, currentToken) + End If - ' make sure previous statement and next type has at least 1 blank lines between them - If TypeOf currentToken.Parent Is TypeStatementSyntax AndAlso - currentToken.Parent.GetFirstToken(includeZeroWidth:=True) = currentToken Then - Return FormattingOperations.CreateAdjustNewLinesOperation(2, AdjustNewLinesOption.ForceLines) - End If + ' between [generated code] and [existing code] + If Not CommonFormattingHelpers.HasAnyWhitespaceElasticTrivia(previousToken, currentToken) Then + Return nextOperation.Invoke(previousToken, currentToken) + End If - Return nextOperation.Invoke(previousToken, currentToken) - End Function + ' make sure attribute and previous statement has at least 1 blank lines between them + If IsLessThanInAttribute(currentToken) Then + Return FormattingOperations.CreateAdjustNewLinesOperation(2, AdjustNewLinesOption.ForceLines) + End If - Private Shared Function IsLessThanInAttribute(token As SyntaxToken) As Boolean - ' < in attribute - If token.Kind = SyntaxKind.LessThanToken AndAlso - token.Parent.Kind = SyntaxKind.AttributeList AndAlso - DirectCast(token.Parent, AttributeListSyntax).LessThanToken.Equals(token) Then - Return True - End If + ' make sure previous statement and next type has at least 1 blank lines between them + If TypeOf currentToken.Parent Is TypeStatementSyntax AndAlso + currentToken.Parent.GetFirstToken(includeZeroWidth:=True) = currentToken Then + Return FormattingOperations.CreateAdjustNewLinesOperation(2, AdjustNewLinesOption.ForceLines) + End If - Return False + Return nextOperation.Invoke(previousToken, currentToken) + End Function + + Private Shared Function IsLessThanInAttribute(token As SyntaxToken) As Boolean + ' < in attribute + If token.Kind = SyntaxKind.LessThanToken AndAlso + token.Parent.Kind = SyntaxKind.AttributeList AndAlso + DirectCast(token.Parent, AttributeListSyntax).LessThanToken.Equals(token) Then + Return True + End If + + Return False + End Function + End Class + + Protected Overrides Function InsertNewLineBeforeLocalFunctionIfNecessaryAsync( + document As Document, + invocationNameToken? As SyntaxToken, + methodDefinition As SyntaxNode, + cancellationToken As CancellationToken) As Task(Of (document As Document, invocationNameToken As SyntaxToken?)) + ' VB doesn't need to do any correction, so we just return the values untouched + Return Task.FromResult((document, invocationNameToken)) End Function End Class - - Protected Overrides Function InsertNewLineBeforeLocalFunctionIfNecessaryAsync( - document As Document, - invocationNameToken? As SyntaxToken, - methodDefinition As SyntaxNode, - cancellationToken As CancellationToken) As Task(Of (document As Document, invocationNameToken As SyntaxToken?)) - ' VB doesn't need to do any correction, so we just return the values untouched - Return Task.FromResult((document, invocationNameToken)) - End Function End Class End Namespace diff --git a/src/Features/VisualBasic/Portable/ExtractMethod/VisualBasicSelectionResult.vb b/src/Features/VisualBasic/Portable/ExtractMethod/VisualBasicSelectionResult.vb index 41804ce0d728a..519669e55f160 100644 --- a/src/Features/VisualBasic/Portable/ExtractMethod/VisualBasicSelectionResult.vb +++ b/src/Features/VisualBasic/Portable/ExtractMethod/VisualBasicSelectionResult.vb @@ -2,11 +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. +Imports System.Collections.Immutable Imports System.Threading Imports Microsoft.CodeAnalysis Imports Microsoft.CodeAnalysis.ExtractMethod Imports Microsoft.CodeAnalysis.LanguageService -Imports Microsoft.CodeAnalysis.Options Imports Microsoft.CodeAnalysis.Text Imports Microsoft.CodeAnalysis.VisualBasic Imports Microsoft.CodeAnalysis.VisualBasic.LanguageService @@ -14,316 +14,367 @@ Imports Microsoft.CodeAnalysis.VisualBasic.Symbols Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Namespace Microsoft.CodeAnalysis.VisualBasic.ExtractMethod - Friend Class VisualBasicSelectionResult - Inherits SelectionResult(Of ExecutableStatementSyntax) - - Public Shared Async Function CreateResultAsync( - originalSpan As TextSpan, - finalSpan As TextSpan, - selectionInExpression As Boolean, - document As SemanticDocument, - firstToken As SyntaxToken, - lastToken As SyntaxToken, - selectionChanged As Boolean, - cancellationToken As CancellationToken) As Task(Of VisualBasicSelectionResult) - - Contract.ThrowIfNull(document) - - Dim firstAnnotation = New SyntaxAnnotation() - Dim lastAnnotation = New SyntaxAnnotation() - - Dim root = document.Root - Dim newDocument = Await SemanticDocument.CreateAsync(document.Document.WithSyntaxRoot(AddAnnotations( - root, {(firstToken, firstAnnotation), (lastToken, lastAnnotation)})), cancellationToken).ConfigureAwait(False) - - Return New VisualBasicSelectionResult( - originalSpan, - finalSpan, - selectionInExpression, - newDocument, - firstAnnotation, - lastAnnotation, - selectionChanged) - End Function - - Private Sub New( - originalSpan As TextSpan, - finalSpan As TextSpan, - selectionInExpression As Boolean, - document As SemanticDocument, - firstTokenAnnotation As SyntaxAnnotation, - lastTokenAnnotation As SyntaxAnnotation, - selectionChanged As Boolean) - - MyBase.New( - originalSpan, - finalSpan, - selectionInExpression, - document, - firstTokenAnnotation, - lastTokenAnnotation, - selectionChanged) - End Sub - - Protected Overrides ReadOnly Property SyntaxFacts As ISyntaxFacts = VisualBasicSyntaxFacts.Instance - - Protected Overrides Function UnderAnonymousOrLocalMethod(token As SyntaxToken, firstToken As SyntaxToken, lastToken As SyntaxToken) As Boolean - Dim current = token.Parent - - While current IsNot Nothing - If TypeOf current Is DeclarationStatementSyntax OrElse - TypeOf current Is LambdaExpressionSyntax Then - Exit While - End If + Partial Friend NotInheritable Class VisualBasicExtractMethodService + Friend NotInheritable Class VisualBasicSelectionResult + Inherits SelectionResult - current = current.Parent - End While + Public Shared Async Function CreateResultAsync( + document As SemanticDocument, + selectionInfo As FinalSelectionInfo, + cancellationToken As CancellationToken) As Task(Of VisualBasicSelectionResult) - If current Is Nothing OrElse TypeOf current Is DeclarationStatementSyntax Then - Return False - End If - - ' make sure selection contains the lambda - Return firstToken.SpanStart <= current.GetFirstToken().SpanStart AndAlso - current.GetLastToken().Span.End <= lastToken.Span.End - End Function - - Public Overrides Function GetOutermostCallSiteContainerToProcess(cancellationToken As CancellationToken) As SyntaxNode - If Me.SelectionInExpression Then - Dim container = Me.InnermostStatementContainer() - - Contract.ThrowIfNull(container) - Contract.ThrowIfFalse(container.IsStatementContainerNode() OrElse - TypeOf container Is TypeBlockSyntax OrElse - TypeOf container Is CompilationUnitSyntax) - - Return container - ElseIf Me.IsExtractMethodOnSingleStatement() Then - Dim first = Me.GetFirstStatement() - Return first.Parent - ElseIf Me.IsExtractMethodOnMultipleStatements() Then - Return Me.GetFirstStatementUnderContainer().Parent - Else - Throw ExceptionUtilities.Unreachable() - End If - End Function - - Public Overrides Function ContainingScopeHasAsyncKeyword() As Boolean - If SelectionInExpression Then - Return False - End If + Contract.ThrowIfNull(document) - Dim node = Me.GetContainingScope() - If TypeOf node Is MethodBlockBaseSyntax Then - Dim methodBlock = DirectCast(node, MethodBlockBaseSyntax) - If methodBlock.BlockStatement IsNot Nothing Then - Return methodBlock.BlockStatement.Modifiers.Any(SyntaxKind.AsyncKeyword) - End If + Dim root = document.Root + Dim newDocument = Await SemanticDocument.CreateAsync(document.Document.WithSyntaxRoot(AddAnnotations( + root, {(selectionInfo.FirstTokenInFinalSpan, s_firstTokenAnnotation), (selectionInfo.LastTokenInFinalSpan, s_lastTokenAnnotation)})), cancellationToken).ConfigureAwait(False) - Return False - ElseIf TypeOf node Is LambdaExpressionSyntax Then - Dim lambda = DirectCast(node, LambdaExpressionSyntax) - If lambda.SubOrFunctionHeader IsNot Nothing Then - Return lambda.SubOrFunctionHeader.Modifiers.Any(SyntaxKind.AsyncKeyword) - End If - End If + Return New VisualBasicSelectionResult( + newDocument, + selectionInfo.GetSelectionType(), + selectionInfo.FinalSpan) + End Function - Return False - End Function + Private Sub New( + document As SemanticDocument, + selectionType As SelectionType, + finalSpan As TextSpan) - Public Overrides Function GetContainingScope() As SyntaxNode - Contract.ThrowIfNull(Me.SemanticDocument) + MyBase.New(document, selectionType, finalSpan) + End Sub - Dim first = GetFirstTokenInSelection() + Protected Overrides Function UnderAnonymousOrLocalMethod(token As SyntaxToken, firstToken As SyntaxToken, lastToken As SyntaxToken) As Boolean + Dim current = token.Parent - If SelectionInExpression Then - Dim last = GetLastTokenInSelection() + While current IsNot Nothing + If TypeOf current Is DeclarationStatementSyntax OrElse + TypeOf current Is LambdaExpressionSyntax Then + Exit While + End If - Dim scope = first.GetCommonRoot(last).GetAncestorOrThis(Of ExpressionSyntax)() - Contract.ThrowIfNull(scope, "Should always find an expression given that SelectionInExpression was true") + current = current.Parent + End While - Return VisualBasicSyntaxFacts.Instance.GetRootStandaloneExpression(scope) - Else - ' it contains statements - Return first.GetAncestors(Of SyntaxNode).FirstOrDefault(Function(n) TypeOf n Is MethodBlockBaseSyntax OrElse TypeOf n Is LambdaExpressionSyntax) - End If - End Function + If current Is Nothing OrElse TypeOf current Is DeclarationStatementSyntax Then + Return False + End If - Public Overrides Function GetReturnType() As (returnType As ITypeSymbol, returnsByRef As Boolean) - ' Todo: consider supporting byref return types in VB - Dim returnType = GetReturnTypeWorker() - Return (returnType, returnsByRef:=False) - End Function + ' make sure selection contains the lambda + Return firstToken.SpanStart <= current.GetFirstToken().SpanStart AndAlso + current.GetLastToken().Span.End <= lastToken.Span.End + End Function + + Public Overrides Function GetOutermostCallSiteContainerToProcess(cancellationToken As CancellationToken) As SyntaxNode + If Me.IsExtractMethodOnExpression Then + Dim container = Me.InnermostStatementContainer() + + Contract.ThrowIfNull(container) + Contract.ThrowIfFalse(container.IsStatementContainerNode() OrElse + TypeOf container Is TypeBlockSyntax OrElse + TypeOf container Is CompilationUnitSyntax) + + Return container + ElseIf Me.IsExtractMethodOnSingleStatement() Then + Dim first = Me.GetFirstStatement() + Return first.Parent + ElseIf Me.IsExtractMethodOnMultipleStatements() Then + Return Me.GetFirstStatementUnderContainer().Parent + Else + Throw ExceptionUtilities.Unreachable() + End If + End Function - Private Function GetReturnTypeWorker() As ITypeSymbol - Dim node = Me.GetContainingScope() - Dim semanticModel = Me.SemanticDocument.SemanticModel + Public Overrides Function ContainingScopeHasAsyncKeyword() As Boolean + If IsExtractMethodOnExpression Then + Return False + End If - ' special case for collection initializer and explicit cast - If node.IsExpressionInCast() Then - Dim castExpression = TryCast(node.Parent, CastExpressionSyntax) - If castExpression IsNot Nothing Then - Return semanticModel.GetTypeInfo(castExpression.Type).Type + Dim node = Me.GetContainingScope() + If TypeOf node Is MethodBlockBaseSyntax Then + Dim methodBlock = DirectCast(node, MethodBlockBaseSyntax) + If methodBlock.BlockStatement IsNot Nothing Then + Return methodBlock.BlockStatement.Modifiers.Any(SyntaxKind.AsyncKeyword) + End If + + Return False + ElseIf TypeOf node Is LambdaExpressionSyntax Then + Dim lambda = DirectCast(node, LambdaExpressionSyntax) + If lambda.SubOrFunctionHeader IsNot Nothing Then + Return lambda.SubOrFunctionHeader.Modifiers.Any(SyntaxKind.AsyncKeyword) + End If End If - End If - - Dim expression As ExpressionSyntax - If TypeOf node Is CollectionInitializerSyntax Then - expression = node.GetUnparenthesizedExpression() - Return semanticModel.GetTypeInfo(expression).ConvertedType - End If - - Dim methodBlock = TryCast(node, MethodBlockBaseSyntax) - If methodBlock IsNot Nothing Then - Dim symbol = semanticModel.GetDeclaredSymbol(methodBlock.BlockStatement) - Dim propertySymbol = TryCast(symbol, IPropertySymbol) - If propertySymbol IsNot Nothing Then - Return propertySymbol.Type + + Return False + End Function + + Public Overrides Function GetContainingScope() As SyntaxNode + Contract.ThrowIfNull(Me.SemanticDocument) + + Dim first = GetFirstTokenInSelection() + + If IsExtractMethodOnExpression Then + Dim last = GetLastTokenInSelection() + + Dim scope = first.GetCommonRoot(last).GetAncestorOrThis(Of ExpressionSyntax)() + Contract.ThrowIfNull(scope, "Should always find an expression given that SelectionInExpression was true") + + Return VisualBasicSyntaxFacts.Instance.GetRootStandaloneExpression(scope) Else - Return DirectCast(symbol, IMethodSymbol).ReturnType + ' it contains statements + Return first.GetRequiredParent().AncestorsAndSelf().First( + Function(n) + Return TypeOf n Is MethodBlockBaseSyntax OrElse TypeOf n Is LambdaExpressionSyntax + End Function) End If - End If - - Dim info As TypeInfo - Dim lambda = TryCast(node, LambdaExpressionSyntax) - If lambda IsNot Nothing Then - If SelectionInExpression Then - info = semanticModel.GetTypeInfo(lambda) - Return If(info.Type.IsObjectType(), info.ConvertedType, info.Type) - Else - Return semanticModel.GetLambdaOrAnonymousMethodReturnType(lambda) + End Function + + Protected Overrides Function GetReturnTypeInfoWorker(cancellationToken As CancellationToken) As (returnType As ITypeSymbol, returnsByRef As Boolean) + ' Todo: consider supporting byref return types in VB + Dim returnType = GetReturnTypeWorker() + Return (returnType, returnsByRef:=False) + End Function + + Private Function GetReturnTypeWorker() As ITypeSymbol + Dim node = Me.GetContainingScope() + Dim semanticModel = Me.SemanticDocument.SemanticModel + + ' special case for collection initializer and explicit cast + If node.IsExpressionInCast() Then + Dim castExpression = TryCast(node.Parent, CastExpressionSyntax) + If castExpression IsNot Nothing Then + Return semanticModel.GetTypeInfo(castExpression.Type).Type + End If End If - End If - expression = DirectCast(node, ExpressionSyntax) - ' regular case. always use ConvertedType to get implicit conversion right. - expression = expression.GetUnparenthesizedExpression() + Dim expression As ExpressionSyntax + If TypeOf node Is CollectionInitializerSyntax Then + expression = node.GetUnparenthesizedExpression() + Return semanticModel.GetTypeInfo(expression).ConvertedType + End If - info = semanticModel.GetTypeInfo(expression) - If info.ConvertedType IsNot Nothing AndAlso - Not info.ConvertedType.IsErrorType() Then - If expression.Kind = SyntaxKind.AddressOfExpression Then - Return info.ConvertedType + Dim methodBlock = TryCast(node, MethodBlockBaseSyntax) + If methodBlock IsNot Nothing Then + Dim symbol = semanticModel.GetDeclaredSymbol(methodBlock.BlockStatement) + Dim propertySymbol = TryCast(symbol, IPropertySymbol) + If propertySymbol IsNot Nothing Then + Return propertySymbol.Type + Else + Return DirectCast(symbol, IMethodSymbol).ReturnType + End If End If - Dim conversion = semanticModel.ClassifyConversion(expression, info.ConvertedType) - If conversion.IsNumeric AndAlso conversion.IsWidening Then - Return info.ConvertedType + Dim info As TypeInfo + Dim lambda = TryCast(node, LambdaExpressionSyntax) + If lambda IsNot Nothing Then + If IsExtractMethodOnExpression Then + info = semanticModel.GetTypeInfo(lambda) + Return If(info.Type.IsObjectType(), info.ConvertedType, info.Type) + Else + Return semanticModel.GetLambdaOrAnonymousMethodReturnType(lambda) + End If End If - Dim conv = semanticModel.GetConversion(expression) - If IsCoClassImplicitConversion(info, conv, semanticModel.Compilation.CoClassType()) Then - Return info.ConvertedType + expression = DirectCast(node, ExpressionSyntax) + ' regular case. always use ConvertedType to get implicit conversion right. + expression = expression.GetUnparenthesizedExpression() + + info = semanticModel.GetTypeInfo(expression) + If info.ConvertedType IsNot Nothing AndAlso + Not info.ConvertedType.IsErrorType() Then + If expression.Kind = SyntaxKind.AddressOfExpression Then + Return info.ConvertedType + End If + + Dim conversion = semanticModel.ClassifyConversion(expression, info.ConvertedType) + If conversion.IsNumeric AndAlso conversion.IsWidening Then + Return info.ConvertedType + End If + + Dim conv = semanticModel.GetConversion(expression) + If IsCoClassImplicitConversion(info, conv, semanticModel.Compilation.CoClassType()) Then + Return info.ConvertedType + End If End If - End If - ' use FormattableString if conversion between String And FormattableString - If If(info.Type?.SpecialType = SpecialType.System_String, False) AndAlso - info.ConvertedType?.IsFormattableStringOrIFormattable() Then + ' use FormattableString if conversion between String And FormattableString + If If(info.Type?.SpecialType = SpecialType.System_String, False) AndAlso + info.ConvertedType?.IsFormattableStringOrIFormattable() Then - Return info.ConvertedType - End If + Return info.ConvertedType + End If - ' get type without considering implicit conversion - Return If(info.Type.IsObjectType(), info.ConvertedType, info.Type) - End Function + ' get type without considering implicit conversion + Return If(info.Type.IsObjectType(), info.ConvertedType, info.Type) + End Function - Private Shared Function IsCoClassImplicitConversion(info As TypeInfo, conversion As Conversion, coclassSymbol As ISymbol) As Boolean - If Not conversion.IsWidening OrElse - info.ConvertedType Is Nothing OrElse - info.ConvertedType.TypeKind <> TypeKind.Interface Then - Return False - End If - - ' let's see whether this interface has coclass attribute - Return info.ConvertedType.GetAttributes().Any(Function(c) c.AttributeClass.Equals(coclassSymbol)) - End Function - - Public Overrides Function GetFirstStatementUnderContainer() As ExecutableStatementSyntax - Contract.ThrowIfTrue(SelectionInExpression) - - Dim firstToken = GetFirstTokenInSelection() - Dim lastToken = GetLastTokenInSelection() - Dim commonRoot = firstToken.GetCommonRoot(lastToken) - - Dim statement As ExecutableStatementSyntax - If commonRoot.IsStatementContainerNode() Then - Dim firstStatement = GetFirstStatement() - statement = firstStatement.GetAncestorsOrThis(Of ExecutableStatementSyntax) _ - .SkipWhile(Function(s) s.Parent IsNot commonRoot) _ - .First() - If statement.Parent.ContainStatement(statement) Then - Return statement + Private Shared Function IsCoClassImplicitConversion(info As TypeInfo, conversion As Conversion, coclassSymbol As INamedTypeSymbol) As Boolean + If Not conversion.IsWidening OrElse + info.ConvertedType Is Nothing OrElse + info.ConvertedType.TypeKind <> TypeKind.Interface Then + Return False + End If + + ' let's see whether this interface has coclass attribute + Return info.ConvertedType.HasAttribute(coclassSymbol) + End Function + + Public Overrides Function GetFirstStatementUnderContainer() As ExecutableStatementSyntax + Contract.ThrowIfTrue(IsExtractMethodOnExpression) + + Dim firstToken = GetFirstTokenInSelection() + Dim lastToken = GetLastTokenInSelection() + Dim commonRoot = firstToken.GetCommonRoot(lastToken) + + Dim statement As ExecutableStatementSyntax + If commonRoot.IsStatementContainerNode() Then + Dim firstStatement = GetFirstStatement() + statement = firstStatement.GetAncestorsOrThis(Of ExecutableStatementSyntax) _ + .SkipWhile(Function(s) s.Parent IsNot commonRoot) _ + .First() + If statement.Parent.ContainStatement(statement) Then + Return statement + End If End If - End If - statement = commonRoot.GetStatementUnderContainer() - Contract.ThrowIfNull(statement) + statement = commonRoot.GetStatementUnderContainer() + Contract.ThrowIfNull(statement) + + Return statement + End Function + + Public Overrides Function GetLastStatementUnderContainer() As ExecutableStatementSyntax + Contract.ThrowIfTrue(IsExtractMethodOnExpression) - Return statement - End Function + Dim firstStatement = GetFirstStatementUnderContainer() + Dim container = firstStatement.GetStatementContainer() - Public Overrides Function GetLastStatementUnderContainer() As ExecutableStatementSyntax - Contract.ThrowIfTrue(SelectionInExpression) + Dim lastStatement = Me.GetLastStatement(). + GetAncestorsOrThis(Of ExecutableStatementSyntax). + SkipWhile(Function(s) s.Parent IsNot container). + First() - Dim firstStatement = GetFirstStatementUnderContainer() - Dim container = firstStatement.GetStatementContainer() + Contract.ThrowIfNull(lastStatement) + Contract.ThrowIfFalse(lastStatement.Parent Is (GetFirstStatementUnderContainer()).Parent) - Dim lastStatement = Me.GetLastStatement().GetAncestorsOrThis(Of ExecutableStatementSyntax) _ - .SkipWhile(Function(s) s.Parent IsNot container) _ - .First() + Return lastStatement + End Function - Contract.ThrowIfNull(lastStatement) - Contract.ThrowIfFalse(lastStatement.Parent Is (GetFirstStatementUnderContainer()).Parent) + Public Function InnermostStatementContainer() As SyntaxNode + Contract.ThrowIfFalse(IsExtractMethodOnExpression) - Return lastStatement - End Function + Dim containingScope = GetContainingScope() + Dim statementContainer = + containingScope.Parent _ + .GetAncestorsOrThis(Of SyntaxNode)() _ + .FirstOrDefault(Function(n) n.IsStatementContainerNode) + + If statementContainer IsNot Nothing Then + Return statementContainer + End If - Public Function InnermostStatementContainer() As SyntaxNode - Contract.ThrowIfFalse(SelectionInExpression) + Dim field = containingScope.GetAncestor(Of FieldDeclarationSyntax)() + If field IsNot Nothing Then + Return field.Parent + End If - Dim containingScope = GetContainingScope() - Dim statementContainer = - containingScope.Parent _ - .GetAncestorsOrThis(Of SyntaxNode)() _ - .FirstOrDefault(Function(n) n.IsStatementContainerNode) + Dim [property] = containingScope.GetAncestor(Of PropertyStatementSyntax)() + If [property] IsNot Nothing Then + Return [property].Parent + End If - If statementContainer IsNot Nothing Then - Return statementContainer - End If + ' no repl yet + ' Contract.ThrowIfFalse(last.IsParentKind(SyntaxKind.GlobalStatement)) + ' Contract.ThrowIfFalse(last.Parent.IsParentKind(SyntaxKind.CompilationUnit)) + ' Return last.Parent.Parent + Throw ExceptionUtilities.Unreachable + End Function + + Public Overrides Function ContainsNonReturnExitPointsStatements(exitPoints As ImmutableArray(Of SyntaxNode)) As Boolean + Dim returnStatement = False + Dim exitStatement = False + + For Each statement In exitPoints + If TypeOf statement Is ReturnStatementSyntax Then + returnStatement = True + ElseIf TypeOf statement Is ExitStatementSyntax Then + exitStatement = True + Else + Return True + End If + Next + + If exitStatement Then + Return Not returnStatement + End If - Dim field = containingScope.GetAncestor(Of FieldDeclarationSyntax)() - If field IsNot Nothing Then - Return field.Parent - End If + Return False + End Function + + Public Overrides Function GetOuterReturnStatements(commonRoot As SyntaxNode, exitPoints As ImmutableArray(Of SyntaxNode)) As ImmutableArray(Of ExecutableStatementSyntax) + Return exitPoints. + OfType(Of ExecutableStatementSyntax). + Where(Function(n) TypeOf n Is ReturnStatementSyntax OrElse TypeOf n Is ExitStatementSyntax). + ToImmutableArray() + End Function + + Public Overrides Function IsFinalSpanSemanticallyValidSpan( + returnStatements As ImmutableArray(Of ExecutableStatementSyntax), + cancellationToken As CancellationToken) As Boolean + + ' do quick check to make sure we are under sub (no return value) container. otherwise, there is no point to anymore checks. + If returnStatements.Any(Function(s) + Return s.TypeSwitch( + Function(e As ExitStatementSyntax) e.BlockKeyword.Kind <> SyntaxKind.SubKeyword, + Function(r As ReturnStatementSyntax) r.Expression IsNot Nothing, + Function(n As ExecutableStatementSyntax) True) + End Function) Then + Return False + End If - Dim [property] = containingScope.GetAncestor(Of PropertyStatementSyntax)() - If [property] IsNot Nothing Then - Return [property].Parent - End If + ' check whether selection reaches the end of the container + Dim lastToken = Me.GetLastTokenInSelection() + Dim nextToken = lastToken.GetNextToken(includeZeroWidth:=True) - ' no repl yet - ' Contract.ThrowIfFalse(last.IsParentKind(SyntaxKind.GlobalStatement)) - ' Contract.ThrowIfFalse(last.Parent.IsParentKind(SyntaxKind.CompilationUnit)) - ' Return last.Parent.Parent - Throw ExceptionUtilities.Unreachable - End Function + Dim container = returnStatements.First().AncestorsAndSelf().FirstOrDefault(Function(n) n.IsReturnableConstruct()) + If container Is Nothing Then + Return False + End If - Public Function IsUnderModuleBlock() As Boolean - Dim currentScope = GetContainingScope() - Dim types = currentScope.GetAncestors(Of TypeBlockSyntax)() + Dim match = If(TryCast(container, MethodBlockBaseSyntax)?.EndBlockStatement.EndKeyword = nextToken, False) OrElse + If(TryCast(container, MultiLineLambdaExpressionSyntax)?.EndSubOrFunctionStatement.EndKeyword = nextToken, False) - Return types.Any(Function(t) t.BlockStatement.Kind = SyntaxKind.ModuleStatement) - End Function + If Not match Then + Return False + End If - Public Function ContainsInstanceExpression() As Boolean - Dim first = GetFirstTokenInSelection() - Dim last = GetLastTokenInSelection() - Dim node = first.GetCommonRoot(last) + If TryCast(container, MethodBlockBaseSyntax)?.BlockStatement.Kind = SyntaxKind.SubStatement Then + Return True + ElseIf TryCast(container, MultiLineLambdaExpressionSyntax)?.SubOrFunctionHeader.Kind = SyntaxKind.SubLambdaHeader Then + Return True + Else + Return False + End If + End Function + + Protected Overrides Function ValidateLanguageSpecificRules(cancellationToken As CancellationToken) As OperationStatus + ' static local can't exist in field initializer + If Me.GetFirstTokenInSelection().GetAncestor(Of FieldDeclarationSyntax)() Is Nothing AndAlso + Me.GetFirstTokenInSelection().GetAncestor(Of PropertyStatementSyntax)() Is Nothing Then + + Dim dataFlowAnalysis = Me.GetDataFlowAnalysis() + For Each symbol In dataFlowAnalysis.VariablesDeclared + Dim local = TryCast(symbol, ILocalSymbol) + If local?.IsStatic = True Then + If dataFlowAnalysis.WrittenOutside().Contains(local) OrElse + dataFlowAnalysis.ReadOutside().Contains(local) Then + Return New OperationStatus(succeeded:=True, VBFeaturesResources.all_static_local_usages_defined_in_the_selection_must_be_included_in_the_selection) + End If + End If + Next + End If - Return node.DescendantNodesAndSelf( - TextSpan.FromBounds(first.SpanStart, last.Span.End)) _ - .Any(Function(n) TypeOf n Is InstanceExpressionSyntax) - End Function + Return OperationStatus.SucceededStatus + End Function + End Class End Class End Namespace diff --git a/src/Features/VisualBasic/Portable/ExtractMethod/VisualBasicSelectionValidator.Validator.vb b/src/Features/VisualBasic/Portable/ExtractMethod/VisualBasicSelectionValidator.Validator.vb index 9854cac508bca..a3d339ba1033c 100644 --- a/src/Features/VisualBasic/Portable/ExtractMethod/VisualBasicSelectionValidator.Validator.vb +++ b/src/Features/VisualBasic/Portable/ExtractMethod/VisualBasicSelectionValidator.Validator.vb @@ -7,67 +7,69 @@ Imports Microsoft.CodeAnalysis Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Namespace Microsoft.CodeAnalysis.VisualBasic.ExtractMethod - Partial Friend Class VisualBasicSelectionValidator - Public Shared Function Check(semanticModel As SemanticModel, node As SyntaxNode, cancellationToken As CancellationToken) As Boolean - If TypeOf node Is ExpressionSyntax Then - Return CheckExpression(semanticModel, DirectCast(node, ExpressionSyntax), cancellationToken) - ElseIf TypeOf node Is StatementSyntax Then - Return CheckStatement(DirectCast(node, StatementSyntax)) - Else - Return False - End If - End Function + Partial Friend NotInheritable Class VisualBasicExtractMethodService + Partial Friend Class VisualBasicSelectionValidator + Public Shared Function Check(semanticModel As SemanticModel, node As SyntaxNode, cancellationToken As CancellationToken) As Boolean + If TypeOf node Is ExpressionSyntax Then + Return CheckExpression(semanticModel, DirectCast(node, ExpressionSyntax), cancellationToken) + ElseIf TypeOf node Is StatementSyntax Then + Return CheckStatement(DirectCast(node, StatementSyntax)) + Else + Return False + End If + End Function - Private Shared Function CheckExpression(semanticModel As SemanticModel, expression As ExpressionSyntax, cancellationToken As CancellationToken) As Boolean - cancellationToken.ThrowIfCancellationRequested() + Private Shared Function CheckExpression(semanticModel As SemanticModel, expression As ExpressionSyntax, cancellationToken As CancellationToken) As Boolean + cancellationToken.ThrowIfCancellationRequested() - ' TODO(cyrusn): This is probably unnecessary. What we should be doing is binding - ' the type of the expression and seeing if it contains an anonymous type. - If TypeOf expression Is AnonymousObjectCreationExpressionSyntax Then - Return False - End If + ' TODO(cyrusn): This is probably unnecessary. What we should be doing is binding + ' the type of the expression and seeing if it contains an anonymous type. + If TypeOf expression Is AnonymousObjectCreationExpressionSyntax Then + Return False + End If - Return expression.CanReplaceWithRValue(semanticModel, cancellationToken) AndAlso Not expression.ContainsImplicitMemberAccess() - End Function + Return expression.CanReplaceWithRValue(semanticModel, cancellationToken) AndAlso Not expression.ContainsImplicitMemberAccess() + End Function - Private Shared Function CheckStatement(statement As StatementSyntax) As Boolean - If statement.GetAncestor(Of WithBlockSyntax)() IsNot Nothing Then - If statement.ContainsImplicitMemberAccess() Then - Return False + Private Shared Function CheckStatement(statement As StatementSyntax) As Boolean + If statement.GetAncestor(Of WithBlockSyntax)() IsNot Nothing Then + If statement.ContainsImplicitMemberAccess() Then + Return False + End If End If - End If - ' don't support malformed code (bug # 10875) - Dim localDeclaration = TryCast(statement, LocalDeclarationStatementSyntax) - If localDeclaration IsNot Nothing AndAlso localDeclaration.Declarators.Any(Function(d) d.Names.Count > 1 AndAlso d.Initializer IsNot Nothing) Then - Return False - End If + ' don't support malformed code (bug # 10875) + Dim localDeclaration = TryCast(statement, LocalDeclarationStatementSyntax) + If localDeclaration IsNot Nothing AndAlso localDeclaration.Declarators.Any(Function(d) d.Names.Count > 1 AndAlso d.Initializer IsNot Nothing) Then + Return False + End If - If TypeOf statement Is WhileBlockSyntax OrElse - TypeOf statement Is UsingBlockSyntax OrElse - TypeOf statement Is WithBlockSyntax OrElse - TypeOf statement Is ReturnStatementSyntax OrElse - TypeOf statement Is SingleLineIfStatementSyntax OrElse - TypeOf statement Is MultiLineIfBlockSyntax OrElse - TypeOf statement Is TryBlockSyntax OrElse - TypeOf statement Is ErrorStatementSyntax OrElse - TypeOf statement Is SelectBlockSyntax OrElse - TypeOf statement Is DoLoopBlockSyntax OrElse - TypeOf statement Is ForOrForEachBlockSyntax OrElse - TypeOf statement Is ThrowStatementSyntax OrElse - TypeOf statement Is AssignmentStatementSyntax OrElse - TypeOf statement Is CallStatementSyntax OrElse - TypeOf statement Is ExpressionStatementSyntax OrElse - TypeOf statement Is AddRemoveHandlerStatementSyntax OrElse - TypeOf statement Is RaiseEventStatementSyntax OrElse - TypeOf statement Is ReDimStatementSyntax OrElse - TypeOf statement Is EraseStatementSyntax OrElse - TypeOf statement Is LocalDeclarationStatementSyntax OrElse - TypeOf statement Is SyncLockBlockSyntax Then - Return True - End If + If TypeOf statement Is WhileBlockSyntax OrElse + TypeOf statement Is UsingBlockSyntax OrElse + TypeOf statement Is WithBlockSyntax OrElse + TypeOf statement Is ReturnStatementSyntax OrElse + TypeOf statement Is SingleLineIfStatementSyntax OrElse + TypeOf statement Is MultiLineIfBlockSyntax OrElse + TypeOf statement Is TryBlockSyntax OrElse + TypeOf statement Is ErrorStatementSyntax OrElse + TypeOf statement Is SelectBlockSyntax OrElse + TypeOf statement Is DoLoopBlockSyntax OrElse + TypeOf statement Is ForOrForEachBlockSyntax OrElse + TypeOf statement Is ThrowStatementSyntax OrElse + TypeOf statement Is AssignmentStatementSyntax OrElse + TypeOf statement Is CallStatementSyntax OrElse + TypeOf statement Is ExpressionStatementSyntax OrElse + TypeOf statement Is AddRemoveHandlerStatementSyntax OrElse + TypeOf statement Is RaiseEventStatementSyntax OrElse + TypeOf statement Is ReDimStatementSyntax OrElse + TypeOf statement Is EraseStatementSyntax OrElse + TypeOf statement Is LocalDeclarationStatementSyntax OrElse + TypeOf statement Is SyncLockBlockSyntax Then + Return True + End If - Return False - End Function + Return False + End Function + End Class End Class End Namespace diff --git a/src/Features/VisualBasic/Portable/ExtractMethod/VisualBasicSelectionValidator.vb b/src/Features/VisualBasic/Portable/ExtractMethod/VisualBasicSelectionValidator.vb index 2e2493d1c85f9..b7f39493b72ed 100644 --- a/src/Features/VisualBasic/Portable/ExtractMethod/VisualBasicSelectionValidator.vb +++ b/src/Features/VisualBasic/Portable/ExtractMethod/VisualBasicSelectionValidator.vb @@ -5,655 +5,351 @@ Imports System.Threading Imports Microsoft.CodeAnalysis Imports Microsoft.CodeAnalysis.ExtractMethod -Imports Microsoft.CodeAnalysis.Options Imports Microsoft.CodeAnalysis.Text Imports Microsoft.CodeAnalysis.VisualBasic -Imports Microsoft.CodeAnalysis.VisualBasic.LanguageService Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Namespace Microsoft.CodeAnalysis.VisualBasic.ExtractMethod - Friend Class VisualBasicSelectionValidator - Inherits SelectionValidator(Of VisualBasicSelectionResult, ExecutableStatementSyntax) - - Public Sub New(document As SemanticDocument, - textSpan As TextSpan) - MyBase.New(document, textSpan) - End Sub - - Public Overrides Async Function GetValidSelectionAsync(cancellationToken As CancellationToken) As Task(Of (VisualBasicSelectionResult, OperationStatus)) - If Not ContainsValidSelection Then - Return (Nothing, OperationStatus.FailedWithUnknownReason) - End If - - Dim text = Me.SemanticDocument.Text - Dim root = SemanticDocument.Root - Dim model = Me.SemanticDocument.SemanticModel - - Dim selectionInfo = GetInitialSelectionInfo(root) - selectionInfo = AssignInitialFinalTokens(selectionInfo, root, cancellationToken) - selectionInfo = AdjustFinalTokensBasedOnContext(selectionInfo, model, cancellationToken) - selectionInfo = AdjustFinalTokensIfNextStatement(selectionInfo, model, cancellationToken) - selectionInfo = FixUpFinalTokensAndAssignFinalSpan(selectionInfo, root, cancellationToken) - selectionInfo = CheckErrorCasesAndAppendDescriptions(selectionInfo, model, cancellationToken) - - If selectionInfo.Status.Failed() Then - Return (Nothing, selectionInfo.Status) - End If - - Dim controlFlowSpan = GetControlFlowSpan(selectionInfo) - If Not selectionInfo.SelectionInExpression Then - Dim statementRange = GetStatementRangeContainedInSpan(Of StatementSyntax)(root, controlFlowSpan, cancellationToken) - If statementRange Is Nothing Then - With selectionInfo - .Status = .Status.With(succeeded:=False, VBFeaturesResources.can_t_determine_valid_range_of_statements_to_extract_out) - End With - - Return (Nothing, selectionInfo.Status) + Partial Friend NotInheritable Class VisualBasicExtractMethodService + Friend NotInheritable Class VisualBasicSelectionValidator + Inherits SelectionValidator + + Public Sub New(document As SemanticDocument, textSpan As TextSpan) + MyBase.New(document, textSpan) + End Sub + + Protected Overrides Function GetInitialSelectionInfo(cancellationToken As CancellationToken) As InitialSelectionInfo + Dim root = Me.SemanticDocument.Root + Dim adjustedSpan = GetAdjustedSpan(Me.OriginalSpan) + Dim firstTokenInSelection = root.FindTokenOnRightOfPosition(adjustedSpan.Start, includeSkipped:=False) + Dim lastTokenInSelection = root.FindTokenOnLeftOfPosition(adjustedSpan.End, includeSkipped:=False) + + If firstTokenInSelection.Kind = SyntaxKind.None OrElse lastTokenInSelection.Kind = SyntaxKind.None Then + Return InitialSelectionInfo.Failure(FeaturesResources.Invalid_selection) End If - Dim isFinalSpanSemanticallyValid = IsFinalSpanSemanticallyValidSpan(model, controlFlowSpan, statementRange.Value, cancellationToken) - If Not isFinalSpanSemanticallyValid Then - ' check control flow only if we are extracting statement level, not expression level. - ' you can't have goto that moves control out of scope in expression level (even in lambda) - With selectionInfo - .Status = .Status.With(succeeded:=True, VBFeaturesResources.Not_all_code_paths_return) - End With - End If - End If - - Dim result = Await VisualBasicSelectionResult.CreateResultAsync( - selectionInfo.OriginalSpan, - selectionInfo.FinalSpan, - selectionInfo.SelectionInExpression, - Me.SemanticDocument, - selectionInfo.FirstTokenInFinalSpan, - selectionInfo.LastTokenInFinalSpan, - SelectionChanged(selectionInfo), - cancellationToken).ConfigureAwait(False) - Return (result, selectionInfo.Status) - End Function - - Private Shared Function GetControlFlowSpan(selectionInfo As SelectionInfo) As TextSpan - Return TextSpan.FromBounds(selectionInfo.FirstTokenInFinalSpan.SpanStart, selectionInfo.LastTokenInFinalSpan.Span.End) - End Function - - Private Shared Function CheckErrorCasesAndAppendDescriptions(selectionInfo As SelectionInfo, semanticModel As SemanticModel, cancellationToken As CancellationToken) As SelectionInfo - If selectionInfo.Status.Failed() Then - Return selectionInfo - End If - - Dim clone = selectionInfo.Clone() - - If selectionInfo.FirstTokenInFinalSpan.IsMissing OrElse selectionInfo.LastTokenInFinalSpan.IsMissing Then - With clone - .Status = .Status.With(succeeded:=False, VBFeaturesResources.contains_invalid_selection) - End With - End If - - ' get the node that covers the selection - Dim commonNode = GetFinalTokenCommonRoot(selectionInfo) - - If (selectionInfo.SelectionInExpression OrElse selectionInfo.SelectionInSingleStatement) AndAlso commonNode.HasDiagnostics() Then - With clone - .Status = .Status.With(succeeded:=False, VBFeaturesResources.the_selection_contains_syntactic_errors) - End With - End If - - Dim root = semanticModel.SyntaxTree.GetRoot(cancellationToken) - Dim tokens = root.DescendantTokens(selectionInfo.FinalSpan) - If tokens.ContainPreprocessorCrossOver(selectionInfo.FinalSpan) Then - With clone - .Status = .Status.With(succeeded:=True, VBFeaturesResources.Selection_can_t_be_crossed_over_preprocessors) - End With - End If - - ' TODO : check behavior of control flow analysis engine around exception and exception handling. - If tokens.ContainArgumentlessThrowWithoutEnclosingCatch(selectionInfo.FinalSpan) Then - With clone - .Status = .Status.With(succeeded:=True, VBFeaturesResources.Selection_can_t_contain_throw_without_enclosing_catch_block) - End With - End If - - If selectionInfo.SelectionInExpression AndAlso commonNode.PartOfConstantInitializerExpression() Then - With clone - .Status = .Status.With(succeeded:=False, VBFeaturesResources.Selection_can_t_be_parts_of_constant_initializer_expression) - End With - End If - - If selectionInfo.SelectionInExpression AndAlso commonNode.IsArgumentForByRefParameter(semanticModel, cancellationToken) Then - With clone - .Status = .Status.With(succeeded:=True, VBFeaturesResources.Argument_used_for_ByRef_parameter_can_t_be_extracted_out) - End With - End If - - Dim containsAllStaticLocals = ContainsAllStaticLocalUsagesDefinedInSelectionIfExist(selectionInfo, semanticModel, cancellationToken) - If Not containsAllStaticLocals Then - With clone - .Status = .Status.With(succeeded:=True, VBFeaturesResources.all_static_local_usages_defined_in_the_selection_must_be_included_in_the_selection) - End With - End If - - ' if it is multiple statement case. - If Not selectionInfo.SelectionInExpression AndAlso Not selectionInfo.SelectionInSingleStatement Then - If commonNode.GetAncestorOrThis(Of WithBlockSyntax)() IsNot Nothing Then - If commonNode.GetImplicitMemberAccessExpressions(selectionInfo.FinalSpan).Any() Then - With clone - .Status = .Status.With(succeeded:=True, VBFeaturesResources.Implicit_member_access_can_t_be_included_in_the_selection_without_containing_statement) - End With - End If - End If - End If - - If Not selectionInfo.SelectionInExpression AndAlso Not selectionInfo.SelectionInSingleStatement Then - If selectionInfo.FirstTokenInFinalSpan.GetAncestor(Of ExecutableStatementSyntax)() Is Nothing OrElse - selectionInfo.LastTokenInFinalSpan.GetAncestor(Of ExecutableStatementSyntax)() Is Nothing Then - With clone - .Status = .Status.With(succeeded:=False, VBFeaturesResources.Selection_must_be_part_of_executable_statements) - End With - End If - End If - - Return clone - End Function - - Private Shared Function SelectionChanged(selectionInfo As SelectionInfo) As Boolean - ' get final token that doesn't pointing to empty token - Dim finalFirstToken = If(selectionInfo.FirstTokenInFinalSpan.Width = 0, - selectionInfo.FirstTokenInFinalSpan.GetNextToken(), - selectionInfo.FirstTokenInFinalSpan) - - Dim finalLastToken = If(selectionInfo.LastTokenInFinalSpan.Width = 0, - selectionInfo.LastTokenInFinalSpan.GetPreviousToken(), - selectionInfo.LastTokenInFinalSpan) - - ' adjust original tokens to point to statement terminator token if needed - Dim originalFirstToken = selectionInfo.FirstTokenInOriginalSpan - - Dim originalLastToken = selectionInfo.LastTokenInOriginalSpan - - Return originalFirstToken <> finalFirstToken OrElse originalLastToken <> finalLastToken - End Function - - Private Shared Function ContainsAllStaticLocalUsagesDefinedInSelectionIfExist(selectionInfo As SelectionInfo, - semanticModel As SemanticModel, - cancellationToken As CancellationToken) As Boolean - If selectionInfo.FirstTokenInFinalSpan.GetAncestor(Of FieldDeclarationSyntax)() IsNot Nothing OrElse - selectionInfo.FirstTokenInFinalSpan.GetAncestor(Of PropertyStatementSyntax)() IsNot Nothing Then - ' static local can't exist in field initializer - Return True - End If - - Dim result As DataFlowAnalysis - - If selectionInfo.SelectionInExpression Then - Dim expression = GetFinalTokenCommonRoot(selectionInfo).GetAncestorOrThis(Of ExpressionSyntax)() - result = semanticModel.AnalyzeDataFlow(expression) - Else - Dim range = GetStatementRangeContainedInSpan(Of StatementSyntax)( - semanticModel.SyntaxTree.GetRoot(cancellationToken), GetControlFlowSpan(selectionInfo), cancellationToken) - - ' we can't determine valid range of statements, don't bother to do the analysis - If range Is Nothing Then - Return True + If firstTokenInSelection <> lastTokenInSelection AndAlso + firstTokenInSelection.Span.End > lastTokenInSelection.SpanStart Then + Return InitialSelectionInfo.Failure(FeaturesResources.Invalid_selection) End If - result = semanticModel.AnalyzeDataFlow(range.Value.Item1, range.Value.Item2) - End If + If (Not adjustedSpan.Contains(firstTokenInSelection.Span)) AndAlso (Not adjustedSpan.Contains(lastTokenInSelection.Span)) Then + Return InitialSelectionInfo.Failure(FeaturesResources.Selection_does_not_contain_a_valid_token) + End If - For Each symbol In result.VariablesDeclared - Dim local = TryCast(symbol, ILocalSymbol) - If local Is Nothing Then - Continue For + If (Not firstTokenInSelection.UnderValidContext()) OrElse (Not lastTokenInSelection.UnderValidContext()) Then + Return InitialSelectionInfo.Failure(FeaturesResources.No_valid_selection_to_perform_extraction) End If - If Not local.IsStatic Then - Continue For + Dim commonRoot = GetCommonRoot(firstTokenInSelection, lastTokenInSelection) + If commonRoot Is Nothing Then + Return InitialSelectionInfo.Failure(FeaturesResources.No_common_root_node_for_extraction) End If - If result.WrittenOutside().Any(Function(s) Equals(s, local)) OrElse -result.ReadOutside().Any(Function(s) Equals(s, local)) Then - Return False + If Not commonRoot.ContainedInValidType() Then + Return InitialSelectionInfo.Failure(FeaturesResources.Selection_not_contained_inside_a_type) End If - Next - Return True - End Function + Dim selectionInExpression = TypeOf commonRoot Is ExpressionSyntax AndAlso + commonRoot.GetFirstToken(includeZeroWidth:=True) = firstTokenInSelection AndAlso + commonRoot.GetLastToken(includeZeroWidth:=True) = lastTokenInSelection - Private Shared Function GetFinalTokenCommonRoot(selection As SelectionInfo) As SyntaxNode - Return GetCommonRoot(selection.FirstTokenInFinalSpan, selection.LastTokenInFinalSpan) - End Function + If (Not selectionInExpression) AndAlso (Not commonRoot.UnderValidContext()) Then + Return InitialSelectionInfo.Failure(FeaturesResources.No_valid_selection_to_perform_extraction) + End If - Private Shared Function GetCommonRoot(token1 As SyntaxToken, token2 As SyntaxToken) As SyntaxNode - Return token1.GetCommonRoot(token2) - End Function + ' make sure type block enclosing the selection exist + If commonRoot.GetAncestor(Of TypeBlockSyntax)() Is Nothing Then + Return InitialSelectionInfo.Failure(FeaturesResources.No_valid_selection_to_perform_extraction) + End If - Private Shared Function FixUpFinalTokensAndAssignFinalSpan(selectionInfo As SelectionInfo, - root As SyntaxNode, - cancellationToken As CancellationToken) As SelectionInfo - If selectionInfo.Status.Failed() Then - Return selectionInfo - End If + Return CreateInitialSelectionInfo( + selectionInExpression, firstTokenInSelection, lastTokenInSelection, cancellationToken) + End Function - Dim clone = selectionInfo.Clone() + Protected Overrides Function UpdateSelectionInfo(initialSelectionInfo As InitialSelectionInfo, cancellationToken As CancellationToken) As FinalSelectionInfo + Dim model = Me.SemanticDocument.SemanticModel - ' make sure we include statement terminator token if selection contains them - Dim firstToken = selectionInfo.FirstTokenInFinalSpan - Dim lastToken = selectionInfo.LastTokenInFinalSpan + Dim selectionInfo = AssignInitialFinalTokens(initialSelectionInfo) + selectionInfo = AdjustFinalTokensBasedOnContext(selectionInfo, model, cancellationToken) + selectionInfo = AdjustFinalTokensIfNextStatement(selectionInfo, model, cancellationToken) + selectionInfo = AssignFinalSpan(initialSelectionInfo, selectionInfo) + selectionInfo = CheckErrorCasesAndAppendDescriptions(selectionInfo, model, cancellationToken) - ' set final span - Dim start = If(selectionInfo.OriginalSpan.Start <= firstToken.SpanStart, selectionInfo.OriginalSpan.Start, firstToken.FullSpan.Start) - Dim [end] = If(lastToken.Span.End <= selectionInfo.OriginalSpan.End, selectionInfo.OriginalSpan.End, lastToken.Span.End) + Return selectionInfo + End Function - With clone - .FinalSpan = GetAdjustedSpan(root, TextSpan.FromBounds(start, [end])) - .FirstTokenInFinalSpan = firstToken - .LastTokenInFinalSpan = lastToken - End With + Protected Overrides Async Function CreateSelectionResultAsync( + finalSelectionInfo As FinalSelectionInfo, + cancellationToken As CancellationToken) As Task(Of SelectionResult) - Return clone - End Function + Contract.ThrowIfFalse(ContainsValidSelection) + Contract.ThrowIfFalse(finalSelectionInfo.Status.Succeeded) - Private Shared Function AdjustFinalTokensIfNextStatement(selectionInfo As SelectionInfo, - semanticModel As SemanticModel, - cancellationToken As CancellationToken) As SelectionInfo - If selectionInfo.Status.Failed() Then - Return selectionInfo - End If + Return Await VisualBasicSelectionResult.CreateResultAsync( + Me.SemanticDocument, finalSelectionInfo, cancellationToken).ConfigureAwait(False) + End Function - ' if last statement is next statement, make sure its corresponding loop statement is - ' included - Dim nextStatement = selectionInfo.LastTokenInFinalSpan.GetAncestor(Of NextStatementSyntax)() - If nextStatement Is Nothing OrElse nextStatement.ControlVariables.Count < 2 Then - Return selectionInfo - End If + Private Shared Function CheckErrorCasesAndAppendDescriptions( + selectionInfo As FinalSelectionInfo, + semanticModel As SemanticModel, + cancellationToken As CancellationToken) As FinalSelectionInfo + If selectionInfo.Status.Failed() Then + Return selectionInfo + End If - Dim clone = selectionInfo.Clone() - Dim outmostControlVariable = nextStatement.ControlVariables.Last + Dim clone = selectionInfo - Dim symbolInfo = semanticModel.GetSymbolInfo(outmostControlVariable, cancellationToken) - Dim symbol = symbolInfo.GetBestOrAllSymbols().FirstOrDefault() + If selectionInfo.FirstTokenInFinalSpan.IsMissing OrElse selectionInfo.LastTokenInFinalSpan.IsMissing Then + clone = clone.With( + status:=clone.Status.With(succeeded:=False, VBFeaturesResources.contains_invalid_selection)) + End If - ' can't find symbol for the control variable. don't provide extract method - If symbol Is Nothing OrElse - symbol.Locations.Length <> 1 OrElse - Not symbol.Locations.First().IsInSource OrElse - symbol.Locations.First().SourceTree IsNot semanticModel.SyntaxTree Then - With clone - .Status = .Status.With(succeeded:=False, VBFeaturesResources.next_statement_control_variable_doesn_t_have_matching_declaration_statement) - End With + ' get the node that covers the selection + Dim commonNode = GetFinalTokenCommonRoot(selectionInfo) - Return clone - End If + If selectionInfo.GetSelectionType() <> SelectionType.MultipleStatements AndAlso commonNode.HasDiagnostics() Then + clone = clone.With( + status:=clone.Status.With(succeeded:=False, VBFeaturesResources.the_selection_contains_syntactic_errors)) + End If - Dim startPosition = symbol.Locations.First().SourceSpan.Start - Dim root = semanticModel.SyntaxTree.GetRoot(cancellationToken) - Dim forBlock = root.FindToken(startPosition).GetAncestor(Of ForOrForEachBlockSyntax)() - If forBlock Is Nothing Then - With clone - .Status = .Status.With(succeeded:=False, VBFeaturesResources.next_statement_control_variable_doesn_t_have_matching_declaration_statement) - End With + Dim root = semanticModel.SyntaxTree.GetRoot(cancellationToken) + Dim tokens = root.DescendantTokens(selectionInfo.FinalSpan) + If tokens.ContainPreprocessorCrossOver(selectionInfo.FinalSpan) Then + clone = clone.With( + status:=clone.Status.With(succeeded:=True, VBFeaturesResources.Selection_can_t_be_crossed_over_preprocessors)) + End If - Return clone - End If - - Dim firstStatement = forBlock.ForOrForEachStatement - With clone - .SelectionInExpression = False - .SelectionInSingleStatement = forBlock.Span.Contains(nextStatement.Span) - .FirstTokenInFinalSpan = firstStatement.GetFirstToken(includeZeroWidth:=True) - .LastTokenInFinalSpan = nextStatement.GetLastToken(includeZeroWidth:=True) - End With - - Return clone - End Function - - Private Shared Function AdjustFinalTokensBasedOnContext(selectionInfo As SelectionInfo, - semanticModel As SemanticModel, - cancellationToken As CancellationToken) As SelectionInfo - If selectionInfo.Status.Failed() Then - Return selectionInfo - End If + ' TODO : check behavior of control flow analysis engine around exception and exception handling. + If tokens.ContainArgumentlessThrowWithoutEnclosingCatch(selectionInfo.FinalSpan) Then + clone = clone.With( + status:=clone.Status.With(succeeded:=True, VBFeaturesResources.Selection_can_t_contain_throw_without_enclosing_catch_block)) + End If - ' don't need to adjust anything if it is multi-statements case - If (Not selectionInfo.SelectionInExpression) AndAlso (Not selectionInfo.SelectionInSingleStatement) Then - Return selectionInfo - End If + If selectionInfo.SelectionInExpression AndAlso commonNode.PartOfConstantInitializerExpression() Then + clone = clone.With( + status:=clone.Status.With(succeeded:=False, VBFeaturesResources.Selection_can_t_be_parts_of_constant_initializer_expression)) + End If - Dim clone = selectionInfo.Clone() + If selectionInfo.SelectionInExpression AndAlso commonNode.IsArgumentForByRefParameter(semanticModel, cancellationToken) Then + clone = clone.With( + status:=clone.Status.With(succeeded:=True, VBFeaturesResources.Argument_used_for_ByRef_parameter_can_t_be_extracted_out)) + End If - ' get the node that covers the selection - Dim node = GetFinalTokenCommonRoot(selectionInfo) + ' if it is multiple statement case. + If selectionInfo.GetSelectionType() = SelectionType.MultipleStatements Then + If commonNode.GetAncestorOrThis(Of WithBlockSyntax)() IsNot Nothing Then + If commonNode.GetImplicitMemberAccessExpressions(selectionInfo.FinalSpan).Any() Then + clone = clone.With( + status:=clone.Status.With(succeeded:=True, VBFeaturesResources.Implicit_member_access_can_t_be_included_in_the_selection_without_containing_statement)) + End If + End If - Dim validNode = Check(semanticModel, node, cancellationToken) - If validNode Then - Return selectionInfo - End If + If selectionInfo.FirstTokenInFinalSpan.GetAncestor(Of ExecutableStatementSyntax)() Is Nothing OrElse + selectionInfo.LastTokenInFinalSpan.GetAncestor(Of ExecutableStatementSyntax)() Is Nothing Then + clone = clone.With( + status:=clone.Status.With(succeeded:=False, VBFeaturesResources.Selection_must_be_part_of_executable_statements)) + End If + End If - Dim firstValidNode = node.GetAncestors(Of SyntaxNode)().FirstOrDefault( - Function(n) Check(semanticModel, n, cancellationToken)) + Return clone + End Function + + Private Shared Function GetFinalTokenCommonRoot(selection As FinalSelectionInfo) As SyntaxNode + Return GetCommonRoot(selection.FirstTokenInFinalSpan, selection.LastTokenInFinalSpan) + End Function + + Private Shared Function GetCommonRoot(token1 As SyntaxToken, token2 As SyntaxToken) As SyntaxNode + Return token1.GetCommonRoot(token2) + End Function + + Private Shared Function AdjustFinalTokensIfNextStatement( + selectionInfo As FinalSelectionInfo, + semanticModel As SemanticModel, + cancellationToken As CancellationToken) As FinalSelectionInfo + If selectionInfo.Status.Failed() Then + Return selectionInfo + End If - If firstValidNode Is Nothing Then - ' couldn't find any valid node - With clone - .Status = New OperationStatus(succeeded:=False, VBFeaturesResources.Selection_doesn_t_contain_any_valid_node) - .FirstTokenInFinalSpan = Nothing - .LastTokenInFinalSpan = Nothing - End With + ' if last statement is next statement, make sure its corresponding loop statement is + ' included + Dim nextStatement = selectionInfo.LastTokenInFinalSpan.GetAncestor(Of NextStatementSyntax)() + If nextStatement Is Nothing OrElse nextStatement.ControlVariables.Count < 2 Then + Return selectionInfo + End If - Return clone - End If + Dim outmostControlVariable = nextStatement.ControlVariables.Last - With clone - .SelectionInExpression = TypeOf firstValidNode Is ExpressionSyntax - .SelectionInSingleStatement = TypeOf firstValidNode Is StatementSyntax - .FirstTokenInFinalSpan = firstValidNode.GetFirstToken(includeZeroWidth:=True) - .LastTokenInFinalSpan = firstValidNode.GetLastToken(includeZeroWidth:=True) - End With + Dim symbolInfo = semanticModel.GetSymbolInfo(outmostControlVariable, cancellationToken) + Dim symbol = symbolInfo.GetBestOrAllSymbols().FirstOrDefault() - Return clone - End Function + ' can't find symbol for the control variable. don't provide extract method + If symbol Is Nothing OrElse + symbol.Locations.Length <> 1 OrElse + Not symbol.Locations.First().IsInSource OrElse + symbol.Locations.First().SourceTree IsNot semanticModel.SyntaxTree Then + Return selectionInfo.With( + status:=selectionInfo.Status.With(succeeded:=False, VBFeaturesResources.next_statement_control_variable_doesn_t_have_matching_declaration_statement)) + End If - Private Shared Function AssignInitialFinalTokens(selectionInfo As SelectionInfo, root As SyntaxNode, cancellationToken As CancellationToken) As SelectionInfo - If selectionInfo.Status.Failed() Then - Return selectionInfo - End If + Dim startPosition = symbol.Locations.First().SourceSpan.Start + Dim root = semanticModel.SyntaxTree.GetRoot(cancellationToken) + Dim forBlock = root.FindToken(startPosition).GetAncestor(Of ForOrForEachBlockSyntax)() + If forBlock Is Nothing Then + Return selectionInfo.With( + status:=selectionInfo.Status.With(succeeded:=False, VBFeaturesResources.next_statement_control_variable_doesn_t_have_matching_declaration_statement)) + End If - Dim clone = selectionInfo.Clone() + Dim firstStatement = forBlock.ForOrForEachStatement + Return selectionInfo.With( + firstTokenInFinalSpan:=firstStatement.GetFirstToken(includeZeroWidth:=True), + lastTokenInFinalSpan:=nextStatement.GetLastToken(includeZeroWidth:=True)) + End Function + + Private Shared Function AdjustFinalTokensBasedOnContext( + selectionInfo As FinalSelectionInfo, + semanticModel As SemanticModel, + cancellationToken As CancellationToken) As FinalSelectionInfo + If selectionInfo.Status.Failed() Then + Return selectionInfo + End If - If selectionInfo.SelectionInExpression Then - ' prefer outer statement or expression if two has same span - Dim outerNode = selectionInfo.CommonRootFromOriginalSpan.GetOutermostNodeWithSameSpan(Function(n) TypeOf n Is StatementSyntax OrElse TypeOf n Is ExpressionSyntax) + ' don't need to adjust anything if it is multi-statements case + If selectionInfo.GetSelectionType() = SelectionType.MultipleStatements Then + Return selectionInfo + End If - ' simple expression case - With clone - .SelectionInExpression = TypeOf outerNode Is ExpressionSyntax - .SelectionInSingleStatement = TypeOf outerNode Is StatementSyntax - .FirstTokenInFinalSpan = outerNode.GetFirstToken(includeZeroWidth:=True) - .LastTokenInFinalSpan = outerNode.GetLastToken(includeZeroWidth:=True) - End With + ' get the node that covers the selection + Dim node = GetFinalTokenCommonRoot(selectionInfo) - Return clone - End If + Dim validNode = Check(semanticModel, node, cancellationToken) + If validNode Then + Return selectionInfo + End If - Dim range = GetStatementRangeContainingSpan(Of StatementSyntax)( - VisualBasicSyntaxFacts.Instance, - root, TextSpan.FromBounds(selectionInfo.FirstTokenInOriginalSpan.SpanStart, selectionInfo.LastTokenInOriginalSpan.Span.End), - cancellationToken) + Dim firstValidNode = node.GetAncestors(Of SyntaxNode)().FirstOrDefault( + Function(n) Check(semanticModel, n, cancellationToken)) - If range Is Nothing Then - With clone - .Status = clone.Status.With(succeeded:=False, VBFeaturesResources.no_valid_statement_range_to_extract_out) - End With + If firstValidNode Is Nothing Then + ' couldn't find any valid node + Return selectionInfo.With( + status:=New OperationStatus(succeeded:=False, VBFeaturesResources.Selection_doesn_t_contain_any_valid_node), + firstTokenInFinalSpan:=Nothing, + lastTokenInFinalSpan:=Nothing) + End If - Return clone - End If - - Dim statement1 = DirectCast(range.Value.Item1, StatementSyntax) - Dim statement2 = DirectCast(range.Value.Item2, StatementSyntax) - - If statement1 Is statement2 Then - ' check one more time to see whether it is an expression case - Dim expression = selectionInfo.CommonRootFromOriginalSpan.GetAncestor(Of ExpressionSyntax)() - If expression IsNot Nothing AndAlso statement1.Span.Contains(expression.Span) Then - With clone - .SelectionInExpression = True - .FirstTokenInFinalSpan = expression.GetFirstToken(includeZeroWidth:=True) - .LastTokenInFinalSpan = expression.GetLastToken(includeZeroWidth:=True) - End With - - Return clone + Return selectionInfo.With( + selectionInExpression:=TypeOf firstValidNode Is ExpressionSyntax, + firstTokenInFinalSpan:=firstValidNode.GetFirstToken(includeZeroWidth:=True), + lastTokenInFinalSpan:=firstValidNode.GetLastToken(includeZeroWidth:=True)) + End Function + + Private Shared Function AssignInitialFinalTokens( + selectionInfo As InitialSelectionInfo) As FinalSelectionInfo + + If selectionInfo.SelectionInExpression Then + ' prefer outer statement or expression if two has same span + Dim outerNode = selectionInfo.CommonRoot.GetOutermostNodeWithSameSpan(Function(n) TypeOf n Is ExecutableStatementSyntax OrElse TypeOf n Is ExpressionSyntax) + + ' simple expression case + Return New FinalSelectionInfo With { + .Status = selectionInfo.Status, + .SelectionInExpression = TypeOf outerNode Is ExpressionSyntax, + .FirstTokenInFinalSpan = outerNode.GetFirstToken(includeZeroWidth:=True), + .LastTokenInFinalSpan = outerNode.GetLastToken(includeZeroWidth:=True) + } End If - ' single statement case - ' current way to find out a statement that can be extracted out - Dim singleStatement = statement1.GetAncestorsOrThis(Of StatementSyntax)().FirstOrDefault( - Function(s) s.Parent IsNot Nothing AndAlso s.Parent.IsStatementContainerNode() AndAlso s.Parent.ContainStatement(s)) + Dim statement1 = selectionInfo.FirstStatement + Dim statement2 = selectionInfo.LastStatement + + If statement1 Is statement2 Then + ' check one more time to see whether it is an expression case + Dim expression = selectionInfo.CommonRoot.GetAncestor(Of ExpressionSyntax)() + If expression IsNot Nothing AndAlso statement1.Span.Contains(expression.Span) Then + Return New FinalSelectionInfo With { + .Status = selectionInfo.Status, + .SelectionInExpression = True, + .FirstTokenInFinalSpan = expression.GetFirstToken(includeZeroWidth:=True), + .LastTokenInFinalSpan = expression.GetLastToken(includeZeroWidth:=True) + } + End If - If singleStatement Is Nothing Then - With clone - .Status = clone.Status.With(succeeded:=False, VBFeaturesResources.no_valid_statement_range_to_extract_out) - End With + ' single statement case + ' current way to find out a statement that can be extracted out + Dim singleStatement = statement1.GetAncestorsOrThis(Of ExecutableStatementSyntax)().FirstOrDefault( + Function(s) s.Parent IsNot Nothing AndAlso s.Parent.IsStatementContainerNode() AndAlso s.Parent.ContainStatement(s)) + + If singleStatement Is Nothing Then + Return New FinalSelectionInfo With { + .Status = selectionInfo.Status.With(succeeded:=False, FeaturesResources.No_valid_statement_range_to_extract) + } + End If - Return clone + Return New FinalSelectionInfo With { + .Status = selectionInfo.Status, + .FirstTokenInFinalSpan = singleStatement.GetFirstToken(includeZeroWidth:=True), + .LastTokenInFinalSpan = singleStatement.GetLastToken(includeZeroWidth:=True) + } End If - With clone - .SelectionInSingleStatement = True - .FirstTokenInFinalSpan = singleStatement.GetFirstToken(includeZeroWidth:=True) - .LastTokenInFinalSpan = singleStatement.GetLastToken(includeZeroWidth:=True) - End With + ' Special check for vb + ' either statement1 or statement2 is pointing to header and end of a block node + ' return the block instead of each node + If statement1.Parent.IsStatementContainerNode() Then + Dim contain1 = statement1.Parent.ContainStatement(statement1) + Dim contain2 = statement2.Parent.ContainStatement(statement2) + + If Not contain1 OrElse Not contain2 Then + Dim parent = statement1.Parent _ + .GetAncestorsOrThis(Of SyntaxNode)() _ + .Where(Function(n) TypeOf n Is ExpressionSyntax OrElse TypeOf n Is ExecutableStatementSyntax) _ + .First() + + ' single statement case + Return New FinalSelectionInfo With { + .Status = selectionInfo.Status, + .SelectionInExpression = TypeOf parent Is ExpressionSyntax, + .FirstTokenInFinalSpan = parent.GetFirstToken(), + .LastTokenInFinalSpan = parent.GetLastToken() + } + End If + End If - Return clone - End If + Return New FinalSelectionInfo With { + .Status = selectionInfo.Status, + .FirstTokenInFinalSpan = statement1.GetFirstToken(includeZeroWidth:=True), + .LastTokenInFinalSpan = statement2.GetLastToken(includeZeroWidth:=True) + } + End Function - ' Special check for vb - ' either statement1 or statement2 is pointing to header and end of a block node - ' return the block instead of each node - If statement1.Parent.IsStatementContainerNode() Then - Dim contain1 = statement1.Parent.ContainStatement(statement1) - Dim contain2 = statement2.Parent.ContainStatement(statement2) + Protected Overrides Function GetAdjustedSpan(textSpan As TextSpan) As TextSpan + Dim root = Me.SemanticDocument.Root + Dim text = Me.SemanticDocument.Text - If Not contain1 OrElse Not contain2 Then - Dim parent = statement1.Parent _ - .GetAncestorsOrThis(Of SyntaxNode)() _ - .Where(Function(n) TypeOf n Is ExpressionSyntax OrElse TypeOf n Is StatementSyntax) _ - .First() + ' quick exit + If textSpan.IsEmpty OrElse textSpan.End = 0 Then + Return textSpan + End If - ' single statement case - With clone - .SelectionInExpression = TypeOf parent Is ExpressionSyntax - .SelectionInSingleStatement = TypeOf parent Is StatementSyntax - .FirstTokenInFinalSpan = parent.GetFirstToken() - .LastTokenInFinalSpan = parent.GetLastToken() - End With - - Return clone + ' regular column 0 check + Dim line = text.Lines.GetLineFromPosition(textSpan.End) + If line.Start <> textSpan.End Then + Return textSpan End If - End If - - With clone - .FirstTokenInFinalSpan = statement1.GetFirstToken(includeZeroWidth:=True) - .LastTokenInFinalSpan = statement2.GetLastToken(includeZeroWidth:=True) - End With - - Return clone - End Function - - Private Function GetInitialSelectionInfo(root As SyntaxNode) As SelectionInfo - Dim adjustedSpan = GetAdjustedSpan(root, Me.OriginalSpan) - Dim firstTokenInSelection = root.FindTokenOnRightOfPosition(adjustedSpan.Start, includeSkipped:=False) - Dim lastTokenInSelection = root.FindTokenOnLeftOfPosition(adjustedSpan.End, includeSkipped:=False) - - If firstTokenInSelection.Kind = SyntaxKind.None OrElse lastTokenInSelection.Kind = SyntaxKind.None Then - Return New SelectionInfo With {.Status = New OperationStatus(succeeded:=False, FeaturesResources.Invalid_selection), .OriginalSpan = adjustedSpan} - End If - - If firstTokenInSelection <> lastTokenInSelection AndAlso - firstTokenInSelection.Span.End > lastTokenInSelection.SpanStart Then - Return New SelectionInfo With {.Status = New OperationStatus(succeeded:=False, FeaturesResources.Invalid_selection), .OriginalSpan = adjustedSpan} - End If - - If (Not adjustedSpan.Contains(firstTokenInSelection.Span)) AndAlso (Not adjustedSpan.Contains(lastTokenInSelection.Span)) Then - Return New SelectionInfo With - { - .Status = New OperationStatus(succeeded:=False, FeaturesResources.Selection_does_not_contain_a_valid_token), - .OriginalSpan = adjustedSpan, - .FirstTokenInOriginalSpan = firstTokenInSelection, - .LastTokenInOriginalSpan = lastTokenInSelection - } - End If - - If (Not firstTokenInSelection.UnderValidContext()) OrElse (Not lastTokenInSelection.UnderValidContext()) Then - Return New SelectionInfo With - { - .Status = New OperationStatus(succeeded:=False, FeaturesResources.No_valid_selection_to_perform_extraction), - .OriginalSpan = adjustedSpan, - .FirstTokenInOriginalSpan = firstTokenInSelection, - .LastTokenInOriginalSpan = lastTokenInSelection - } - End If - - Dim commonRoot = GetCommonRoot(firstTokenInSelection, lastTokenInSelection) - If commonRoot Is Nothing Then - Return New SelectionInfo With - { - .Status = New OperationStatus(succeeded:=False, FeaturesResources.No_common_root_node_for_extraction), - .OriginalSpan = adjustedSpan, - .FirstTokenInOriginalSpan = firstTokenInSelection, - .LastTokenInOriginalSpan = lastTokenInSelection - } - End If - - If Not commonRoot.ContainedInValidType() Then - Return New SelectionInfo With - { - .Status = New OperationStatus(succeeded:=False, FeaturesResources.Selection_not_contained_inside_a_type), - .OriginalSpan = adjustedSpan, - .FirstTokenInOriginalSpan = firstTokenInSelection, - .LastTokenInOriginalSpan = lastTokenInSelection - } - End If - - Dim selectionInExpression = TypeOf commonRoot Is ExpressionSyntax AndAlso - commonRoot.GetFirstToken(includeZeroWidth:=True) = firstTokenInSelection AndAlso - commonRoot.GetLastToken(includeZeroWidth:=True) = lastTokenInSelection - - If (Not selectionInExpression) AndAlso (Not commonRoot.UnderValidContext()) Then - Return New SelectionInfo With - { - .Status = New OperationStatus(succeeded:=False, FeaturesResources.No_valid_selection_to_perform_extraction), - .OriginalSpan = adjustedSpan, - .FirstTokenInOriginalSpan = firstTokenInSelection, - .LastTokenInOriginalSpan = lastTokenInSelection - } - End If - - ' make sure type block enclosing the selection exist - If commonRoot.GetAncestor(Of TypeBlockSyntax)() Is Nothing Then - Return New SelectionInfo With - { - .Status = New OperationStatus(succeeded:=False, FeaturesResources.No_valid_selection_to_perform_extraction), - .OriginalSpan = adjustedSpan, - .FirstTokenInOriginalSpan = firstTokenInSelection, - .LastTokenInOriginalSpan = lastTokenInSelection - } - End If - - Return New SelectionInfo With - { - .Status = OperationStatus.SucceededStatus, - .OriginalSpan = adjustedSpan, - .CommonRootFromOriginalSpan = commonRoot, - .SelectionInExpression = selectionInExpression, - .FirstTokenInOriginalSpan = firstTokenInSelection, - .LastTokenInOriginalSpan = lastTokenInSelection - } - End Function - - Public Overrides Function ContainsNonReturnExitPointsStatements(jumpsOutOfRegion As IEnumerable(Of SyntaxNode)) As Boolean - Dim returnStatement = False - Dim exitStatement = False - - For Each statement In jumpsOutOfRegion - If TypeOf statement Is ReturnStatementSyntax Then - returnStatement = True - ElseIf TypeOf statement Is ExitStatementSyntax Then - exitStatement = True - Else - Return True + + ' previous line + Contract.ThrowIfFalse(line.LineNumber > 0) + Dim previousLine = text.Lines(line.LineNumber - 1) + + ' check whether end of previous line is last token of a statement. if it is, don't do anything + If root.FindTokenOnLeftOfPosition(previousLine.End).IsLastTokenOfStatement() Then + Return textSpan End If - Next - - If exitStatement Then - Return Not returnStatement - End If - - Return False - End Function - - Public Overrides Function GetOuterReturnStatements(commonRoot As SyntaxNode, jumpsOutOfRegionStatements As IEnumerable(Of SyntaxNode)) As IEnumerable(Of SyntaxNode) - Dim returnStatements = jumpsOutOfRegionStatements.Where(Function(n) TypeOf n Is ReturnStatementSyntax OrElse TypeOf n Is ExitStatementSyntax) - - Dim container = commonRoot.GetAncestorsOrThis(Of SyntaxNode)().Where(Function(a) a.IsReturnableConstruct()).FirstOrDefault() - If container Is Nothing Then - Return SpecializedCollections.EmptyEnumerable(Of SyntaxNode)() - End If - - Dim returnableConstructPairs = returnStatements. - Select(Function(r) (r, r.GetAncestors(Of SyntaxNode)().Where(Function(a) a.IsReturnableConstruct()).FirstOrDefault())). - Where(Function(p) p.Item2 IsNot Nothing) - - ' now filter return statements to only include the one under outmost container - Return returnableConstructPairs.Where(Function(p) p.Item2 Is container).Select(Function(p) p.Item1) - End Function - - Public Overrides Function IsFinalSpanSemanticallyValidSpan(root As SyntaxNode, - textSpan As TextSpan, - returnStatements As IEnumerable(Of SyntaxNode), - cancellationToken As CancellationToken) As Boolean - - ' do quick check to make sure we are under sub (no return value) container. otherwise, there is no point to anymore checks. - If returnStatements.Any(Function(s) - Return s.TypeSwitch( - Function(e As ExitStatementSyntax) e.BlockKeyword.Kind <> SyntaxKind.SubKeyword, - Function(r As ReturnStatementSyntax) r.Expression IsNot Nothing, - Function(n As SyntaxNode) True) - End Function) Then - Return False - End If - - ' check whether selection reaches the end of the container - Dim lastToken = root.FindToken(textSpan.End) - If lastToken.Kind = SyntaxKind.None Then - Return False - End If - - Dim nextToken = lastToken.GetNextToken(includeZeroWidth:=True) - - Dim container = nextToken.GetAncestors(Of SyntaxNode).Where(Function(n) n.IsReturnableConstruct()).FirstOrDefault() - If container Is Nothing Then - Return False - End If - - Dim match = If(TryCast(container, MethodBlockBaseSyntax)?.EndBlockStatement.EndKeyword = nextToken, False) OrElse - If(TryCast(container, MultiLineLambdaExpressionSyntax)?.EndSubOrFunctionStatement.EndKeyword = nextToken, False) - - If Not match Then - Return False - End If - - If TryCast(container, MethodBlockBaseSyntax)?.BlockStatement.Kind = SyntaxKind.SubStatement Then - Return True - ElseIf TryCast(container, MultiLineLambdaExpressionSyntax)?.SubOrFunctionHeader.Kind = SyntaxKind.SubLambdaHeader Then - Return True - Else - Return False - End If - End Function - - Private Shared Function GetAdjustedSpan(root As SyntaxNode, textSpan As TextSpan) As TextSpan - ' quick exit - If textSpan.IsEmpty OrElse textSpan.End = 0 Then - Return textSpan - End If - - ' regular column 0 check - Dim line = root.GetText().Lines.GetLineFromPosition(textSpan.End) - If line.Start <> textSpan.End Then - Return textSpan - End If - - ' previous line - Contract.ThrowIfFalse(line.LineNumber > 0) - Dim previousLine = root.GetText().Lines(line.LineNumber - 1) - - ' check whether end of previous line is last token of a statement. if it is, don't do anything - If root.FindTokenOnLeftOfPosition(previousLine.End).IsLastTokenOfStatement() Then - Return textSpan - End If - - ' move end position of the selection - Return TextSpan.FromBounds(textSpan.Start, previousLine.End) - End Function + + ' move end position of the selection + Return textSpan.FromBounds(textSpan.Start, previousLine.End) + End Function + End Class End Class End Namespace diff --git a/src/Features/VisualBasic/Portable/GenerateConstructorFromMembers/VisualBasicGenerateConstructorFromMembersCodeRefactoringProvider.vb b/src/Features/VisualBasic/Portable/GenerateConstructors/VisualBasicGenerateConstructorsCodeRefactoringProvider.vb similarity index 87% rename from src/Features/VisualBasic/Portable/GenerateConstructorFromMembers/VisualBasicGenerateConstructorFromMembersCodeRefactoringProvider.vb rename to src/Features/VisualBasic/Portable/GenerateConstructors/VisualBasicGenerateConstructorsCodeRefactoringProvider.vb index 7c7983dddbe40..2a4dc4523e591 100644 --- a/src/Features/VisualBasic/Portable/GenerateConstructorFromMembers/VisualBasicGenerateConstructorFromMembersCodeRefactoringProvider.vb +++ b/src/Features/VisualBasic/Portable/GenerateConstructors/VisualBasicGenerateConstructorsCodeRefactoringProvider.vb @@ -6,17 +6,15 @@ Imports System.Composition Imports System.Diagnostics.CodeAnalysis Imports System.Threading Imports Microsoft.CodeAnalysis.CodeRefactorings -Imports Microsoft.CodeAnalysis.GenerateConstructorFromMembers +Imports Microsoft.CodeAnalysis.GenerateConstructors Imports Microsoft.CodeAnalysis.Host.Mef -Imports Microsoft.CodeAnalysis.Options Imports Microsoft.CodeAnalysis.PickMembers -Imports Microsoft.CodeAnalysis.Simplification -Namespace Microsoft.CodeAnalysis.VisualBasic.GenerateConstructorFromMembers +Namespace Microsoft.CodeAnalysis.VisualBasic.GenerateConstructors - Friend NotInheritable Class VisualBasicGenerateConstructorFromMembersCodeRefactoringProvider - Inherits AbstractGenerateConstructorFromMembersCodeRefactoringProvider + Friend NotInheritable Class VisualBasicGenerateConstructorsCodeRefactoringProvider + Inherits AbstractGenerateConstructorsCodeRefactoringProvider diff --git a/src/Features/VisualBasic/Portable/GenerateType/VisualBasicGenerateTypeService.vb b/src/Features/VisualBasic/Portable/GenerateType/VisualBasicGenerateTypeService.vb index f0bf267e39a6f..045323189d8d5 100644 --- a/src/Features/VisualBasic/Portable/GenerateType/VisualBasicGenerateTypeService.vb +++ b/src/Features/VisualBasic/Portable/GenerateType/VisualBasicGenerateTypeService.vb @@ -9,7 +9,6 @@ Imports Microsoft.CodeAnalysis.AddImport Imports Microsoft.CodeAnalysis.CodeGeneration Imports Microsoft.CodeAnalysis.Editing Imports Microsoft.CodeAnalysis.Formatting -Imports Microsoft.CodeAnalysis.GenerateMember.GenerateConstructor Imports Microsoft.CodeAnalysis.GenerateType Imports Microsoft.CodeAnalysis.Host.Mef Imports Microsoft.CodeAnalysis.LanguageService @@ -18,11 +17,10 @@ Imports Microsoft.CodeAnalysis.Text Imports Microsoft.CodeAnalysis.Utilities Imports Microsoft.CodeAnalysis.VisualBasic.Extensions.ContextQuery Imports Microsoft.CodeAnalysis.VisualBasic.Syntax -Imports Microsoft.CodeAnalysis.VisualBasic.Utilities Namespace Microsoft.CodeAnalysis.VisualBasic.GenerateType - Partial Friend Class VisualBasicGenerateTypeService + Partial Friend NotInheritable Class VisualBasicGenerateTypeService Inherits AbstractGenerateTypeService(Of VisualBasicGenerateTypeService, SimpleNameSyntax, ObjectCreationExpressionSyntax, ExpressionSyntax, TypeBlockSyntax, ArgumentSyntax) @@ -30,11 +28,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.GenerateType Public Sub New() End Sub - Protected Overrides ReadOnly Property DefaultFileExtension As String - Get - Return ".vb" - End Get - End Property + Protected Overrides ReadOnly Property DefaultFileExtension As String = ".vb" Protected Overrides Function GenerateParameterNames(semanticModel As SemanticModel, arguments As IList(Of ArgumentSyntax), cancellationToken As CancellationToken) As IList(Of ParameterName) Return semanticModel.GenerateParameterNames(arguments, reservedNames:=Nothing, cancellationToken:=cancellationToken) diff --git a/src/Features/VisualBasic/Portable/Highlighting/KeywordHighlighters/AccessorDeclarationHighlighter.vb b/src/Features/VisualBasic/Portable/Highlighting/KeywordHighlighters/AccessorDeclarationHighlighter.vb index 712f2e1368d08..3c48bae67dde6 100644 --- a/src/Features/VisualBasic/Portable/Highlighting/KeywordHighlighters/AccessorDeclarationHighlighter.vb +++ b/src/Features/VisualBasic/Portable/Highlighting/KeywordHighlighters/AccessorDeclarationHighlighter.vb @@ -21,7 +21,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.KeywordHighlighting Protected Overloads Overrides Sub AddHighlights(node As SyntaxNode, highlights As List(Of TextSpan), cancellationToken As CancellationToken) Dim methodBlock = node.GetAncestor(Of MethodBlockBaseSyntax)() - If methodBlock Is Nothing OrElse Not TypeOf methodBlock.BlockStatement Is AccessorStatementSyntax Then + If methodBlock Is Nothing OrElse TypeOf methodBlock.BlockStatement IsNot AccessorStatementSyntax Then Return End If diff --git a/src/Features/VisualBasic/Portable/Highlighting/KeywordHighlighters/ConstructorDeclarationHighlighter.vb b/src/Features/VisualBasic/Portable/Highlighting/KeywordHighlighters/ConstructorDeclarationHighlighter.vb index b8ed2d1c20948..bd963d359da54 100644 --- a/src/Features/VisualBasic/Portable/Highlighting/KeywordHighlighters/ConstructorDeclarationHighlighter.vb +++ b/src/Features/VisualBasic/Portable/Highlighting/KeywordHighlighters/ConstructorDeclarationHighlighter.vb @@ -21,7 +21,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.KeywordHighlighting Protected Overloads Overrides Sub AddHighlights(node As SyntaxNode, highlights As List(Of TextSpan), cancellationToken As CancellationToken) Dim methodBlock = node.GetAncestor(Of MethodBlockBaseSyntax)() - If methodBlock Is Nothing OrElse Not TypeOf methodBlock.BlockStatement Is SubNewStatementSyntax Then + If methodBlock Is Nothing OrElse TypeOf methodBlock.BlockStatement IsNot SubNewStatementSyntax Then Return End If diff --git a/src/Features/VisualBasic/Portable/Highlighting/KeywordHighlighters/MethodDeclarationHighlighter.vb b/src/Features/VisualBasic/Portable/Highlighting/KeywordHighlighters/MethodDeclarationHighlighter.vb index 3a42bb5fdb463..b488938c04c38 100644 --- a/src/Features/VisualBasic/Portable/Highlighting/KeywordHighlighters/MethodDeclarationHighlighter.vb +++ b/src/Features/VisualBasic/Portable/Highlighting/KeywordHighlighters/MethodDeclarationHighlighter.vb @@ -21,7 +21,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.KeywordHighlighting Protected Overloads Overrides Sub AddHighlights(node As SyntaxNode, highlights As List(Of TextSpan), cancellationToken As CancellationToken) Dim methodBlock = node.GetAncestor(Of MethodBlockBaseSyntax)() - If methodBlock Is Nothing OrElse Not TypeOf methodBlock.BlockStatement Is MethodStatementSyntax Then + If methodBlock Is Nothing OrElse TypeOf methodBlock.BlockStatement IsNot MethodStatementSyntax Then Return End If diff --git a/src/Features/VisualBasic/Portable/Highlighting/KeywordHighlighters/OperatorDeclarationHighlighter.vb b/src/Features/VisualBasic/Portable/Highlighting/KeywordHighlighters/OperatorDeclarationHighlighter.vb index dc5290ce338e4..7d5cc5ce94507 100644 --- a/src/Features/VisualBasic/Portable/Highlighting/KeywordHighlighters/OperatorDeclarationHighlighter.vb +++ b/src/Features/VisualBasic/Portable/Highlighting/KeywordHighlighters/OperatorDeclarationHighlighter.vb @@ -21,7 +21,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.KeywordHighlighting Protected Overloads Overrides Sub AddHighlights(node As SyntaxNode, highlights As List(Of TextSpan), cancellationToken As CancellationToken) Dim methodBlock = node.GetAncestor(Of MethodBlockBaseSyntax)() - If methodBlock Is Nothing OrElse Not TypeOf methodBlock.BlockStatement Is OperatorStatementSyntax Then + If methodBlock Is Nothing OrElse TypeOf methodBlock.BlockStatement IsNot OperatorStatementSyntax Then Return End If diff --git a/src/Features/VisualBasic/Portable/Highlighting/KeywordHighlighters/TryBlockHighlighter.vb b/src/Features/VisualBasic/Portable/Highlighting/KeywordHighlighters/TryBlockHighlighter.vb index 9f4e6ccf532b6..5c322aa006c3f 100644 --- a/src/Features/VisualBasic/Portable/Highlighting/KeywordHighlighters/TryBlockHighlighter.vb +++ b/src/Features/VisualBasic/Portable/Highlighting/KeywordHighlighters/TryBlockHighlighter.vb @@ -64,7 +64,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.KeywordHighlighting End If Dim child = childNodeOrToken.AsNode() - If Not TypeOf child Is TryBlockSyntax AndAlso Not TypeOf child Is LambdaExpressionSyntax Then + If TypeOf child IsNot TryBlockSyntax AndAlso TypeOf child IsNot LambdaExpressionSyntax Then HighlightRelatedStatements(child, highlights) End If Next diff --git a/src/Features/VisualBasic/Portable/Highlighting/KeywordHighlightingHelpers.vb b/src/Features/VisualBasic/Portable/Highlighting/KeywordHighlightingHelpers.vb index c87c04f3f3e7c..46660b010a6de 100644 --- a/src/Features/VisualBasic/Portable/Highlighting/KeywordHighlightingHelpers.vb +++ b/src/Features/VisualBasic/Portable/Highlighting/KeywordHighlightingHelpers.vb @@ -34,8 +34,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.KeywordHighlighting End With Else For Each child In node.ChildNodes() - If Not TypeOf child Is T AndAlso - Not TypeOf child Is LambdaExpressionSyntax Then + If TypeOf child IsNot T AndAlso + TypeOf child IsNot LambdaExpressionSyntax Then HighlightRelatedStatements(Of T)(child, highlights, blockKind, checkReturns) End If @@ -106,7 +106,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.KeywordHighlighting End If For Each child In node.ChildNodes() - If Not TypeOf child Is LambdaExpressionSyntax Then + If TypeOf child IsNot LambdaExpressionSyntax Then HighlightRelatedAwaits(child, highlights, cancellationToken) End If Next @@ -119,7 +119,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.KeywordHighlighting End With Else For Each child In node.ChildNodes() - If Not TypeOf child Is LambdaExpressionSyntax Then + If TypeOf child IsNot LambdaExpressionSyntax Then HighlightRelatedYieldStatements(Of T)(child, highlights) End If Next diff --git a/src/Features/VisualBasic/Portable/InitializeParameter/VisualBasicAddParameterCheckCodeRefactoringProvider.vb b/src/Features/VisualBasic/Portable/InitializeParameter/VisualBasicAddParameterCheckCodeRefactoringProvider.vb index 668d7c46c89b8..45211288f972a 100644 --- a/src/Features/VisualBasic/Portable/InitializeParameter/VisualBasicAddParameterCheckCodeRefactoringProvider.vb +++ b/src/Features/VisualBasic/Portable/InitializeParameter/VisualBasicAddParameterCheckCodeRefactoringProvider.vb @@ -5,10 +5,7 @@ Imports System.Composition Imports System.Diagnostics.CodeAnalysis Imports Microsoft.CodeAnalysis.CodeRefactorings -Imports Microsoft.CodeAnalysis.Editing Imports Microsoft.CodeAnalysis.InitializeParameter -Imports Microsoft.CodeAnalysis.LanguageService -Imports Microsoft.CodeAnalysis.VisualBasic.LanguageService Imports Microsoft.CodeAnalysis.VisualBasic.Simplification Imports Microsoft.CodeAnalysis.VisualBasic.Syntax @@ -37,10 +34,6 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.InitializeParameter Return InitializeParameterHelpers.GetBody(functionDeclaration) End Function - Protected Overrides Sub InsertStatement(editor As SyntaxEditor, functionDeclaration As SyntaxNode, returnsVoid As Boolean, statementToAddAfterOpt As SyntaxNode, statement As StatementSyntax) - InitializeParameterHelpers.InsertStatement(editor, functionDeclaration, statementToAddAfterOpt, statement) - End Sub - Protected Overrides Function IsImplicitConversion(compilation As Compilation, source As ITypeSymbol, destination As ITypeSymbol) As Boolean Return InitializeParameterHelpers.IsImplicitConversion(compilation, source, destination) End Function diff --git a/src/Features/VisualBasic/Portable/InitializeParameter/VisualBasicInitializeMemberFromParameterCodeRefactoringProvider.vb b/src/Features/VisualBasic/Portable/InitializeParameter/VisualBasicInitializeMemberFromParameterCodeRefactoringProvider.vb index e5d054e31ce4e..0190078af6fc7 100644 --- a/src/Features/VisualBasic/Portable/InitializeParameter/VisualBasicInitializeMemberFromParameterCodeRefactoringProvider.vb +++ b/src/Features/VisualBasic/Portable/InitializeParameter/VisualBasicInitializeMemberFromParameterCodeRefactoringProvider.vb @@ -6,18 +6,14 @@ Imports System.Composition Imports System.Diagnostics.CodeAnalysis Imports System.Threading Imports Microsoft.CodeAnalysis.CodeRefactorings -Imports Microsoft.CodeAnalysis.Editing Imports Microsoft.CodeAnalysis.InitializeParameter -Imports Microsoft.CodeAnalysis.LanguageService -Imports Microsoft.CodeAnalysis.Operations -Imports Microsoft.CodeAnalysis.VisualBasic.LanguageService Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Namespace Microsoft.CodeAnalysis.VisualBasic.InitializeParameter - Friend Class VisualBasicInitializeMemberFromParameterCodeRefactoringProvider + Friend NotInheritable Class VisualBasicInitializeMemberFromParameterCodeRefactoringProvider Inherits AbstractInitializeMemberFromParameterCodeRefactoringProvider(Of TypeBlockSyntax, ParameterSyntax, @@ -33,18 +29,10 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.InitializeParameter Return InitializeParameterHelpers.IsFunctionDeclaration(node) End Function - Protected Overrides Function TryGetLastStatement(blockStatement As IBlockOperation) As SyntaxNode - Return InitializeParameterHelpers.TryGetLastStatement(blockStatement) - End Function - Protected Overrides Function IsImplicitConversion(compilation As Compilation, source As ITypeSymbol, destination As ITypeSymbol) As Boolean Return InitializeParameterHelpers.IsImplicitConversion(compilation, source, destination) End Function - Protected Overrides Sub InsertStatement(editor As SyntaxEditor, functionDeclaration As SyntaxNode, returnsVoid As Boolean, statementToAddAfterOpt As SyntaxNode, statement As StatementSyntax) - InitializeParameterHelpers.InsertStatement(editor, functionDeclaration, statementToAddAfterOpt, statement) - End Sub - ' Fields are public by default in VB, except in the case of classes and modules. Protected Overrides Function DetermineDefaultFieldAccessibility(containingType As INamedTypeSymbol) As Accessibility Return If(containingType.TypeKind = TypeKind.Class Or containingType.TypeKind = TypeKind.Module, Accessibility.Private, Accessibility.Public) @@ -59,15 +47,6 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.InitializeParameter Return InitializeParameterHelpers.GetBody(functionDeclaration) End Function - Protected Overrides Function GetAccessorBody(accessor As IMethodSymbol, cancellationToken As CancellationToken) As SyntaxNode - If accessor.DeclaringSyntaxReferences.Length = 0 Then - Return Nothing - End If - - Dim reference = accessor.DeclaringSyntaxReferences(0).GetSyntax(cancellationToken) - Return TryCast(TryCast(reference, AccessorStatementSyntax)?.Parent, AccessorBlockSyntax) - End Function - Protected Overrides Function RemoveThrowNotImplemented(propertySyntax As SyntaxNode) As SyntaxNode Dim propertyBlock = TryCast(propertySyntax, PropertyBlockSyntax) If propertyBlock IsNot Nothing Then @@ -81,10 +60,5 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.InitializeParameter Private Overloads Shared Function RemoveThrowNotImplemented(accessorBlock As AccessorBlockSyntax) As AccessorBlockSyntax Return accessorBlock.WithStatements(Nothing) End Function - - Protected Overrides Function TryUpdateTupleAssignment(blockStatement As IBlockOperation, parameter As IParameterSymbol, fieldOrProperty As ISymbol, editor As SyntaxEditor) As Boolean - ' Not supported in VB - Return False - End Function End Class End Namespace diff --git a/src/Features/VisualBasic/Portable/InlineHints/VisualBasicInlineHintsService.vb b/src/Features/VisualBasic/Portable/InlineHints/VisualBasicInlineHintsService.vb index 642cb370019ee..bfa281ed9e969 100644 --- a/src/Features/VisualBasic/Portable/InlineHints/VisualBasicInlineHintsService.vb +++ b/src/Features/VisualBasic/Portable/InlineHints/VisualBasicInlineHintsService.vb @@ -11,7 +11,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.InlineHints ''' The service to locate all positions where inline hints should be placed. ''' - Friend Class VisualBasicInlineHintsService + Friend NotInheritable Class VisualBasicInlineHintsService Inherits AbstractInlineHintsService diff --git a/src/Features/VisualBasic/Portable/InlineHints/VisualBasicInlineParameterNameHintsService.vb b/src/Features/VisualBasic/Portable/InlineHints/VisualBasicInlineParameterNameHintsService.vb index 76f12f22011ca..0947303ee0d7c 100644 --- a/src/Features/VisualBasic/Portable/InlineHints/VisualBasicInlineParameterNameHintsService.vb +++ b/src/Features/VisualBasic/Portable/InlineHints/VisualBasicInlineParameterNameHintsService.vb @@ -25,7 +25,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.InlineHints semanticModel As SemanticModel, syntaxFacts As ISyntaxFactsService, node As SyntaxNode, - buffer As ArrayBuilder(Of (position As Integer, identifierArgument As String, parameter As IParameterSymbol, kind As HintKind)), + buffer As ArrayBuilder(Of (position As Integer, argument As SyntaxNode, parameter As IParameterSymbol, kind As HintKind)), cancellationToken As CancellationToken) Dim argumentList = TryCast(node, ArgumentListSyntax) @@ -53,7 +53,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.InlineHints End If Dim argumentIdentifier = GetIdentifierNameFromArgument(argument, syntaxFacts) - buffer.Add((argument.Span.Start, argumentIdentifier, parameter, GetKind(argument.Expression))) + buffer.Add((argument.Span.Start, argument, parameter, GetKind(argument.Expression))) Next End Sub diff --git a/src/Features/VisualBasic/Portable/IntroduceUsingStatement/VisualBasicIntroduceUsingStatementCodeRefactoringProvider.vb b/src/Features/VisualBasic/Portable/IntroduceUsingStatement/VisualBasicIntroduceUsingStatementCodeRefactoringProvider.vb index 02635b9a218c6..6df686a655871 100644 --- a/src/Features/VisualBasic/Portable/IntroduceUsingStatement/VisualBasicIntroduceUsingStatementCodeRefactoringProvider.vb +++ b/src/Features/VisualBasic/Portable/IntroduceUsingStatement/VisualBasicIntroduceUsingStatementCodeRefactoringProvider.vb @@ -5,15 +5,19 @@ Imports System.Composition Imports System.Diagnostics.CodeAnalysis Imports Microsoft.CodeAnalysis.CodeRefactorings +Imports Microsoft.CodeAnalysis.Diagnostics Imports Microsoft.CodeAnalysis.IntroduceUsingStatement Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Namespace Microsoft.CodeAnalysis.VisualBasic.IntroduceUsingStatement - Friend NotInheritable Class VisualBasicIntroduceUsingStatementCodeRefactoringProvider - Inherits AbstractIntroduceUsingStatementCodeRefactoringProvider(Of StatementSyntax, LocalDeclarationStatementSyntax, TryBlockSyntax) + Inherits AbstractIntroduceUsingStatementCodeRefactoringProvider(Of + StatementSyntax, + ExpressionStatementSyntax, + LocalDeclarationStatementSyntax, + TryBlockSyntax) @@ -22,6 +26,11 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.IntroduceUsingStatement Protected Overrides ReadOnly Property CodeActionTitle As String = VBFeaturesResources.Introduce_Using_statement + Protected Overrides Function PreferSimpleUsingStatement(options As AnalyzerOptionsProvider) As Boolean + ' VB does not have simple using statements. + Return False + End Function + Protected Overrides Function HasCatchBlocks(tryStatement As TryBlockSyntax) As Boolean Return tryStatement.CatchBlocks.Count > 0 End Function @@ -35,7 +44,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.IntroduceUsingStatement Return parent.IsMultiLineExecutableBlock() End Function - Protected Overrides Function GetSurroundingStatements(declarationStatement As LocalDeclarationStatementSyntax) As SyntaxList(Of StatementSyntax) + Protected Overrides Function GetSurroundingStatements(declarationStatement As StatementSyntax) As SyntaxList(Of StatementSyntax) Return declarationStatement.GetRequiredParent().GetExecutableBlockStatements() End Function @@ -52,6 +61,19 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.IntroduceUsingStatement Return SyntaxFactory.UsingBlock(usingStatement, statementsToSurround) End Function + Protected Overrides Function CreateUsingBlockStatement( + expressionStatement As ExpressionStatementSyntax, + statementsToSurround As SyntaxList(Of StatementSyntax)) As StatementSyntax + Dim usingStatement = SyntaxFactory.UsingStatement( + expression:=expressionStatement.Expression.WithoutTrivia(), + variables:=Nothing).WithTriviaFrom(expressionStatement) + Return SyntaxFactory.UsingBlock(usingStatement, statementsToSurround) + End Function + + Protected Overrides Function CreateUsingLocalDeclarationStatement(expressionStatement As ExpressionStatementSyntax, newVariableName As SyntaxToken) As StatementSyntax + Throw ExceptionUtilities.Unreachable() + End Function + Protected Overrides Function TryCreateUsingLocalDeclaration(options As ParseOptions, declarationStatement As LocalDeclarationStatementSyntax, ByRef usingDeclarationStatement As LocalDeclarationStatementSyntax) As Boolean Return False End Function diff --git a/src/Features/VisualBasic/Portable/IntroduceVariable/VisualBasicIntroduceVariableService.Rewriter.vb b/src/Features/VisualBasic/Portable/IntroduceVariable/VisualBasicIntroduceVariableService.Rewriter.vb index d61b58c1eb33d..edaea1cc1df15 100644 --- a/src/Features/VisualBasic/Portable/IntroduceVariable/VisualBasicIntroduceVariableService.Rewriter.vb +++ b/src/Features/VisualBasic/Portable/IntroduceVariable/VisualBasicIntroduceVariableService.Rewriter.vb @@ -11,7 +11,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.IntroduceVariable Private Class Rewriter Inherits VisualBasicSyntaxRewriter - Private ReadOnly _replacementAnnotation As New SyntaxAnnotation + Private Shared ReadOnly s_replacementAnnotation As New SyntaxAnnotation + Private ReadOnly _replacementNode As SyntaxNode Private ReadOnly _matches As ISet(Of ExpressionSyntax) @@ -23,10 +24,10 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.IntroduceVariable Public Overrides Function Visit(node As SyntaxNode) As SyntaxNode Dim expression = TryCast(node, ExpressionSyntax) If expression IsNot Nothing AndAlso _matches.Contains(expression) Then - Return _replacementNode _ - .WithLeadingTrivia(expression.GetLeadingTrivia()) _ - .WithTrailingTrivia(expression.GetTrailingTrivia()) _ - .WithAdditionalAnnotations(_replacementAnnotation) + Return _replacementNode. + WithLeadingTrivia(expression.GetLeadingTrivia()). + WithTrailingTrivia(expression.GetTrailingTrivia()). + WithAdditionalAnnotations(s_replacementAnnotation) End If Return MyBase.Visit(node) @@ -37,7 +38,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.IntroduceVariable If node IsNot newNode AndAlso newNode.IsKind(SyntaxKind.ParenthesizedExpression) Then Dim parenthesizedExpression = DirectCast(newNode, ParenthesizedExpressionSyntax) Dim innerExpression = parenthesizedExpression.OpenParenToken.GetNextToken().Parent - If innerExpression.HasAnnotation(_replacementAnnotation) AndAlso innerExpression.Equals(parenthesizedExpression.Expression) Then + If innerExpression.HasAnnotation(s_replacementAnnotation) AndAlso innerExpression.Equals(parenthesizedExpression.Expression) Then Return newNode.WithAdditionalAnnotations(Simplifier.Annotation) End If End If @@ -49,6 +50,39 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.IntroduceVariable Return New Rewriter(replacementNode, matches).Visit(node) End Function + Public Overrides Function VisitInferredFieldInitializer(node As InferredFieldInitializerSyntax) As SyntaxNode + Dim newNode = DirectCast(MyBase.VisitInferredFieldInitializer(node), InferredFieldInitializerSyntax) + If newNode IsNot node AndAlso + newNode.Expression.HasAnnotation(s_replacementAnnotation) Then + + Dim inferredName = node.Expression.TryGetInferredMemberName() + If inferredName IsNot Nothing Then + Return SyntaxFactory.NamedFieldInitializer( + SyntaxFactory.IdentifierName(inferredName.EscapeIdentifier(afterDot:=True)), + newNode.Expression.WithoutLeadingTrivia()).WithTriviaFrom(newNode) + End If + End If + + Return newNode + End Function + + Public Overrides Function VisitSimpleArgument(node As SimpleArgumentSyntax) As SyntaxNode + Dim newNode = DirectCast(MyBase.VisitSimpleArgument(node), SimpleArgumentSyntax) + If newNode IsNot node AndAlso + node.NameColonEquals Is Nothing AndAlso + newNode.Expression.HasAnnotation(s_replacementAnnotation) AndAlso + TypeOf node.Parent Is TupleExpressionSyntax Then + + Dim inferredName = node.Expression.TryGetInferredMemberName() + If inferredName IsNot Nothing Then + Return SyntaxFactory.SimpleArgument( + SyntaxFactory.NameColonEquals(SyntaxFactory.IdentifierName(inferredName.EscapeIdentifier())), + newNode.Expression.WithoutLeadingTrivia()).WithTriviaFrom(newNode) + End If + End If + + Return newNode + End Function End Class End Class End Namespace diff --git a/src/Features/VisualBasic/Portable/IntroduceVariable/VisualBasicIntroduceVariableService_IntroduceField.vb b/src/Features/VisualBasic/Portable/IntroduceVariable/VisualBasicIntroduceVariableService_IntroduceField.vb index e54a4cdd34506..bd4982b0b0822 100644 --- a/src/Features/VisualBasic/Portable/IntroduceVariable/VisualBasicIntroduceVariableService_IntroduceField.vb +++ b/src/Features/VisualBasic/Portable/IntroduceVariable/VisualBasicIntroduceVariableService_IntroduceField.vb @@ -200,7 +200,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.IntroduceVariable isConstant As Boolean, cancellationToken As CancellationToken) As FieldDeclarationSyntax - Dim matches = FindMatches(document, expression, document, oldTypeDeclaration, allOccurrences, cancellationToken) + Dim matches = FindMatches(document, expression, document, {oldTypeDeclaration}, allOccurrences, cancellationToken) Dim trimmedExpression = expression.WithoutTrailingTrivia().WithoutLeadingTrivia() Return SyntaxFactory.FieldDeclaration( diff --git a/src/Features/VisualBasic/Portable/IntroduceVariable/VisualBasicIntroduceVariableService_IntroduceLocal.vb b/src/Features/VisualBasic/Portable/IntroduceVariable/VisualBasicIntroduceVariableService_IntroduceLocal.vb index 85392c485de60..5c0a1606b4fce 100644 --- a/src/Features/VisualBasic/Portable/IntroduceVariable/VisualBasicIntroduceVariableService_IntroduceLocal.vb +++ b/src/Features/VisualBasic/Portable/IntroduceVariable/VisualBasicIntroduceVariableService_IntroduceLocal.vb @@ -6,17 +6,19 @@ Imports System.Threading Imports Microsoft.CodeAnalysis Imports Microsoft.CodeAnalysis.CodeActions Imports Microsoft.CodeAnalysis.Formatting +Imports Microsoft.CodeAnalysis.CodeCleanup Imports Microsoft.CodeAnalysis.VisualBasic Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Namespace Microsoft.CodeAnalysis.VisualBasic.IntroduceVariable Partial Friend Class VisualBasicIntroduceVariableService - Protected Overrides Async Function IntroduceLocalAsync( + Protected Overrides Function IntroduceLocal( document As SemanticDocument, + options As CodeCleanupOptions, expression As ExpressionSyntax, allOccurrences As Boolean, isConstant As Boolean, - cancellationToken As CancellationToken) As Task(Of Document) + cancellationToken As CancellationToken) As Document Dim container = GetContainerToGenerateInfo(document, expression, cancellationToken) Dim newLocalNameToken = GenerateUniqueLocalName( @@ -34,7 +36,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.IntroduceVariable SyntaxFactory.VariableDeclarator( SyntaxFactory.SingletonSeparatedList(SyntaxFactory.ModifiedIdentifier(newLocalNameToken.WithAdditionalAnnotations(RenameAnnotation.Create()))), asClause, - SyntaxFactory.EqualsValue(value:=expression.WithoutTrailingTrivia().WithoutLeadingTrivia())))) + SyntaxFactory.EqualsValue(value:=expression.Parenthesize().WithoutTrivia())))) If Not declarationStatement.GetTrailingTrivia().Any(SyntaxKind.EndOfLineTrivia) Then declarationStatement = declarationStatement.WithAppendedTrailingTrivia(SyntaxFactory.ElasticCarriageReturnLineFeed) @@ -45,9 +47,9 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.IntroduceVariable document, DirectCast(container, SingleLineLambdaExpressionSyntax), expression, newLocalName, declarationStatement, allOccurrences, cancellationToken) Else - Return Await IntroduceLocalDeclarationIntoBlockAsync( + Return IntroduceLocalDeclarationIntoBlock( document, container, expression, newLocalName, - declarationStatement, allOccurrences, cancellationToken).ConfigureAwait(False) + declarationStatement, allOccurrences, cancellationToken) End If End Function @@ -113,14 +115,14 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.IntroduceVariable Return Nothing End Function - Private Async Function IntroduceLocalDeclarationIntoBlockAsync( + Private Function IntroduceLocalDeclarationIntoBlock( document As SemanticDocument, container As SyntaxNode, expression As ExpressionSyntax, newLocalName As NameSyntax, declarationStatement As LocalDeclarationStatementSyntax, allOccurrences As Boolean, - cancellationToken As CancellationToken) As Task(Of Document) + cancellationToken As CancellationToken) As Document Dim localAnnotation = New SyntaxAnnotation() declarationStatement = declarationStatement.WithAdditionalAnnotations(Formatter.Annotation, localAnnotation) @@ -130,15 +132,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.IntroduceVariable oldOutermostBlock = oldOutermostBlock.Parent End If - Dim matches = FindMatches(document, expression, document, oldOutermostBlock, allOccurrences, cancellationToken) - - Dim complexified = Await ComplexifyParentingStatementsAsync(document, matches, cancellationToken).ConfigureAwait(False) - document = complexified.newSemanticDocument - matches = complexified.newMatches - - ' Our original expression should have been one of the matches, which were tracked as part - ' of complexification, so we can retrieve the latest version of the expression here. - expression = document.Root.GetCurrentNodes(expression).First() + Dim matches = FindMatches(document, expression, document, {oldOutermostBlock}, allOccurrences, cancellationToken) Dim innermostStatements = New HashSet(Of StatementSyntax)(matches.Select(Function(expr) expr.GetAncestorOrThis(Of StatementSyntax)())) If innermostStatements.Count = 1 Then diff --git a/src/Features/VisualBasic/Portable/IntroduceVariable/VisualBasicIntroduceVariableService_IntroduceQueryLocal.vb b/src/Features/VisualBasic/Portable/IntroduceVariable/VisualBasicIntroduceVariableService_IntroduceQueryLocal.vb index f6bf292e13901..f02281306484c 100644 --- a/src/Features/VisualBasic/Portable/IntroduceVariable/VisualBasicIntroduceVariableService_IntroduceQueryLocal.vb +++ b/src/Features/VisualBasic/Portable/IntroduceVariable/VisualBasicIntroduceVariableService_IntroduceQueryLocal.vb @@ -10,11 +10,11 @@ Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Namespace Microsoft.CodeAnalysis.VisualBasic.IntroduceVariable Partial Friend Class VisualBasicIntroduceVariableService - Protected Overrides Function IntroduceQueryLocalAsync( + Protected Overrides Function IntroduceQueryLocal( document As SemanticDocument, expression As ExpressionSyntax, allOccurrences As Boolean, - cancellationToken As CancellationToken) As Task(Of Document) + cancellationToken As CancellationToken) As Document Dim oldOutermostQuery = expression.GetAncestorsOrThis(Of QueryExpressionSyntax)().LastOrDefault() @@ -29,7 +29,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.IntroduceVariable SyntaxFactory.ModifiedIdentifier(newLocalNameToken.WithAdditionalAnnotations(RenameAnnotation.Create()))), expression)).WithAdditionalAnnotations(Formatter.Annotation) - Dim matches = FindMatches(document, expression, document, oldOutermostQuery, allOccurrences, cancellationToken) + Dim matches = FindMatches(document, expression, document, {oldOutermostQuery}, allOccurrences, cancellationToken) Dim innermostClauses = New HashSet(Of QueryClauseSyntax)( matches.Select(Function(expr) expr.GetAncestor(Of QueryClauseSyntax)())) @@ -38,8 +38,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.IntroduceVariable ' statement, then we want to place the declaration right above that ' statement. Note: we special case this because the statement we are going ' to go above might not be in a block and we may have to generate it - Return Task.FromResult(IntroduceQueryLocalForSingleOccurrence( - document, expression, newLocalName, letClause, allOccurrences, cancellationToken)) + Return IntroduceQueryLocalForSingleOccurrence( + document, expression, newLocalName, letClause, allOccurrences, cancellationToken) End If Dim oldInnerMostCommonQuery = matches.FindInnermostCommonNode(Of QueryExpressionSyntax)() @@ -61,7 +61,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.IntroduceVariable Dim finalQuery = newInnerMostQuery.WithClauses(SyntaxFactory.List(finalClauses)) Dim newRoot = document.Root.ReplaceNode(oldInnerMostCommonQuery, finalQuery) - Return Task.FromResult(document.Document.WithSyntaxRoot(newRoot)) + Return document.Document.WithSyntaxRoot(newRoot) End Function Private Function IntroduceQueryLocalForSingleOccurrence( diff --git a/src/Features/VisualBasic/Portable/MoveDeclarationNearReference/VisualBasicMoveDeclarationNearRefactoringProvider.vb b/src/Features/VisualBasic/Portable/MoveDeclarationNearReference/VisualBasicMoveDeclarationNearRefactoringProvider.vb index edd18d44ade0b..da8aad14a2252 100644 --- a/src/Features/VisualBasic/Portable/MoveDeclarationNearReference/VisualBasicMoveDeclarationNearRefactoringProvider.vb +++ b/src/Features/VisualBasic/Portable/MoveDeclarationNearReference/VisualBasicMoveDeclarationNearRefactoringProvider.vb @@ -11,7 +11,7 @@ Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Namespace Microsoft.CodeAnalysis.VisualBasic.MoveDeclarationNearReference - Friend Class VisualBasicMoveDeclarationNearReferenceCodeRefactoringProvider + Friend NotInheritable Class VisualBasicMoveDeclarationNearReferenceCodeRefactoringProvider Inherits AbstractMoveDeclarationNearReferenceCodeRefactoringProvider(Of LocalDeclarationStatementSyntax) diff --git a/src/Features/VisualBasic/Portable/SignatureHelp/AttributeSignatureHelpProvider.vb b/src/Features/VisualBasic/Portable/SignatureHelp/AttributeSignatureHelpProvider.vb index 642dea7974879..ce05078afad17 100644 --- a/src/Features/VisualBasic/Portable/SignatureHelp/AttributeSignatureHelpProvider.vb +++ b/src/Features/VisualBasic/Portable/SignatureHelp/AttributeSignatureHelpProvider.vb @@ -169,7 +169,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.SignatureHelp Private Shared Function GetParameterPrefixDisplayParts(i As Integer) As List(Of SymbolDisplayPart) If i = 0 Then Return New List(Of SymbolDisplayPart) From { - New SymbolDisplayPart(SymbolDisplayPartKind.Text, Nothing, VBFeaturesResources.Properties), + New SymbolDisplayPart(SymbolDisplayPartKind.Text, Nothing, FeaturesResources.Properties), Punctuation(SyntaxKind.ColonToken), Space() } diff --git a/src/Features/VisualBasic/Portable/SimplifyTypeNames/SimplifyTypeNamesCodeFixProvider.vb b/src/Features/VisualBasic/Portable/SimplifyTypeNames/SimplifyTypeNamesCodeFixProvider.vb index d28d543d2b490..4cc39bd47f991 100644 --- a/src/Features/VisualBasic/Portable/SimplifyTypeNames/SimplifyTypeNamesCodeFixProvider.vb +++ b/src/Features/VisualBasic/Portable/SimplifyTypeNames/SimplifyTypeNamesCodeFixProvider.vb @@ -28,10 +28,10 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.SimplifyTypeNames Select Case simplifyDiagnosticId Case IDEDiagnosticIds.SimplifyNamesDiagnosticId, IDEDiagnosticIds.PreferBuiltInOrFrameworkTypeDiagnosticId - Return String.Format(VBFeaturesResources.Simplify_name_0, nodeText) + Return String.Format(FeaturesResources.Simplify_name_0, nodeText) Case IDEDiagnosticIds.SimplifyMemberAccessDiagnosticId - Return String.Format(VBFeaturesResources.Simplify_member_access_0, nodeText) + Return String.Format(FeaturesResources.Simplify_member_access_0, nodeText) Case Else Throw ExceptionUtilities.UnexpectedValue(simplifyDiagnosticId) diff --git a/src/Features/VisualBasic/Portable/VBFeaturesResources.resx b/src/Features/VisualBasic/Portable/VBFeaturesResources.resx index 310eaf5dbd866..50f0be21cee17 100644 --- a/src/Features/VisualBasic/Portable/VBFeaturesResources.resx +++ b/src/Features/VisualBasic/Portable/VBFeaturesResources.resx @@ -132,9 +132,6 @@ Insert the missing '{0}'. - - Conflict(s) detected. - Invert If @@ -213,22 +210,10 @@ Fix Incorrect Function Return Type - - Simplify name '{0}' - - - Simplify member access '{0}' - Remove 'Me' qualification {Locked="Me"} "Me" is a VB keyword and should not be localized. - - can't determine valid range of statements to extract out - - - Not all code paths return - contains invalid selection @@ -262,9 +247,6 @@ Selection doesn't contain any valid node - - no valid statement range to extract out - Deprecated @@ -1107,24 +1089,12 @@ Sub(<parameterList>) <statement> Add a metadata reference to specified assembly and all its dependencies, e.g. #r "myLib.dll". - - Properties - - - <namespace name> - Type a name here to declare a namespace. Type a name here to declare a partial class. - - <class name> - - - <interface name> - <module name> diff --git a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.cs.xlf b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.cs.xlf index 931bbf61f7e04..b5df205f28f71 100644 --- a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.cs.xlf +++ b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.cs.xlf @@ -67,11 +67,6 @@ Vložte chybějící {0}. - - Conflict(s) detected. - Zjistily se konflikty. - - Introduce 'Using' statement Zavést příkaz Using @@ -222,31 +217,11 @@ Opravit nesprávný návratový typ funkce - - Simplify name '{0}' - Zjednodušit název {0} - - - - Simplify member access '{0}' - Zjednodušit přístup ke členu {0} - - Remove 'Me' qualification Odebrat kvalifikaci Me {Locked="Me"} "Me" is a VB keyword and should not be localized. - - can't determine valid range of statements to extract out - nemůže určit platný rozsah příkazů k extrakci ven - - - - Not all code paths return - Ne všechny cesty kódu vracejí - - contains invalid selection obsahuje neplatný výběr @@ -302,11 +277,6 @@ Výběr nemůže obsahovat žádný platný uzel. - - no valid statement range to extract out - žádný platný rozsah příkazů pro extrakci ven - - Deprecated Zastaralé @@ -1647,16 +1617,6 @@ Sub(<seznam_parametrů>) <výraz> Přidá odkaz na metadata k určenému sestavení a všem jeho závislostem, třeba #r "myLib.dll". - - Properties - Vlastnosti - - - - <namespace name> - <název oboru názvů> - - Type a name here to declare a namespace. Sem zadejte název k deklarování oboru názvů. @@ -1667,16 +1627,6 @@ Sub(<seznam_parametrů>) <výraz> Zadáním názvu na toto místo deklarujte částečnou třídu. - - <class name> - <název třídy> - - - - <interface name> - <název rozhraní> - - <module name> <název modulu> diff --git a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.de.xlf b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.de.xlf index 2a4ed298eeb31..86fbb06a50748 100644 --- a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.de.xlf +++ b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.de.xlf @@ -67,11 +67,6 @@ Fügen Sie das fehlende "{0}" ein. - - Conflict(s) detected. - Konflikt(e) erkannt. - - Introduce 'Using' statement Using-Anweisung einführen @@ -222,31 +217,11 @@ Rückgabetyp für unzulässige Funktion beheben - - Simplify name '{0}' - Namen "{0}" vereinfachen - - - - Simplify member access '{0}' - Memberzugriff "{0}" vereinfachen - - Remove 'Me' qualification Qualifikation "Me" entfernen {Locked="Me"} "Me" is a VB keyword and should not be localized. - - can't determine valid range of statements to extract out - gültiger Bereich der zu extrahierenden Anweisungen kann nicht bestimmt werden - - - - Not all code paths return - Nicht alle Codepfadrückgaben - - contains invalid selection enthält ungültige Auswahl @@ -302,11 +277,6 @@ Auswahl enthält keinen gültigen Knoten - - no valid statement range to extract out - kein gültiger Anweisungsbereich für die Extraktion - - Deprecated Veraltet @@ -1647,16 +1617,6 @@ Sub(<Parameterliste>) <Ausdruck> Fügt der angegebenen Assembly und allen ihren Abhängigkeiten einen Metadatenverweis hinzu. Beispiel: #r "myLib.dll". - - Properties - Eigenschaften - - - - <namespace name> - <Namespacename> - - Type a name here to declare a namespace. Geben Sie hier einen Namen ein, um einen Namespace zu deklarieren. @@ -1667,16 +1627,6 @@ Sub(<Parameterliste>) <Ausdruck> Geben Sie hier einen Namen ein, um eine partielle Klasse zu deklarieren. - - <class name> - <Klassenname> - - - - <interface name> - <Schnittstellenname> - - <module name> <Modulname> diff --git a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.es.xlf b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.es.xlf index 6d0d9953583e4..aed9c60cf3e0c 100644 --- a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.es.xlf +++ b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.es.xlf @@ -67,11 +67,6 @@ Inserte el "{0}" que falta. - - Conflict(s) detected. - Conflicto(s) detectado(s). - - Introduce 'Using' statement Introducir instrucción "Using" @@ -222,31 +217,11 @@ Corregir tipo devuelto de función incorrecto - - Simplify name '{0}' - Simplificar nombre "{0}" - - - - Simplify member access '{0}' - Simplificar acceso a miembros "{0}" - - Remove 'Me' qualification Quitar calificación "Me" {Locked="Me"} "Me" is a VB keyword and should not be localized. - - can't determine valid range of statements to extract out - no se puede determinar el intervalo válido de instrucciones para extraer - - - - Not all code paths return - No todas las rutas de acceso de código vuelven - - contains invalid selection contiene una selección no válida @@ -302,11 +277,6 @@ Selection no contiene ningún nodo válido - - no valid statement range to extract out - ningún intervalo de instrucciones válido para extraer - - Deprecated En desuso @@ -1647,16 +1617,6 @@ Sub(<listaDeParámetros>) <instrucción>wo laopo fuke Agregue una referencia de metadatos al ensamblado especificado y todas sus dependencias, p. ej. #r "myLib.dll". - - Properties - Propiedades - - - - <namespace name> - <nombre de espacio de nombres> - - Type a name here to declare a namespace. Escriba aquí un nombre para declarar un espacio de nombres. @@ -1667,16 +1627,6 @@ Sub(<listaDeParámetros>) <instrucción>wo laopo fuke Escriba aquí un nombre para declarar una clase parcial. - - <class name> - <nombre de la clase> - - - - <interface name> - <nombre de la interfaz> - - <module name> <nombre de módulo> diff --git a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.fr.xlf b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.fr.xlf index 44a54bf49d7d7..333f6532e8ff0 100644 --- a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.fr.xlf +++ b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.fr.xlf @@ -67,11 +67,6 @@ Insérez le '{0}' manquant. - - Conflict(s) detected. - Conflit(s) détecté(s). - - Introduce 'Using' statement Introduire l'instruction 'Using' @@ -222,31 +217,11 @@ Corriger le type de retour de fonction incorrect - - Simplify name '{0}' - Simplifier le nom '{0}' - - - - Simplify member access '{0}' - Simplifier l'accès au membre '{0}' - - Remove 'Me' qualification Supprimer la qualification 'Me' {Locked="Me"} "Me" is a VB keyword and should not be localized. - - can't determine valid range of statements to extract out - impossible de déterminer la plage valide d'instructions à extraire - - - - Not all code paths return - Tous les chemins du code n'ont pas été retournés - - contains invalid selection contient une sélection non valide @@ -302,11 +277,6 @@ La sélection ne contient aucun nœud valide - - no valid statement range to extract out - Aucune plage d'instructions valides à extraire - - Deprecated Déconseillé @@ -1647,16 +1617,6 @@ Sub(<parameterList>) <statement> Permet d'ajouter une référence de métadonnées à l'assembly spécifié et toutes ses dépendances. Exemple : #r "myLib.dll". - - Properties - Propriétés - - - - <namespace name> - <nom de l'espace de noms> - - Type a name here to declare a namespace. Tapez un nom ici pour déclarer un espace de noms. @@ -1667,16 +1627,6 @@ Sub(<parameterList>) <statement> Tapez un nom ici pour déclarer une classe partielle. - - <class name> - <nom de la classe> - - - - <interface name> - <nom de l'interface> - - <module name> <nom du module> diff --git a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.it.xlf b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.it.xlf index dc38e5874667a..d7dd34f055537 100644 --- a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.it.xlf +++ b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.it.xlf @@ -67,11 +67,6 @@ Inserire l'elemento '{0}' mancante. - - Conflict(s) detected. - Sono stati rilevati conflitti. - - Introduce 'Using' statement Introduci istruzioni 'Using' @@ -222,31 +217,11 @@ Correggi tipo errato restituito da funzione - - Simplify name '{0}' - Semplifica il nome '{0}' - - - - Simplify member access '{0}' - Semplifica l'accesso dei membri '{0}' - - Remove 'Me' qualification Rimuovi qualificazione 'Me' {Locked="Me"} "Me" is a VB keyword and should not be localized. - - can't determine valid range of statements to extract out - non è possibile determinare l'intervallo valido di istruzioni da estrarre - - - - Not all code paths return - Non vengono restituiti tutti i percorsi del codice - - contains invalid selection contiene una selezione non valida @@ -302,11 +277,6 @@ La selezione non contiene nodi validi - - no valid statement range to extract out - l'intervallo di istruzioni non è valido per l'estrazione - - Deprecated Deprecato @@ -1647,16 +1617,6 @@ Sub(<elencoParametri>) <istruzione> Aggiunge un riferimento ai metadati all'assembly specificato e a tutte le relative dipendenze, ad esempio #r "myLib.dll". - - Properties - Proprietà - - - - <namespace name> - <nome spazio dei nomi> - - Type a name here to declare a namespace. Digitare qui un nome per dichiarare uno spazio dei nomi. @@ -1667,16 +1627,6 @@ Sub(<elencoParametri>) <istruzione> Digitare qui un nome per dichiarare una classe parziale. - - <class name> - <nome classe> - - - - <interface name> - <nome dell'interfaccia> - - <module name> <nome del modulo> diff --git a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.ja.xlf b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.ja.xlf index 9cbf48911c113..2f36b3492eeba 100644 --- a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.ja.xlf +++ b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.ja.xlf @@ -67,11 +67,6 @@ 不足している '{0}' を挿入します。 - - Conflict(s) detected. - 競合が検出されました。 - - Introduce 'Using' statement ’Using’ ステートメントの導入 @@ -222,31 +217,11 @@ 無効な関数の戻り値の型を修正する - - Simplify name '{0}' - 名前 '{0}' の単純化 - - - - Simplify member access '{0}' - メンバーのアクセス '{0}' を単純化します - - Remove 'Me' qualification 修飾子 'Me' を削除します {Locked="Me"} "Me" is a VB keyword and should not be localized. - - can't determine valid range of statements to extract out - 抽出するステートメントの有効な範囲を決定できません - - - - Not all code paths return - 返されないコード パスがあります - - contains invalid selection 無効な選択が含まれています @@ -302,11 +277,6 @@ 選択範囲に有効なノードが含まれていません - - no valid statement range to extract out - 抽出する有効なステートメントの範囲がありません - - Deprecated 非推奨 @@ -1647,16 +1617,6 @@ Sub(<parameterList>) <statement> 指定されたアセンブリとそのすべての依存関係へのメタデータ参照を追加します (例: #r "myLib.dll")。 - - Properties - プロパティ - - - - <namespace name> - <名前空間名> - - Type a name here to declare a namespace. 名前空間を宣言するには、ここに名前を入力してください。 @@ -1667,16 +1627,6 @@ Sub(<parameterList>) <statement> 部分クラスを宣言する名前をここに入力します。 - - <class name> - <クラス名> - - - - <interface name> - <インターフェイス名> - - <module name> <モジュール名> diff --git a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.ko.xlf b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.ko.xlf index b42832f0e0917..4356c4cefa873 100644 --- a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.ko.xlf +++ b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.ko.xlf @@ -67,11 +67,6 @@ 누락된 '{0}'을(를) 삽입합니다. - - Conflict(s) detected. - 충돌이 감지되었습니다. - - Introduce 'Using' statement 'Using' 문 지정 @@ -222,31 +217,11 @@ 잘못된 함수 반환 형식 수정 - - Simplify name '{0}' - '{0}' 이름 단순화 - - - - Simplify member access '{0}' - 멤버 액세스 '{0}' 단순화 - - Remove 'Me' qualification Me' 한정자 제거 {Locked="Me"} "Me" is a VB keyword and should not be localized. - - can't determine valid range of statements to extract out - 추출할 문에 유효한 범위를 결정할 수 없습니다. - - - - Not all code paths return - 일부 코드 경로가 반환됩니다. - - contains invalid selection 선택 영역이 잘못되었습니다. @@ -302,11 +277,6 @@ 선택 영역에 유효한 노드가 포함되어 있지 않습니다. - - no valid statement range to extract out - 추출하는 데 유효한 문 범위가 없습니다. - - Deprecated 사용되지 않음 @@ -1647,16 +1617,6 @@ Sub(<parameterList>) <statement> 지정한 어셈블리 및 모든 해당 종속성에 대한 메타데이터 참조를 추가합니다(예: #r "myLib.dll"). - - Properties - 속성 - - - - <namespace name> - <네임스페이스 이름> - - Type a name here to declare a namespace. 네임스페이스를 선언하려면 여기에 이름을 입력하세요. @@ -1667,16 +1627,6 @@ Sub(<parameterList>) <statement> Partial 클래스를 선언하려면 여기에 이름을 입력하세요. - - <class name> - <클래스 이름> - - - - <interface name> - <인터페이스 이름> - - <module name> <모듈 이름> diff --git a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.pl.xlf b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.pl.xlf index b81329c2ca0bd..adba0504e637f 100644 --- a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.pl.xlf +++ b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.pl.xlf @@ -67,11 +67,6 @@ Wstaw brakujący element „{0}”. - - Conflict(s) detected. - Wykryto konflikty. - - Introduce 'Using' statement Wprowadź instrukcję „Using” @@ -222,31 +217,11 @@ Napraw nieprawidłowy typ zwracany funkcji - - Simplify name '{0}' - Uprość nazwę „{0}” - - - - Simplify member access '{0}' - Uprość dostęp do składowej „{0}” - - Remove 'Me' qualification Usuń kwalifikację „Me” {Locked="Me"} "Me" is a VB keyword and should not be localized. - - can't determine valid range of statements to extract out - nie można określić prawidłowego zakresu instrukcji do wyodrębnienia - - - - Not all code paths return - Nie wszystkie ścieżki w kodzie zwracają wartość - - contains invalid selection zawiera nieprawidłowe zaznaczenie @@ -302,11 +277,6 @@ Zaznaczenie nie zawiera prawidłowych węzłów - - no valid statement range to extract out - brak prawidłowego zakresu instrukcji do wyodrębnienia - - Deprecated Przestarzały @@ -1647,16 +1617,6 @@ Sub(<listaParametrów>) <instrukcja> Dodaj odwołanie do metadanych do określonego zestawu i wszystkich jego zależności, np. #r "myLib.dll". - - Properties - Właściwości - - - - <namespace name> - <nazwa przestrzeni nazw> - - Type a name here to declare a namespace. Wpisz tutaj nazwę, aby utworzyć deklarację przestrzeni nazw. @@ -1667,16 +1627,6 @@ Sub(<listaParametrów>) <instrukcja> Wpisz tutaj nazwę, aby zadeklarować klasę częściową. - - <class name> - <nazwa klasy> - - - - <interface name> - <nazwa interfejsu> - - <module name> <nazwa modułu> diff --git a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.pt-BR.xlf b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.pt-BR.xlf index 69dd91cda7e14..3db1a8c844ace 100644 --- a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.pt-BR.xlf +++ b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.pt-BR.xlf @@ -67,11 +67,6 @@ Inserir '{0}' ausente. - - Conflict(s) detected. - Conflito(s) detectado(s). - - Introduce 'Using' statement Apresente a instrução 'Using' @@ -222,31 +217,11 @@ Corrigir Tipo de Retorno de Função Incorreta - - Simplify name '{0}' - Simplificar nome '{0}' - - - - Simplify member access '{0}' - Simplificar acesso do membro '{0}' - - Remove 'Me' qualification Remover qualificação 'Me' {Locked="Me"} "Me" is a VB keyword and should not be localized. - - can't determine valid range of statements to extract out - não pode determinar o intervalo válido de instruções para extrair - - - - Not all code paths return - Nem todos os caminhos de código são retornados - - contains invalid selection contém seleção inválida @@ -302,11 +277,6 @@ A seleção não contém qualquer nó válido - - no valid statement range to extract out - nenhum intervalo de instrução válido para extrair - - Deprecated Preterido @@ -1647,16 +1617,6 @@ Sub(<parameterList>) <statement> Adicione uma referência de metadados para o assembly especificado e a todas as suas dependências, por ex., #r "myLib.dll". - - Properties - Propriedades - - - - <namespace name> - <nome do namespace> - - Type a name here to declare a namespace. Digite um nome aqui para declarar um namespace. @@ -1667,16 +1627,6 @@ Sub(<parameterList>) <statement> Digite um nome aqui para declarar uma classe parcial. - - <class name> - <nome da classe> - - - - <interface name> - <nome da interface> - - <module name> <nome do módulo> diff --git a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.ru.xlf b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.ru.xlf index d1a1cd855b1f8..b49b20063f50b 100644 --- a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.ru.xlf +++ b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.ru.xlf @@ -67,11 +67,6 @@ Вставьте отсутствующий "{0}". - - Conflict(s) detected. - Обнаружены конфликты. - - Introduce 'Using' statement Ввести оператор "Using" @@ -222,31 +217,11 @@ Исправить неверный тип возвращения функции - - Simplify name '{0}' - Упрощение имени "{0}" - - - - Simplify member access '{0}' - Упрощение доступа для членов "{0}" - - Remove 'Me' qualification Удаление квалификации Me {Locked="Me"} "Me" is a VB keyword and should not be localized. - - can't determine valid range of statements to extract out - Невозможно определить допустимый диапазон операторов для извлечения. - - - - Not all code paths return - Не все пути к коду возвращают значения - - contains invalid selection содержит недопустимый выделенный фрагмент @@ -302,11 +277,6 @@ Выделенный фрагмент не содержит допустимый узел - - no valid statement range to extract out - Отсутствует допустимый диапазон оператора для извлечения. - - Deprecated Нерекомендуемый @@ -1647,16 +1617,6 @@ Sub(<parameterList>) <statement> Добавляет ссылку на метаданные в указанную сборку и все ее зависимости, например #r myLib.dll. - - Properties - Свойства - - - - <namespace name> - <имя пространства имен> - - Type a name here to declare a namespace. Введите имя для объявления пространства имен. @@ -1667,16 +1627,6 @@ Sub(<parameterList>) <statement> Введите имя для объявления частичного класса. - - <class name> - <имя класса> - - - - <interface name> - <имя интерфейса> - - <module name> <имя модуля> diff --git a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.tr.xlf b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.tr.xlf index 7e7a4e90fa42b..33125a1f21824 100644 --- a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.tr.xlf +++ b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.tr.xlf @@ -67,11 +67,6 @@ Eksik '{0}' öğesini ekleyin. - - Conflict(s) detected. - Çakışmalar algılandı. - - Introduce 'Using' statement 'Using' deyimi ekle @@ -222,31 +217,11 @@ Hatalı İşlev Dönüş Türünü Düzelt - - Simplify name '{0}' - '{0}' adını basitleştir - - - - Simplify member access '{0}' - '{0}' üye erişimini basitleştir - - Remove 'Me' qualification Me' nitelemesini kaldır {Locked="Me"} "Me" is a VB keyword and should not be localized. - - can't determine valid range of statements to extract out - Dışarıya ayıklanacak deyimlerin geçerli aralığı belirlenemiyor - - - - Not all code paths return - Kod yollarından bazıları dönmüyor - - contains invalid selection Geçersiz seçim içeriyor @@ -302,11 +277,6 @@ Seçim geçerli düğüm içermiyor - - no valid statement range to extract out - Dışarıya ayıklanacak geçerli deyim aralığı yok - - Deprecated Kullanım Dışı @@ -1647,16 +1617,6 @@ Sub(<parameterList>) <statement> Belirtilen bütünleştirilmiş koda ve tüm bağımlılıklarına bir meta veri başvurusu ekleyin örn. #r "myLib.dll". - - Properties - Özellikler - - - - <namespace name> - <ad alanı adı> - - Type a name here to declare a namespace. Bir ad alanı bildirmek için buraya bir ad girin. @@ -1667,16 +1627,6 @@ Sub(<parameterList>) <statement> Kısmi bir sınıf tanımlamak için buraya bir ad girin. - - <class name> - <sınıf adı> - - - - <interface name> - <arabirim adı> - - <module name> <modül adı> diff --git a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.zh-Hans.xlf b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.zh-Hans.xlf index 36c5c449da042..760776b6c6499 100644 --- a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.zh-Hans.xlf +++ b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.zh-Hans.xlf @@ -67,11 +67,6 @@ 插入缺少的“{0}”。 - - Conflict(s) detected. - 检测到冲突。 - - Introduce 'Using' statement 引入 “Using” 语句 @@ -222,31 +217,11 @@ 修复不正确的函数返回类型 - - Simplify name '{0}' - 简化名称“{0}” - - - - Simplify member access '{0}' - 简化成员访问“{0}” - - Remove 'Me' qualification 删除 "Me" 资格 {Locked="Me"} "Me" is a VB keyword and should not be localized. - - can't determine valid range of statements to extract out - 无法确定要提取的语句的有效范围 - - - - Not all code paths return - 未返回所有代码路径 - - contains invalid selection 包含无效的选择 @@ -302,11 +277,6 @@ 所选内容不包含任何有效的节点 - - no valid statement range to extract out - 没有可供提取的有效语句范围 - - Deprecated 已弃用 @@ -1647,16 +1617,6 @@ Sub(<parameterList>) <statement> 添加对指定程序集及其所有依赖项的元数据引用,例如 #r "myLib.dll"。 - - Properties - 属性 - - - - <namespace name> - <命名空间名称> - - Type a name here to declare a namespace. 在此处键入名称来声明命名空间。 @@ -1667,16 +1627,6 @@ Sub(<parameterList>) <statement> 在此处键入名称以声明分部类。 - - <class name> - <类名> - - - - <interface name> - <接口名称> - - <module name> <模块名> diff --git a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.zh-Hant.xlf b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.zh-Hant.xlf index e3089b0028533..3b9b0bdfbc8c4 100644 --- a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.zh-Hant.xlf +++ b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.zh-Hant.xlf @@ -67,11 +67,6 @@ 插入遺漏的 '{0}'。 - - Conflict(s) detected. - 偵測到衝突。 - - Introduce 'Using' statement 引入 'Using' 陳述式 @@ -222,31 +217,11 @@ 修正不正確的函式傳回類型 - - Simplify name '{0}' - 簡化名稱 '{0}' - - - - Simplify member access '{0}' - 簡化成員存取 '{0}' - - Remove 'Me' qualification 移除 'Me' 限定性條件 {Locked="Me"} "Me" is a VB keyword and should not be localized. - - can't determine valid range of statements to extract out - 無法決定要擷取的有效陳述式範圍 - - - - Not all code paths return - 未傳回所有程式碼路徑 - - contains invalid selection 包含無效的選取範圍 @@ -302,11 +277,6 @@ 選取範圍不包含任何有效的節點 - - no valid statement range to extract out - 沒有可擷取內容的有效陳述式範圍 - - Deprecated 取代 @@ -1647,16 +1617,6 @@ Sub(<parameterList>) <statement> 將中繼資料參考加入指定的組件及其所有相依性中,例如 #r "myLib.dll"。 - - Properties - 屬性 - - - - <namespace name> - <命名空間名稱> - - Type a name here to declare a namespace. 在此輸入名稱以宣告命名空間。 @@ -1667,16 +1627,6 @@ Sub(<parameterList>) <statement> 在這裡鍵入名稱以宣告部分類別。 - - <class name> - <類別名稱> - - - - <interface name> - <interface name> - - <module name> <模組名稱> diff --git a/src/Features/VisualBasicTest/Diagnostics/Suppression/SuppressionAllCodeTests.vb b/src/Features/VisualBasicTest/Diagnostics/Suppression/SuppressionAllCodeTests.vb index 3d5e494cae508..56ec53542f7ee 100644 --- a/src/Features/VisualBasicTest/Diagnostics/Suppression/SuppressionAllCodeTests.vb +++ b/src/Features/VisualBasicTest/Diagnostics/Suppression/SuppressionAllCodeTests.vb @@ -43,7 +43,7 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.Diagnostics.Suppre Return True End If - Return Not TypeOf n Is StatementSyntax + Return TypeOf n IsNot StatementSyntax End Function, verifier:=Function(t) t.IndexOf("SuppressMessage", StringComparison.Ordinal) >= 0) End Function diff --git a/src/Features/VisualBasicTest/ExtractMethod/ExtractMethodTests.vb b/src/Features/VisualBasicTest/ExtractMethod/ExtractMethodTests.vb index cac7c90038dff..934393d336dd0 100644 --- a/src/Features/VisualBasicTest/ExtractMethod/ExtractMethodTests.vb +++ b/src/Features/VisualBasicTest/ExtractMethod/ExtractMethodTests.vb @@ -4,7 +4,8 @@ Imports Microsoft.CodeAnalysis.CodeRefactorings Imports Microsoft.CodeAnalysis.CodeRefactorings.ExtractMethod -Imports Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces +Imports Microsoft.CodeAnalysis.CodeStyle +Imports Microsoft.CodeAnalysis.Editor.UnitTests.CodeActions Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.CodeRefactorings.ExtractMethod @@ -1078,5 +1079,107 @@ class C End Function end class") End Function + + + Public Function TestPreferMePreference_NotForInstanceMethodWhenOff() As Task + Return TestInRegularAndScriptAsync( +" +Imports System + +class Program + dim i as integer + + public sub M() + [|Console.WriteLine(i)|] + end sub +end class +", + " +Imports System + +class Program + dim i as integer + + public sub M() + {|Rename:NewMethod|}() + end sub + + Private Sub NewMethod() + Console.WriteLine(i) + End Sub +end class +", + options:=New OptionsCollection(LanguageNames.VisualBasic) From { + {CodeStyleOptions2.QualifyMethodAccess, CodeStyleOption2.FalseWithSilentEnforcement} + }) + End Function + + + Public Async Function TestPreferThisPreference_ForInstanceMethodWhenOn(diagnostic As ReportDiagnostic) As Task + If diagnostic = ReportDiagnostic.Default Then + Return + End If + + Await TestInRegularAndScriptAsync( +" +Imports System + +class Program + dim i as integer + + public sub M() + [|Console.WriteLine(i)|] + end sub +end class +", +" +Imports System + +class Program + dim i as integer + + public sub M() + Me.{|Rename:NewMethod|}() + end sub + + Private Sub NewMethod() + Console.WriteLine(i) + End Sub +end class +", + options:=New OptionsCollection(LanguageNames.VisualBasic) From { + {CodeStyleOptions2.QualifyMethodAccess, New CodeStyleOption2(Of Boolean)(True, New NotificationOption2(diagnostic, True))} + }) + End Function + + + Public Function TestPreferThisPreference_NotForStaticMethodWhenOn() As Task + Return TestInRegularAndScriptAsync( +" +Imports System + +class Program + public sub M() + [|Console.WriteLine()|] + end sub +end class +", +" +Imports System + +class Program + public sub M() + {|Rename:NewMethod|}() + end sub + + Private Shared Sub NewMethod() + Console.WriteLine() + End Sub +end class +", + options:=New OptionsCollection(LanguageNames.VisualBasic) From { + {CodeStyleOptions2.QualifyMethodAccess, CodeStyleOption2.FalseWithSilentEnforcement} + }) + End Function End Class End Namespace diff --git a/src/Features/VisualBasicTest/IntroduceUsingStatement/IntroduceUsingStatementTests.vb b/src/Features/VisualBasicTest/IntroduceUsingStatement/IntroduceUsingStatementTests.vb index 2e823c8565881..b4311ec7cdea1 100644 --- a/src/Features/VisualBasicTest/IntroduceUsingStatement/IntroduceUsingStatementTests.vb +++ b/src/Features/VisualBasicTest/IntroduceUsingStatement/IntroduceUsingStatementTests.vb @@ -3,9 +3,8 @@ ' See the LICENSE file in the project root for more information. Imports Microsoft.CodeAnalysis.CodeRefactorings -Imports Microsoft.CodeAnalysis.VisualBasic.IntroduceUsingStatement Imports Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.CodeRefactorings -Imports Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces +Imports Microsoft.CodeAnalysis.VisualBasic.IntroduceUsingStatement Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.IntroduceUsingStatement @@ -746,6 +745,34 @@ Class C End Try End Using End Sub +End Class") + End Function + + + Public Async Function TestExpressionStatement() As Task + Await TestInRegularAndScriptAsync( +"Imports System + +Class C + Sub M() + [||]MethodThatReturnsDisposable() + Console.WriteLine() + End Sub + + Function MethodThatReturnsDisposable() as IDisposable + End Function +End Class", +"Imports System + +Class C + Sub M() + Using MethodThatReturnsDisposable() + Console.WriteLine() + End Using + End Sub + + Function MethodThatReturnsDisposable() as IDisposable + End Function End Class") End Function End Class diff --git a/src/Features/VisualBasicTest/IntroduceVariable/IntroduceVariableTests.vb b/src/Features/VisualBasicTest/IntroduceVariable/IntroduceVariableTests.vb index 702cc04e82f5c..36a3b3f1c196a 100644 --- a/src/Features/VisualBasicTest/IntroduceVariable/IntroduceVariableTests.vb +++ b/src/Features/VisualBasicTest/IntroduceVariable/IntroduceVariableTests.vb @@ -293,7 +293,7 @@ End Class" Class C Sub M() Dim {|Rename:tickCount|} As Integer = Environment.TickCount - Dim a As New With {tickCount} + Dim a As New With {.TickCount = tickCount} End Sub End Class" Await TestInRegularAndScriptAsync(source, expected, index:=1) @@ -1248,8 +1248,8 @@ End Module", Module Program Sub Main Dim a = Sub(x As Integer) Dim {|Rename:value|} As Integer = x + 1 - Console.WriteLine(value) - End Sub ' Introduce local + Console.WriteLine(value) ' Introduce local + End Sub End Sub End Module") End Function @@ -2151,8 +2151,8 @@ Imports System.Collections.Generic Imports System.Linq Module Program Sub Main() - Dim {|Rename:x1|} As IEnumerable(Of Char) = From x In """" - [Take](x1) + Dim {|Rename:x1|} As IEnumerable(Of Char) = (From x In """") + Take(x1) End Sub Sub Take(x) End Sub @@ -2792,7 +2792,7 @@ Class C Shared Dim y As Integer = 2 Sub M() Dim {|Rename:y1|} As Integer = C.y - Dim t = (y1, y1) + Dim t = (y:=y1, y:=y1) End Sub End Class " @@ -2816,7 +2816,7 @@ Class C Sub M() Dim a As Integer = 1 Dim {|Rename:rest1|} As Integer = C.rest - Dim t = (a, rest1) + Dim t = (a, rest:=rest1) End Sub End Class " diff --git a/src/Interactive/Host/Interactive/Core/InteractiveHost.LazyRemoteService.cs b/src/Interactive/Host/Interactive/Core/InteractiveHost.LazyRemoteService.cs index 24e2a62a3da25..459fee6a16281 100644 --- a/src/Interactive/Host/Interactive/Core/InteractiveHost.LazyRemoteService.cs +++ b/src/Interactive/Host/Interactive/Core/InteractiveHost.LazyRemoteService.cs @@ -75,13 +75,13 @@ private async Task TryStartAndInitializeProcessAsync(C { result = new RemoteExecutionResult( success: true, - sourcePaths: ImmutableArray.Empty, - referencePaths: ImmutableArray.Empty, + sourcePaths: [], + referencePaths: [], workingDirectory: Host._initialWorkingDirectory, initializationResult: new RemoteInitializationResult( initializationScript: null, - metadataReferencePaths: ImmutableArray.Create(typeof(object).Assembly.Location, typeof(InteractiveScriptGlobals).Assembly.Location), - imports: ImmutableArray.Empty)); + metadataReferencePaths: [typeof(object).Assembly.Location, typeof(InteractiveScriptGlobals).Assembly.Location], + imports: [])); Host.ProcessInitialized?.Invoke(remoteService.PlatformInfo, Options, result); return new InitializedRemoteService(remoteService, result); diff --git a/src/Interactive/Host/Interactive/Core/InteractiveHost.Service.cs b/src/Interactive/Host/Interactive/Core/InteractiveHost.Service.cs index 25bd5eb681232..1d852e5ec7386 100644 --- a/src/Interactive/Host/Interactive/Core/InteractiveHost.Service.cs +++ b/src/Interactive/Host/Interactive/Core/InteractiveHost.Service.cs @@ -106,11 +106,13 @@ internal EvaluationState WithOptions(ScriptOptions options) } } - private static readonly ImmutableArray s_systemNoShadowCopyDirectories = ImmutableArray.Create( + private static readonly ImmutableArray s_systemNoShadowCopyDirectories = + [ FileUtilities.NormalizeDirectoryPath(Environment.GetFolderPath(Environment.SpecialFolder.Windows)), FileUtilities.NormalizeDirectoryPath(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles)), FileUtilities.NormalizeDirectoryPath(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86)), - FileUtilities.NormalizeDirectoryPath(RuntimeEnvironment.GetRuntimeDirectory())); + FileUtilities.NormalizeDirectoryPath(RuntimeEnvironment.GetRuntimeDirectory()), + ]; #region Setup @@ -122,7 +124,7 @@ private Service(Func, object> invokeOnMainThread) var workingDirectory = Directory.GetCurrentDirectory(); var referenceResolver = new RuntimeMetadataReferenceResolver( - searchPaths: ImmutableArray.Empty, + searchPaths: [], baseDirectory: workingDirectory, packageResolver: null, gacFileResolver: s_currentPlatformInfo.HasGlobalAssemblyCache ? new GacFileResolver(preferredCulture: CultureInfo.CurrentCulture) : null, @@ -132,7 +134,7 @@ private Service(Func, object> invokeOnMainThread) var initialState = new EvaluationState( scriptState: null, scriptOptions: ScriptOptions.Default.WithMetadataResolver(new ScriptMetadataResolver(referenceResolver)), - ImmutableArray.Empty, + [], workingDirectory); _lastTask = Task.FromResult(initialState); diff --git a/src/Interactive/Host/Interactive/Core/InteractiveHostPlatformInfo.cs b/src/Interactive/Host/Interactive/Core/InteractiveHostPlatformInfo.cs index 6b74a78f68399..5a593b58f19e8 100644 --- a/src/Interactive/Host/Interactive/Core/InteractiveHostPlatformInfo.cs +++ b/src/Interactive/Host/Interactive/Core/InteractiveHostPlatformInfo.cs @@ -22,7 +22,7 @@ internal sealed class Data public InteractiveHostPlatformInfo Deserialize() => new InteractiveHostPlatformInfo( - PlatformAssemblyPaths.ToImmutableArray(), + [.. PlatformAssemblyPaths], HasGlobalAssemblyCache); } @@ -43,12 +43,12 @@ public Data Serialize() => new Data() { HasGlobalAssemblyCache = HasGlobalAssemblyCache, - PlatformAssemblyPaths = PlatformAssemblyPaths.ToArray(), + PlatformAssemblyPaths = [.. PlatformAssemblyPaths], }; public static InteractiveHostPlatformInfo GetCurrentPlatformInfo() => new InteractiveHostPlatformInfo( - RuntimeMetadataReferenceResolver.GetTrustedPlatformAssemblyPaths().Where(IsNotHostAssembly).ToImmutableArray(), + [.. RuntimeMetadataReferenceResolver.GetTrustedPlatformAssemblyPaths().Where(IsNotHostAssembly)], GacFileResolver.IsAvailable); private static bool IsNotHostAssembly(string path) diff --git a/src/Interactive/Host/Interactive/Core/RemoteExecutionResult.cs b/src/Interactive/Host/Interactive/Core/RemoteExecutionResult.cs index a0de02da7a666..095c037b07198 100644 --- a/src/Interactive/Host/Interactive/Core/RemoteExecutionResult.cs +++ b/src/Interactive/Host/Interactive/Core/RemoteExecutionResult.cs @@ -20,8 +20,8 @@ internal sealed class Data public RemoteExecutionResult Deserialize() => new RemoteExecutionResult( Success, - SourcePaths.ToImmutableArray(), - ReferencePaths.ToImmutableArray(), + [.. SourcePaths], + [.. ReferencePaths], WorkingDirectory, InitializationResult?.Deserialize()); } @@ -63,8 +63,8 @@ public Data Serialize() => new Data() { Success = Success, - SourcePaths = SourcePaths.ToArray(), - ReferencePaths = ReferencePaths.ToArray(), + SourcePaths = [.. SourcePaths], + ReferencePaths = [.. ReferencePaths], WorkingDirectory = WorkingDirectory, InitializationResult = InitializationResult?.Serialize(), }; diff --git a/src/Interactive/Host/Interactive/Core/RemoteInitializationResult.cs b/src/Interactive/Host/Interactive/Core/RemoteInitializationResult.cs index cd07c514f00e6..f08abbf15a830 100644 --- a/src/Interactive/Host/Interactive/Core/RemoteInitializationResult.cs +++ b/src/Interactive/Host/Interactive/Core/RemoteInitializationResult.cs @@ -42,8 +42,8 @@ public Data Serialize() => new Data() { ScriptPath = ScriptPath, - MetadataReferencePaths = MetadataReferencePaths.ToArray(), - Imports = Imports.ToArray(), + MetadataReferencePaths = [.. MetadataReferencePaths], + Imports = [.. Imports], }; } } diff --git a/src/Interactive/HostTest/AbstractInteractiveHostTests.cs b/src/Interactive/HostTest/AbstractInteractiveHostTests.cs index b42f23985f7a6..a733de3dad070 100644 --- a/src/Interactive/HostTest/AbstractInteractiveHostTests.cs +++ b/src/Interactive/HostTest/AbstractInteractiveHostTests.cs @@ -126,7 +126,7 @@ public void RedirectOutput() public static ImmutableArray SplitLines(string text) { - return ImmutableArray.Create(text.Split(new[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries)); + return ImmutableArray.Create(text.Split(["\r\n"], StringSplitOptions.RemoveEmptyEntries)); } public async Task LoadReference(string reference) diff --git a/src/LanguageServer/ExternalAccess/VisualDiagnostics/Internal/HotReloadDiagnosticSourceProvider.cs b/src/LanguageServer/ExternalAccess/VisualDiagnostics/Internal/HotReloadDiagnosticSourceProvider.cs index bdf530f4a9732..3a23f07fedc99 100644 --- a/src/LanguageServer/ExternalAccess/VisualDiagnostics/Internal/HotReloadDiagnosticSourceProvider.cs +++ b/src/LanguageServer/ExternalAccess/VisualDiagnostics/Internal/HotReloadDiagnosticSourceProvider.cs @@ -27,7 +27,7 @@ public async ValueTask> CreateDiagnosticSource { if (context.Solution is not Solution solution) { - return ImmutableArray.Empty; + return []; } var hotReloadContext = new HotReloadRequestContext(context); diff --git a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer.UnitTests/ExportProviderBuilderTests.cs b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer.UnitTests/ExportProviderBuilderTests.cs new file mode 100644 index 0000000000000..1cc57db6f508f --- /dev/null +++ b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer.UnitTests/ExportProviderBuilderTests.cs @@ -0,0 +1,170 @@ +// 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 Basic.Reference.Assemblies; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.Test.Utilities; +using Microsoft.CodeAnalysis.Text; +using Roslyn.Test.Utilities; +using Xunit.Abstractions; + +namespace Microsoft.CodeAnalysis.LanguageServer.UnitTests +{ + public sealed class ExportProviderBuilderTests(ITestOutputHelper testOutputHelper) + : AbstractLanguageServerHostTests(testOutputHelper) + { + [Fact] + public async Task MefCompositionIsCached() + { + await using var testServer = await CreateLanguageServerAsync(includeDevKitComponents: false); + + await AssertCacheWriteWasAttemptedAsync(); + + AssertCachedCompositionCountEquals(expectedCount: 1); + } + + [Fact] + public async Task MefCompositionIsReused() + { + await using var testServer = await CreateLanguageServerAsync(includeDevKitComponents: false); + + await AssertCacheWriteWasAttemptedAsync(); + + // Second test server with the same set of assemblies. + await using var testServer2 = await CreateLanguageServerAsync(includeDevKitComponents: false); + + AssertNoCacheWriteWasAttempted(); + + AssertCachedCompositionCountEquals(expectedCount: 1); + } + + [Fact] + public async Task MultipleMefCompositionsAreCached() + { + await using var testServer = await CreateLanguageServerAsync(includeDevKitComponents: false); + + await AssertCacheWriteWasAttemptedAsync(); + + // Second test server with a different set of assemblies. + await using var testServer2 = await CreateLanguageServerAsync(includeDevKitComponents: true); + + await AssertCacheWriteWasAttemptedAsync(); + + AssertCachedCompositionCountEquals(expectedCount: 2); + } + + [Theory, WorkItem("https://github.com/microsoft/vscode-dotnettools/issues/1686")] + // gen-delims + [InlineData("#"), + InlineData(":"), + InlineData("?"), + InlineData("["), + InlineData("]"), + InlineData("@"), + // sub-delims + InlineData("!"), + InlineData("$"), + InlineData("&"), + InlineData("'"), + InlineData("("), + InlineData(")"), + InlineData("*"), + InlineData("+"), + InlineData(","), + InlineData(";"), + InlineData("=")] + public async Task CanFindCodeBaseWhenReservedCharactersInPath(string reservedCharacter) + { + // Test that given an unescaped code base URI (as vs-mef gives us), we can resolve the file path even if it contains reserved characters. + + // Certain characters aren't valid file paths on different file systems and so can't be in the path. + if (ExecutionConditionUtil.IsWindows && reservedCharacter is "*" or ":" or "?") + { + return; + } + + var dllPath = GenerateDll(reservedCharacter, out var assemblyName); + + await using var testServer = await TestLspServer.CreateAsync(new Roslyn.LanguageServer.Protocol.ClientCapabilities(), TestOutputLogger, MefCacheDirectory.Path, includeDevKitComponents: true, [dllPath]); + + var assemblies = AppDomain.CurrentDomain.GetAssemblies(); + var assembly = Assert.Single(assemblies, a => a.GetName().Name == assemblyName); + var type = Assert.Single(assembly.GetTypes(), t => t.FullName?.Contains("ExportedType") == true); + var values = testServer.ExportProvider.GetExportedValues(type, contractName: null); + Assert.Single(values); + } + + private string GenerateDll(string reservedCharacter, out string assemblyName) + { + var directory = TempRoot.CreateDirectory(); + CSharpCompilationOptions options = new(OutputKind.DynamicallyLinkedLibrary); + + // Create a dll that exports and imports a mef type to ensure that MEF attempts to load and create a MEF graph + // using this assembly. + var source = """ + namespace MyTestExportNamespace + { + [System.ComponentModel.Composition.Export(typeof(ExportedType))] + public class ExportedType { } + + public class ImportType + { + [System.ComponentModel.Composition.ImportingConstructorAttribute] + public ImportType(ExportedType t) { } + } + } + """; + + // Generate an assembly name associated with the character we're testing - this ensures + // that if multiple of these tests run in the same process we're making sure that the correct expected assembly is loaded. + assemblyName = "MyAssembly" + reservedCharacter.GetHashCode(); +#pragma warning disable RS0030 // Do not use banned APIs - intentionally using System.ComponentModel.Composition to verify mef construction. + var compilation = CSharpCompilation.Create( + assemblyName, + syntaxTrees: [SyntaxFactory.ParseSyntaxTree(SourceText.From(source, encoding: null, SourceHashAlgorithms.Default))], + references: + [ + NetStandard20.References.mscorlib, + NetStandard20.References.netstandard, + NetStandard20.References.SystemRuntime, + MetadataReference.CreateFromFile(typeof(System.ComponentModel.Composition.ExportAttribute).Assembly.Location) + ], + options: options); +#pragma warning restore RS0030 // Do not use banned APIs + + // Write a dll to a subdir with a reserved character in the name. + var tempSubDir = directory.CreateDirectory(reservedCharacter); + var tempFile = tempSubDir.CreateFile($"{assemblyName}.dll"); + var dllData = compilation.EmitToStream(); + tempFile.WriteAllBytes(dllData.ToArray()); + + // Mark the file as read only to prevent mutations. + var fileInfo = new FileInfo(tempFile.Path); + fileInfo.IsReadOnly = true; + + return tempFile.Path; + } + + private async Task AssertCacheWriteWasAttemptedAsync() + { + var cacheWriteTask = ExportProviderBuilder.TestAccessor.GetCacheWriteTask(); + Assert.NotNull(cacheWriteTask); + + await cacheWriteTask; + } + + private void AssertNoCacheWriteWasAttempted() + { + var cacheWriteTask2 = ExportProviderBuilder.TestAccessor.GetCacheWriteTask(); + Assert.Null(cacheWriteTask2); + } + + private void AssertCachedCompositionCountEquals(int expectedCount) + { + var mefCompositions = Directory.EnumerateFiles(MefCacheDirectory.Path, "*.mef-composition", SearchOption.AllDirectories); + + Assert.Equal(expectedCount, mefCompositions.Count()); + } + } +} diff --git a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer.UnitTests/LspFileChangeWatcherTests.cs b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer.UnitTests/LspFileChangeWatcherTests.cs index 9e3a07e88d383..900cf1a438c89 100644 --- a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer.UnitTests/LspFileChangeWatcherTests.cs +++ b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer.UnitTests/LspFileChangeWatcherTests.cs @@ -14,7 +14,8 @@ namespace Microsoft.CodeAnalysis.LanguageServer.UnitTests; -public class LspFileChangeWatcherTests : AbstractLanguageServerHostTests +public class LspFileChangeWatcherTests(ITestOutputHelper testOutputHelper) + : AbstractLanguageServerHostTests(testOutputHelper) { private readonly ClientCapabilities _clientCapabilitiesWithFileWatcherSupport = new ClientCapabilities { @@ -24,14 +25,10 @@ public class LspFileChangeWatcherTests : AbstractLanguageServerHostTests } }; - public LspFileChangeWatcherTests(ITestOutputHelper testOutputHelper) : base(testOutputHelper) - { - } - [Fact] public async Task LspFileWatcherNotSupportedWithoutClientSupport() { - await using var testLspServer = await TestLspServer.CreateAsync(new ClientCapabilities(), TestOutputLogger); + await using var testLspServer = await TestLspServer.CreateAsync(new ClientCapabilities(), TestOutputLogger, MefCacheDirectory.Path); Assert.False(LspFileChangeWatcher.SupportsLanguageServerHost(testLspServer.LanguageServerHost)); } @@ -39,7 +36,7 @@ public async Task LspFileWatcherNotSupportedWithoutClientSupport() [Fact] public async Task LspFileWatcherSupportedWithClientSupport() { - await using var testLspServer = await TestLspServer.CreateAsync(_clientCapabilitiesWithFileWatcherSupport, TestOutputLogger); + await using var testLspServer = await TestLspServer.CreateAsync(_clientCapabilitiesWithFileWatcherSupport, TestOutputLogger, MefCacheDirectory.Path); Assert.True(LspFileChangeWatcher.SupportsLanguageServerHost(testLspServer.LanguageServerHost)); } @@ -49,7 +46,7 @@ public async Task CreatingDirectoryWatchRequestsDirectoryWatch() { AsynchronousOperationListenerProvider.Enable(enable: true); - await using var testLspServer = await TestLspServer.CreateAsync(_clientCapabilitiesWithFileWatcherSupport, TestOutputLogger); + await using var testLspServer = await TestLspServer.CreateAsync(_clientCapabilitiesWithFileWatcherSupport, TestOutputLogger, MefCacheDirectory.Path); var lspFileChangeWatcher = new LspFileChangeWatcher( testLspServer.LanguageServerHost, testLspServer.ExportProvider.GetExportedValue()); @@ -57,8 +54,7 @@ public async Task CreatingDirectoryWatchRequestsDirectoryWatch() var dynamicCapabilitiesRpcTarget = new DynamicCapabilitiesRpcTarget(); testLspServer.AddClientLocalRpcTarget(dynamicCapabilitiesRpcTarget); - using var tempRoot = new TempRoot(); - var tempDirectory = tempRoot.CreateDirectory(); + var tempDirectory = TempRoot.CreateDirectory(); // Try creating a context and ensure we created the registration var context = lspFileChangeWatcher.CreateContext([new ProjectSystem.WatchedDirectory(tempDirectory.Path, extensionFilters: [])]); @@ -80,7 +76,7 @@ public async Task CreatingFileWatchRequestsFileWatch() { AsynchronousOperationListenerProvider.Enable(enable: true); - await using var testLspServer = await TestLspServer.CreateAsync(_clientCapabilitiesWithFileWatcherSupport, TestOutputLogger); + await using var testLspServer = await TestLspServer.CreateAsync(_clientCapabilitiesWithFileWatcherSupport, TestOutputLogger, MefCacheDirectory.Path); var lspFileChangeWatcher = new LspFileChangeWatcher( testLspServer.LanguageServerHost, testLspServer.ExportProvider.GetExportedValue()); @@ -88,8 +84,7 @@ public async Task CreatingFileWatchRequestsFileWatch() var dynamicCapabilitiesRpcTarget = new DynamicCapabilitiesRpcTarget(); testLspServer.AddClientLocalRpcTarget(dynamicCapabilitiesRpcTarget); - using var tempRoot = new TempRoot(); - var tempDirectory = tempRoot.CreateDirectory(); + var tempDirectory = TempRoot.CreateDirectory(); // Try creating a single file watch and ensure we created the registration var context = lspFileChangeWatcher.CreateContext([]); diff --git a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer.UnitTests/TelemetryReporterTests.cs b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer.UnitTests/TelemetryReporterTests.cs index d17821d269de5..641514d4eff5d 100644 --- a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer.UnitTests/TelemetryReporterTests.cs +++ b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer.UnitTests/TelemetryReporterTests.cs @@ -9,16 +9,18 @@ namespace Microsoft.CodeAnalysis.LanguageServer.UnitTests; -public sealed class TelemetryReporterTests : AbstractLanguageServerHostTests +public sealed class TelemetryReporterTests(ITestOutputHelper testOutputHelper) + : AbstractLanguageServerHostTests(testOutputHelper) { - public TelemetryReporterTests(ITestOutputHelper testOutputHelper) - : base(testOutputHelper) - { - } - private async Task CreateReporterAsync() { - var exportProvider = await LanguageServerTestComposition.CreateExportProviderAsync(TestOutputLogger.Factory, includeDevKitComponents: true, out var _, out var _); + var exportProvider = await LanguageServerTestComposition.CreateExportProviderAsync( + TestOutputLogger.Factory, + includeDevKitComponents: true, + MefCacheDirectory.Path, + [], + out var _, + out var _); // VS Telemetry requires this environment variable to be set. Environment.SetEnvironmentVariable("CommonPropertyBagPath", Path.GetTempFileName()); diff --git a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer.UnitTests/Utilities/AbstractLanguageServerHostTests.cs b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer.UnitTests/Utilities/AbstractLanguageServerHostTests.cs index 5b286f9873c04..209704c7f0593 100644 --- a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer.UnitTests/Utilities/AbstractLanguageServerHostTests.cs +++ b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer.UnitTests/Utilities/AbstractLanguageServerHostTests.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using Microsoft.CodeAnalysis.LanguageServer.LanguageServer; +using Microsoft.CodeAnalysis.Test.Utilities; using Microsoft.VisualStudio.Composition; using Nerdbank.Streams; using Roslyn.LanguageServer.Protocol; @@ -11,18 +12,27 @@ namespace Microsoft.CodeAnalysis.LanguageServer.UnitTests; -public abstract class AbstractLanguageServerHostTests +public abstract class AbstractLanguageServerHostTests : IDisposable { protected TestOutputLogger TestOutputLogger { get; } + protected TempRoot TempRoot { get; } + protected TempDirectory MefCacheDirectory { get; } protected AbstractLanguageServerHostTests(ITestOutputHelper testOutputHelper) { TestOutputLogger = new TestOutputLogger(testOutputHelper); + TempRoot = new(); + MefCacheDirectory = TempRoot.CreateDirectory(); } protected Task CreateLanguageServerAsync(bool includeDevKitComponents = true) { - return TestLspServer.CreateAsync(new ClientCapabilities(), TestOutputLogger, includeDevKitComponents); + return TestLspServer.CreateAsync(new ClientCapabilities(), TestOutputLogger, MefCacheDirectory.Path, includeDevKitComponents); + } + + public void Dispose() + { + TempRoot.Dispose(); } protected sealed class TestLspServer : IAsyncDisposable @@ -32,10 +42,10 @@ protected sealed class TestLspServer : IAsyncDisposable private ServerCapabilities? _serverCapabilities; - internal static async Task CreateAsync(ClientCapabilities clientCapabilities, TestOutputLogger logger, bool includeDevKitComponents = true) + internal static async Task CreateAsync(ClientCapabilities clientCapabilities, TestOutputLogger logger, string cacheDirectory, bool includeDevKitComponents = true, string[]? extensionPaths = null) { var exportProvider = await LanguageServerTestComposition.CreateExportProviderAsync( - logger.Factory, includeDevKitComponents, out var _, out var assemblyLoader); + logger.Factory, includeDevKitComponents, cacheDirectory, extensionPaths, out var _, out var assemblyLoader); var testLspServer = new TestLspServer(exportProvider, logger, assemblyLoader); var initializeResponse = await testLspServer.ExecuteRequestAsync(Methods.InitializeName, new InitializeParams { Capabilities = clientCapabilities }, CancellationToken.None); Assert.NotNull(initializeResponse?.Capabilities); diff --git a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer.UnitTests/Utilities/LanguageServerTestComposition.cs b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer.UnitTests/Utilities/LanguageServerTestComposition.cs index b0406766a5b72..7072b452461ee 100644 --- a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer.UnitTests/Utilities/LanguageServerTestComposition.cs +++ b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer.UnitTests/Utilities/LanguageServerTestComposition.cs @@ -23,6 +23,8 @@ private static string GetDevKitExtensionPath() public static Task CreateExportProviderAsync( ILoggerFactory loggerFactory, bool includeDevKitComponents, + string cacheDirectory, + string[]? extensionPaths, out ServerConfiguration serverConfiguration, out IAssemblyLoader assemblyLoader) { @@ -32,13 +34,14 @@ public static Task CreateExportProviderAsync( StarredCompletionsPath: null, TelemetryLevel: null, SessionId: null, - ExtensionAssemblyPaths: [], + ExtensionAssemblyPaths: extensionPaths ?? [], DevKitDependencyPath: devKitDependencyPath, RazorSourceGenerator: null, RazorDesignTimePath: null, - ExtensionLogDirectory: string.Empty); + ExtensionLogDirectory: string.Empty, + ServerPipeName: null); var extensionManager = ExtensionAssemblyManager.Create(serverConfiguration, loggerFactory); assemblyLoader = new CustomExportAssemblyLoader(extensionManager, loggerFactory); - return ExportProviderBuilder.CreateExportProviderAsync(extensionManager, assemblyLoader, devKitDependencyPath, loggerFactory); + return ExportProviderBuilder.CreateExportProviderAsync(extensionManager, assemblyLoader, devKitDependencyPath, cacheDirectory, loggerFactory); } } diff --git a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer.UnitTests/WorkspaceProjectFactoryServiceTests.cs b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer.UnitTests/WorkspaceProjectFactoryServiceTests.cs index d8e07cd2cbd82..2e8a168a93c96 100644 --- a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer.UnitTests/WorkspaceProjectFactoryServiceTests.cs +++ b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer.UnitTests/WorkspaceProjectFactoryServiceTests.cs @@ -7,17 +7,19 @@ using Microsoft.CodeAnalysis.Remote.ProjectSystem; using Microsoft.Extensions.Logging; using Microsoft.VisualStudio.Shell.ServiceBroker; +using Xunit.Abstractions; namespace Microsoft.CodeAnalysis.LanguageServer.UnitTests; -public class WorkspaceProjectFactoryServiceTests +public class WorkspaceProjectFactoryServiceTests(ITestOutputHelper testOutputHelper) + : AbstractLanguageServerHostTests(testOutputHelper) { [Fact] public async Task CreateProjectAndBatch() { var loggerFactory = new LoggerFactory(); using var exportProvider = await LanguageServerTestComposition.CreateExportProviderAsync( - loggerFactory, includeDevKitComponents: false, out var serverConfiguration, out var _); + loggerFactory, includeDevKitComponents: false, MefCacheDirectory.Path, [], out var serverConfiguration, out var _); exportProvider.GetExportedValue() .InitializeConfiguration(serverConfiguration); diff --git a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/BrokeredServices/BrokeredServiceBridgeProvider.cs b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/BrokeredServices/BrokeredServiceBridgeProvider.cs index eb420c2bc0f9a..b0c88de11a7fd 100644 --- a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/BrokeredServices/BrokeredServiceBridgeProvider.cs +++ b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/BrokeredServices/BrokeredServiceBridgeProvider.cs @@ -69,7 +69,7 @@ async Task ConsumeServicesFromRemoteAsync() .WithTraceSource(_brokeredServiceTraceSource) .ConstructRpc(consumingServiceBrokerChannel); - using (container.ProfferRemoteBroker(remoteClient, bridgeMxStream, ServiceSource.OtherProcessOnSameMachine, Descriptors.RemoteServicesToRegister.Keys.ToImmutableHashSet())) + using (container.ProfferRemoteBroker(remoteClient, bridgeMxStream, ServiceSource.OtherProcessOnSameMachine, [.. Descriptors.RemoteServicesToRegister.Keys])) { await consumingServiceBrokerChannel.Completion; } diff --git a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/BrokeredServices/ServiceBrokerFactory.cs b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/BrokeredServices/ServiceBrokerFactory.cs index 30de915c94972..4f8294626029f 100644 --- a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/BrokeredServices/ServiceBrokerFactory.cs +++ b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/BrokeredServices/ServiceBrokerFactory.cs @@ -43,7 +43,7 @@ public ServiceBrokerFactory([ImportMany] IEnumerable public ValueTask> GetAvailableServicesAsync(CancellationToken cancellationToken) { - var services = (IReadOnlyCollection)_serviceBrokerFactory.GetRequiredServiceBrokerContainer().GetRegisteredServices() + var services = (IReadOnlyCollection)[.. _serviceBrokerFactory.GetRequiredServiceBrokerContainer().GetRegisteredServices() .Select(s => s.Key) .Where(s => s.Name.StartsWith("Microsoft.CodeAnalysis.LanguageServer.", StringComparison.Ordinal) || s.Name.StartsWith("Microsoft.VisualStudio.LanguageServer.", StringComparison.Ordinal) || - s.Name.StartsWith("Microsoft.VisualStudio.LanguageServices.", StringComparison.Ordinal)) - .ToImmutableArray(); + s.Name.StartsWith("Microsoft.VisualStudio.LanguageServices.", StringComparison.Ordinal))]; _logger.LogDebug($"Proffered services: {string.Join(',', services.Select(s => s.ToString()))}"); return ValueTask.FromResult(services); } diff --git a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/CustomExportAssemblyLoader.cs b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/CustomExportAssemblyLoader.cs index 3ac9864ec660b..1249170adf6e8 100644 --- a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/CustomExportAssemblyLoader.cs +++ b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/CustomExportAssemblyLoader.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.Diagnostics.CodeAnalysis; using System.Reflection; using System.Runtime.Loader; using Microsoft.CodeAnalysis.LanguageServer.Services; @@ -74,7 +75,13 @@ private Assembly LoadAssembly(AssemblyName assemblyName, string? codeBasePath) private Assembly LoadAssemblyFromCodeBase(AssemblyName assemblyName, string codeBaseUriStr) { - // CodeBase is spec'd as being a URL string. + // CodeBase is spec'd as being a URI string - however VS-MEF doesn't always give us a URI, nor do they always give us a valid URI representation of the code base (for compatibility with clr behavior). + // For example, when doing initial part discovery, we get a normal path as a string. But when loading the assembly to create the graph, VS-MEF will pass us + // a file URI with an unescaped path part. + // See https://github.com/microsoft/vs-mef/blob/21feb66e55cbef129801de3a6d572c087ee5b0b6/src/Microsoft.VisualStudio.Composition/Resolver.cs#L172 + // + // This can cause issues during URI parsing, but we will handle that below. First we try to parse the code base as a normal URI, which handles all the cases where we get + // a non-URI string as well as the majority of the cases where we get a file URI string. var codeBaseUri = ProtocolConversions.CreateAbsoluteUri(codeBaseUriStr); if (!codeBaseUri.IsFile) { @@ -83,10 +90,27 @@ private Assembly LoadAssemblyFromCodeBase(AssemblyName assemblyName, string code var codeBasePath = codeBaseUri.LocalPath; - var assembly = extensionAssemblyManager.TryLoadAssemblyInExtensionContext(codeBasePath); - if (assembly is not null) + if (TryLoadAssemblyFromCodeBasePath(assemblyName, codeBasePath, out var assembly)) + { + return assembly; + } + + // As described above, we can get a code base URI that contains the unescaped code base file path. This can cause issues when we parse it as a URI if the code base file path + // contains URI reserved characters (for example '#') which are left unescaped in the URI string. While it is a well formed URI, when System.Uri parses the code base URI + // the path component can get mangled and longer accurately represent the actual file system path. + // + // A concrete example - given code base URI 'file:///c:/Learn C#/file.dll', the path component from System.Uri will be 'c:/learn c' and '#/file.dll' is parsed as part of the fragment. + // Of course we do not find a dll at 'c:/learn c' and crash. + // + // Unfortunately, solving this can be difficult - there is an EscapedCodeBase property on AssemblyName, but it does not escape reserved characters. It uses + // the same implementation as Uri.EscapeUriString (which explicitly does not escape reserved characters as it cannot accurately do so). + // + // However - we do know that if we are given a file URI, the scheme and authority parts of the URI are correct (only the path can have unescaped reserved characters, which comes after both). + // We can attempt to reconstruct the real code base file path by combining all the URI parts following the authority (the path, query, and fragment). + // Note - System.URI returns the escaped versions of all these parts, so we unescape them first. + var possibleCodeBasePath = Uri.UnescapeDataString(codeBaseUri.PathAndQuery) + Uri.UnescapeDataString(codeBaseUri.Fragment); + if (TryLoadAssemblyFromCodeBasePath(assemblyName, possibleCodeBasePath, out assembly)) { - _logger.LogTrace("{assemblyName} with code base {codeBase} found in extension context.", assemblyName, codeBasePath); return assembly; } @@ -94,4 +118,24 @@ private Assembly LoadAssemblyFromCodeBase(AssemblyName assemblyName, string code // This is unexpected, so we'll throw an exception. throw new FileNotFoundException($"Could not find assembly {assemblyName} with code base {codeBasePath} in any extension context."); } + + private bool TryLoadAssemblyFromCodeBasePath(AssemblyName assemblyName, string codeBasePath, [NotNullWhen(true)] out Assembly? assembly) + { + assembly = null; + if (!File.Exists(codeBasePath)) + { + _logger.LogTrace("Code base {codeBase} does not exist for {assemblyName}", codeBasePath, assemblyName); + return false; + } + + assembly = extensionAssemblyManager.TryLoadAssemblyInExtensionContext(codeBasePath); + if (assembly is not null) + { + _logger.LogTrace("{assemblyName} with code base {codeBase} found in extension context.", assemblyName, codeBasePath); + return true; + } + + _logger.LogTrace("Code base {codeBase} not found in any extension context for {assemblyName}", codeBasePath, assemblyName); + return false; + } } diff --git a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/ExportProviderBuilder.cs b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/ExportProviderBuilder.cs index 47139da193da3..63cebc020eaff 100644 --- a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/ExportProviderBuilder.cs +++ b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/ExportProviderBuilder.cs @@ -3,6 +3,8 @@ // See the LICENSE file in the project root for more information. using System.Collections.Immutable; +using System.IO.Hashing; +using System.Text; using Microsoft.CodeAnalysis.LanguageServer.Logging; using Microsoft.CodeAnalysis.LanguageServer.Services; using Microsoft.CodeAnalysis.Shared.Collections; @@ -14,12 +16,20 @@ namespace Microsoft.CodeAnalysis.LanguageServer; internal sealed class ExportProviderBuilder { + // For testing purposes, track the last cache write task. + private static Task? _cacheWriteTask; + public static async Task CreateExportProviderAsync( ExtensionAssemblyManager extensionManager, IAssemblyLoader assemblyLoader, string? devKitDependencyPath, + string cacheDirectory, ILoggerFactory loggerFactory) { + // Clear any previous cache write task, so that it is easy to discern whether + // a cache write was attempted. + _cacheWriteTask = null; + var logger = loggerFactory.CreateLogger(); var baseDirectory = AppContext.BaseDirectory; @@ -38,17 +48,60 @@ public static async Task CreateExportProviderAsync( // Add the extension assemblies to the MEF catalog. assemblyPaths = assemblyPaths.Concat(extensionManager.ExtensionAssemblyPaths); - logger.LogTrace($"Composing MEF catalog using:{Environment.NewLine}{string.Join($" {Environment.NewLine}", assemblyPaths)}."); + // Get the cached MEF composition or create a new one. + var exportProviderFactory = await GetCompositionConfigurationAsync([.. assemblyPaths], assemblyLoader, cacheDirectory, logger); + + // Create an export provider, which represents a unique container of values. + // You can create as many of these as you want, but typically an app needs just one. + var exportProvider = exportProviderFactory.CreateExportProvider(); + + // Immediately set the logger factory, so that way it'll be available for the rest of the composition + exportProvider.GetExportedValue().SetFactory(loggerFactory); + + // Also add the ExtensionAssemblyManager so it will be available for the rest of the composition. + exportProvider.GetExportedValue().SetMefExtensionAssemblyManager(extensionManager); + + return exportProvider; + } + private static async Task GetCompositionConfigurationAsync( + ImmutableArray assemblyPaths, + IAssemblyLoader assemblyLoader, + string cacheDirectory, + ILogger logger) + { // Create a MEF resolver that can resolve assemblies in the extension contexts. var resolver = new Resolver(assemblyLoader); + var compositionCacheFile = GetCompositionCacheFilePath(cacheDirectory, assemblyPaths); + + // Try to load a cached composition. + try + { + if (File.Exists(compositionCacheFile)) + { + logger.LogTrace($"Loading cached MEF catalog: {compositionCacheFile}"); + + CachedComposition cachedComposition = new(); + using FileStream cacheStream = new(compositionCacheFile, FileMode.Open, FileAccess.Read, FileShare.Read, bufferSize: 4096, useAsync: true); + var exportProviderFactory = await cachedComposition.LoadExportProviderFactoryAsync(cacheStream, resolver); + + return exportProviderFactory; + } + } + catch (Exception ex) + { + // Log the error, and move on to recover by recreating the MEF composition. + logger.LogError($"Loading cached MEF composition failed: {ex}"); + } + + logger.LogTrace($"Composing MEF catalog using:{Environment.NewLine}{string.Join($" {Environment.NewLine}", assemblyPaths)}."); + var discovery = PartDiscovery.Combine( resolver, new AttributedPartDiscovery(resolver, isNonPublicSupported: true), // "NuGet MEF" attributes (Microsoft.Composition) new AttributedPartDiscoveryV1(resolver)); - // TODO - we should likely cache the catalog so we don't have to rebuild it every time. var catalog = ComposableCatalog.Create(resolver) .AddParts(await discovery.CreatePartsAsync(assemblyPaths)) .WithCompositionService(); // Makes an ICompositionService export available to MEF parts to import @@ -59,20 +112,69 @@ public static async Task CreateExportProviderAsync( // Verify we only have expected errors. ThrowOnUnexpectedErrors(config, catalog, logger); + // Try to cache the composition. + _cacheWriteTask = WriteCompositionCacheAsync(compositionCacheFile, config, logger).ReportNonFatalErrorAsync(); + // Prepare an ExportProvider factory based on this graph. - var exportProviderFactory = config.CreateExportProviderFactory(); + return config.CreateExportProviderFactory(); + } - // Create an export provider, which represents a unique container of values. - // You can create as many of these as you want, but typically an app needs just one. - var exportProvider = exportProviderFactory.CreateExportProvider(); + private static string GetCompositionCacheFilePath(string cacheDirectory, ImmutableArray assemblyPaths) + { + // This should vary based on .NET runtime major version so that as some of our processes switch between our target + // .NET version and the user's selected SDK runtime version (which may be newer), the MEF cache is kept isolated. + // This can be important when the MEF catalog records full assembly names such as "System.Runtime, 8.0.0.0" yet + // we might be running on .NET 7 or .NET 8, depending on the particular session and user settings. + var cacheSubdirectory = $".NET {Environment.Version.Major}"; - // Immediately set the logger factory, so that way it'll be available for the rest of the composition - exportProvider.GetExportedValue().SetFactory(loggerFactory); + return Path.Combine(cacheDirectory, cacheSubdirectory, $"c#-languageserver.{ComputeAssemblyHash(assemblyPaths)}.mef-composition"); - // Also add the ExtensionAssemblyManager so it will be available for the rest of the composition. - exportProvider.GetExportedValue().SetMefExtensionAssemblyManager(extensionManager); + static string ComputeAssemblyHash(ImmutableArray assemblyPaths) + { + // Ensure AssemblyPaths are always in the same order. + assemblyPaths = assemblyPaths.Sort(); - return exportProvider; + var assemblies = new StringBuilder(); + foreach (var assemblyPath in assemblyPaths) + { + // Include assembly path in the hash so that changes to the set of included + // assemblies cause the composition to be rebuilt. + assemblies.Append(assemblyPath); + // Include the last write time in the hash so that newer assemblies written + // to the same location cause the composition to be rebuilt. + assemblies.Append(File.GetLastWriteTimeUtc(assemblyPath).ToString("F")); + } + + var hash = XxHash128.Hash(Encoding.UTF8.GetBytes(assemblies.ToString())); + // Convert to filename safe base64 string. + return Convert.ToBase64String(hash).Replace('+', '-').Replace('/', '_').TrimEnd('='); + } + } + + private static async Task WriteCompositionCacheAsync(string compositionCacheFile, CompositionConfiguration config, ILogger logger) + { + try + { + await Task.Yield(); + + if (Path.GetDirectoryName(compositionCacheFile) is string directory) + { + Directory.CreateDirectory(directory); + } + + CachedComposition cachedComposition = new(); + var tempFilePath = Path.Combine(Path.GetTempPath(), Path.GetTempFileName()); + using (FileStream cacheStream = new(tempFilePath, FileMode.Create, FileAccess.Write, FileShare.None, bufferSize: 4096, useAsync: true)) + { + await cachedComposition.SaveAsync(config, cacheStream); + } + + File.Move(tempFilePath, compositionCacheFile, overwrite: true); + } + catch (Exception ex) + { + logger.LogError($"Failed to save MEF cache: {ex}"); + } } private static void ThrowOnUnexpectedErrors(CompositionConfiguration configuration, ComposableCatalog catalog, ILogger logger) @@ -85,7 +187,7 @@ private static void ThrowOnUnexpectedErrors(CompositionConfiguration configurati // TypeIdentityName: Microsoft.CodeAnalysis.ExternalAccess.Pythia.Api.IPythiaSignatureHelpProviderImplementation // but found 0. // part definition Microsoft.CodeAnalysis.ExternalAccess.Pythia.PythiaSignatureHelpProvider - var erroredParts = configuration.CompositionErrors.FirstOrDefault()?.SelectMany(error => error.Parts).Select(part => part.Definition.Type.Name) ?? Enumerable.Empty(); + var erroredParts = configuration.CompositionErrors.FirstOrDefault()?.SelectMany(error => error.Parts).Select(part => part.Definition.Type.Name) ?? []; var expectedErroredParts = new string[] { "PythiaSignatureHelpProvider" }; var hasUnexpectedErroredParts = erroredParts.Any(part => !expectedErroredParts.Contains(part)); @@ -104,4 +206,11 @@ private static void ThrowOnUnexpectedErrors(CompositionConfiguration configurati } } } + + internal static class TestAccessor + { +#pragma warning disable VSTHRD200 // Use "Async" suffix for async methods + public static Task? GetCacheWriteTask() => _cacheWriteTask; +#pragma warning restore VSTHRD200 // Use "Async" suffix for async methods + } } diff --git a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/HostDiagnosticAnalyzerProvider.cs b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/HostDiagnosticAnalyzerProvider.cs index cbaa86c9589e5..f1dc4a0530581 100644 --- a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/HostDiagnosticAnalyzerProvider.cs +++ b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/HostDiagnosticAnalyzerProvider.cs @@ -17,14 +17,14 @@ public HostDiagnosticAnalyzerProvider(string? razorSourceGenerator) { if (razorSourceGenerator == null || !File.Exists(razorSourceGenerator)) { - _analyzerReferences = ImmutableArray<(AnalyzerFileReference reference, string extensionId)>.Empty; + _analyzerReferences = []; } else { - _analyzerReferences = ImmutableArray.Create<(AnalyzerFileReference reference, string extensionId)>(( + _analyzerReferences = [( new AnalyzerFileReference(razorSourceGenerator, new SimpleAnalyzerAssemblyLoader()), ProjectSystemProject.RazorVsixExtensionId - )); + )]; } } diff --git a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/LanguageServerWorkspaceFactory.cs b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/LanguageServerWorkspaceFactory.cs index 4b9c548e08fda..9822e7020a5ab 100644 --- a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/LanguageServerWorkspaceFactory.cs +++ b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/LanguageServerWorkspaceFactory.cs @@ -42,7 +42,7 @@ public LanguageServerWorkspaceFactory( var razorSourceGenerator = serverConfigurationFactory?.ServerConfiguration?.RazorSourceGenerator; ProjectSystemHostInfo = new ProjectSystemHostInfo( - DynamicFileInfoProviders: dynamicFileInfoProviders.ToImmutableArray(), + DynamicFileInfoProviders: [.. dynamicFileInfoProviders], new HostDiagnosticAnalyzerProvider(razorSourceGenerator)); TargetFrameworkManager = projectTargetFrameworkManager; diff --git a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/LoadedProject.cs b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/LoadedProject.cs index 0cdec8f2bd4f0..72a9d11a5612e 100644 --- a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/LoadedProject.cs +++ b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/LoadedProject.cs @@ -37,8 +37,8 @@ internal sealed class LoadedProject : IDisposable /// private Lazy>? _mostRecentFileMatchers; private IWatchedFile? _mostRecentProjectAssetsFileWatcher; - private ImmutableArray _mostRecentMetadataReferences = ImmutableArray.Empty; - private ImmutableArray _mostRecentAnalyzerReferences = ImmutableArray.Empty; + private ImmutableArray _mostRecentMetadataReferences = []; + private ImmutableArray _mostRecentAnalyzerReferences = []; public LoadedProject(ProjectSystemProject projectSystemProject, SolutionServices solutionServices, IFileChangeWatcher fileWatcher, ProjectTargetFrameworkManager targetFrameworkManager) { @@ -211,7 +211,7 @@ public void Dispose() newProjectInfo.AdditionalDocuments.Where(TreatAsIsDynamicFile), _mostRecentFileInfo?.AdditionalDocuments.Where(TreatAsIsDynamicFile), DocumentFileInfoComparer.Instance, - document => _projectSystemProject.AddDynamicSourceFile(document.FilePath, folders: ImmutableArray.Empty), + document => _projectSystemProject.AddDynamicSourceFile(document.FilePath, folders: []), document => _projectSystemProject.RemoveDynamicSourceFile(document.FilePath), "Project {0} now has {1} dynamic file(s)."); @@ -221,14 +221,14 @@ public void Dispose() _mostRecentFileMatchers = new Lazy>(() => { - return newProjectInfo.FileGlobs.Select(glob => + return [.. newProjectInfo.FileGlobs.Select(glob => { var matcher = new Matcher(); matcher.AddIncludePatterns(glob.Includes); matcher.AddExcludePatterns(glob.Excludes); matcher.AddExcludePatterns(glob.Removes); return matcher; - }).ToImmutableArray(); + })]; }); _mostRecentFileInfo = newProjectInfo; diff --git a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/ProjectTelemetry/ProjectLoadTelemetryReporter.cs b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/ProjectTelemetry/ProjectLoadTelemetryReporter.cs index 1e04c70de2bb5..936d932a1185d 100644 --- a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/ProjectTelemetry/ProjectLoadTelemetryReporter.cs +++ b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/ProjectTelemetry/ProjectLoadTelemetryReporter.cs @@ -150,7 +150,7 @@ private static async Task GetProjectIdAsync(ProjectToLoad projectToLoad) private static ImmutableArray GetTargetFrameworks(IEnumerable projectFileInfos) { - return projectFileInfos.Select(p => GetTargetFramework(p)?.ToLower()).WhereNotNull().ToImmutableArray(); + return [.. projectFileInfos.Select(p => GetTargetFramework(p)?.ToLower()).WhereNotNull()]; string? GetTargetFramework(ProjectFileInfo projectFileInfo) => projectFileInfo.TargetFramework ?? projectFileInfo.TargetFrameworkVersion; diff --git a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/Razor/RazorDynamicFileChangedHandler.cs b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/Razor/RazorDynamicFileChangedHandler.cs new file mode 100644 index 0000000000000..48c1c3fa8595f --- /dev/null +++ b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/Razor/RazorDynamicFileChangedHandler.cs @@ -0,0 +1,34 @@ +// 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.Composition; +using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.CodeAnalysis.LanguageServer.Handler; + +namespace Microsoft.CodeAnalysis.LanguageServer.HostWorkspace.Razor; + +[Shared] +[ExportCSharpVisualBasicStatelessLspService(typeof(RazorDynamicFileChangedHandler))] +[Method("razor/dynamicFileInfoChanged")] +internal class RazorDynamicFileChangedHandler : ILspServiceNotificationHandler +{ + private readonly RazorDynamicFileInfoProvider _razorDynamicFileInfoProvider; + + [ImportingConstructor] + [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] + public RazorDynamicFileChangedHandler(RazorDynamicFileInfoProvider razorDynamicFileInfoProvider) + { + _razorDynamicFileInfoProvider = razorDynamicFileInfoProvider; + } + + public bool MutatesSolutionState => false; + public bool RequiresLSPSolution => false; + + public Task HandleNotificationAsync(RazorDynamicFileChangedParams request, RequestContext requestContext, CancellationToken cancellationToken) + { + var filePath = ProtocolConversions.GetDocumentFilePathFromUri(request.RazorDocument.Uri); + _razorDynamicFileInfoProvider.Update(filePath); + return Task.CompletedTask; + } +} diff --git a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/Razor/RazorDynamicFileChangedParams.cs b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/Razor/RazorDynamicFileChangedParams.cs new file mode 100644 index 0000000000000..73a2cf4dd186c --- /dev/null +++ b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/Razor/RazorDynamicFileChangedParams.cs @@ -0,0 +1,14 @@ +// 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.Text.Json.Serialization; +using Roslyn.LanguageServer.Protocol; + +namespace Microsoft.CodeAnalysis.LanguageServer.HostWorkspace.Razor; + +internal class RazorDynamicFileChangedParams +{ + [JsonPropertyName("razorDocument")] + public required TextDocumentIdentifier RazorDocument { get; set; } +} diff --git a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/Razor/RazorDynamicFileInfoProvider.TextChangesTextLoader.cs b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/Razor/RazorDynamicFileInfoProvider.TextChangesTextLoader.cs new file mode 100644 index 0000000000000..0f62d58b1d221 --- /dev/null +++ b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/Razor/RazorDynamicFileInfoProvider.TextChangesTextLoader.cs @@ -0,0 +1,113 @@ +// 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.Text; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.LanguageServer.LanguageServer; +using Microsoft.CodeAnalysis.Text; +using Roslyn.Utilities; + +namespace Microsoft.CodeAnalysis.LanguageServer.HostWorkspace.Razor; + +internal partial class RazorDynamicFileInfoProvider +{ + private sealed class TextChangesTextLoader( + TextDocument? document, + IEnumerable updates, + byte[] checksum, + SourceHashAlgorithm checksumAlgorithm, + int? codePage, + Uri razorUri) : TextLoader + { + private readonly TextDocument? _document = document; + private readonly IEnumerable _updates = updates; + private readonly byte[] _checksum = checksum; + private readonly SourceHashAlgorithm _checksumAlgorithm = checksumAlgorithm; + private readonly int? _codePage = codePage; + private readonly Uri _razorUri = razorUri; + + private readonly Lazy _emptySourceText = new Lazy(() => + { + var encoding = codePage is null ? null : Encoding.GetEncoding(codePage.Value); + return SourceText.From("", checksumAlgorithm: checksumAlgorithm, encoding: encoding); + }); + + public override async Task LoadTextAndVersionAsync(LoadTextOptions options, CancellationToken cancellationToken) + { + if (_document is null) + { + var text = UpdateSourceTextWithEdits(_emptySourceText.Value, _updates); + return TextAndVersion.Create(text, VersionStamp.Default.GetNewerVersion()); + } + + var sourceText = await _document.GetTextAsync(cancellationToken).ConfigureAwait(false); + + // Validate the checksum information so the edits are known to be correct + if (IsSourceTextMatching(sourceText)) + { + var version = await _document.GetTextVersionAsync(cancellationToken).ConfigureAwait(false); + var newText = UpdateSourceTextWithEdits(sourceText, _updates); + return TextAndVersion.Create(newText, version.GetNewerVersion()); + } + + return await GetFullDocumentFromServerAsync(cancellationToken).ConfigureAwait(false); + } + + private bool IsSourceTextMatching(SourceText sourceText) + { + if (sourceText.ChecksumAlgorithm != _checksumAlgorithm) + { + return false; + } + + if (sourceText.Encoding?.CodePage != _codePage) + { + return false; + } + + if (!sourceText.GetChecksum().SequenceEqual(_checksum)) + { + return false; + } + + return true; + } + + private async Task GetFullDocumentFromServerAsync(CancellationToken cancellationToken) + { + Contract.ThrowIfNull(LanguageServerHost.Instance, "We don't have an LSP channel yet to send this request through."); + var clientLanguageServerManager = LanguageServerHost.Instance.GetRequiredLspService(); + + var response = await clientLanguageServerManager.SendRequestAsync( + ProvideRazorDynamicFileInfoMethodName, + new RazorProvideDynamicFileParams + { + RazorDocument = new() + { + Uri = _razorUri, + }, + FullText = true + }, + cancellationToken); + + RoslynDebug.AssertNotNull(response.Updates); + RoslynDebug.Assert(response.Updates.IsSingle()); + + var text = UpdateSourceTextWithEdits(_emptySourceText.Value, response.Updates); + return TextAndVersion.Create(text, VersionStamp.Default.GetNewerVersion()); + } + + private static SourceText UpdateSourceTextWithEdits(SourceText sourceText, IEnumerable updates) + { + foreach (var update in updates) + { + var changes = update.Edits.Select(e => new TextChange(e.Span.ToTextSpan(), e.NewText)); + sourceText = sourceText.WithChanges(changes); + } + + return sourceText; + } + } + +} diff --git a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/RazorDynamicFileInfoProvider.cs b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/Razor/RazorDynamicFileInfoProvider.cs similarity index 50% rename from src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/RazorDynamicFileInfoProvider.cs rename to src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/Razor/RazorDynamicFileInfoProvider.cs index 4e3d57878fdb8..b064fb31132c3 100644 --- a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/RazorDynamicFileInfoProvider.cs +++ b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/Razor/RazorDynamicFileInfoProvider.cs @@ -3,90 +3,113 @@ // See the LICENSE file in the project root for more information. using System.Composition; -using System.Text.Json.Serialization; +using System.Text; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Collections; using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.LanguageServer.LanguageServer; +using Microsoft.CodeAnalysis.Shared.TestHooks; using Microsoft.CodeAnalysis.Text; -using Roslyn.LanguageServer.Protocol; using Roslyn.Utilities; -namespace Microsoft.CodeAnalysis.LanguageServer.HostWorkspace; +namespace Microsoft.CodeAnalysis.LanguageServer.HostWorkspace.Razor; -[Export(typeof(IDynamicFileInfoProvider)), Shared] +[Shared] +[Export(typeof(IDynamicFileInfoProvider))] +[Export(typeof(RazorDynamicFileInfoProvider))] [ExportMetadata("Extensions", new string[] { "cshtml", "razor", })] -internal class RazorDynamicFileInfoProvider : IDynamicFileInfoProvider +internal partial class RazorDynamicFileInfoProvider : IDynamicFileInfoProvider { private const string ProvideRazorDynamicFileInfoMethodName = "razor/provideDynamicFileInfo"; - - private class ProvideDynamicFileParams - { - [JsonPropertyName("razorDocument")] - public required TextDocumentIdentifier RazorDocument { get; set; } - } - - private class ProvideDynamicFileResponse - { - [JsonPropertyName("csharpDocument")] - public required TextDocumentIdentifier CSharpDocument { get; set; } - } - private const string RemoveRazorDynamicFileInfoMethodName = "razor/removeDynamicFileInfo"; - private class RemoveDynamicFileParams - { - [JsonPropertyName("csharpDocument")] - public required TextDocumentIdentifier CSharpDocument { get; set; } - } - -#pragma warning disable CS0067 // We won't fire the Updated event -- we expect Razor to send us textual changes via didChange instead - public event EventHandler? Updated; -#pragma warning restore CS0067 - private readonly Lazy _razorWorkspaceListenerInitializer; + private readonly LanguageServerWorkspaceFactory _workspaceFactory; + private readonly AsyncBatchingWorkQueue _updateWorkQueue; [ImportingConstructor] [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - public RazorDynamicFileInfoProvider(Lazy razorWorkspaceListenerInitializer) + public RazorDynamicFileInfoProvider( + Lazy razorWorkspaceListenerInitializer, + LanguageServerWorkspaceFactory workspaceFactory, + IAsynchronousOperationListenerProvider listenerProvider) { _razorWorkspaceListenerInitializer = razorWorkspaceListenerInitializer; + _updateWorkQueue = new AsyncBatchingWorkQueue( + TimeSpan.FromMilliseconds(200), + UpdateAsync, + listenerProvider.GetListener(nameof(RazorDynamicFileInfoProvider)), + CancellationToken.None); + _workspaceFactory = workspaceFactory; + } + + public event EventHandler? Updated; + + public void Update(string filePath) + { + _updateWorkQueue.AddWork(filePath); } public async Task GetDynamicFileInfoAsync(ProjectId projectId, string? projectFilePath, string filePath, CancellationToken cancellationToken) { _razorWorkspaceListenerInitializer.Value.NotifyDynamicFile(projectId); - var requestParams = new ProvideDynamicFileParams + var razorUri = ProtocolConversions.CreateAbsoluteUri(filePath); + var requestParams = new RazorProvideDynamicFileParams { RazorDocument = new() { - Uri = ProtocolConversions.CreateAbsoluteUri(filePath) + Uri = razorUri } }; Contract.ThrowIfNull(LanguageServerHost.Instance, "We don't have an LSP channel yet to send this request through."); var clientLanguageServerManager = LanguageServerHost.Instance.GetRequiredLspService(); - var response = await clientLanguageServerManager.SendRequestAsync( + var response = await clientLanguageServerManager.SendRequestAsync( ProvideRazorDynamicFileInfoMethodName, requestParams, cancellationToken); - // Since we only sent one file over, we should get either zero or one URI back - var responseUri = response.CSharpDocument?.Uri; - - if (responseUri == null) + if (response.CSharpDocument is null) { return null; } - else + + // Since we only sent one file over, we should get either zero or one URI back + var responseUri = response.CSharpDocument.Uri; + var dynamicFileInfoFilePath = ProtocolConversions.GetDocumentFilePathFromUri(responseUri); + + if (response.Updates is not null) { - var dynamicFileInfoFilePath = ProtocolConversions.GetDocumentFilePathFromUri(responseUri); - return new DynamicFileInfo(dynamicFileInfoFilePath, SourceCodeKind.Regular, EmptyStringTextLoader.Instance, designTimeOnly: true, documentServiceProvider: null); + var textDocument = await _workspaceFactory.Workspace.CurrentSolution.GetTextDocumentAsync(response.CSharpDocument, cancellationToken).ConfigureAwait(false); + var checksum = Convert.FromBase64String(response.Checksum); + var textLoader = new TextChangesTextLoader( + textDocument, + response.Updates, + checksum, + response.ChecksumAlgorithm, + response.SourceEncodingCodePage, + razorUri); + + return new DynamicFileInfo( + dynamicFileInfoFilePath, + SourceCodeKind.Regular, + textLoader, + designTimeOnly: true, + documentServiceProvider: null); } + + return new DynamicFileInfo( + dynamicFileInfoFilePath, + SourceCodeKind.Regular, + EmptyStringTextLoader.Instance, + designTimeOnly: true, + documentServiceProvider: null); } public Task RemoveDynamicFileInfoAsync(ProjectId projectId, string? projectFilePath, string filePath, CancellationToken cancellationToken) { - var notificationParams = new RemoveDynamicFileParams + var notificationParams = new RazorRemoveDynamicFileParams { CSharpDocument = new() { @@ -101,11 +124,20 @@ public Task RemoveDynamicFileInfoAsync(ProjectId projectId, string? projectFileP RemoveRazorDynamicFileInfoMethodName, notificationParams, cancellationToken).AsTask(); } - private sealed class EmptyStringTextLoader : TextLoader + private ValueTask UpdateAsync(ImmutableSegmentedList paths, CancellationToken token) { - public static readonly TextLoader Instance = new EmptyStringTextLoader(); + foreach (var path in paths) + { + token.ThrowIfCancellationRequested(); + Updated?.Invoke(this, path); + } - private EmptyStringTextLoader() { } + return ValueTask.CompletedTask; + } + + private sealed class EmptyStringTextLoader() : TextLoader + { + public static readonly TextLoader Instance = new EmptyStringTextLoader(); public override Task LoadTextAndVersionAsync(LoadTextOptions options, CancellationToken cancellationToken) { diff --git a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/Razor/RazorDynamicFileUpdate.cs b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/Razor/RazorDynamicFileUpdate.cs new file mode 100644 index 0000000000000..4853793e33e84 --- /dev/null +++ b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/Razor/RazorDynamicFileUpdate.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.Text.Json.Serialization; +using Microsoft.CodeAnalysis.Text; +using Roslyn.LanguageServer.Protocol; + +namespace Microsoft.CodeAnalysis.LanguageServer.HostWorkspace.Razor; + +class RazorDynamicFileUpdate +{ + [JsonPropertyName("edits")] + public required ServerTextChange[] Edits { get; set; } +} diff --git a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/RazorInitializeHandler.cs b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/Razor/RazorInitializeHandler.cs similarity index 95% rename from src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/RazorInitializeHandler.cs rename to src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/Razor/RazorInitializeHandler.cs index c872b2303ef39..546b0a3f6edd7 100644 --- a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/RazorInitializeHandler.cs +++ b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/Razor/RazorInitializeHandler.cs @@ -8,7 +8,7 @@ using Microsoft.CodeAnalysis.LanguageServer.Handler; using Microsoft.CommonLanguageServerProtocol.Framework; -namespace Microsoft.CodeAnalysis.LanguageServer.HostWorkspace; +namespace Microsoft.CodeAnalysis.LanguageServer.HostWorkspace.Razor; [ExportCSharpVisualBasicStatelessLspService(typeof(RazorInitializeHandler)), Shared] [Method("razor/initialize")] diff --git a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/Razor/RazorProvideDynamicFileParams.cs b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/Razor/RazorProvideDynamicFileParams.cs new file mode 100644 index 0000000000000..1d6f4a24dbd22 --- /dev/null +++ b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/Razor/RazorProvideDynamicFileParams.cs @@ -0,0 +1,21 @@ +// 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.Text.Json.Serialization; +using Roslyn.LanguageServer.Protocol; + +namespace Microsoft.CodeAnalysis.LanguageServer.HostWorkspace.Razor; + +internal class RazorProvideDynamicFileParams +{ + [JsonPropertyName("razorDocument")] + public required TextDocumentIdentifier RazorDocument { get; set; } + + /// + /// When true, the full text of the document will be sent over as a single + /// edit instead of diff edits + /// + [JsonPropertyName("fullText")] + public bool FullText { get; set; } +} diff --git a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/Razor/RazorProvideDynamicFileResponse.cs b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/Razor/RazorProvideDynamicFileResponse.cs new file mode 100644 index 0000000000000..6d51c27199d86 --- /dev/null +++ b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/Razor/RazorProvideDynamicFileResponse.cs @@ -0,0 +1,27 @@ +// 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.Text.Json.Serialization; +using Microsoft.CodeAnalysis.Text; +using Roslyn.LanguageServer.Protocol; + +namespace Microsoft.CodeAnalysis.LanguageServer.HostWorkspace.Razor; + +internal class RazorProvideDynamicFileResponse +{ + [JsonPropertyName("csharpDocument")] + public required TextDocumentIdentifier CSharpDocument { get; set; } + + [JsonPropertyName("updates")] + public RazorDynamicFileUpdate[]? Updates { get; set; } + + [JsonPropertyName("checksum")] + public required string Checksum { get; set; } + + [JsonPropertyName("checksumAlgorithm")] + public SourceHashAlgorithm ChecksumAlgorithm { get; set; } + + [JsonPropertyName("encodingCodePage")] + public int? SourceEncodingCodePage { get; set; } +} diff --git a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/Razor/RazorRemoveDynamicFileParams.cs b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/Razor/RazorRemoveDynamicFileParams.cs new file mode 100644 index 0000000000000..2388208108769 --- /dev/null +++ b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/Razor/RazorRemoveDynamicFileParams.cs @@ -0,0 +1,14 @@ +// 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.Text.Json.Serialization; +using Roslyn.LanguageServer.Protocol; + +namespace Microsoft.CodeAnalysis.LanguageServer.HostWorkspace.Razor; + +internal class RazorRemoveDynamicFileParams +{ + [JsonPropertyName("csharpDocument")] + public required TextDocumentIdentifier CSharpDocument { get; set; } +} diff --git a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/RazorWorkspaceListenerInitializer.cs b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/Razor/RazorWorkspaceListenerInitializer.cs similarity index 97% rename from src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/RazorWorkspaceListenerInitializer.cs rename to src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/Razor/RazorWorkspaceListenerInitializer.cs index b0d2ab8a94e4c..80d366ca58c13 100644 --- a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/RazorWorkspaceListenerInitializer.cs +++ b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/Razor/RazorWorkspaceListenerInitializer.cs @@ -7,7 +7,7 @@ using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.Extensions.Logging; -namespace Microsoft.CodeAnalysis.LanguageServer.HostWorkspace; +namespace Microsoft.CodeAnalysis.LanguageServer.HostWorkspace.Razor; [Export(typeof(RazorWorkspaceListenerInitializer)), Shared] internal sealed class RazorWorkspaceListenerInitializer diff --git a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/Razor/ServerTextChange.cs b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/Razor/ServerTextChange.cs new file mode 100644 index 0000000000000..272a69316d4b0 --- /dev/null +++ b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/Razor/ServerTextChange.cs @@ -0,0 +1,16 @@ +// 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.Text.Json.Serialization; + +namespace Microsoft.CodeAnalysis.LanguageServer.HostWorkspace.Razor; + +internal class ServerTextChange +{ + [JsonPropertyName("span")] + public required ServerTextSpan Span { get; set; } + + [JsonPropertyName("newText")] + public required string NewText { get; set; } +} diff --git a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/Razor/ServerTextSpan.cs b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/Razor/ServerTextSpan.cs new file mode 100644 index 0000000000000..80d3d035aeb3e --- /dev/null +++ b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/Razor/ServerTextSpan.cs @@ -0,0 +1,20 @@ +// 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.Text.Json.Serialization; +using Microsoft.CodeAnalysis.Text; + +namespace Microsoft.CodeAnalysis.LanguageServer.HostWorkspace.Razor; + +internal class ServerTextSpan +{ + [JsonPropertyName("start")] + public int Start { get; set; } + + [JsonPropertyName("length")] + public int Length { get; set; } + + public TextSpan ToTextSpan() + => new(Start, Length); +} diff --git a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/WorkspaceProjectFactoryService.cs b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/WorkspaceProjectFactoryService.cs index 1debf920753bd..255be35a19bd2 100644 --- a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/WorkspaceProjectFactoryService.cs +++ b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/WorkspaceProjectFactoryService.cs @@ -75,7 +75,7 @@ public async Task CreateAndAddProjectAsync(WorkspaceProjectCr public Task> GetSupportedBuildSystemPropertiesAsync(CancellationToken _) { // TODO: implement - return Task.FromResult((IReadOnlyCollection)ImmutableArray.Empty); + return Task.FromResult((IReadOnlyCollection)[]); } } #pragma warning restore RS0030 // Do not used banned APIs diff --git a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/LanguageServerFatalError.cs b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/LanguageServerFatalError.cs index de3ef431adc0c..91236b30ebd9f 100644 --- a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/LanguageServerFatalError.cs +++ b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/LanguageServerFatalError.cs @@ -8,7 +8,7 @@ namespace Microsoft.CodeAnalysis.LanguageServer; -public class LanguageServerFatalError +public static class LanguageServerFatalError { /// /// Use in an exception filter to report an error without catching the exception. diff --git a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/Program.cs b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/Program.cs index efc71ddc547da..e054470b1b666 100644 --- a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/Program.cs +++ b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/Program.cs @@ -86,7 +86,9 @@ static async Task RunAsync(ServerConfiguration serverConfiguration, Cancellation var assemblyLoader = new CustomExportAssemblyLoader(extensionManager, loggerFactory); var typeRefResolver = new ExtensionTypeRefResolver(assemblyLoader, loggerFactory); - using var exportProvider = await ExportProviderBuilder.CreateExportProviderAsync(extensionManager, assemblyLoader, serverConfiguration.DevKitDependencyPath, loggerFactory); + var cacheDirectory = Path.Combine(Path.GetDirectoryName(typeof(Program).Assembly.Location)!, "cache"); + + using var exportProvider = await ExportProviderBuilder.CreateExportProviderAsync(extensionManager, assemblyLoader, serverConfiguration.DevKitDependencyPath, cacheDirectory, loggerFactory); // LSP server doesn't have the pieces yet to support 'balanced' mode for source-generators. Hardcode us to // 'automatic' for now. @@ -123,7 +125,10 @@ static async Task RunAsync(ServerConfiguration serverConfiguration, Cancellation var languageServerLogger = loggerFactory.CreateLogger(nameof(LanguageServerHost)); - var (clientPipeName, serverPipeName) = CreateNewPipeNames(); + var (clientPipeName, serverPipeName) = serverConfiguration.ServerPipeName is null + ? CreateNewPipeNames() + : (serverConfiguration.ServerPipeName, serverConfiguration.ServerPipeName); + var pipeServer = new NamedPipeServerStream(serverPipeName, PipeDirection.InOut, maxNumberOfServerInstances: 1, @@ -222,6 +227,12 @@ static CliRootCommand CreateCommandLineParser() Required = false }; + var serverPipeNameOption = new CliOption("--pipe") + { + Description = "The name of the pipe the server will connect to.", + Required = false, + }; + var rootCommand = new CliRootCommand() { debugOption, @@ -234,7 +245,8 @@ static CliRootCommand CreateCommandLineParser() devKitDependencyPathOption, razorSourceGeneratorOption, razorDesignTimePathOption, - extensionLogDirectoryOption + extensionLogDirectoryOption, + serverPipeNameOption }; rootCommand.SetAction((parseResult, cancellationToken) => { @@ -248,6 +260,7 @@ static CliRootCommand CreateCommandLineParser() var razorSourceGenerator = parseResult.GetValue(razorSourceGeneratorOption); var razorDesignTimePath = parseResult.GetValue(razorDesignTimePathOption); var extensionLogDirectory = parseResult.GetValue(extensionLogDirectoryOption)!; + var serverPipeName = parseResult.GetValue(serverPipeNameOption); var serverConfiguration = new ServerConfiguration( LaunchDebugger: launchDebugger, @@ -259,6 +272,7 @@ static CliRootCommand CreateCommandLineParser() DevKitDependencyPath: devKitDependencyPath, RazorSourceGenerator: razorSourceGenerator, RazorDesignTimePath: razorDesignTimePath, + ServerPipeName: serverPipeName, ExtensionLogDirectory: extensionLogDirectory); return RunAsync(serverConfiguration, cancellationToken); diff --git a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/ServerConfigurationFactory.cs b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/ServerConfigurationFactory.cs index e7a3c79ef06ab..25b4bceaf754f 100644 --- a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/ServerConfigurationFactory.cs +++ b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/ServerConfigurationFactory.cs @@ -51,6 +51,7 @@ internal record class ServerConfiguration( string? DevKitDependencyPath, string? RazorSourceGenerator, string? RazorDesignTimePath, + string? ServerPipeName, string ExtensionLogDirectory); internal class LogConfiguration diff --git a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/Services/StarredCompletions/StarredCompletionsAssemblyHelper.cs b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/Services/StarredCompletions/StarredCompletionsAssemblyHelper.cs index fe5227ad42abe..9702b71d27f11 100644 --- a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/Services/StarredCompletions/StarredCompletionsAssemblyHelper.cs +++ b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/Services/StarredCompletions/StarredCompletionsAssemblyHelper.cs @@ -137,7 +137,7 @@ private static MethodInfo GetMethodInfo(Assembly assembly, string className, str private static async Task CreateCompletionProviderAsync(MethodInfo createCompletionProviderMethodInfo, IServiceBroker serviceBroker, string modelBasePath, ILogger logger) { - var completionProviderObj = createCompletionProviderMethodInfo.Invoke(null, new object[4] { serviceBroker, BrokeredServices.Services.Descriptors.RemoteModelService, modelBasePath, logger }); + var completionProviderObj = createCompletionProviderMethodInfo.Invoke(null, [serviceBroker, BrokeredServices.Services.Descriptors.RemoteModelService, modelBasePath, logger]); if (completionProviderObj == null) { throw new NotSupportedException($"{createCompletionProviderMethodInfo.Name} method could not be invoked"); diff --git a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/Testing/TestDiscoverer.cs b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/Testing/TestDiscoverer.cs index 7237daa8f6cb9..58136f991d763 100644 --- a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/Testing/TestDiscoverer.cs +++ b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/Testing/TestDiscoverer.cs @@ -49,7 +49,7 @@ public async Task> DiscoverTestsAsync( if (potentialTestMethods.IsEmpty) { progress.Report(partialResult with { Message = LanguageServerResources.No_test_methods_found_in_requested_range }); - return ImmutableArray.Empty; + return []; } // Next, run the actual vs test discovery on the output dll to figure out what tests actually exist. @@ -64,7 +64,7 @@ public async Task> DiscoverTestsAsync( if (discoveryHandler.IsAborted()) { progress.Report(partialResult with { Message = LanguageServerResources.Test_discovery_aborted }); - return ImmutableArray.Empty; + return []; } var testCases = discoveryHandler.GetTestCases(); diff --git a/src/LanguageServer/Microsoft.CommonLanguageServerProtocol.Framework.UnitTests/Mocks/TestHandlerProvider.cs b/src/LanguageServer/Microsoft.CommonLanguageServerProtocol.Framework.UnitTests/Mocks/TestHandlerProvider.cs index 85fbd5d00a9a3..e7db7579a3646 100644 --- a/src/LanguageServer/Microsoft.CommonLanguageServerProtocol.Framework.UnitTests/Mocks/TestHandlerProvider.cs +++ b/src/LanguageServer/Microsoft.CommonLanguageServerProtocol.Framework.UnitTests/Mocks/TestHandlerProvider.cs @@ -20,5 +20,5 @@ public override IMethodHandler GetMethodHandler(string method, TypeRef? requestT => _providers.Single(p => p.metadata.MethodName == method && p.metadata.Language == language).provider; public override ImmutableArray GetRegisteredMethods() - => _providers.Select(p => p.metadata).ToImmutableArray(); + => [.. _providers.Select(p => p.metadata)]; } diff --git a/src/LanguageServer/Microsoft.CommonLanguageServerProtocol.Framework.UnitTests/Mocks/TestLspServices.cs b/src/LanguageServer/Microsoft.CommonLanguageServerProtocol.Framework.UnitTests/Mocks/TestLspServices.cs index cdd46b75a7b06..5bd883292b5f3 100644 --- a/src/LanguageServer/Microsoft.CommonLanguageServerProtocol.Framework.UnitTests/Mocks/TestLspServices.cs +++ b/src/LanguageServer/Microsoft.CommonLanguageServerProtocol.Framework.UnitTests/Mocks/TestLspServices.cs @@ -48,9 +48,7 @@ private sealed class WithMethodHandlerProvider(IEnumerable<(Type type, object in : TestLspServices(services), IMethodHandlerProvider { public ImmutableArray<(IMethodHandler? Instance, TypeRef HandlerTypeRef, ImmutableArray HandlerDetails)> GetMethodHandlers() - => Services.Where(s => s.instance is IMethodHandler) - .Select(s => ((IMethodHandler?)s.instance, TypeRef.From(s.instance.GetType()), MethodHandlerDetails.From(s.instance.GetType()))) - .ToImmutableArray(); + => [.. Services.Where(s => s.instance is IMethodHandler).Select(s => ((IMethodHandler?)s.instance, TypeRef.From(s.instance.GetType()), MethodHandlerDetails.From(s.instance.GetType())))]; public override IEnumerable GetRequiredServices() => []; diff --git a/src/LanguageServer/Microsoft.CommonLanguageServerProtocol.Framework.UnitTests/RequestExecutionQueueTests.cs b/src/LanguageServer/Microsoft.CommonLanguageServerProtocol.Framework.UnitTests/RequestExecutionQueueTests.cs index 7547505b2f97a..cb96f39adc27f 100644 --- a/src/LanguageServer/Microsoft.CommonLanguageServerProtocol.Framework.UnitTests/RequestExecutionQueueTests.cs +++ b/src/LanguageServer/Microsoft.CommonLanguageServerProtocol.Framework.UnitTests/RequestExecutionQueueTests.cs @@ -62,12 +62,12 @@ public async Task ExecuteAsync_WithCancelInProgressWork_CancelsInProgressWorkWhe for (var i = 0; i < 20; i++) { // Arrange - var requestExecutionQueue = GetRequestExecutionQueue(cancelInProgressWorkUponMutatingRequest: true, handlers: new[] - { + var requestExecutionQueue = GetRequestExecutionQueue(cancelInProgressWorkUponMutatingRequest: true, handlers: + [ (CancellingHandler.Metadata, CancellingHandler.Instance), (CompletingHandler.Metadata, CompletingHandler.Instance), (MutatingHandler.Metadata, MutatingHandler.Instance), - }); + ]); var lspServices = GetLspServices(); var cancellingRequestCancellationToken = new CancellationToken(); diff --git a/src/LanguageServer/Microsoft.CommonLanguageServerProtocol.Framework/TypeRef.cs b/src/LanguageServer/Microsoft.CommonLanguageServerProtocol.Framework/TypeRef.cs index 837b33f210264..cad8ecf214836 100644 --- a/src/LanguageServer/Microsoft.CommonLanguageServerProtocol.Framework/TypeRef.cs +++ b/src/LanguageServer/Microsoft.CommonLanguageServerProtocol.Framework/TypeRef.cs @@ -61,14 +61,16 @@ public override int GetHashCode() var comparer = StringComparer.Ordinal; var hashCode = 2037759866; - hashCode = hashCode * -1521134295 + comparer.GetHashCode(TypeName); - hashCode = hashCode * -1521134295 + comparer.GetHashCode(AssemblyName); - - if (CodeBase is string codeBase) + unchecked { - hashCode = hashCode * -1521134295 + comparer.GetHashCode(codeBase); - } + hashCode = hashCode * -1521134295 + comparer.GetHashCode(TypeName); + hashCode = hashCode * -1521134295 + comparer.GetHashCode(AssemblyName); + if (CodeBase is string codeBase) + { + hashCode = hashCode * -1521134295 + comparer.GetHashCode(codeBase); + } + } return hashCode; } diff --git a/src/LanguageServer/Protocol/DefaultCapabilitiesProvider.cs b/src/LanguageServer/Protocol/DefaultCapabilitiesProvider.cs index ae55d4bce2eff..07bfdbf829b13 100644 --- a/src/LanguageServer/Protocol/DefaultCapabilitiesProvider.cs +++ b/src/LanguageServer/Protocol/DefaultCapabilitiesProvider.cs @@ -27,9 +27,7 @@ internal sealed class ExperimentalCapabilitiesProvider : ICapabilitiesProvider public ExperimentalCapabilitiesProvider( [ImportMany] IEnumerable> completionProviders) { - _completionProviders = completionProviders - .Where(lz => lz.Metadata.Language is LanguageNames.CSharp or LanguageNames.VisualBasic) - .ToImmutableArray(); + _completionProviders = [.. completionProviders.Where(lz => lz.Metadata.Language is LanguageNames.CSharp or LanguageNames.VisualBasic)]; } public void Initialize() diff --git a/src/LanguageServer/Protocol/Extensions/ProtocolConversions.cs b/src/LanguageServer/Protocol/Extensions/ProtocolConversions.cs index a86a0e660cca9..d4a1eda80a6cb 100644 --- a/src/LanguageServer/Protocol/Extensions/ProtocolConversions.cs +++ b/src/LanguageServer/Protocol/Extensions/ProtocolConversions.cs @@ -77,7 +77,7 @@ internal static partial class ProtocolConversions { WellKnownTags.Method, ImmutableArray.Create(LSP.CompletionItemKind.Method) }, { WellKnownTags.Module, ImmutableArray.Create(LSP.CompletionItemKind.Module) }, { WellKnownTags.Operator, ImmutableArray.Create(LSP.CompletionItemKind.Operator) }, - { WellKnownTags.Parameter, ImmutableArray.Create(LSP.CompletionItemKind.Value) }, + { WellKnownTags.Parameter, ImmutableArray.Create(LSP.CompletionItemKind.Variable) }, { WellKnownTags.Property, ImmutableArray.Create(LSP.CompletionItemKind.Property) }, { WellKnownTags.RangeVariable, ImmutableArray.Create(LSP.CompletionItemKind.Variable) }, { WellKnownTags.Reference, ImmutableArray.Create(LSP.CompletionItemKind.Reference) }, @@ -401,7 +401,7 @@ public static LSP.Range TextSpanToRange(TextSpan textSpan, SourceText text) } // Map all the text changes' spans for this document. - var mappedResults = await GetMappedSpanResultAsync(oldDocument, textChanges.Select(tc => tc.Span).ToImmutableArray(), cancellationToken).ConfigureAwait(false); + var mappedResults = await GetMappedSpanResultAsync(oldDocument, [.. textChanges.Select(tc => tc.Span)], cancellationToken).ConfigureAwait(false); if (mappedResults == null) { // There's no span mapping available, just create text edits from the original text changes. @@ -432,7 +432,7 @@ public static LSP.Range TextSpanToRange(TextSpan textSpan, SourceText text) var documentEdits = uriToTextEdits.GroupBy(uriAndEdit => uriAndEdit.Uri, uriAndEdit => new LSP.SumType(uriAndEdit.TextEdit), (uri, edits) => new LSP.TextDocumentEdit { TextDocument = new LSP.OptionalVersionedTextDocumentIdentifier { Uri = uri }, - Edits = edits.ToArray(), + Edits = [.. edits], }).ToArray(); return documentEdits; diff --git a/src/LanguageServer/Protocol/ExternalAccess/Razor/SimplifyMethodHandler.cs b/src/LanguageServer/Protocol/ExternalAccess/Razor/SimplifyMethodHandler.cs index f9eae08e54024..2a5e5765c0b5b 100644 --- a/src/LanguageServer/Protocol/ExternalAccess/Razor/SimplifyMethodHandler.cs +++ b/src/LanguageServer/Protocol/ExternalAccess/Razor/SimplifyMethodHandler.cs @@ -69,6 +69,6 @@ internal static async Task GetSimplifiedEditsAsync(Document original var options = simplificationService.GetSimplifierOptions(configOptions); var newDocument = await Simplifier.ReduceAsync(annotatedDocument, options, cancellationToken).ConfigureAwait(false); var changes = await newDocument.GetTextChangesAsync(originalDocument, cancellationToken).ConfigureAwait(false); - return changes.Select(change => ProtocolConversions.TextChangeToTextEdit(change, originalSourceText)).ToArray(); + return [.. changes.Select(change => ProtocolConversions.TextChangeToTextEdit(change, originalSourceText))]; } } diff --git a/src/LanguageServer/Protocol/Features/CodeFixes/CodeFixService.cs b/src/LanguageServer/Protocol/Features/CodeFixes/CodeFixService.cs index 0a2112d3e8db3..10f077b002883 100644 --- a/src/LanguageServer/Protocol/Features/CodeFixes/CodeFixService.cs +++ b/src/LanguageServer/Protocol/Features/CodeFixes/CodeFixService.cs @@ -65,9 +65,9 @@ public CodeFixService( [ImportMany] IEnumerable> configurationProviders) { _diagnosticService = diagnosticAnalyzerService; - _errorLoggers = loggers.ToImmutableArray(); + _errorLoggers = [.. loggers]; - _fixers = fixers.ToImmutableArray(); + _fixers = [.. fixers]; _fixersPerLanguageMap = _fixers.ToPerLanguageMapWithMultipleLanguages(); _configurationProvidersMap = GetConfigurationProvidersPerLanguageMap(configurationProviders); diff --git a/src/LanguageServer/Protocol/Features/DecompiledSource/AssemblyResolver.cs b/src/LanguageServer/Protocol/Features/DecompiledSource/AssemblyResolver.cs index 00d5807883c73..e68ef976c26f6 100644 --- a/src/LanguageServer/Protocol/Features/DecompiledSource/AssemblyResolver.cs +++ b/src/LanguageServer/Protocol/Features/DecompiledSource/AssemblyResolver.cs @@ -64,7 +64,7 @@ public PEFile TryResolve(MetadataReference metadataReference, PEStreamOptions st { if (_inMemoryImagesForTesting.TryGetValue(metadataReference, out var pair)) { - return new PEFile(pair.fileName, new MemoryStream(pair.image.ToArray()), streamOptions); + return new PEFile(pair.fileName, new MemoryStream([.. pair.image]), streamOptions); } return null; diff --git a/src/LanguageServer/Protocol/Features/EditAndContinue/EditAndContinueDiagnosticSource_Workspace.cs b/src/LanguageServer/Protocol/Features/EditAndContinue/EditAndContinueDiagnosticSource_Workspace.cs index 8906835b732ae..978c15faa0213 100644 --- a/src/LanguageServer/Protocol/Features/EditAndContinue/EditAndContinueDiagnosticSource_Workspace.cs +++ b/src/LanguageServer/Protocol/Features/EditAndContinue/EditAndContinueDiagnosticSource_Workspace.cs @@ -59,7 +59,7 @@ group data by data.DocumentId into documentData var document = await solution.GetDocumentAsync(documentId, includeSourceGenerated: true, cancellationToken).ConfigureAwait(false); if (document != null && !isDocumentOpen(document)) { - sources.Add(new ClosedDocumentSource(document, diagnostics.ToImmutableArray())); + sources.Add(new ClosedDocumentSource(document, [.. diagnostics])); } } @@ -70,7 +70,7 @@ from data in applyDiagnostics group data by data.ProjectId into projectData let project = solution.GetProject(projectData.Key) where project != null - select new ProjectSource(project, projectData.ToImmutableArray())); + select new ProjectSource(project, [.. projectData])); return sources.ToImmutable(); } diff --git a/src/LanguageServer/Protocol/Features/UnifiedSuggestions/UnifiedSuggestedActionsSource.cs b/src/LanguageServer/Protocol/Features/UnifiedSuggestions/UnifiedSuggestedActionsSource.cs index 323323d041cd9..0a59ed87a9d9c 100644 --- a/src/LanguageServer/Protocol/Features/UnifiedSuggestions/UnifiedSuggestedActionsSource.cs +++ b/src/LanguageServer/Protocol/Features/UnifiedSuggestions/UnifiedSuggestedActionsSource.cs @@ -462,7 +462,7 @@ private static ImmutableArray FilterOnAnyThread( ImmutableArray refactorings, TextSpan selection, bool filterOutsideSelection) - => refactorings.Select(r => FilterOnAnyThread(r, selection, filterOutsideSelection)).WhereNotNull().ToImmutableArray(); + => [.. refactorings.Select(r => FilterOnAnyThread(r, selection, filterOutsideSelection)).WhereNotNull()]; private static CodeRefactoring? FilterOnAnyThread( CodeRefactoring refactoring, diff --git a/src/LanguageServer/Protocol/Handler/Breakpoints/ValidateBreakableRangeHandler.cs b/src/LanguageServer/Protocol/Handler/Breakpoints/ValidateBreakableRangeHandler.cs index 7ba5975703810..bf11f6a5f659e 100644 --- a/src/LanguageServer/Protocol/Handler/Breakpoints/ValidateBreakableRangeHandler.cs +++ b/src/LanguageServer/Protocol/Handler/Breakpoints/ValidateBreakableRangeHandler.cs @@ -18,26 +18,23 @@ namespace Microsoft.CodeAnalysis.LanguageServer.Handler { [ExportCSharpVisualBasicStatelessLspService(typeof(ValidateBreakableRangeHandler)), Shared] [Method(LSP.VSInternalMethods.TextDocumentValidateBreakableRangeName)] - internal sealed class ValidateBreakableRangeHandler : ILspServiceDocumentRequestHandler + [method: ImportingConstructor] + [method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] + internal sealed class ValidateBreakableRangeHandler() : ILspServiceDocumentRequestHandler { - [ImportingConstructor] - [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - public ValidateBreakableRangeHandler() - { - } - public bool MutatesSolutionState => false; public bool RequiresLSPSolution => true; public TextDocumentIdentifier GetTextDocumentIdentifier(LSP.VSInternalValidateBreakableRangeParams request) => request.TextDocument; - public async Task HandleRequestAsync(LSP.VSInternalValidateBreakableRangeParams request, RequestContext context, CancellationToken cancellationToken) - { - var document = context.GetRequiredDocument(); + public Task HandleRequestAsync(LSP.VSInternalValidateBreakableRangeParams request, RequestContext context, CancellationToken cancellationToken) + => GetBreakableRangeAsync(context.GetRequiredDocument(), request.Range, cancellationToken); + public static async Task GetBreakableRangeAsync(Document document, LSP.Range range, CancellationToken cancellationToken) + { var text = await document.GetValueTextAsync(cancellationToken).ConfigureAwait(false); - var span = ProtocolConversions.RangeToTextSpan(request.Range, text); + var span = ProtocolConversions.RangeToTextSpan(range, text); var breakpointService = document.Project.Services.GetRequiredService(); if (span.Length > 0) @@ -66,7 +63,7 @@ public TextDocumentIdentifier GetTextDocumentIdentifier(LSP.VSInternalValidateBr if (tree.GetDiagnostics(cancellationToken).Any(d => d.Severity == DiagnosticSeverity.Error)) { // Keep the span as is. - return request.Range; + return range; } } } @@ -97,7 +94,7 @@ public TextDocumentIdentifier GetTextDocumentIdentifier(LSP.VSInternalValidateBr // BP: int a = $$ GetData(); // // If the user types "1;" we'd shrink the breakpoint, so stick to the end of the range. - if (!result.IsLineBreakpoint && BreakpointRangeIsSmaller(breakpointRange, request.Range)) + if (!result.IsLineBreakpoint && BreakpointRangeIsSmaller(breakpointRange, range)) { var secondResult = await breakpointService.ResolveBreakpointAsync(document, new TextSpan(span.End, length: 0), cancellationToken).ConfigureAwait(false); if (secondResult is not null) diff --git a/src/LanguageServer/Protocol/Handler/CodeActions/CodeActionHelpers.cs b/src/LanguageServer/Protocol/Handler/CodeActions/CodeActionHelpers.cs index cbfd9f869d226..42a87764d251d 100644 --- a/src/LanguageServer/Protocol/Handler/CodeActions/CodeActionHelpers.cs +++ b/src/LanguageServer/Protocol/Handler/CodeActions/CodeActionHelpers.cs @@ -197,7 +197,7 @@ private static void AddLSPCodeActions( { CommandIdentifier = CodeActionsHandler.RunFixAllCodeActionCommandName, Title = fixAllTitle, - Arguments = [new CodeActionResolveData(fixAllTitle, codeAction.CustomTags, request.Range, request.TextDocument, codeActionPath, fixAllFlavors.ToArray(), nestedCodeActions: null)] + Arguments = [new CodeActionResolveData(fixAllTitle, codeAction.CustomTags, request.Range, request.TextDocument, codeActionPath, [.. fixAllFlavors], nestedCodeActions: null)] }; builder.Add(new LSP.CodeAction @@ -206,7 +206,7 @@ private static void AddLSPCodeActions( Command = command, Kind = codeActionKind, Diagnostics = diagnosticsForFix, - Data = new CodeActionResolveData(fixAllTitle, codeAction.CustomTags, request.Range, request.TextDocument, codeActionPath, fixAllFlavors.ToArray(), nestedCodeActions: null) + Data = new CodeActionResolveData(fixAllTitle, codeAction.CustomTags, request.Range, request.TextDocument, codeActionPath, [.. fixAllFlavors], nestedCodeActions: null) }); } } diff --git a/src/LanguageServer/Protocol/Handler/Completion/CompletionResultFactory.cs b/src/LanguageServer/Protocol/Handler/Completion/CompletionResultFactory.cs index a01923c0fe5f9..ae0bf6c7d66df 100644 --- a/src/LanguageServer/Protocol/Handler/Completion/CompletionResultFactory.cs +++ b/src/LanguageServer/Protocol/Handler/Completion/CompletionResultFactory.cs @@ -420,7 +420,7 @@ public static string[] CreateCommitCharacterArrayFromRules(CompletionItemRules r } } - return commitCharacters.Select(c => c.ToString()).ToArray(); + return [.. commitCharacters.Select(c => c.ToString())]; } private sealed class CommitCharacterArrayComparer : IEqualityComparer> diff --git a/src/LanguageServer/Protocol/Handler/Configuration/DidChangeConfigurationNotificationHandler_OptionList.cs b/src/LanguageServer/Protocol/Handler/Configuration/DidChangeConfigurationNotificationHandler_OptionList.cs index a6402a1305666..b8d9b8b310d01 100644 --- a/src/LanguageServer/Protocol/Handler/Configuration/DidChangeConfigurationNotificationHandler_OptionList.cs +++ b/src/LanguageServer/Protocol/Handler/Configuration/DidChangeConfigurationNotificationHandler_OptionList.cs @@ -54,6 +54,7 @@ internal partial class DidChangeConfigurationNotificationHandler SolutionCrawlerOptionsStorage.CompilerDiagnosticsScopeOption, LspOptionsStorage.LspEnableReferencesCodeLens, LspOptionsStorage.LspEnableTestsCodeLens, + LspOptionsStorage.LspEnableAutoInsert, LanguageServerProjectSystemOptionsStorage.BinaryLogPath, LanguageServerProjectSystemOptionsStorage.EnableAutomaticRestore, MetadataAsSourceOptionsStorage.NavigateToSourceLinkAndEmbeddedSources, diff --git a/src/LanguageServer/Protocol/Handler/DataTips/DataTipRangeHandler.cs b/src/LanguageServer/Protocol/Handler/DataTips/DataTipRangeHandler.cs new file mode 100644 index 0000000000000..e7627bb00bec8 --- /dev/null +++ b/src/LanguageServer/Protocol/Handler/DataTips/DataTipRangeHandler.cs @@ -0,0 +1,49 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Composition; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Debugging; +using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.CodeAnalysis.Shared.Extensions; +using Roslyn.LanguageServer.Protocol; + +namespace Microsoft.CodeAnalysis.LanguageServer.Handler; + +[ExportCSharpVisualBasicStatelessLspService(typeof(DataTipRangeHandler)), Shared] +[Method(VSInternalMethods.TextDocumentDataTipRangeName)] +[method: ImportingConstructor] +[method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] +internal sealed class DataTipRangeHandler() + : ILspServiceDocumentRequestHandler +{ + public bool MutatesSolutionState => false; + public bool RequiresLSPSolution => true; + + public TextDocumentIdentifier GetTextDocumentIdentifier(TextDocumentPositionParams request) + => request.TextDocument; + + public async Task HandleRequestAsync(TextDocumentPositionParams request, RequestContext context, CancellationToken cancellationToken) + { + var document = context.GetRequiredDocument(); + + var service = document.GetRequiredLanguageService(); + + var text = await document.GetValueTextAsync(cancellationToken).ConfigureAwait(false); + var linePosition = ProtocolConversions.PositionToLinePosition(request.Position); + var position = text.Lines.GetPosition(linePosition); + var info = await service.GetDataTipInfoAsync(document, position, includeKind: true, cancellationToken).ConfigureAwait(false); + if (info.IsDefault) + return null; + + return new VSInternalDataTip + { + DataTipTags = info.Kind == DebugDataTipInfoKind.LinqExpression ? VSInternalDataTipTags.LinqExpression : 0, + HoverRange = ProtocolConversions.TextSpanToRange(info.Span, text), + ExpressionRange = ProtocolConversions.TextSpanToRange(info.ExpressionSpan, text), + }; + } +} diff --git a/src/LanguageServer/Protocol/Handler/Definitions/AbstractGoToDefinitionHandler.cs b/src/LanguageServer/Protocol/Handler/Definitions/AbstractGoToDefinitionHandler.cs index 1e20de1c0703c..a0c753ff3ff9d 100644 --- a/src/LanguageServer/Protocol/Handler/Definitions/AbstractGoToDefinitionHandler.cs +++ b/src/LanguageServer/Protocol/Handler/Definitions/AbstractGoToDefinitionHandler.cs @@ -75,7 +75,8 @@ await definition.Document.GetRequiredDocumentAsync(document.Project.Solution, ca else if (document.SupportsSemanticModel && metadataAsSourceFileService != null) { // No definition found - see if we can get metadata as source but that's only applicable for C#\VB. - var symbol = await SymbolFinder.FindSymbolAtPositionAsync(document, position, cancellationToken).ConfigureAwait(false); + var semanticModel = await document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false); + var symbol = await SymbolFinder.FindSymbolAtPositionAsync(semanticModel, position, document.Project.Solution.Services, includeType: true, cancellationToken).ConfigureAwait(false); if (forSymbolType) symbol = symbol?.GetSymbolType(); diff --git a/src/LanguageServer/Protocol/Handler/Diagnostics/DiagnosticSourceProviders/DiagnosticSourceManager.cs b/src/LanguageServer/Protocol/Handler/Diagnostics/DiagnosticSourceProviders/DiagnosticSourceManager.cs index 2af9fa8710706..633f20dd6014e 100644 --- a/src/LanguageServer/Protocol/Handler/Diagnostics/DiagnosticSourceProviders/DiagnosticSourceManager.cs +++ b/src/LanguageServer/Protocol/Handler/Diagnostics/DiagnosticSourceProviders/DiagnosticSourceManager.cs @@ -115,9 +115,7 @@ public static ImmutableArray AggregateSourcesIfNeeded(Immutab // will have same value for GetDocumentIdentifier and GetProject(). Thus can be // aggregated in a single source which will return same values. See // AggregatedDocumentDiagnosticSource implementation for more details. - sources = sources.GroupBy(s => (s.GetId(), s.IsLiveSource()), s => s) - .SelectMany(g => AggregatedDocumentDiagnosticSource.AggregateIfNeeded(g)) - .ToImmutableArray(); + sources = [.. sources.GroupBy(s => (s.GetId(), s.IsLiveSource()), s => s).SelectMany(g => AggregatedDocumentDiagnosticSource.AggregateIfNeeded(g))]; } return sources; diff --git a/src/LanguageServer/Protocol/Handler/Diagnostics/DiagnosticSources/AbstractWorkspaceDocumentDiagnosticSource.cs b/src/LanguageServer/Protocol/Handler/Diagnostics/DiagnosticSources/AbstractWorkspaceDocumentDiagnosticSource.cs index e4712010ac803..8d65f234de69b 100644 --- a/src/LanguageServer/Protocol/Handler/Diagnostics/DiagnosticSources/AbstractWorkspaceDocumentDiagnosticSource.cs +++ b/src/LanguageServer/Protocol/Handler/Diagnostics/DiagnosticSources/AbstractWorkspaceDocumentDiagnosticSource.cs @@ -64,7 +64,7 @@ private async ValueTask> GetProjectDiagnosticsAsy } var result = await lazyDiagnostics.GetValueAsync(cancellationToken).ConfigureAwait(false); - return result[Document.Id].ToImmutableArray(); + return [.. result[Document.Id]]; AsyncLazy> GetLazyDiagnostics() { diff --git a/src/LanguageServer/Protocol/Handler/Diagnostics/Public/PublicWorkspacePullDiagnosticsHandler.cs b/src/LanguageServer/Protocol/Handler/Diagnostics/Public/PublicWorkspacePullDiagnosticsHandler.cs index abd295573170c..8b375e0059b3e 100644 --- a/src/LanguageServer/Protocol/Handler/Diagnostics/Public/PublicWorkspacePullDiagnosticsHandler.cs +++ b/src/LanguageServer/Protocol/Handler/Diagnostics/Public/PublicWorkspacePullDiagnosticsHandler.cs @@ -82,7 +82,7 @@ protected override bool TryCreateUnchangedReport(TextDocumentIdentifier identifi return new WorkspaceDiagnosticReport { Items = progressValues != null - ? progressValues.SelectMany(report => report.Match(r => r.Items, partial => partial.Items)).ToArray() + ? [.. progressValues.SelectMany(report => report.Match(r => r.Items, partial => partial.Items))] : [], }; } diff --git a/src/LanguageServer/Protocol/Handler/Formatting/AbstractFormatDocumentHandlerBase.cs b/src/LanguageServer/Protocol/Handler/Formatting/AbstractFormatDocumentHandlerBase.cs index 331c3971595bf..3281cc74471b6 100644 --- a/src/LanguageServer/Protocol/Handler/Formatting/AbstractFormatDocumentHandlerBase.cs +++ b/src/LanguageServer/Protocol/Handler/Formatting/AbstractFormatDocumentHandlerBase.cs @@ -41,10 +41,7 @@ internal abstract class AbstractFormatDocumentHandlerBase.GetInstance(out var edits); - edits.AddRange(textChanges.Select(change => ProtocolConversions.TextChangeToTextEdit(change, text))); - return edits.ToArray(); + return [.. textChanges.Select(change => ProtocolConversions.TextChangeToTextEdit(change, text))]; } public abstract LSP.TextDocumentIdentifier GetTextDocumentIdentifier(RequestType request); diff --git a/src/LanguageServer/Protocol/Handler/Formatting/FormatDocumentOnTypeHandler.cs b/src/LanguageServer/Protocol/Handler/Formatting/FormatDocumentOnTypeHandler.cs index 87efbd4a7a72c..e6e6df6215855 100644 --- a/src/LanguageServer/Protocol/Handler/Formatting/FormatDocumentOnTypeHandler.cs +++ b/src/LanguageServer/Protocol/Handler/Formatting/FormatDocumentOnTypeHandler.cs @@ -72,9 +72,7 @@ public FormatDocumentOnTypeHandler(IGlobalOptionService globalOptions) return []; } - using var _ = ArrayBuilder.GetInstance(out var edits); - edits.AddRange(textChanges.Select(change => ProtocolConversions.TextChangeToTextEdit(change, documentSyntax.Text))); - return edits.ToArray(); + return [.. textChanges.Select(change => ProtocolConversions.TextChangeToTextEdit(change, documentSyntax.Text))]; } } } diff --git a/src/LanguageServer/Protocol/Handler/InlineCompletions/InlineCompletionsHandler.cs b/src/LanguageServer/Protocol/Handler/InlineCompletions/InlineCompletionsHandler.cs index 4c10603b4f061..dd3349b39c65f 100644 --- a/src/LanguageServer/Protocol/Handler/InlineCompletions/InlineCompletionsHandler.cs +++ b/src/LanguageServer/Protocol/Handler/InlineCompletions/InlineCompletionsHandler.cs @@ -19,8 +19,10 @@ using Microsoft.CodeAnalysis.Simplification; using Microsoft.CodeAnalysis.Snippets; using Microsoft.CodeAnalysis.Text; +using Microsoft.CommonLanguageServerProtocol.Framework; using Roslyn.LanguageServer.Protocol; using Roslyn.Utilities; +using LSP = Roslyn.LanguageServer.Protocol; using static Microsoft.CodeAnalysis.LanguageServer.Handler.InlineCompletions.XmlSnippetParser; namespace Microsoft.CodeAnalysis.LanguageServer.Handler.InlineCompletions; @@ -102,7 +104,19 @@ public TextDocumentIdentifier GetTextDocumentIdentifier(VSInternalInlineCompleti public async Task HandleRequestAsync(VSInternalInlineCompletionRequest request, RequestContext context, CancellationToken cancellationToken) { var document = context.GetRequiredDocument(); + var linePosition = ProtocolConversions.PositionToLinePosition(request.Position); + var item = await GetInlineCompletionItemsAsync(context.Logger, document, linePosition, request.Options, _xmlSnippetParser, cancellationToken).ConfigureAwait(false); + + if (item is null) + { + return null; + } + return new VSInternalInlineCompletionList { Items = [item] }; + } + + internal static async Task GetInlineCompletionItemsAsync(ILspLogger logger, Document document, LinePosition linePosition, LSP.FormattingOptions options, XmlSnippetParser xmlSnippetParser, CancellationToken cancellationToken) + { // First get available snippets if any. var snippetInfoService = document.Project.GetRequiredLanguageService(); var snippetInfo = snippetInfoService.GetSnippetsIfAvailable(); @@ -114,7 +128,6 @@ public TextDocumentIdentifier GetTextDocumentIdentifier(VSInternalInlineCompleti // Then attempt to get the word at the requested position. var sourceText = await document.GetValueTextAsync(cancellationToken).ConfigureAwait(false); var syntaxFactsService = document.Project.GetRequiredLanguageService(); - var linePosition = ProtocolConversions.PositionToLinePosition(request.Position); var position = sourceText.Lines.GetPosition(linePosition); if (!SnippetUtilities.TryGetWordOnLeft(position, sourceText, syntaxFactsService, out var wordOnLeft)) { @@ -130,29 +143,23 @@ public TextDocumentIdentifier GetTextDocumentIdentifier(VSInternalInlineCompleti var matchingSnippetInfo = snippetInfo.First(s => wordText.Equals(s.Shortcut, StringComparison.OrdinalIgnoreCase)); - var parsedSnippet = _xmlSnippetParser.GetParsedXmlSnippet(matchingSnippetInfo, context); + var parsedSnippet = xmlSnippetParser.GetParsedXmlSnippet(matchingSnippetInfo, logger); if (parsedSnippet == null) { return null; } // Use the formatting options specified by the client to format the snippet. - var formattingOptions = await ProtocolConversions.GetFormattingOptionsAsync(request.Options, document, cancellationToken).ConfigureAwait(false); + var formattingOptions = await ProtocolConversions.GetFormattingOptionsAsync(options, document, cancellationToken).ConfigureAwait(false); var simplifierOptions = await document.GetSimplifierOptionsAsync(cancellationToken).ConfigureAwait(false); var formattedLspSnippet = await GetFormattedLspSnippetAsync(parsedSnippet, wordOnLeft.Value, document, sourceText, formattingOptions, simplifierOptions, cancellationToken).ConfigureAwait(false); - return new VSInternalInlineCompletionList + return new VSInternalInlineCompletionItem { - Items = - [ - new VSInternalInlineCompletionItem - { - Range = ProtocolConversions.TextSpanToRange(wordOnLeft.Value, sourceText), - Text = formattedLspSnippet, - TextFormat = InsertTextFormat.Snippet, - } - ] + Range = ProtocolConversions.TextSpanToRange(wordOnLeft.Value, sourceText), + Text = formattedLspSnippet, + TextFormat = InsertTextFormat.Snippet, }; } diff --git a/src/LanguageServer/Protocol/Handler/InlineCompletions/XmlSnippetParser.CodeSnippet.cs b/src/LanguageServer/Protocol/Handler/InlineCompletions/XmlSnippetParser.CodeSnippet.cs index 38b3e105eca70..823f45f8263d9 100644 --- a/src/LanguageServer/Protocol/Handler/InlineCompletions/XmlSnippetParser.CodeSnippet.cs +++ b/src/LanguageServer/Protocol/Handler/InlineCompletions/XmlSnippetParser.CodeSnippet.cs @@ -45,7 +45,7 @@ public CodeSnippet(XElement codeSnippetElement) var snippetTypes = GetElementsWithoutNamespace(header, "SnippetTypes"); if (snippetTypes != null) { - _snippetTypes = snippetTypes.Elements().Select(e => e.Value.Trim()).ToArray(); + _snippetTypes = [.. snippetTypes.Elements().Select(e => e.Value.Trim())]; } } diff --git a/src/LanguageServer/Protocol/Handler/InlineCompletions/XmlSnippetParser.cs b/src/LanguageServer/Protocol/Handler/InlineCompletions/XmlSnippetParser.cs index e7e444888012b..ed5b3cd09dbde 100644 --- a/src/LanguageServer/Protocol/Handler/InlineCompletions/XmlSnippetParser.cs +++ b/src/LanguageServer/Protocol/Handler/InlineCompletions/XmlSnippetParser.cs @@ -9,6 +9,7 @@ using Microsoft.CodeAnalysis.ErrorReporting; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Snippets; +using Microsoft.CommonLanguageServerProtocol.Framework; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.LanguageServer.Handler.InlineCompletions; @@ -32,13 +33,13 @@ public XmlSnippetParser() { } - internal ParsedXmlSnippet? GetParsedXmlSnippet(SnippetInfo matchingSnippetInfo, RequestContext context) + internal ParsedXmlSnippet? GetParsedXmlSnippet(SnippetInfo matchingSnippetInfo, ILspLogger logger) { if (_parsedSnippetsCache.TryGetValue(matchingSnippetInfo.Title, out var cachedSnippet)) { if (cachedSnippet == null) { - context.TraceWarning($"Returning a null cached snippet for {matchingSnippetInfo.Title}"); + logger.LogWarning($"Returning a null cached snippet for {matchingSnippetInfo.Title}"); } return cachedSnippet; @@ -47,13 +48,13 @@ public XmlSnippetParser() ParsedXmlSnippet? parsedSnippet = null; try { - context.TraceInformation($"Reading snippet for {matchingSnippetInfo.Title} with path {matchingSnippetInfo.Path}"); + logger.LogInformation($"Reading snippet for {matchingSnippetInfo.Title} with path {matchingSnippetInfo.Path}"); parsedSnippet = GetAndParseSnippetFromFile(matchingSnippetInfo); } catch (Exception ex) when (FatalError.ReportAndCatch(ex, ErrorSeverity.General)) { - context.TraceError($"Got exception parsing xml snippet {matchingSnippetInfo.Title} from file {matchingSnippetInfo.Path}"); - context.TraceException(ex); + logger.LogError($"Got exception parsing xml snippet {matchingSnippetInfo.Title} from file {matchingSnippetInfo.Path}"); + logger.LogException(ex); } // Add the snippet to the cache regardless of if we succeeded in parsing it. diff --git a/src/LanguageServer/Protocol/Handler/MapCode/MapCodeHandler.cs b/src/LanguageServer/Protocol/Handler/MapCode/MapCodeHandler.cs index 59279fcf4a48a..a404c848ff4ec 100644 --- a/src/LanguageServer/Protocol/Handler/MapCode/MapCodeHandler.cs +++ b/src/LanguageServer/Protocol/Handler/MapCode/MapCodeHandler.cs @@ -65,7 +65,7 @@ public MapCodeHandler() DocumentChanges = uriToEditsMap.Select(kvp => new TextDocumentEdit { TextDocument = new OptionalVersionedTextDocumentIdentifier { Uri = kvp.Key }, - Edits = kvp.Value.Select(v => new SumType(v)).ToArray(), + Edits = [.. kvp.Value.Select(v => new SumType(v))], }).ToArray() }; } diff --git a/src/LanguageServer/Protocol/Handler/OnAutoInsert/OnAutoInsertHandler.cs b/src/LanguageServer/Protocol/Handler/OnAutoInsert/OnAutoInsertHandler.cs index cc6c5cd737189..eaedf3586b005 100644 --- a/src/LanguageServer/Protocol/Handler/OnAutoInsert/OnAutoInsertHandler.cs +++ b/src/LanguageServer/Protocol/Handler/OnAutoInsert/OnAutoInsertHandler.cs @@ -33,7 +33,7 @@ internal sealed class OnAutoInsertHandler( [ImportMany] IEnumerable> braceCompletionServices, IGlobalOptionService globalOptions) : ILspServiceDocumentRequestHandler { - private readonly ImmutableArray> _braceCompletionServices = braceCompletionServices.ToImmutableArray(); + private readonly ImmutableArray> _braceCompletionServices = [.. braceCompletionServices]; private readonly IGlobalOptionService _globalOptions = globalOptions; public bool MutatesSolutionState => false; @@ -50,6 +50,10 @@ internal sealed class OnAutoInsertHandler( if (document == null) return SpecializedTasks.Null(); + var onAutoInsertEnabled = _globalOptions.GetOption(LspOptionsStorage.LspEnableAutoInsert, document.Project.Language); + if (!onAutoInsertEnabled) + return SpecializedTasks.Null(); + var servicesForDocument = _braceCompletionServices.Where(s => s.Metadata.Language == document.Project.Language).SelectAsArray(s => s.Value); var isRazorRequest = context.ServerKind == WellKnownLspServerKinds.RazorLspServer; var position = ProtocolConversions.PositionToLinePosition(request.Position); diff --git a/src/LanguageServer/Protocol/Handler/References/FindAllReferencesHandler.cs b/src/LanguageServer/Protocol/Handler/References/FindAllReferencesHandler.cs index c97d512ca5a42..20a1c131bfcea 100644 --- a/src/LanguageServer/Protocol/Handler/References/FindAllReferencesHandler.cs +++ b/src/LanguageServer/Protocol/Handler/References/FindAllReferencesHandler.cs @@ -14,6 +14,7 @@ using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.TestHooks; +using Microsoft.CodeAnalysis.Text; using Roslyn.LanguageServer.Protocol; using Roslyn.Utilities; using LSP = Roslyn.LanguageServer.Protocol; @@ -45,7 +46,7 @@ public FindAllReferencesHandler( public TextDocumentIdentifier GetTextDocumentIdentifier(VSInternalReferenceParams request) => request.TextDocument; - public async Task[]?> HandleRequestAsync( + public async Task[]?> HandleRequestAsync( VSInternalReferenceParams referenceParams, RequestContext context, CancellationToken cancellationToken) @@ -55,23 +56,37 @@ public FindAllReferencesHandler( Contract.ThrowIfNull(document); Contract.ThrowIfNull(workspace); + var linePosition = ProtocolConversions.PositionToLinePosition(referenceParams.Position); + var clientCapabilities = context.GetRequiredClientCapabilities(); + using var progress = BufferedProgress.Create(referenceParams.PartialResultToken); - var findUsagesService = document.GetRequiredLanguageService(); - var position = await document.GetPositionFromLinePositionAsync( - ProtocolConversions.PositionToLinePosition(referenceParams.Position), cancellationToken).ConfigureAwait(false); + await FindReferencesAsync(progress, workspace, document, linePosition, clientCapabilities.HasVisualStudioLspCapability(), _globalOptions, _metadataAsSourceFileService, _asyncListener, cancellationToken).ConfigureAwait(false); - var clientCapabilities = context.GetRequiredClientCapabilities(); + return progress.GetFlattenedValues(); + } + + internal static async Task FindReferencesAsync( + IProgress[]> progress, + Workspace workspace, + Document document, + LinePosition linePosition, + bool supportsVSExtensions, + IGlobalOptionService globalOptions, + IMetadataAsSourceFileService metadataAsSourceFileService, + IAsynchronousOperationListener asyncListener, + CancellationToken cancellationToken) + { + var findUsagesService = document.GetRequiredLanguageService(); + var position = await document.GetPositionFromLinePositionAsync(linePosition, cancellationToken).ConfigureAwait(false); var findUsagesContext = new FindUsagesLSPContext( - progress, workspace, document, position, _metadataAsSourceFileService, _asyncListener, _globalOptions, clientCapabilities, cancellationToken); + progress, workspace, document, position, metadataAsSourceFileService, asyncListener, globalOptions, supportsVSExtensions, cancellationToken); // Finds the references for the symbol at the specific position in the document, reporting them via streaming to the LSP client. - var classificationOptions = _globalOptions.GetClassificationOptionsProvider(); + var classificationOptions = globalOptions.GetClassificationOptionsProvider(); await findUsagesService.FindReferencesAsync(findUsagesContext, document, position, classificationOptions, cancellationToken).ConfigureAwait(false); await findUsagesContext.OnCompletedAsync(cancellationToken).ConfigureAwait(false); - - return progress.GetFlattenedValues(); } } } diff --git a/src/LanguageServer/Protocol/Handler/References/FindUsagesLSPContext.cs b/src/LanguageServer/Protocol/Handler/References/FindUsagesLSPContext.cs index eb6ae129e6aff..4196abef13bbe 100644 --- a/src/LanguageServer/Protocol/Handler/References/FindUsagesLSPContext.cs +++ b/src/LanguageServer/Protocol/Handler/References/FindUsagesLSPContext.cs @@ -80,7 +80,7 @@ public FindUsagesLSPContext( IMetadataAsSourceFileService metadataAsSourceFileService, IAsynchronousOperationListener asyncListener, IGlobalOptionService globalOptions, - ClientCapabilities clientCapabilities, + bool supportsVSExtensions, CancellationToken cancellationToken) { _progress = progress; @@ -89,7 +89,7 @@ public FindUsagesLSPContext( _position = position; _metadataAsSourceFileService = metadataAsSourceFileService; _globalOptions = globalOptions; - _supportsVSExtensions = clientCapabilities.HasVisualStudioLspCapability(); + _supportsVSExtensions = supportsVSExtensions; _workQueue = new AsyncBatchingWorkQueue>( DelayTimeSpan.Medium, ReportReferencesAsync, asyncListener, cancellationToken); } diff --git a/src/LanguageServer/Protocol/Handler/RelatedDocuments/RelatedDocumentsHandler.cs b/src/LanguageServer/Protocol/Handler/RelatedDocuments/RelatedDocumentsHandler.cs index f30fe7ad72219..513be4762d6fc 100644 --- a/src/LanguageServer/Protocol/Handler/RelatedDocuments/RelatedDocumentsHandler.cs +++ b/src/LanguageServer/Protocol/Handler/RelatedDocuments/RelatedDocumentsHandler.cs @@ -76,7 +76,7 @@ await relatedDocumentsService.GetRelatedDocumentIdsAsync( // progress reporter. progress.Report(new VSInternalRelatedDocumentReport { - FilePaths = relatedDocumentIds.Select(id => solution.GetRequiredDocument(id).FilePath).WhereNotNull().ToArray(), + FilePaths = [.. relatedDocumentIds.Select(id => solution.GetRequiredDocument(id).FilePath).WhereNotNull()], }); return ValueTaskFactory.CompletedTask; diff --git a/src/LanguageServer/Protocol/Handler/RequestContext.cs b/src/LanguageServer/Protocol/Handler/RequestContext.cs index a9426705cc246..f7169785d6951 100644 --- a/src/LanguageServer/Protocol/Handler/RequestContext.cs +++ b/src/LanguageServer/Protocol/Handler/RequestContext.cs @@ -55,6 +55,8 @@ internal readonly struct RequestContext /// private readonly StrongBox<(Workspace Workspace, Solution Solution, TextDocument? Document)>? _lspSolution; + public ILspLogger Logger => _logger; + /// /// The workspace this request is for, if applicable. This will be present if is /// present. It will be if requiresLSPSolution is false. diff --git a/src/LanguageServer/Protocol/Handler/SemanticTokens/SemanticTokensHelpers.cs b/src/LanguageServer/Protocol/Handler/SemanticTokens/SemanticTokensHelpers.cs index c843c239128ee..f291526b0e130 100644 --- a/src/LanguageServer/Protocol/Handler/SemanticTokens/SemanticTokensHelpers.cs +++ b/src/LanguageServer/Protocol/Handler/SemanticTokens/SemanticTokensHelpers.cs @@ -266,7 +266,7 @@ private static int[] ComputeTokens( data.Add(tokenModifiers); } - return data.ToArray(); + return [.. data]; } private static int ComputeNextToken( diff --git a/src/LanguageServer/Protocol/Handler/SignatureHelp/SignatureHelpHandler.cs b/src/LanguageServer/Protocol/Handler/SignatureHelp/SignatureHelpHandler.cs index 055fba092cd05..6a83ee35172d7 100644 --- a/src/LanguageServer/Protocol/Handler/SignatureHelp/SignatureHelpHandler.cs +++ b/src/LanguageServer/Protocol/Handler/SignatureHelp/SignatureHelpHandler.cs @@ -69,11 +69,11 @@ internal class SignatureHelpHandler(SignatureHelpService signatureHelpService) : sigInfo.Label = GetSignatureText(item); sigInfo.Documentation = new LSP.MarkupContent { Kind = LSP.MarkupKind.PlainText, Value = item.DocumentationFactory(cancellationToken).GetFullText() }; - sigInfo.Parameters = item.Parameters.Select(p => new LSP.ParameterInformation + sigInfo.Parameters = [.. item.Parameters.Select(p => new LSP.ParameterInformation { Label = p.Name, Documentation = new LSP.MarkupContent { Kind = LSP.MarkupKind.PlainText, Value = p.DocumentationFactory(cancellationToken).GetFullText() } - }).ToArray(); + })]; sigInfos.Add(sigInfo); } diff --git a/src/LanguageServer/Protocol/Handler/SourceGenerators/SourceGeneratorRefreshQueue.cs b/src/LanguageServer/Protocol/Handler/SourceGenerators/SourceGeneratorRefreshQueue.cs index e88c75b25ae9c..f1e315fc18004 100644 --- a/src/LanguageServer/Protocol/Handler/SourceGenerators/SourceGeneratorRefreshQueue.cs +++ b/src/LanguageServer/Protocol/Handler/SourceGenerators/SourceGeneratorRefreshQueue.cs @@ -79,22 +79,26 @@ private async Task OnLspSolutionChangedAsync(WorkspaceChangeEventArgs e) // source generators possibly changed. Note that this overreports actual // changes to the source generated text; we rely on resultIds in the text retrieval to avoid unnecessary serialization. - // Trivial check. see if the SG version of these projects changed. If so, we definitely want to update - // this generated file. - if (e.OldSolution.GetSourceGeneratorExecutionVersion(projectId) != - e.NewSolution.GetSourceGeneratorExecutionVersion(projectId)) + var oldProject = e.OldSolution.GetProject(projectId); + var newProject = e.NewSolution.GetProject(projectId); + + // If the project has been added/removed, we need to update the generated files. + if (oldProject is null || newProject is null) { _refreshQueue.AddWork(); return; } - var oldProject = e.OldSolution.GetProject(projectId); - var newProject = e.NewSolution.GetProject(projectId); - - if (oldProject != null && newProject != null) + // Trivial check. see if the SG version of these projects changed. If so, we definitely want to update generated files. + if (e.OldSolution.GetSourceGeneratorExecutionVersion(projectId) != + e.NewSolution.GetSourceGeneratorExecutionVersion(projectId)) { - await CheckDependentVersionsAsync(oldProject, newProject).ConfigureAwait(false); + _refreshQueue.AddWork(); + return; } + + // More expensive check - see if the dependent versions are different. + await CheckDependentVersionsAsync(oldProject, newProject).ConfigureAwait(false); } else { diff --git a/src/LanguageServer/Protocol/LspOptionsStorage.cs b/src/LanguageServer/Protocol/LspOptionsStorage.cs index 0dde83ac8fb59..9addbcb9d63ca 100644 --- a/src/LanguageServer/Protocol/LspOptionsStorage.cs +++ b/src/LanguageServer/Protocol/LspOptionsStorage.cs @@ -32,6 +32,8 @@ internal sealed class LspOptionsStorage private static readonly OptionGroup s_codeLensOptionGroup = new(name: "code_lens", description: ""); + private static readonly OptionGroup s_autoInsertOptionGroup = new(name: "auto_insert", description: ""); + /// /// Flag indicating whether or not references should be returned in LSP codelens. /// @@ -41,5 +43,10 @@ internal sealed class LspOptionsStorage /// Flag indicating whether or not test and debug code lens items should be returned. /// public static readonly PerLanguageOption2 LspEnableTestsCodeLens = new("dotnet_enable_tests_code_lens", defaultValue: true, group: s_codeLensOptionGroup); + + /// + /// Flag indicating whether or not auto-insert should be abled by default in LSP. + /// + public static readonly PerLanguageOption2 LspEnableAutoInsert = new("dotnet_enable_auto_insert", defaultValue: true, group: s_autoInsertOptionGroup); } } diff --git a/src/LanguageServer/Protocol/LspServices/AbstractLspServiceProvider.cs b/src/LanguageServer/Protocol/LspServices/AbstractLspServiceProvider.cs index e626ca8cf8f1f..433505c395690 100644 --- a/src/LanguageServer/Protocol/LspServices/AbstractLspServiceProvider.cs +++ b/src/LanguageServer/Protocol/LspServices/AbstractLspServiceProvider.cs @@ -18,8 +18,8 @@ public AbstractLspServiceProvider( IEnumerable> specificLspServices, IEnumerable> specificLspServiceFactories) { - _lspServices = specificLspServices.ToImmutableArray(); - _lspServiceFactories = specificLspServiceFactories.ToImmutableArray(); + _lspServices = [.. specificLspServices]; + _lspServiceFactories = [.. specificLspServiceFactories]; } public LspServices CreateServices(WellKnownLspServerKinds serverKind, FrozenDictionary> baseServices) diff --git a/src/LanguageServer/Protocol/Protocol/Internal/VSInternalDataTips.cs b/src/LanguageServer/Protocol/Protocol/Internal/VSInternalDataTips.cs new file mode 100644 index 0000000000000..cddf349772e96 --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/Internal/VSInternalDataTips.cs @@ -0,0 +1,47 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Runtime.Serialization; +using System.Text.Json.Serialization; + +namespace Roslyn.LanguageServer.Protocol; + +/// +/// DataTip tag enum. +/// +[Flags] +internal enum VSInternalDataTipTags +{ + /// + /// Data tip range is a linq expression. + /// + LinqExpression = 0x1, +} + +/// +/// Class which represents debugger data tip response. +/// +internal sealed record VSInternalDataTip +{ + /// + /// Gets or sets the value which indicates the applicable hover range within the document. + /// + [JsonPropertyName("_vs_hoverRange")] + public Range HoverRange { get; init; } + + /// + /// Gets or sets the value which indicates the expression's range within the document. + /// + [JsonPropertyName("_vs_expressionRange")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public Range? ExpressionRange { get; init; } + + /// + /// Gets or sets the for the data tip. + /// + [JsonPropertyName("_vs_dataTipTags")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public VSInternalDataTipTags DataTipTags { get; init; } +} diff --git a/src/LanguageServer/Protocol/Protocol/Internal/VSInternalMethods.cs b/src/LanguageServer/Protocol/Protocol/Internal/VSInternalMethods.cs index 1be519d95de57..6891d629a975b 100644 --- a/src/LanguageServer/Protocol/Protocol/Internal/VSInternalMethods.cs +++ b/src/LanguageServer/Protocol/Protocol/Internal/VSInternalMethods.cs @@ -9,75 +9,21 @@ namespace Roslyn.LanguageServer.Protocol /// internal static class VSInternalMethods { - /// - /// Method name for 'copilot/_related_documents'. - /// public const string CopilotRelatedDocumentsName = "copilot/_related_documents"; - - /// - /// Method name for 'textDocument/foldingRange/_vs_refresh'. - /// public const string DocumentFoldingRangeRefreshName = "textDocument/foldingRange/_vs_refresh"; - - /// - /// Method name for 'textDocument/_vs_references'. - /// + public const string DocumentPullDiagnosticName = "textdocument/_vs_diagnostic"; public const string DocumentReferencesName = "textDocument/_vs_references"; - - /// - /// Method name for 'textDocument/_vs_onAutoInsert'. - /// public const string OnAutoInsertName = "textDocument/_vs_onAutoInsert"; - - /// - /// Method name for 'textDocument/_vs_iconMappingResolve'. - /// + public const string TextDocumentDataTipRangeName = "textdocument/_vs_dataTipRange"; public const string TextDocumentIconMappingResolveName = "textDocument/_vs_iconMappingResolve"; - - /// - /// Method name for 'textdocument/_vs_diagnostic'. - /// - public const string DocumentPullDiagnosticName = "textdocument/_vs_diagnostic"; - - /// - /// Method name for 'workspace/_vs_diagnostic'. - /// - public const string WorkspacePullDiagnosticName = "workspace/_vs_diagnostic"; - - /// - /// Method name for 'textDocument/_vs_validateBreakableRange'. - /// - public const string TextDocumentValidateBreakableRangeName = "textDocument/_vs_validateBreakableRange"; - - /// - /// Method name for 'textDocument/_vs_inlineCompletion'. - /// public const string TextDocumentInlineCompletionName = "textDocument/_vs_inlineCompletion"; - - /// - /// Method name for 'textDocument/_vs_spellCheckableRanges'. - /// public const string TextDocumentSpellCheckableRangesName = "textDocument/_vs_spellCheckableRanges"; - - /// - /// Method name for 'textDocument/_vs_uriPresentation'. - /// - public const string TextDocumentUriPresentationName = "textDocument/_vs_uriPresentation"; - - /// - /// Method name for 'textDocument/_vs_textPresentation'. - /// public const string TextDocumentTextPresentationName = "textDocument/_vs_textPresentation"; - - /// - /// Method name for 'workspace/_vs_spellCheckableRanges'. - /// - public const string WorkspaceSpellCheckableRangesName = "workspace/_vs_spellCheckableRanges"; - - /// - /// Method name for 'workspace/_vs_mapCode'. - /// + public const string TextDocumentUriPresentationName = "textDocument/_vs_uriPresentation"; + public const string TextDocumentValidateBreakableRangeName = "textDocument/_vs_validateBreakableRange"; public const string WorkspaceMapCodeName = "workspace/_vs_mapCode"; + public const string WorkspacePullDiagnosticName = "workspace/_vs_diagnostic"; + public const string WorkspaceSpellCheckableRangesName = "workspace/_vs_spellCheckableRanges"; /// /// Strongly typed message object for 'textDocument/_vs_onAutoInsert'. diff --git a/src/LanguageServer/Protocol/Protocol/Internal/VSInternalServerCapabilities.cs b/src/LanguageServer/Protocol/Protocol/Internal/VSInternalServerCapabilities.cs index b0c441bcd1a93..667651ed7b104 100644 --- a/src/LanguageServer/Protocol/Protocol/Internal/VSInternalServerCapabilities.cs +++ b/src/LanguageServer/Protocol/Protocol/Internal/VSInternalServerCapabilities.cs @@ -2,163 +2,170 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -namespace Roslyn.LanguageServer.Protocol +using System.Text.Json.Serialization; + +namespace Roslyn.LanguageServer.Protocol; + +/// +/// Extension class for ServerCapabilities with fields specific to Visual Studio. +/// +internal class VSInternalServerCapabilities : VSServerCapabilities { - using System.Text.Json.Serialization; + /// + /// Gets or sets a value indicating whether or not GoTo's integration with + /// 'workspace/symbol' and the deprecated 16.3 'workspace/beginSymbol' messages + /// should be disabled. + /// + /// + /// This is provided to facilitate transition from in-proc to OOP for teams that + /// currently own both a Language Server for Ctrl+Q and a GoTo provider. + /// + [JsonPropertyName("_vs_disableGoToWorkspaceSymbols")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public bool DisableGoToWorkspaceSymbols + { + get; + set; + } + + /// + /// Gets or sets a value indicating whether document/_ms_references is supported. + /// + [JsonPropertyName("_vs_ReferencesProvider")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public bool MSReferencesProvider + { + get; + set; + } + + /// + /// Gets or sets a value indicating whether the server supports OnAutoInsert. + /// + [JsonPropertyName("_vs_onAutoInsertProvider")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public VSInternalDocumentOnAutoInsertOptions? OnAutoInsertProvider + { + get; + set; + } + + /// + /// Gets or sets a value indicating whether the server requires document text to be included in textDocument/didOpen notifications. + /// + /// This capability is not intended to be included into the official LSP, hence _ms_ prefix. + [JsonPropertyName("_vs_doNotIncludeTextInTextDocumentDidOpen")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public bool DoNotIncludeTextInTextDocumentDidOpen + { + get; + set; + } + + /// + /// Gets or sets a value indicating whether the server provides support to resolve string based response kinds. + /// + [JsonPropertyName("_vs_KindDescriptionResolveProvider")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public bool KindDescriptionResolveProvider + { + get; + set; + } + + /// + /// Gets or sets a value indicating whether the server provides support for diagnostic pull requests. + /// + [JsonPropertyName("_vs_supportsDiagnosticRequests")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public bool SupportsDiagnosticRequests + { + get; + set; + } + + /// + /// Gets or sets server specified options for diagnostic pull requests. + /// + [JsonPropertyName("_vs_diagnosticProvider")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public VSInternalDiagnosticOptions? DiagnosticProvider + { + get; + set; + } + + /// + /// Gets or sets a value indicating whether the server provides support for inline completion requests. + /// + [JsonPropertyName("_vs_inlineCompletionOptions")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public VSInternalInlineCompletionOptions? InlineCompletionOptions + { + get; + set; + } + + /// + /// Gets or sets a value indicating whether the server provides support for spell checking. + /// + [JsonPropertyName("_vs_spellCheckingProvider")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public bool SpellCheckingProvider + { + get; + set; + } + + /// + /// Gets or sets a value indicating whether the server supports validating breakable ranges. + /// + [JsonPropertyName("_vs_breakableRangeProvider")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public bool BreakableRangeProvider + { + get; + set; + } + + /// + /// Gets or sets a value indicating whether the server supports uri presentation. + /// + [JsonPropertyName("_vs_uriPresentationProvider")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public bool UriPresentationProvider + { + get; + set; + } /// - /// Extension class for ServerCapabilities with fields specific to Visual Studio. + /// Gets or sets a value indicating whether the server supports text presentation. /// - internal class VSInternalServerCapabilities : VSServerCapabilities + [JsonPropertyName("_vs_textPresentationProvider")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public bool TextPresentationProvider { - /// - /// Gets or sets a value indicating whether or not GoTo's integration with - /// 'workspace/symbol' and the deprecated 16.3 'workspace/beginSymbol' messages - /// should be disabled. - /// - /// - /// This is provided to facilitate transition from in-proc to OOP for teams that - /// currently own both a Language Server for Ctrl+Q and a GoTo provider. - /// - [JsonPropertyName("_vs_disableGoToWorkspaceSymbols")] - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] - public bool DisableGoToWorkspaceSymbols - { - get; - set; - } - - /// - /// Gets or sets a value indicating whether document/_ms_references is supported. - /// - [JsonPropertyName("_vs_ReferencesProvider")] - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] - public bool MSReferencesProvider - { - get; - set; - } - - /// - /// Gets or sets a value indicating whether the server supports OnAutoInsert. - /// - [JsonPropertyName("_vs_onAutoInsertProvider")] - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - public VSInternalDocumentOnAutoInsertOptions? OnAutoInsertProvider - { - get; - set; - } - - /// - /// Gets or sets a value indicating whether the server requires document text to be included in textDocument/didOpen notifications. - /// - /// This capability is not intended to be included into the official LSP, hence _ms_ prefix. - [JsonPropertyName("_vs_doNotIncludeTextInTextDocumentDidOpen")] - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] - public bool DoNotIncludeTextInTextDocumentDidOpen - { - get; - set; - } - - /// - /// Gets or sets a value indicating whether the server provides support to resolve string based response kinds. - /// - [JsonPropertyName("_vs_KindDescriptionResolveProvider")] - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] - public bool KindDescriptionResolveProvider - { - get; - set; - } - - /// - /// Gets or sets a value indicating whether the server provides support for diagnostic pull requests. - /// - [JsonPropertyName("_vs_supportsDiagnosticRequests")] - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] - public bool SupportsDiagnosticRequests - { - get; - set; - } - - /// - /// Gets or sets server specified options for diagnostic pull requests. - /// - [JsonPropertyName("_vs_diagnosticProvider")] - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - public VSInternalDiagnosticOptions? DiagnosticProvider - { - get; - set; - } - - /// - /// Gets or sets a value indicating whether the server provides support for inline completion requests. - /// - [JsonPropertyName("_vs_inlineCompletionOptions")] - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - public VSInternalInlineCompletionOptions? InlineCompletionOptions - { - get; - set; - } - - /// - /// Gets or sets a value indicating whether the server provides support for spell checking. - /// - [JsonPropertyName("_vs_spellCheckingProvider")] - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] - public bool SpellCheckingProvider - { - get; - set; - } - - /// - /// Gets or sets a value indicating whether the server supports validating breakable ranges. - /// - [JsonPropertyName("_vs_breakableRangeProvider")] - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] - public bool BreakableRangeProvider - { - get; - set; - } - - /// - /// Gets or sets a value indicating whether the server supports uri presentation. - /// - [JsonPropertyName("_vs_uriPresentationProvider")] - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] - public bool UriPresentationProvider - { - get; - set; - } - - /// - /// Gets or sets a value indicating whether the server supports text presentation. - /// - [JsonPropertyName("_vs_textPresentationProvider")] - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] - public bool TextPresentationProvider - { - get; - set; - } - - /// - /// Gets or sets the value which indicates what support the server has for code mapping. - /// - [JsonPropertyName("_vs_mapCodeProvider")] - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] - public bool MapCodeProvider - { - get; - set; - } + get; + set; } + + /// + /// Gets or sets the value which indicates what support the server has for code mapping. + /// + [JsonPropertyName("_vs_mapCodeProvider")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public bool MapCodeProvider + { + get; + set; + } + + /// + /// Gets or sets a value indicating whether is + /// supported. + /// + [JsonPropertyName("_vs_DataTipRangeProvider")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public bool DataTipRangeProvider { get; set; } } diff --git a/src/LanguageServer/Protocol/Workspaces/LspWorkspaceManager.cs b/src/LanguageServer/Protocol/Workspaces/LspWorkspaceManager.cs index 1121ca2c28c49..f9e31132397a7 100644 --- a/src/LanguageServer/Protocol/Workspaces/LspWorkspaceManager.cs +++ b/src/LanguageServer/Protocol/Workspaces/LspWorkspaceManager.cs @@ -329,10 +329,13 @@ public void UpdateTrackedDocument(Uri uri, SourceText newSourceText) { // Ensure that the loose files workspace is searched last. var registeredWorkspaces = _lspWorkspaceRegistrationService.GetAllRegistrations(); - registeredWorkspaces = registeredWorkspaces - .Where(workspace => workspace.Kind != WorkspaceKind.MiscellaneousFiles) - .Concat(registeredWorkspaces.Where(workspace => workspace.Kind == WorkspaceKind.MiscellaneousFiles)) - .ToImmutableArray(); + registeredWorkspaces = + [ + .. registeredWorkspaces + .Where(workspace => workspace.Kind != WorkspaceKind.MiscellaneousFiles) +, + .. registeredWorkspaces.Where(workspace => workspace.Kind == WorkspaceKind.MiscellaneousFiles), + ]; var solutions = new FixedSizeArrayBuilder<(Workspace, Solution, bool)>(registeredWorkspaces.Length); foreach (var workspace in registeredWorkspaces) @@ -391,7 +394,7 @@ public void UpdateTrackedDocument(Uri uri, SourceText newSourceText) // Step 3: Check to see if the LSP text matches the workspace text. - var documentsInWorkspace = GetDocumentsForUris(_trackedDocuments.Keys.ToImmutableArray(), workspaceCurrentSolution); + var documentsInWorkspace = GetDocumentsForUris([.. _trackedDocuments.Keys], workspaceCurrentSolution); var sourceGeneratedDocuments = _trackedDocuments.Keys.Where(static uri => uri.Scheme == SourceGeneratedDocumentUri.Scheme) .Select(uri => (identity: SourceGeneratedDocumentUri.DeserializeIdentity(workspaceCurrentSolution, uri), _trackedDocuments[uri].Text)) diff --git a/src/LanguageServer/ProtocolUnitTests/CodeActions/CodeActionResolveTests.cs b/src/LanguageServer/ProtocolUnitTests/CodeActions/CodeActionResolveTests.cs index 09b362a39c737..115998c9c86ca 100644 --- a/src/LanguageServer/ProtocolUnitTests/CodeActions/CodeActionResolveTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/CodeActions/CodeActionResolveTests.cs @@ -355,8 +355,8 @@ class BCD new TextDocumentEdit() { TextDocument = new OptionalVersionedTextDocumentIdentifier { Uri = newDocumentUri }, - Edits = new SumType[] - { + Edits = + [ new TextEdit() { Range = new LSP.Range @@ -377,14 +377,14 @@ class BCD } " } - } + ] }, // Remove the declaration from existing file new TextDocumentEdit() { TextDocument = new OptionalVersionedTextDocumentIdentifier() { Uri = existingDocumentUri }, - Edits = new SumType[] - { + Edits = + [ new TextEdit() { Range = new LSP.Range @@ -402,7 +402,7 @@ class BCD }, NewText = "" } - } + ] } } }; @@ -447,7 +447,7 @@ class {|caret:BCD|} } }, - DocumentFileContainingFolders = new[] { Path.Combine("dir1", "dir2", "dir3") }, + DocumentFileContainingFolders = [Path.Combine("dir1", "dir2", "dir3")], }); var titlePath = new string[] { string.Format(FeaturesResources.Move_type_to_0, "BCD.cs") }; @@ -482,8 +482,8 @@ class {|caret:BCD|} new TextDocumentEdit() { TextDocument = new OptionalVersionedTextDocumentIdentifier { Uri = newDocumentUri }, - Edits = new SumType[] - { + Edits = + [ new TextEdit() { Range = new LSP.Range @@ -503,14 +503,14 @@ class {|caret:BCD|} { }" } - } + ] }, // Remove the declaration from existing file new TextDocumentEdit() { TextDocument = new OptionalVersionedTextDocumentIdentifier() { Uri = existingDocumentUri }, - Edits = new SumType[] - { + Edits = + [ new TextEdit() { Range = new LSP.Range @@ -528,7 +528,7 @@ class {|caret:BCD|} }, NewText = "" } - } + ] } } }; diff --git a/src/LanguageServer/ProtocolUnitTests/CodeActions/CodeActionsTests.cs b/src/LanguageServer/ProtocolUnitTests/CodeActions/CodeActionsTests.cs index fd61f024551da..e62cd3c664ca5 100644 --- a/src/LanguageServer/ProtocolUnitTests/CodeActions/CodeActionsTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/CodeActions/CodeActionsTests.cs @@ -89,7 +89,7 @@ void M() var results = await RunGetCodeActionsAsync(testLspServer, CreateCodeActionParams(caretLocation)); - var topLevelAction = Assert.Single(results.Where(action => action.Title == titlePath[0])); + var topLevelAction = Assert.Single(results, action => action.Title == titlePath[0]); var introduceConstant = topLevelAction.Children.FirstOrDefault( r => JsonSerializer.Deserialize((JsonElement)r.Data!, ProtocolConversions.LspJsonSerializerOptions)!.UniqueIdentifier == titlePath[1]); @@ -306,7 +306,7 @@ private static async Task RunGetCodeActionsAsync( { var result = await testLspServer.ExecuteRequestAsync( LSP.Methods.TextDocumentCodeActionName, codeActionParams, CancellationToken.None); - return result.Cast().ToArray(); + return [.. result.Cast()]; } private static async Task RunGetCodeActionResolveAsync( diff --git a/src/LanguageServer/ProtocolUnitTests/CodeActions/RunCodeActionsTests.cs b/src/LanguageServer/ProtocolUnitTests/CodeActions/RunCodeActionsTests.cs index dea32cb40c3e7..80bd47e9d2207 100644 --- a/src/LanguageServer/ProtocolUnitTests/CodeActions/RunCodeActionsTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/CodeActions/RunCodeActionsTests.cs @@ -51,7 +51,7 @@ class B }; var titlePath = new[] { string.Format(FeaturesResources.Move_type_to_0, "B.cs") }; - var commandArgument = new CodeActionResolveData(string.Format(FeaturesResources.Move_type_to_0, "B.cs"), customTags: ImmutableArray.Empty, caretLocation.Range, documentId, fixAllFlavors: null, nestedCodeActions: null, codeActionPath: titlePath); + var commandArgument = new CodeActionResolveData(string.Format(FeaturesResources.Move_type_to_0, "B.cs"), customTags: [], caretLocation.Range, documentId, fixAllFlavors: null, nestedCodeActions: null, codeActionPath: titlePath); var results = await ExecuteRunCodeActionCommandAsync(testLspServer, commandArgument); diff --git a/src/LanguageServer/ProtocolUnitTests/Completion/CompletionFeaturesTests.cs b/src/LanguageServer/ProtocolUnitTests/Completion/CompletionFeaturesTests.cs index 0b68236cd9f3a..37c2a75ef4739 100644 --- a/src/LanguageServer/ProtocolUnitTests/Completion/CompletionFeaturesTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/Completion/CompletionFeaturesTests.cs @@ -44,13 +44,13 @@ public class CompletionFeaturesTests : AbstractLanguageServerProtocolTests LabelDetailsSupport = true, ResolveSupport = new LSP.ResolveSupportSetting { - Properties = new string[] { "documentation", "additionalTextEdits", "command", "labelDetail" } + Properties = ["documentation", "additionalTextEdits", "command", "labelDetail"] } }, CompletionListSetting = new LSP.CompletionListSetting { - ItemDefaults = new string[] { CompletionCapabilityHelper.EditRangePropertyName, CompletionCapabilityHelper.DataPropertyName, CompletionCapabilityHelper.CommitCharactersPropertyName } + ItemDefaults = [CompletionCapabilityHelper.EditRangePropertyName, CompletionCapabilityHelper.DataPropertyName, CompletionCapabilityHelper.CommitCharactersPropertyName] }, }, } @@ -385,10 +385,10 @@ void M() if (!hasDefaultCommitCharCapability) { clientCapability.TextDocument.Completion.CompletionListSetting.ItemDefaults - = new string[] { CompletionCapabilityHelper.EditRangePropertyName, CompletionCapabilityHelper.DataPropertyName }; + = [CompletionCapabilityHelper.EditRangePropertyName, CompletionCapabilityHelper.DataPropertyName]; } - await using var testLspServer = await CreateTestLspServerAsync(new[] { markup }, LanguageNames.CSharp, mutatingLspWorkspace, + await using var testLspServer = await CreateTestLspServerAsync([markup], LanguageNames.CSharp, mutatingLspWorkspace, new InitializationOptions { ClientCapabilities = clientCapability, CallInitialized = true }, Composition.AddParts(typeof(CSharpLspMockCompletionService.Factory))); @@ -435,7 +435,7 @@ void M() public async Task TestUsingServerDefaultCommitCharacters(bool mutatingLspWorkspace, bool shouldPromoteDefaultCommitCharsToList) { var markup = "Item{|caret:|}"; - await using var testLspServer = await CreateTestLspServerAsync(new[] { markup }, LanguageNames.CSharp, mutatingLspWorkspace, + await using var testLspServer = await CreateTestLspServerAsync([markup], LanguageNames.CSharp, mutatingLspWorkspace, new InitializationOptions { ClientCapabilities = DefaultClientCapabilities, CallInitialized = true }, composition: Composition.AddParts(typeof(CSharpLspMockCompletionService.Factory))); @@ -762,7 +762,7 @@ public Foo(List myList) public async Task TestSoftSelectionWhenFilterTextIsEmptyForPreselectItemAsync(bool mutatingLspWorkspace) { var markup = "{|caret:|}"; - await using var testLspServer = await CreateTestLspServerAsync(new[] { markup }, LanguageNames.CSharp, mutatingLspWorkspace, + await using var testLspServer = await CreateTestLspServerAsync([markup], LanguageNames.CSharp, mutatingLspWorkspace, new InitializationOptions { ClientCapabilities = DefaultClientCapabilities, CallInitialized = true }, composition: Composition.AddParts(typeof(CSharpLspMockCompletionService.Factory))); @@ -879,7 +879,7 @@ internal override bool ShouldTriggerCompletion( return true; } - public ImmutableArray ReturnedItems { get; set; } = ImmutableArray.Empty; + public ImmutableArray ReturnedItems { get; set; } = []; public (int defaultItemCount, int nonDefaultItemCount) ItemCounts { get; set; } @@ -922,7 +922,7 @@ public ILanguageService CreateLanguageService(HostLanguageServices languageServi public async Task TestHandleExceptionFromGetCompletionChange(bool mutatingLspWorkspace) { var markup = "Item {|caret:|}"; - await using var testLspServer = await CreateTestLspServerAsync(new[] { markup }, LanguageNames.CSharp, mutatingLspWorkspace, + await using var testLspServer = await CreateTestLspServerAsync([markup], LanguageNames.CSharp, mutatingLspWorkspace, new InitializationOptions { ClientCapabilities = DefaultClientCapabilities, CallInitialized = true }, composition: Composition.AddParts(typeof(CSharpLspThrowExceptionOnChangeCompletionService.Factory))); @@ -1004,7 +1004,7 @@ public class MyClass : BaseClass override {|caret:|} } """; - await using var testLspServer = await CreateTestLspServerAsync(new[] { markup }, LanguageNames.CSharp, mutatingLspWorkspace, + await using var testLspServer = await CreateTestLspServerAsync([markup], LanguageNames.CSharp, mutatingLspWorkspace, new InitializationOptions { ClientCapabilities = DefaultClientCapabilities, CallInitialized = true }, commonReferences: false); var caret = testLspServer.GetLocations("caret").Single(); diff --git a/src/LanguageServer/ProtocolUnitTests/Completion/CompletionTests.cs b/src/LanguageServer/ProtocolUnitTests/Completion/CompletionTests.cs index eb4ee12a49099..bf88d490792f3 100644 --- a/src/LanguageServer/ProtocolUnitTests/Completion/CompletionTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/Completion/CompletionTests.cs @@ -34,7 +34,7 @@ private static LSP.VSInternalClientCapabilities CreateCoreCompletionCapabilities { CompletionListSetting = new CompletionListSetting() { - ItemDefaults = new[] { CompletionCapabilityHelper.EditRangePropertyName }, + ItemDefaults = [CompletionCapabilityHelper.EditRangePropertyName], }, CompletionItemKind = new(), @@ -119,7 +119,7 @@ public async Task TestGetCompletions_PromotesNothingWhenNoCommitCharactersAsync( { CompletionListSetting = new LSP.CompletionListSetting { - ItemDefaults = new string[] { CompletionCapabilityHelper.EditRangePropertyName } + ItemDefaults = [CompletionCapabilityHelper.EditRangePropertyName] }, CompletionList = new LSP.VSInternalCompletionListSetting { diff --git a/src/LanguageServer/ProtocolUnitTests/Configuration/DidChangeConfigurationNotificationHandlerTest.cs b/src/LanguageServer/ProtocolUnitTests/Configuration/DidChangeConfigurationNotificationHandlerTest.cs index d8c3e3e15ff66..0eba17655c104 100644 --- a/src/LanguageServer/ProtocolUnitTests/Configuration/DidChangeConfigurationNotificationHandlerTest.cs +++ b/src/LanguageServer/ProtocolUnitTests/Configuration/DidChangeConfigurationNotificationHandlerTest.cs @@ -144,6 +144,7 @@ public void VerifyLspClientOptionNames() "background_analysis.dotnet_compiler_diagnostics_scope", "code_lens.dotnet_enable_references_code_lens", "code_lens.dotnet_enable_tests_code_lens", + "auto_insert.dotnet_enable_auto_insert", "projects.dotnet_binary_log_path", "projects.dotnet_enable_automatic_restore", "navigation.dotnet_navigate_to_source_link_and_embedded_sources" diff --git a/src/LanguageServer/ProtocolUnitTests/DataTips/DataTipRangeHandlerTests.cs b/src/LanguageServer/ProtocolUnitTests/DataTips/DataTipRangeHandlerTests.cs new file mode 100644 index 0000000000000..b2ce61104190b --- /dev/null +++ b/src/LanguageServer/ProtocolUnitTests/DataTips/DataTipRangeHandlerTests.cs @@ -0,0 +1,61 @@ +// 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.Linq; +using System.Threading; +using System.Threading.Tasks; +using Roslyn.Test.Utilities; +using Xunit; +using Xunit.Abstractions; +using LSP = Roslyn.LanguageServer.Protocol; + +namespace Microsoft.CodeAnalysis.LanguageServer.UnitTests.DataTips; + +public class DataTipRangeHandlerTests(ITestOutputHelper testOutputHelper) + : AbstractLanguageServerProtocolTests(testOutputHelper) +{ + private static async Task RunAsync(TestLspServer testLspServer, LSP.Location caret) + { + return await testLspServer.ExecuteRequestAsync( + LSP.VSInternalMethods.TextDocumentDataTipRangeName, + new LSP.TextDocumentPositionParams() + { + TextDocument = new LSP.TextDocumentIdentifier { Uri = caret.Uri }, + Position = caret.Range.Start, + }, + CancellationToken.None); + } + + [Theory, CombinatorialData] + public async Task SimpleStatement(bool mutatingLspWorkspace) + { + var markup = """ + using System.Linq; + + int[] args; + var v = args.{|caret:|}Select(a => a.ToString()).Where(a => a.Length >= 0); + """; + await using var testLspServer = await CreateTestLspServerAsync(markup, mutatingLspWorkspace); + + var caret = testLspServer.GetLocations("caret").Single(); + + var result = await RunAsync(testLspServer, caret); + Assert.NotNull(result); + + Assert.Equal(new LSP.VSInternalDataTip + { + DataTipTags = LSP.VSInternalDataTipTags.LinqExpression, + HoverRange = new LSP.Range + { + Start = new LSP.Position { Line = 3, Character = 8 }, + End = new LSP.Position { Line = 3, Character = 19 }, + }, + ExpressionRange = new LSP.Range + { + Start = new LSP.Position { Line = 3, Character = 8 }, + End = new LSP.Position { Line = 3, Character = 38 }, + }, + }, result); + } +} diff --git a/src/LanguageServer/ProtocolUnitTests/Definitions/GoToDefinitionTests.cs b/src/LanguageServer/ProtocolUnitTests/Definitions/GoToDefinitionTests.cs index b1d249cbd3f68..72b31c470e6a5 100644 --- a/src/LanguageServer/ProtocolUnitTests/Definitions/GoToDefinitionTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/Definitions/GoToDefinitionTests.cs @@ -256,6 +256,25 @@ class B Assert.Equal(SourceGeneratedDocumentUri.Scheme, result.Uri.Scheme); } + [Theory, CombinatorialData] + public async Task TestGotoDefinitionMetadataIncludesTypeAsync(bool mutatingLspWorkspace) + { + var markup = + """ + class A + { + void M() + { + System.Console.Write("Hel{|caret:|}lo"); + } + } + """; + await using var testLspServer = await CreateTestLspServerAsync(markup, mutatingLspWorkspace); + + var results = await RunGotoDefinitionAsync(testLspServer, testLspServer.GetLocations("caret").Single()); + Assert.True(results.Single().Uri.OriginalString.EndsWith("String.cs")); + } + private static async Task RunGotoDefinitionAsync(TestLspServer testLspServer, LSP.Location caret) { return await testLspServer.ExecuteRequestAsync(LSP.Methods.TextDocumentDefinitionName, diff --git a/src/LanguageServer/ProtocolUnitTests/Diagnostics/AbstractPullDiagnosticTestsBase.cs b/src/LanguageServer/ProtocolUnitTests/Diagnostics/AbstractPullDiagnosticTestsBase.cs index b35a3e04649f3..094dec54538ad 100644 --- a/src/LanguageServer/ProtocolUnitTests/Diagnostics/AbstractPullDiagnosticTestsBase.cs +++ b/src/LanguageServer/ProtocolUnitTests/Diagnostics/AbstractPullDiagnosticTestsBase.cs @@ -40,15 +40,17 @@ public abstract class AbstractPullDiagnosticTestsBase(ITestOutputHelper testOutp private protected override TestAnalyzerReferenceByLanguage CreateTestAnalyzersReference() { var builder = ImmutableDictionary.CreateBuilder>(); - builder.Add(LanguageNames.CSharp, ImmutableArray.Create( + builder.Add(LanguageNames.CSharp, + [ DiagnosticExtensions.GetCompilerDiagnosticAnalyzer(LanguageNames.CSharp), new CSharpRemoveUnnecessaryImportsDiagnosticAnalyzer(), new CSharpRemoveUnnecessaryExpressionParenthesesDiagnosticAnalyzer(), new CSharpRemoveUnusedParametersAndValuesDiagnosticAnalyzer(), new CSharpRemoveUnnecessaryInlineSuppressionsDiagnosticAnalyzer(), - new CSharpUseImplicitObjectCreationDiagnosticAnalyzer())); - builder.Add(LanguageNames.VisualBasic, ImmutableArray.Create(DiagnosticExtensions.GetCompilerDiagnosticAnalyzer(LanguageNames.VisualBasic))); - builder.Add(InternalLanguageNames.TypeScript, ImmutableArray.Create(new MockTypescriptDiagnosticAnalyzer())); + new CSharpUseImplicitObjectCreationDiagnosticAnalyzer(), + ]); + builder.Add(LanguageNames.VisualBasic, [DiagnosticExtensions.GetCompilerDiagnosticAnalyzer(LanguageNames.VisualBasic)]); + builder.Add(InternalLanguageNames.TypeScript, [new MockTypescriptDiagnosticAnalyzer()]); return new(builder.ToImmutableDictionary()); } @@ -107,7 +109,7 @@ private protected static async Task> RunVSG } AssertEx.NotNull(diagnostics); - return diagnostics.Select(d => new TestDiagnosticResult(d.TextDocument!, d.ResultId!, d.Diagnostics)).ToImmutableArray(); + return [.. diagnostics.Select(d => new TestDiagnosticResult(d.TextDocument!, d.ResultId!, d.Diagnostics))]; } private protected static async Task> RunPublicGetWorkspacePullDiagnosticsAsync( @@ -139,12 +141,12 @@ private protected static async Task> RunPub Assert.Empty(returnedResult!.Items); var progressValues = progress!.Value.GetValues(); Assert.NotNull(progressValues); - return progressValues.SelectMany(value => value.Match(v => v.Items, v => v.Items)).Select(diagnostics => ConvertWorkspaceDiagnosticResult(diagnostics)).ToImmutableArray(); + return [.. progressValues.SelectMany(value => value.Match(v => v.Items, v => v.Items)).Select(diagnostics => ConvertWorkspaceDiagnosticResult(diagnostics))]; } AssertEx.NotNull(returnedResult); - return returnedResult.Items.Select(diagnostics => ConvertWorkspaceDiagnosticResult(diagnostics)).ToImmutableArray(); + return [.. returnedResult.Items.Select(diagnostics => ConvertWorkspaceDiagnosticResult(diagnostics))]; } private static WorkspaceDiagnosticParams CreateProposedWorkspaceDiagnosticParams( @@ -183,7 +185,7 @@ private static TestDiagnosticResult ConvertWorkspaceDiagnosticResult(SumType CreateDiagnosticParamsFromPreviousReports(ImmutableArray results) { // If there was no resultId provided in the response, we cannot create previous results for it. - return results.Where(r => r.ResultId != null).Select(r => (r.ResultId!, r.TextDocument)).ToImmutableArray(); + return [.. results.Where(r => r.ResultId != null).Select(r => (r.ResultId!, r.TextDocument))]; } private protected static VSInternalDocumentDiagnosticsParams CreateDocumentDiagnosticParams( @@ -265,7 +267,7 @@ private protected static async Task> RunGet } AssertEx.NotNull(diagnostics); - return diagnostics.Select(d => new TestDiagnosticResult(vsTextDocumentIdentifier, d.ResultId!, d.Diagnostics)).ToImmutableArray(); + return [.. diagnostics.Select(d => new TestDiagnosticResult(vsTextDocumentIdentifier, d.ResultId!, d.Diagnostics))]; } else { @@ -283,16 +285,16 @@ private protected static async Task> RunGet if (diagnostics == null) { // The public LSP spec returns null when no diagnostics are available for a document wheres VS returns an empty array. - return ImmutableArray.Empty; + return []; } else if (diagnostics.Value.Value is UnchangedDocumentDiagnosticReport) { // The public LSP spec returns different types when unchanged in contrast to VS which just returns null diagnostic array. - return ImmutableArray.Create(new TestDiagnosticResult(vsTextDocumentIdentifier, diagnostics.Value.Second.ResultId!, null)); + return [new TestDiagnosticResult(vsTextDocumentIdentifier, diagnostics.Value.Second.ResultId!, null)]; } else { - return ImmutableArray.Create(new TestDiagnosticResult(vsTextDocumentIdentifier, diagnostics.Value.First.ResultId!, diagnostics.Value.First.Items)); + return [new TestDiagnosticResult(vsTextDocumentIdentifier, diagnostics.Value.First.ResultId!, diagnostics.Value.First.Items)]; } } @@ -374,7 +376,7 @@ private class MockTypescriptDiagnosticAnalyzer : DocumentDiagnosticAnalyzer public static readonly DiagnosticDescriptor Descriptor = new DiagnosticDescriptor( "TS01", "TS error", "TS error", "Error", DiagnosticSeverity.Error, isEnabledByDefault: true); - public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create(Descriptor); + public override ImmutableArray SupportedDiagnostics => [Descriptor]; public override Task> AnalyzeSemanticsAsync(Document document, CancellationToken cancellationToken) => SpecializedTasks.EmptyImmutableArray(); diff --git a/src/LanguageServer/ProtocolUnitTests/Diagnostics/AdditionalFileDiagnosticsTests.cs b/src/LanguageServer/ProtocolUnitTests/Diagnostics/AdditionalFileDiagnosticsTests.cs index 0bd88792bf0d4..140598171eaa0 100644 --- a/src/LanguageServer/ProtocolUnitTests/Diagnostics/AdditionalFileDiagnosticsTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/Diagnostics/AdditionalFileDiagnosticsTests.cs @@ -115,9 +115,7 @@ public async Task TestWorkspaceDiagnosticsWithAdditionalFileInMultipleProjects(b protected override TestComposition Composition => base.Composition.AddParts(typeof(MockAdditionalFileDiagnosticAnalyzer)); private protected override TestAnalyzerReferenceByLanguage CreateTestAnalyzersReference() - => new(ImmutableDictionary>.Empty.Add(LanguageNames.CSharp, ImmutableArray.Create( - DiagnosticExtensions.GetCompilerDiagnosticAnalyzer(LanguageNames.CSharp), - new MockAdditionalFileDiagnosticAnalyzer()))); + => new(ImmutableDictionary>.Empty.Add(LanguageNames.CSharp, [DiagnosticExtensions.GetCompilerDiagnosticAnalyzer(LanguageNames.CSharp), new MockAdditionalFileDiagnosticAnalyzer()])); [DiagnosticAnalyzer(LanguageNames.CSharp), PartNotDiscoverable] private class MockAdditionalFileDiagnosticAnalyzer : DiagnosticAnalyzer @@ -126,7 +124,7 @@ private class MockAdditionalFileDiagnosticAnalyzer : DiagnosticAnalyzer private readonly DiagnosticDescriptor _descriptor = new(Id, "MockAdditionalDiagnostic", "MockAdditionalDiagnostic", "InternalCategory", DiagnosticSeverity.Warning, isEnabledByDefault: true, helpLinkUri: "https://github.com/dotnet/roslyn"); public override ImmutableArray SupportedDiagnostics - => ImmutableArray.Create(_descriptor); + => [_descriptor]; public override void Initialize(AnalysisContext context) => context.RegisterCompilationStartAction(CreateAnalyzerWithinCompilation); diff --git a/src/LanguageServer/ProtocolUnitTests/Diagnostics/BuildOnlyDiagnosticIdsHandlerTests.cs b/src/LanguageServer/ProtocolUnitTests/Diagnostics/BuildOnlyDiagnosticIdsHandlerTests.cs index 68fe2bf280f65..1a30c88c6168f 100644 --- a/src/LanguageServer/ProtocolUnitTests/Diagnostics/BuildOnlyDiagnosticIdsHandlerTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/Diagnostics/BuildOnlyDiagnosticIdsHandlerTests.cs @@ -50,14 +50,8 @@ Class C private protected override TestAnalyzerReferenceByLanguage CreateTestAnalyzersReference() { var builder = ImmutableDictionary.CreateBuilder>(); - builder.Add(LanguageNames.CSharp, ImmutableArray.Create( - DiagnosticExtensions.GetCompilerDiagnosticAnalyzer(LanguageNames.CSharp), - new BuildOnlyAnalyzer(), - new LiveAnalyzer())); - builder.Add(LanguageNames.VisualBasic, ImmutableArray.Create( - DiagnosticExtensions.GetCompilerDiagnosticAnalyzer(LanguageNames.VisualBasic), - new BuildOnlyAnalyzer(), - new LiveAnalyzer())); + builder.Add(LanguageNames.CSharp, [DiagnosticExtensions.GetCompilerDiagnosticAnalyzer(LanguageNames.CSharp), new BuildOnlyAnalyzer(), new LiveAnalyzer()]); + builder.Add(LanguageNames.VisualBasic, [DiagnosticExtensions.GetCompilerDiagnosticAnalyzer(LanguageNames.VisualBasic), new BuildOnlyAnalyzer(), new LiveAnalyzer()]); return new(builder.ToImmutableDictionary()); } @@ -90,7 +84,7 @@ private sealed class BuildOnlyAnalyzer : DiagnosticAnalyzer { public const string Id = "BuildOnly0001"; private static readonly DiagnosticDescriptor s_descriptor = new(Id, "Title", "Message", "Category", DiagnosticSeverity.Warning, isEnabledByDefault: true, customTags: [WellKnownDiagnosticTags.CompilationEnd]); - public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create(s_descriptor); + public override ImmutableArray SupportedDiagnostics => [s_descriptor]; public override void Initialize(AnalysisContext context) { @@ -102,7 +96,7 @@ private sealed class LiveAnalyzer : DiagnosticAnalyzer { public const string Id = "Live0001"; private static readonly DiagnosticDescriptor s_descriptor = new(Id, "Title", "Message", "Category", DiagnosticSeverity.Warning, isEnabledByDefault: true); - public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create(s_descriptor); + public override ImmutableArray SupportedDiagnostics => [s_descriptor]; public override void Initialize(AnalysisContext context) { diff --git a/src/LanguageServer/ProtocolUnitTests/Diagnostics/DiagnosticRegistrationTests.cs b/src/LanguageServer/ProtocolUnitTests/Diagnostics/DiagnosticRegistrationTests.cs index 9ee002a27e92e..8da3d27e9b705 100644 --- a/src/LanguageServer/ProtocolUnitTests/Diagnostics/DiagnosticRegistrationTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/Diagnostics/DiagnosticRegistrationTests.cs @@ -111,7 +111,7 @@ public void ClientRegisterCapability(RegistrationParams registrationParams, Canc /// public ImmutableArray GetRegistrations() { - return _registrations.ToImmutableArray(); + return [.. _registrations]; } } } diff --git a/src/LanguageServer/ProtocolUnitTests/Diagnostics/NonLocalDiagnosticTests.cs b/src/LanguageServer/ProtocolUnitTests/Diagnostics/NonLocalDiagnosticTests.cs index 24b0be51a26dc..c1379550ec811 100644 --- a/src/LanguageServer/ProtocolUnitTests/Diagnostics/NonLocalDiagnosticTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/Diagnostics/NonLocalDiagnosticTests.cs @@ -31,7 +31,7 @@ internal async Task TestNonLocalDocumentDiagnosticsAreReportedWhenFSAEnabled(boo var markup2 = @"class B { }"; var scope = fsaEnabled ? BackgroundAnalysisScope.FullSolution : BackgroundAnalysisScope.OpenFiles; await using var testLspServer = await CreateTestWorkspaceWithDiagnosticsAsync( - new[] { markup1, markup2 }, mutatingLspWorkspace, scope, useVSDiagnostics: false); + [markup1, markup2], mutatingLspWorkspace, scope, useVSDiagnostics: false); var document = testLspServer.GetCurrentSolution().Projects.Single().Documents.First(); @@ -68,16 +68,14 @@ internal async Task TestNonLocalDocumentDiagnosticsAreReportedWhenFSAEnabled(boo protected override TestComposition Composition => base.Composition.AddParts(typeof(NonLocalDiagnosticsAnalyzer)); private protected override TestAnalyzerReferenceByLanguage CreateTestAnalyzersReference() - => new(ImmutableDictionary>.Empty.Add(LanguageNames.CSharp, ImmutableArray.Create( - DiagnosticExtensions.GetCompilerDiagnosticAnalyzer(LanguageNames.CSharp), - new NonLocalDiagnosticsAnalyzer()))); + => new(ImmutableDictionary>.Empty.Add(LanguageNames.CSharp, [DiagnosticExtensions.GetCompilerDiagnosticAnalyzer(LanguageNames.CSharp), new NonLocalDiagnosticsAnalyzer()])); [DiagnosticAnalyzer(LanguageNames.CSharp)] private sealed class NonLocalDiagnosticsAnalyzer : DiagnosticAnalyzer { public static readonly DiagnosticDescriptor NonLocalDescriptor = new("NonLocal0001", "Title1", "NonLocal0001", "Category", DiagnosticSeverity.Warning, isEnabledByDefault: true); public static readonly DiagnosticDescriptor CompilationEndDescriptor = new("NonLocal0002", "Title2", "NonLocal0002", "Category", DiagnosticSeverity.Warning, isEnabledByDefault: true, customTags: [WellKnownDiagnosticTags.CompilationEnd]); - public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create(NonLocalDescriptor, CompilationEndDescriptor); + public override ImmutableArray SupportedDiagnostics => [NonLocalDescriptor, CompilationEndDescriptor]; public override void Initialize(AnalysisContext context) { diff --git a/src/LanguageServer/ProtocolUnitTests/Diagnostics/PullDiagnosticTests.cs b/src/LanguageServer/ProtocolUnitTests/Diagnostics/PullDiagnosticTests.cs index 778167de168cf..8e5958674d2b3 100644 --- a/src/LanguageServer/ProtocolUnitTests/Diagnostics/PullDiagnosticTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/Diagnostics/PullDiagnosticTests.cs @@ -129,7 +129,7 @@ private sealed class CSharpSyntaxAnalyzer : DiagnosticAnalyzer public const string RuleId = "SYN0001"; private readonly DiagnosticDescriptor _descriptor = new(RuleId, "Title", "Message", "Category", DiagnosticSeverity.Warning, isEnabledByDefault: true); - public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create(_descriptor); + public override ImmutableArray SupportedDiagnostics => [_descriptor]; public override void Initialize(AnalysisContext context) { @@ -143,7 +143,7 @@ private sealed class CSharpSemanticAnalyzer : DiagnosticAnalyzer public const string RuleId = "SEM0001"; private readonly DiagnosticDescriptor _descriptor = new(RuleId, "Title", "Message", "Category", DiagnosticSeverity.Warning, isEnabledByDefault: true); - public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create(_descriptor); + public override ImmutableArray SupportedDiagnostics => [_descriptor]; public override void Initialize(AnalysisContext context) { @@ -1092,7 +1092,7 @@ class A { testLspServer.TestWorkspace.GlobalOptions.SetGlobalOption( TaskListOptionsStorage.Descriptors, - ImmutableArray.Create("HACK:2", $"TODO:{priString}", "UNDONE:2", "UnresolvedMergeConflict:3")); + ["HACK:2", $"TODO:{priString}", "UNDONE:2", "UnresolvedMergeConflict:3"]); var results = await RunGetWorkspacePullDiagnosticsAsync(testLspServer, useVSDiagnostics: true, includeTaskListItems: true, category: PullDiagnosticCategories.Task); @@ -2008,7 +2008,7 @@ public async Task TestWorkspaceDiagnosticsWaitsForLspSolutionChanges(bool useVSD Assert.NotEmpty(results); } - [Theory, CombinatorialData] + [Theory(Skip = "https://github.com/dotnet/roslyn/issues/76503"), CombinatorialData] public async Task TestWorkspaceDiagnosticsWaitsForLspTextChangesWithMultipleSources(bool useVSDiagnostics, bool mutatingLspWorkspace) { var markup1 = @@ -2045,7 +2045,8 @@ public async Task TestWorkspaceDiagnosticsWaitsForLspTextChangesWithMultipleSour // 1. LSP changed, which triggers immediately via the queue. // 2. Workspace changed, which can be delayed until after the requests complete. // To ensure the workspace changed is processed, we need to wait for all workspace events. - await testLspServer.WaitForDiagnosticsAsync(); + var listenerProvider = testLspServer.TestWorkspace.GetService(); + await listenerProvider.WaitAllDispatcherOperationAndTasksAsync(testLspServer.TestWorkspace); // Make new requests - these requests should again wait for new changes. resultTaskOne = RunGetWorkspacePullDiagnosticsAsync(testLspServer, useVSDiagnostics, useProgress: true, category: PullDiagnosticCategories.WorkspaceDocumentsAndProject, triggerConnectionClose: false); diff --git a/src/LanguageServer/ProtocolUnitTests/Diagnostics/WorkspaceProjectDiagnosticsTests.cs b/src/LanguageServer/ProtocolUnitTests/Diagnostics/WorkspaceProjectDiagnosticsTests.cs index 3e9c8413166d8..ce607c6a9fc25 100644 --- a/src/LanguageServer/ProtocolUnitTests/Diagnostics/WorkspaceProjectDiagnosticsTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/Diagnostics/WorkspaceProjectDiagnosticsTests.cs @@ -64,9 +64,7 @@ public async Task TestWorkspaceDiagnosticsWithRemovedProject(bool useVSDiagnosti protected override TestComposition Composition => base.Composition.AddParts(typeof(MockProjectDiagnosticAnalyzer)); private protected override TestAnalyzerReferenceByLanguage CreateTestAnalyzersReference() - => new(ImmutableDictionary>.Empty.Add(LanguageNames.CSharp, ImmutableArray.Create( - DiagnosticExtensions.GetCompilerDiagnosticAnalyzer(LanguageNames.CSharp), - new MockProjectDiagnosticAnalyzer()))); + => new(ImmutableDictionary>.Empty.Add(LanguageNames.CSharp, [DiagnosticExtensions.GetCompilerDiagnosticAnalyzer(LanguageNames.CSharp), new MockProjectDiagnosticAnalyzer()])); [DiagnosticAnalyzer(LanguageNames.CSharp), PartNotDiscoverable] private class MockProjectDiagnosticAnalyzer : DiagnosticAnalyzer @@ -75,7 +73,7 @@ private class MockProjectDiagnosticAnalyzer : DiagnosticAnalyzer private readonly DiagnosticDescriptor _descriptor = new(Id, "MockProjectDiagnostic", "MockProjectDiagnostic", "InternalCategory", DiagnosticSeverity.Warning, isEnabledByDefault: true, helpLinkUri: "https://github.com/dotnet/roslyn"); public override ImmutableArray SupportedDiagnostics - => ImmutableArray.Create(_descriptor); + => [_descriptor]; public override void Initialize(AnalysisContext context) => context.RegisterCompilationStartAction(CreateAnalyzerWithinCompilation); diff --git a/src/LanguageServer/ProtocolUnitTests/Hover/HoverTests.cs b/src/LanguageServer/ProtocolUnitTests/Hover/HoverTests.cs index f614909890de6..4e6ed1c73639e 100644 --- a/src/LanguageServer/ProtocolUnitTests/Hover/HoverTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/Hover/HoverTests.cs @@ -61,7 +61,7 @@ public async Task TestGetHoverAsync_WithExceptions(bool mutatingLspWorkspace) var expectedLocation = testLspServer.GetLocations("caret").Single(); var results = await RunGetHoverAsync(testLspServer, expectedLocation).ConfigureAwait(false); - VerifyVSContent(results, $"string A.Method(int i)|A great method|{FeaturesResources.Exceptions_colon}| System.NullReferenceException"); + VerifyVSContent(results, $"string A.Method(int i)|A great method|{WorkspacesResources.Exceptions_colon}| System.NullReferenceException"); } [Theory, CombinatorialData] @@ -256,7 +256,7 @@ Remarks are cool too\. {FeaturesResources.Returns_colon}   a string -{FeaturesResources.Exceptions_colon} +{WorkspacesResources.Exceptions_colon}   System\.NullReferenceException "; @@ -323,7 +323,7 @@ Remarks are cool too. {FeaturesResources.Returns_colon} a string -{FeaturesResources.Exceptions_colon} +{WorkspacesResources.Exceptions_colon} System.NullReferenceException "; diff --git a/src/LanguageServer/ProtocolUnitTests/MapCode/MapCodeTests.cs b/src/LanguageServer/ProtocolUnitTests/MapCode/MapCodeTests.cs index e48b9fdc934f0..0aaf597dec428 100644 --- a/src/LanguageServer/ProtocolUnitTests/MapCode/MapCodeTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/MapCode/MapCodeTests.cs @@ -121,7 +121,7 @@ static void Main(string[] args) var textDocumentEdits = results.DocumentChanges!.Value.First.Single(); Assert.Equal(textDocumentEdits.TextDocument.Uri, mapCodeParams.Mappings.Single().TextDocument!.Uri); - edits = textDocumentEdits.Edits.Select(e => e.Unify()).ToArray(); + edits = [.. textDocumentEdits.Edits.Select(e => e.Unify())]; } else { diff --git a/src/LanguageServer/ProtocolUnitTests/References/FindAllReferencesHandlerTests.cs b/src/LanguageServer/ProtocolUnitTests/References/FindAllReferencesHandlerTests.cs index 47b09605f0dc1..1c641c461e89e 100644 --- a/src/LanguageServer/ProtocolUnitTests/References/FindAllReferencesHandlerTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/References/FindAllReferencesHandlerTests.cs @@ -319,7 +319,7 @@ private static LSP.ReferenceParams CreateReferenceParams(LSP.Location caret, IPr if (progress != null) { Assert.Null(results); - results = UnwrapProgress(progress.Value).ToArray(); + results = [.. UnwrapProgress(progress.Value)]; } // Results are returned in a non-deterministic order, so we order them by location @@ -336,7 +336,7 @@ private static LSP.ReferenceParams CreateReferenceParams(LSP.Location caret, IPr if (progress != null) { Assert.Null(results); - results = UnwrapProgress(progress.Value).ToArray(); + results = [.. UnwrapProgress(progress.Value)]; } // Results are returned in a non-deterministic order, so we order them by location @@ -350,9 +350,8 @@ private static T[] UnwrapProgress(BufferedProgress progress) // with the test creating one, and the handler another, we have to unwrap. // Additionally, the VS LSP protocol specifies T from IProgress as an object and not as the actual T type // so we have to correctly convert the JObject into the expected type. - return progress.GetValues() - .SelectMany(r => (List)r).Select(r => JsonSerializer.Deserialize((JsonElement)r, ProtocolConversions.LspJsonSerializerOptions)) - .ToArray(); + return [.. progress.GetValues() + .SelectMany(r => (List)r).Select(r => JsonSerializer.Deserialize((JsonElement)r, ProtocolConversions.LspJsonSerializerOptions))]; } private static void AssertValidDefinitionProperties(LSP.VSInternalReferenceItem[] referenceItems, int definitionIndex, Glyph definitionGlyph) diff --git a/src/LanguageServer/ProtocolUnitTests/References/FindImplementationsTests.cs b/src/LanguageServer/ProtocolUnitTests/References/FindImplementationsTests.cs index 81f359d23dd46..d3081ad800a86 100644 --- a/src/LanguageServer/ProtocolUnitTests/References/FindImplementationsTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/References/FindImplementationsTests.cs @@ -118,7 +118,7 @@ void M() public async Task TestFindImplementationAsync_MultipleLocations(bool mutatingLspWorkspace) { var markup = -@"class {|caret:|}{|implementation:A|} { } +@"class {|caret:|}A { } class {|implementation:B|} : A { } diff --git a/src/LanguageServer/ProtocolUnitTests/SpellCheck/SpellCheckTests.cs b/src/LanguageServer/ProtocolUnitTests/SpellCheck/SpellCheckTests.cs index 46a5b5668f8df..f9eaf873a3a5f 100644 --- a/src/LanguageServer/ProtocolUnitTests/SpellCheck/SpellCheckTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/SpellCheck/SpellCheckTests.cs @@ -99,7 +99,7 @@ class {|Identifier:A{{v}}|} AssertJsonEquals(results[i], new VSInternalSpellCheckableRangeReport { ResultId = "DocumentSpellCheckHandler:1", - Ranges = allRanges.Skip(3 * i * 1000).Take(3 * 1000).ToArray(), + Ranges = [.. allRanges.Skip(3 * i * 1000).Take(3 * 1000)], }); } } @@ -679,7 +679,7 @@ private static VSInternalWorkspaceSpellCheckableParams CreateWorkspaceParams( private static ImmutableArray<(string resultId, Uri uri)> CreateParamsFromPreviousReports(VSInternalWorkspaceSpellCheckableReport[] results) { - return results.Select(r => (r.ResultId!, r.TextDocument.Uri)).ToImmutableArray(); + return [.. results.Select(r => (r.ResultId!, r.TextDocument.Uri))]; } } } diff --git a/src/LanguageServer/ProtocolUnitTests/Symbols/DocumentSymbolsTests.cs b/src/LanguageServer/ProtocolUnitTests/Symbols/DocumentSymbolsTests.cs index b7c02a130b7ae..ced52fbfa5939 100644 --- a/src/LanguageServer/ProtocolUnitTests/Symbols/DocumentSymbolsTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/Symbols/DocumentSymbolsTests.cs @@ -179,7 +179,7 @@ private static LSP.DocumentSymbol CreateDocumentSymbol(LSP.SymbolKind kind, stri Kind = kind, Name = name, Range = location.Range, - Children = new LSP.DocumentSymbol[0], + Children = [], Detail = detail, #pragma warning disable 618 // obsolete member Deprecated = false, diff --git a/src/LanguageServer/ProtocolUnitTests/VSTypeScriptHandlerTests.cs b/src/LanguageServer/ProtocolUnitTests/VSTypeScriptHandlerTests.cs index 6093ca628acc8..043c8670f2733 100644 --- a/src/LanguageServer/ProtocolUnitTests/VSTypeScriptHandlerTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/VSTypeScriptHandlerTests.cs @@ -120,7 +120,7 @@ private static RoslynLanguageServer CreateLanguageServer(Stream inputStream, Str capabilitiesProvider, logger, workspace.Services.HostServices, - ImmutableArray.Create(InternalLanguageNames.TypeScript), + [InternalLanguageNames.TypeScript], WellKnownLspServerKinds.RoslynTypeScriptLspServer); jsonRpc.StartListening(); diff --git a/src/LanguageServer/ProtocolUnitTests/ValidateBreakableRange/ValidateBreakableRangeTests.cs b/src/LanguageServer/ProtocolUnitTests/ValidateBreakableRange/ValidateBreakableRangeTests.cs index 740fc49e4cb53..efb5e3b3028c3 100644 --- a/src/LanguageServer/ProtocolUnitTests/ValidateBreakableRange/ValidateBreakableRangeTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/ValidateBreakableRange/ValidateBreakableRangeTests.cs @@ -10,246 +10,261 @@ using Xunit.Abstractions; using LSP = Roslyn.LanguageServer.Protocol; -namespace Microsoft.CodeAnalysis.LanguageServer.UnitTests.ValidateBreakableRange -{ - public class ValidateBreakableRange : AbstractLanguageServerProtocolTests - { - public ValidateBreakableRange(ITestOutputHelper testOutputHelper) : base(testOutputHelper) - { - } - - [Theory, CombinatorialData] - public async Task SimpleStatement(bool mutatingLspWorkspace) - { - var markup = -@"class A +namespace Microsoft.CodeAnalysis.LanguageServer.UnitTests.ValidateBreakableRange; + +public sealed class ValidateBreakableRange(ITestOutputHelper testOutputHelper) : AbstractLanguageServerProtocolTests(testOutputHelper) { - void M() + [Theory, CombinatorialData] + public async Task SimpleStatement(bool mutatingLspWorkspace) { - {|expected:{|caret:|}M();|} - } -}"; - await using var testLspServer = await CreateTestLspServerAsync(markup, mutatingLspWorkspace); + var markup = + """ + class A + { + void M() + { + {|expected:{|caret:|}M();|} + } + } + """; + await using var testLspServer = await CreateTestLspServerAsync(markup, mutatingLspWorkspace); - var caret = testLspServer.GetLocations("caret").Single(); + var caret = testLspServer.GetLocations("caret").Single(); - var expected = testLspServer.GetLocations("expected").Single().Range; + var expected = testLspServer.GetLocations("expected").Single().Range; - var result = await RunAsync(testLspServer, caret); - AssertJsonEquals(expected, result); - } + var result = await RunAsync(testLspServer, caret); + AssertJsonEquals(expected, result); + } - [Theory, CombinatorialData] - public async Task LineBreakpoint(bool mutatingLspWorkspace) - { - var markup = -@"class A -{ - void M() + [Theory, CombinatorialData] + public async Task LineBreakpoint(bool mutatingLspWorkspace) { -#if FALSE - {|caret:|}M(); -#endif - } -}"; - await using var testLspServer = await CreateTestLspServerAsync(markup, mutatingLspWorkspace); + var markup = + """ + class A + { + void M() + { + #if FALSE + {|caret:|}M(); + #endif + } + } + """; + await using var testLspServer = await CreateTestLspServerAsync(markup, mutatingLspWorkspace); - var caret = testLspServer.GetLocations("caret").Single(); + var caret = testLspServer.GetLocations("caret").Single(); - var expected = caret.Range; + var expected = caret.Range; - var result = await RunAsync(testLspServer, caret); - AssertJsonEquals(expected, result); - } + var result = await RunAsync(testLspServer, caret); + AssertJsonEquals(expected, result); + } - [Theory, CombinatorialData] - public async Task NoBreakpointSpan(bool mutatingLspWorkspace) - { - var markup = -@"class A -{ - void M() + [Theory, CombinatorialData] + public async Task NoBreakpointSpan(bool mutatingLspWorkspace) { - {|caret:|}const int a = 1; - } -}"; - await using var testLspServer = await CreateTestLspServerAsync(markup, mutatingLspWorkspace); + var markup = + """ + class A + { + void M() + { + {|caret:|}const int a = 1; + } + } + """; + await using var testLspServer = await CreateTestLspServerAsync(markup, mutatingLspWorkspace); - var caret = testLspServer.GetLocations("caret").Single(); + var caret = testLspServer.GetLocations("caret").Single(); - var result = await RunAsync(testLspServer, caret); - Assert.Null(result); - } + var result = await RunAsync(testLspServer, caret); + Assert.Null(result); + } - [Theory, CombinatorialData] - public async Task SplitBreakpoint(bool mutatingLspWorkspace) - { - var markup = -@"class A -{ - void M() + [Theory, CombinatorialData] + public async Task SplitBreakpoint(bool mutatingLspWorkspace) { - {|breakpoint:int a = 1; {|expected:Console.WriteLine(""hello"");|}|} - } -}"; - await using var testLspServer = await CreateTestLspServerAsync(markup, mutatingLspWorkspace); + var markup = + """ + class A + { + void M() + { + {|breakpoint:int a = 1; {|expected:Console.WriteLine("hello");|}|} + } + } + """; + await using var testLspServer = await CreateTestLspServerAsync(markup, mutatingLspWorkspace); - var breakpoint = testLspServer.GetLocations("breakpoint").Single(); + var breakpoint = testLspServer.GetLocations("breakpoint").Single(); - var expected = testLspServer.GetLocations("expected").Single().Range; + var expected = testLspServer.GetLocations("expected").Single().Range; - var result = await RunAsync(testLspServer, breakpoint); - AssertJsonEquals(expected, result); - } + var result = await RunAsync(testLspServer, breakpoint); + AssertJsonEquals(expected, result); + } - [Theory, CombinatorialData, WorkItem("https://devdiv.visualstudio.com/DevDiv/_workitems/edit/1501785")] - public async Task InvalidExistingBreakpoint1(bool mutatingLspWorkspace) - { - var markup = -@"class A -{ - void M() + [Theory, CombinatorialData, WorkItem("https://devdiv.visualstudio.com/DevDiv/_workitems/edit/1501785")] + public async Task InvalidExistingBreakpoint1(bool mutatingLspWorkspace) { - {|breakpoint:int a Console.WriteLine(""hello"");|} - } -}"; - await using var testLspServer = await CreateTestLspServerAsync(markup, mutatingLspWorkspace); + var markup = + """ + class A + { + void M() + { + {|breakpoint:int a Console.WriteLine("hello");|} + } + } + """; + await using var testLspServer = await CreateTestLspServerAsync(markup, mutatingLspWorkspace); - var breakpoint = testLspServer.GetLocations("breakpoint").Single(); + var breakpoint = testLspServer.GetLocations("breakpoint").Single(); - var expected = breakpoint.Range; + var expected = breakpoint.Range; - var result = await RunAsync(testLspServer, breakpoint); - AssertJsonEquals(expected, result); - } + var result = await RunAsync(testLspServer, breakpoint); + AssertJsonEquals(expected, result); + } - [Theory, CombinatorialData, WorkItem("https://devdiv.visualstudio.com/DevDiv/_workitems/edit/1501882")] - public async Task InvalidExistingBreakpoint2(bool mutatingLspWorkspace) - { - var markup = -@"class A -{ - void M() + [Theory, CombinatorialData, WorkItem("https://devdiv.visualstudio.com/DevDiv/_workitems/edit/1501882")] + public async Task InvalidExistingBreakpoint2(bool mutatingLspWorkspace) { - int b= - {|breakpoint:int a = 1;|} - } -}"; - await using var testLspServer = await CreateTestLspServerAsync(markup, mutatingLspWorkspace); + var markup = + """ + class A + { + void M() + { + int b= + {|breakpoint:int a = 1;|} + } + } + """; + await using var testLspServer = await CreateTestLspServerAsync(markup, mutatingLspWorkspace); - var breakpoint = testLspServer.GetLocations("breakpoint").Single(); + var breakpoint = testLspServer.GetLocations("breakpoint").Single(); - var expected = breakpoint.Range; + var expected = breakpoint.Range; - var result = await RunAsync(testLspServer, breakpoint); - AssertJsonEquals(expected, result); - } + var result = await RunAsync(testLspServer, breakpoint); + AssertJsonEquals(expected, result); + } - [Theory, CombinatorialData] - public async Task TypingInMultilineBreakpoint(bool mutatingLspWorkspace) - { - // This simulates the request we get just after the user types the semi-colon on the first line - var markup = -@"class A -{ - void M() + [Theory, CombinatorialData] + public async Task TypingInMultilineBreakpoint(bool mutatingLspWorkspace) { - {|breakpoint:int a = 1; - {|expected:Console.WriteLine(""hello"");|}|} - } -}"; - await using var testLspServer = await CreateTestLspServerAsync(markup, mutatingLspWorkspace); + // This simulates the request we get just after the user types the semi-colon on the first line + var markup = + """ + class A + { + void M() + { + {|breakpoint:int a = 1; + {|expected:Console.WriteLine("hello");|}|} + } + } + """; + await using var testLspServer = await CreateTestLspServerAsync(markup, mutatingLspWorkspace); - var breakpoint = testLspServer.GetLocations("breakpoint").Single(); + var breakpoint = testLspServer.GetLocations("breakpoint").Single(); - var expected = testLspServer.GetLocations("expected").Single().Range; + var expected = testLspServer.GetLocations("expected").Single().Range; - var result = await RunAsync(testLspServer, breakpoint); - AssertJsonEquals(expected, result); - } + var result = await RunAsync(testLspServer, breakpoint); + AssertJsonEquals(expected, result); + } - [Theory, CombinatorialData] - public async Task TypingInMultilineBreakpoint2(bool mutatingLspWorkspace) - { - // This simulates the request we get just after the user types the semi-colon on the third line - var markup = -@"class A -{ - void M() + [Theory, CombinatorialData] + public async Task TypingInMultilineBreakpoint2(bool mutatingLspWorkspace) { - {|breakpoint:int a - = - 1; - {|expected:Console.WriteLine( - ""hello"" - );|}|} + // This simulates the request we get just after the user types the semi-colon on the third line + var markup = + """ + class A + { + void M() + { + {|breakpoint:int a + = + 1; + {|expected:Console.WriteLine( + "hello" + );|}|} + } + } + """; + await using var testLspServer = await CreateTestLspServerAsync(markup, mutatingLspWorkspace); + + var breakpoint = testLspServer.GetLocations("breakpoint").Single(); + + var expected = testLspServer.GetLocations("expected").Single().Range; + + var result = await RunAsync(testLspServer, breakpoint); + AssertJsonEquals(expected, result); } -}"; - await using var testLspServer = await CreateTestLspServerAsync(markup, mutatingLspWorkspace); - - var breakpoint = testLspServer.GetLocations("breakpoint").Single(); - - var expected = testLspServer.GetLocations("expected").Single().Range; - var result = await RunAsync(testLspServer, breakpoint); - AssertJsonEquals(expected, result); - } - - [Theory, CombinatorialData] - public async Task ExpandToMultilineBreakpoint(bool mutatingLspWorkspace) - { - // This simulates the request we get just after the user types the equals sign on the first line - var markup = -@"class A -{ - void M() + [Theory, CombinatorialData] + public async Task ExpandToMultilineBreakpoint(bool mutatingLspWorkspace) { - {|expected:int a = - {|breakpoint:GetSomeValue();|}|} - } -}"; - await using var testLspServer = await CreateTestLspServerAsync(markup, mutatingLspWorkspace); + // This simulates the request we get just after the user types the equals sign on the first line + var markup = + """ + class A + { + void M() + { + {|expected:int a = + {|breakpoint:GetSomeValue();|}|} + } + } + """; + await using var testLspServer = await CreateTestLspServerAsync(markup, mutatingLspWorkspace); - var breakpoint = testLspServer.GetLocations("breakpoint").Single(); + var breakpoint = testLspServer.GetLocations("breakpoint").Single(); - var expected = testLspServer.GetLocations("expected").Single().Range; + var expected = testLspServer.GetLocations("expected").Single().Range; - var result = await RunAsync(testLspServer, breakpoint); - AssertJsonEquals(expected, result); - } + var result = await RunAsync(testLspServer, breakpoint); + AssertJsonEquals(expected, result); + } - [Theory, CombinatorialData] - public async Task DoNotShrinkValidMultilineBreakpoints(bool mutatingLspWorkspace) - { - var markup = -@"class A -{ - void M() + [Theory, CombinatorialData] + public async Task DoNotShrinkValidMultilineBreakpoints(bool mutatingLspWorkspace) { - {|breakpoint:{|expected:int a = - GetSomeValue();|}|} - } -}"; - await using var testLspServer = await CreateTestLspServerAsync(markup, mutatingLspWorkspace); + var markup = + """ + class A + { + void M() + { + {|breakpoint:{|expected:int a = + GetSomeValue();|}|} + } + } + """; + await using var testLspServer = await CreateTestLspServerAsync(markup, mutatingLspWorkspace); - var breakpoint = testLspServer.GetLocations("breakpoint").Single(); + var breakpoint = testLspServer.GetLocations("breakpoint").Single(); - var expected = testLspServer.GetLocations("expected").Single().Range; + var expected = testLspServer.GetLocations("expected").Single().Range; - var result = await RunAsync(testLspServer, breakpoint); - AssertJsonEquals(expected, result); - } + var result = await RunAsync(testLspServer, breakpoint); + AssertJsonEquals(expected, result); + } - private static async Task RunAsync(TestLspServer testLspServer, LSP.Location caret) - { - return await testLspServer.ExecuteRequestAsync( - LSP.VSInternalMethods.TextDocumentValidateBreakableRangeName, - new LSP.VSInternalValidateBreakableRangeParams() - { - TextDocument = new LSP.TextDocumentIdentifier { Uri = caret.Uri }, - Range = caret.Range - }, - CancellationToken.None); - } + private static async Task RunAsync(TestLspServer testLspServer, LSP.Location caret) + { + return await testLspServer.ExecuteRequestAsync( + LSP.VSInternalMethods.TextDocumentValidateBreakableRangeName, + new LSP.VSInternalValidateBreakableRangeParams() + { + TextDocument = new LSP.TextDocumentIdentifier { Uri = caret.Uri }, + Range = caret.Range + }, + CancellationToken.None); } } diff --git a/src/LanguageServer/ProtocolUnitTests/Workspaces/LspWorkspaceManagerTests.cs b/src/LanguageServer/ProtocolUnitTests/Workspaces/LspWorkspaceManagerTests.cs index c82af271ddc77..5866d332036e1 100644 --- a/src/LanguageServer/ProtocolUnitTests/Workspaces/LspWorkspaceManagerTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/Workspaces/LspWorkspaceManagerTests.cs @@ -538,7 +538,7 @@ public async Task TestLspDocumentPreferredOverProjectSystemDocumentAddInMutating // Start with an empty workspace. await using var testLspServer = await CreateTestLspServerAsync( - Array.Empty(), mutatingLspWorkspace: true, new InitializationOptions { ServerKind = WellKnownLspServerKinds.CSharpVisualBasicLspServer }); + [], mutatingLspWorkspace: true, new InitializationOptions { ServerKind = WellKnownLspServerKinds.CSharpVisualBasicLspServer }); // Open the doc var filePath = "c:\\\ue25b\ud86d\udeac.cs"; diff --git a/src/Scripting/CoreTestUtilities/ScriptingTestHelpers.cs b/src/Scripting/CoreTestUtilities/ScriptingTestHelpers.cs index 649d0240210f1..48394f300e8b3 100644 --- a/src/Scripting/CoreTestUtilities/ScriptingTestHelpers.cs +++ b/src/Scripting/CoreTestUtilities/ScriptingTestHelpers.cs @@ -14,7 +14,7 @@ namespace Microsoft.CodeAnalysis.Scripting.Test { - public class ScriptingTestHelpers + public static class ScriptingTestHelpers { public static ScriptState RunScriptWithOutput(Script script, string expectedOutput) { diff --git a/src/Test/PdbUtilities/EditAndContinue/EditAndContinueTest.cs b/src/Test/PdbUtilities/EditAndContinue/EditAndContinueTest.cs index f51868ce67eab..e43dd0f899fc0 100644 --- a/src/Test/PdbUtilities/EditAndContinue/EditAndContinueTest.cs +++ b/src/Test/PdbUtilities/EditAndContinue/EditAndContinueTest.cs @@ -132,10 +132,10 @@ internal TSelf Verify() } readers.Add(generation.MetadataReader); - var verifier = new GenerationVerifier(index, generation, readers.ToImmutableArray()); + var verifier = new GenerationVerifier(index, generation, [.. readers]); generation.Verifier(verifier); - exceptions.Add(verifier.Exceptions.ToImmutableArray()); + exceptions.Add([.. verifier.Exceptions]); index++; } @@ -179,7 +179,7 @@ private ImmutableArray GetSemanticEdits( { var syntaxMapFromMarkers = oldSource.MarkedSpans.IsEmpty ? null : SourceWithMarkedNodes.GetSyntaxMap(oldSource, newSource, unmappedNodes); - return ImmutableArray.CreateRange(edits.Select(e => + return [.. edits.Select(e => { var oldSymbol = e.Kind is SemanticEditKind.Update or SemanticEditKind.Delete ? e.SymbolProvider(oldCompilation) : null; @@ -201,7 +201,7 @@ private ImmutableArray GetSemanticEdits( } return new SemanticEdit(e.Kind, oldSymbol, newSymbol, syntaxMap, e.RudeEdits); - })); + })]; } public void Dispose() diff --git a/src/Test/PdbUtilities/Reader/MethodDebugInfoBytes.cs b/src/Test/PdbUtilities/Reader/MethodDebugInfoBytes.cs index fac2a61ea912d..1d8b35680acf9 100644 --- a/src/Test/PdbUtilities/Reader/MethodDebugInfoBytes.cs +++ b/src/Test/PdbUtilities/Reader/MethodDebugInfoBytes.cs @@ -51,9 +51,9 @@ public Builder(string[][] importStringGroups = null, bool suppressUsingInfo = fa var namespaces = importStringGroups == null ? default(ImmutableArray) - : importStringGroups.SelectMany(names => names.Select(name => (ISymUnmanagedNamespace)new MockSymUnmanagedNamespace(name))).ToImmutableArray(); + : [.. importStringGroups.SelectMany(names => names.Select(name => (ISymUnmanagedNamespace)new MockSymUnmanagedNamespace(name)))]; var childScope = new MockSymUnmanagedScope(default(ImmutableArray), namespaces, constants); - var rootScope = new MockSymUnmanagedScope(ImmutableArray.Create(childScope), default(ImmutableArray)); + var rootScope = new MockSymUnmanagedScope([childScope], default(ImmutableArray)); _method = new MockSymUnmanagedMethod(rootScope); } diff --git a/src/Test/PdbUtilities/Reader/MockSymUnmanagedReader.cs b/src/Test/PdbUtilities/Reader/MockSymUnmanagedReader.cs index a6f187ce0e361..b158a7f9a477d 100644 --- a/src/Test/PdbUtilities/Reader/MockSymUnmanagedReader.cs +++ b/src/Test/PdbUtilities/Reader/MockSymUnmanagedReader.cs @@ -244,7 +244,7 @@ public MockSymUnmanagedScope(ImmutableArray children, Immuta { _children = children; _namespaces = namespaces; - _constants = constants ?? new ISymUnmanagedConstant[0]; + _constants = constants ?? []; _startOffset = startOffset; _endOffset = endOffset; } @@ -320,10 +320,7 @@ public MockSymUnmanagedNamespace(string name) { if (name != null) { - var builder = ArrayBuilder.GetInstance(); - builder.AddRange(name); - builder.AddRange('\0'); - _nameChars = builder.ToImmutableAndFree(); + _nameChars = [.. name, '\0']; } } diff --git a/src/Test/PdbUtilities/Reader/PdbValidation.cs b/src/Test/PdbUtilities/Reader/PdbValidation.cs index 6a76b2ff3b2fc..dfca25bccafab 100644 --- a/src/Test/PdbUtilities/Reader/PdbValidation.cs +++ b/src/Test/PdbUtilities/Reader/PdbValidation.cs @@ -547,7 +547,7 @@ public static unsafe byte[] GetSourceLinkData(Stream pdbStream) Marshal.ThrowExceptionForHR(symReader.GetSourceServerData(out byte* data, out int size)); if (size == 0) { - return Array.Empty(); + return []; } var result = new byte[size]; diff --git a/src/Test/PdbUtilities/Reader/SymReaderFactory.cs b/src/Test/PdbUtilities/Reader/SymReaderFactory.cs index 8968f175f0b5a..d15171d69a9cd 100644 --- a/src/Test/PdbUtilities/Reader/SymReaderFactory.cs +++ b/src/Test/PdbUtilities/Reader/SymReaderFactory.cs @@ -72,7 +72,7 @@ public static ISymUnmanagedReader5 CreateReader(byte[] pdbImage, byte[] peImageO public static ISymUnmanagedReader5 CreateReader(ImmutableArray pdbImage, ImmutableArray peImageOpt = default(ImmutableArray)) { - return CreateReader(new MemoryStream(pdbImage.ToArray()), (peImageOpt.IsDefault) ? null : new PEReader(peImageOpt)); + return CreateReader(new MemoryStream([.. pdbImage]), (peImageOpt.IsDefault) ? null : new PEReader(peImageOpt)); } public static ISymUnmanagedReader5 CreateReader(Stream pdbStream, Stream peStreamOpt = null) diff --git a/src/Test/PdbUtilities/Reader/Token2SourceLineExporter.cs b/src/Test/PdbUtilities/Reader/Token2SourceLineExporter.cs index 61de9bce50d17..dad4c78166334 100644 --- a/src/Test/PdbUtilities/Reader/Token2SourceLineExporter.cs +++ b/src/Test/PdbUtilities/Reader/Token2SourceLineExporter.cs @@ -12,7 +12,7 @@ namespace Roslyn.Test.PdbUtilities { - public class Token2SourceLineExporter + public static class Token2SourceLineExporter { // NOTE: this type implementation is essentially an extraction from PdbReader // located under ndp\clr\src\ToolBox\CCI2\PdbReader folder @@ -1127,10 +1127,6 @@ private struct OemSymbol //internal byte[] rgl; // user data, force 4-byte alignment }; - private Token2SourceLineExporter() - { - } - private static readonly XmlWriterSettings s_xmlWriterSettings = new XmlWriterSettings { Encoding = Encoding.UTF8, @@ -1147,7 +1143,7 @@ public static string TokenToSourceMap2Xml(Stream read, bool maskToken = false) { writer.WriteStartElement("token-map"); - List list = new List(LoadTokenToSourceMapping(read).Values); + List list = [.. LoadTokenToSourceMapping(read).Values]; list.Sort( (x, y) => { @@ -1467,7 +1463,7 @@ private static void LoadDbiStream(BitAccess bits, out DbiModuleInfo[] modules, o if (modList.Count > 0) { - modules = modList.ToArray(); + modules = [.. modList]; } else { diff --git a/src/Test/PdbUtilities/Roslyn.Test.PdbUtilities.csproj b/src/Test/PdbUtilities/Roslyn.Test.PdbUtilities.csproj index 78b094b4e5bbf..9290b64c955c0 100644 --- a/src/Test/PdbUtilities/Roslyn.Test.PdbUtilities.csproj +++ b/src/Test/PdbUtilities/Roslyn.Test.PdbUtilities.csproj @@ -45,15 +45,6 @@ - - - - - - diff --git a/src/Test/Perf/StackDepthTest/Program.cs b/src/Test/Perf/StackDepthTest/Program.cs index 0ec6f3905b7bd..2294e1fc6b346 100644 --- a/src/Test/Perf/StackDepthTest/Program.cs +++ b/src/Test/Perf/StackDepthTest/Program.cs @@ -13,7 +13,7 @@ namespace OverflowSensitivity { - public class Program + public static class Program { [DllImport("kernel32.dll")] private static extern ErrorModes SetErrorMode(ErrorModes uMode); diff --git a/src/Test/Perf/Utilities/TraceManager.cs b/src/Test/Perf/Utilities/TraceManager.cs index 067c0355f5299..50c4c5dd9abb8 100644 --- a/src/Test/Perf/Utilities/TraceManager.cs +++ b/src/Test/Perf/Utilities/TraceManager.cs @@ -12,7 +12,7 @@ namespace Roslyn.Test.Performance.Utilities { - public class TraceManagerFactory + public static class TraceManagerFactory { public static ITraceManager GetBestTraceManager() { diff --git a/src/Test/Perf/tests/helloworld/HelloWorld.cs b/src/Test/Perf/tests/helloworld/HelloWorld.cs index 55f2b35169308..e638ded629934 100644 --- a/src/Test/Perf/tests/helloworld/HelloWorld.cs +++ b/src/Test/Perf/tests/helloworld/HelloWorld.cs @@ -2,9 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - -public class Hello1 +public static class Hello1 { public static void Main() { diff --git a/src/Tools/BuildActionTelemetryTable/Program.cs b/src/Tools/BuildActionTelemetryTable/Program.cs index e0878467c011b..ed7802956b81f 100644 --- a/src/Tools/BuildActionTelemetryTable/Program.cs +++ b/src/Tools/BuildActionTelemetryTable/Program.cs @@ -18,7 +18,7 @@ namespace BuildActionTelemetryTable { - public class Program + public static class Program { private static readonly string s_executingPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)!; diff --git a/src/Tools/ExternalAccess/Razor/Cohost/Handlers/Completion.cs b/src/Tools/ExternalAccess/Razor/Cohost/Handlers/Completion.cs index 3e284056947b0..873ee420ca5ae 100644 --- a/src/Tools/ExternalAccess/Razor/Cohost/Handlers/Completion.cs +++ b/src/Tools/ExternalAccess/Razor/Cohost/Handlers/Completion.cs @@ -2,13 +2,16 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.LanguageServer; using Microsoft.CodeAnalysis.LanguageServer.Handler; using Microsoft.CodeAnalysis.LanguageServer.Handler.Completion; +using Microsoft.CodeAnalysis.LanguageServer.Handler.InlineCompletions; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Text; +using Microsoft.CommonLanguageServerProtocol.Framework; using Roslyn.Utilities; using LSP = Roslyn.LanguageServer.Protocol; @@ -63,4 +66,45 @@ private static CompletionListCache GetCache() return CompletionResolveHandler.ResolveCompletionItemAsync( completionItem, document, globalOptions, capabilityHelper, cache, cancellationToken); } + + public static Task GetInlineCompletionItemsAsync( + RazorCohostRequestContext? context, + Document document, + LinePosition position, + LSP.FormattingOptions options, + CancellationToken cancellationToken) + { + // Razor can't construct a RazorCohostRequestContext so we need to handle the null case, for their tests + var logger = context is { } razorContext ? razorContext.GetRequiredService() : new EmptyLogger(); + var xmlSnippetParser = document.Project.Solution.Services.ExportProvider.GetService(); + + return InlineCompletionsHandler.GetInlineCompletionItemsAsync(logger, document, position, options, xmlSnippetParser, cancellationToken); + } + + private sealed class EmptyLogger : ILspLogger + { + public void LogStartContext(string message, params object[] @params) + { + } + + public void LogEndContext(string message, params object[] @params) + { + } + + public void LogInformation(string message, params object[] @params) + { + } + + public void LogWarning(string message, params object[] @params) + { + } + + public void LogError(string message, params object[] @params) + { + } + + public void LogException(Exception exception, string? message = null, params object[] @params) + { + } + } } diff --git a/src/Tools/ExternalAccess/Razor/Cohost/Handlers/DocumentSymbols.cs b/src/Tools/ExternalAccess/Razor/Cohost/Handlers/DocumentSymbols.cs index 51db13bc8f38b..dfc26d5ecce9e 100644 --- a/src/Tools/ExternalAccess/Razor/Cohost/Handlers/DocumentSymbols.cs +++ b/src/Tools/ExternalAccess/Razor/Cohost/Handlers/DocumentSymbols.cs @@ -19,9 +19,4 @@ public static Task> GetDocumentSy // with a VSImageId. This value should be retrieved from the language server's client capabilities. return DocumentSymbolsHandler.GetDocumentSymbolsAsync(document, useHierarchicalSymbols, supportsVSExtensions, cancellationToken); } - - [Obsolete("Update to call overload that takes 'supportsVSExtensions' argument.")] - public static Task> GetDocumentSymbolsAsync( - Document document, bool useHierarchicalSymbols, CancellationToken cancellationToken) - => GetDocumentSymbolsAsync(document, useHierarchicalSymbols, supportsVSExtensions: false, cancellationToken); } diff --git a/src/Tools/ExternalAccess/Razor/Cohost/Handlers/FindAllReferences.cs b/src/Tools/ExternalAccess/Razor/Cohost/Handlers/FindAllReferences.cs new file mode 100644 index 0000000000000..074b5330eadd9 --- /dev/null +++ b/src/Tools/ExternalAccess/Razor/Cohost/Handlers/FindAllReferences.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.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.LanguageServer.Handler; +using Microsoft.CodeAnalysis.MetadataAsSource; +using Microsoft.CodeAnalysis.Options; +using Microsoft.CodeAnalysis.Shared.TestHooks; +using Microsoft.CodeAnalysis.Text; +using Roslyn.LanguageServer.Protocol; + +namespace Microsoft.CodeAnalysis.ExternalAccess.Razor.Cohost.Handlers; + +using Location = Roslyn.LanguageServer.Protocol.Location; + +internal static class FindAllReferences +{ + public static async Task[]?> FindReferencesAsync(Workspace workspace, Document document, LinePosition linePosition, bool supportsVSExtensions, CancellationToken cancellationToken) + { + var globalOptions = document.Project.Solution.Services.ExportProvider.GetService(); + var metadataAsSourceFileService = document.Project.Solution.Services.ExportProvider.GetService(); + + // Passing null here means this will just collect items in an array builder + var progress = BufferedProgress.Create[]>(progress: null); + + await FindAllReferencesHandler.FindReferencesAsync(progress, workspace, document, linePosition, supportsVSExtensions, globalOptions, metadataAsSourceFileService, AsynchronousOperationListenerProvider.NullListener, cancellationToken).ConfigureAwait(false); + + return progress.GetFlattenedValues(); + } +} diff --git a/src/Tools/ExternalAccess/Razor/Cohost/Handlers/ValidateBreakableRange.cs b/src/Tools/ExternalAccess/Razor/Cohost/Handlers/ValidateBreakableRange.cs new file mode 100644 index 0000000000000..1b6d917e425f3 --- /dev/null +++ b/src/Tools/ExternalAccess/Razor/Cohost/Handlers/ValidateBreakableRange.cs @@ -0,0 +1,27 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.LanguageServer; +using Microsoft.CodeAnalysis.LanguageServer.Handler; +using Microsoft.CodeAnalysis.Text; + +namespace Microsoft.CodeAnalysis.ExternalAccess.Razor.Cohost.Handlers; + +internal static class ValidateBreakableRange +{ + public static async Task GetBreakableRangeAsync(Document document, LinePositionSpan span, CancellationToken cancellationToken) + { + var range = ProtocolConversions.LinePositionToRange(span); + var result = await ValidateBreakableRangeHandler.GetBreakableRangeAsync(document, range, cancellationToken).ConfigureAwait(false); + + if (result is null) + { + return null; + } + + return ProtocolConversions.RangeToLinePositionSpan(result); + } +} diff --git a/src/Tools/ExternalAccess/Razor/ITextBufferExtensions.cs b/src/Tools/ExternalAccess/Razor/ITextBufferExtensions.cs new file mode 100644 index 0000000000000..b6eb6f2e02df9 --- /dev/null +++ b/src/Tools/ExternalAccess/Razor/ITextBufferExtensions.cs @@ -0,0 +1,18 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Diagnostics.CodeAnalysis; +using Microsoft.CodeAnalysis.Text; +using Microsoft.VisualStudio.Text; + +namespace Microsoft.CodeAnalysis.ExternalAccess.Razor; + +internal static class ITextBufferExtensions +{ + public static bool TryGetTextDocument(this ITextBuffer textBuffer, [NotNullWhen(true)] out TextDocument? textDocument) + { + textDocument = textBuffer.CurrentSnapshot.AsText().GetOpenTextDocumentInCurrentContextWithChanges(); + return textDocument is not null; + } +} diff --git a/src/Tools/ExternalAccess/Razor/RazorAnalyzerAssemblyResolver.cs b/src/Tools/ExternalAccess/Razor/RazorAnalyzerAssemblyResolver.cs index 85c36e8c54a15..f3d0868fd4d5a 100644 --- a/src/Tools/ExternalAccess/Razor/RazorAnalyzerAssemblyResolver.cs +++ b/src/Tools/ExternalAccess/Razor/RazorAnalyzerAssemblyResolver.cs @@ -3,49 +3,56 @@ // See the LICENSE file in the project root for more information. using System; +using System.Collections.Generic; using System.Composition; using System.Diagnostics; using System.Reflection; using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.VisualStudio.Composition; namespace Microsoft.CodeAnalysis.ExternalAccess.Razor { [Export(typeof(IAnalyzerAssemblyResolver)), Shared] - internal class RazorAnalyzerAssemblyResolver : IAnalyzerAssemblyResolver + [method: ImportingConstructor] + [method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] + internal class RazorAnalyzerAssemblyResolver() : IAnalyzerAssemblyResolver { private static Func? s_assemblyResolver; - /// - /// We use this as a heuristic to catch a case where we set the resolver too - /// late and the resolver has already been asked to resolve a razor assembly. - /// - /// Note this isn't perfectly accurate but is only used to trigger an assert - /// in debug builds. - /// - private static bool s_razorRequested = false; + private static readonly HashSet s_assembliesRequested = []; - [ImportingConstructor] - [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - public RazorAnalyzerAssemblyResolver() - { - } + private static readonly object s_resolverLock = new(); - internal static Func? AssemblyResolver + /// + /// Attempts to set the assembly resolver. Will only succeed if the has not already been requested to load and the resolver has not been set previously. + /// + /// The resolver function to set. + /// The name of an assembly that is checked to see if it has been requested to load. Setting the resolver will fail if this has already been requested. + /// true when the resolver was successfully set. + internal static bool TrySetAssemblyResolver(Func resolver, AssemblyName canaryAssembly) { - get => s_assemblyResolver; - set + lock (s_resolverLock) { - Debug.Assert(s_assemblyResolver == null, "Assembly resolver should not be set multiple times."); - Debug.Assert(!s_razorRequested, "A razor assembly has already been requested before setting the resolver."); - s_assemblyResolver = value; + if (s_assemblyResolver is null && !s_assembliesRequested.Contains(canaryAssembly)) + { + s_assemblyResolver = resolver; + return true; + } + return false; } } public Assembly? ResolveAssembly(AssemblyName assemblyName) { - s_razorRequested |= assemblyName.FullName.Contains("Razor"); - return s_assemblyResolver?.Invoke(assemblyName); + Func? resolver = null; + lock (s_resolverLock) + { + s_assembliesRequested.Add(assemblyName); + resolver = s_assemblyResolver; + } + + return resolver?.Invoke(assemblyName); } } } diff --git a/src/Tools/ExternalAccess/Razor/RazorPredefinedCodeRefactoringProviderNames.cs b/src/Tools/ExternalAccess/Razor/RazorPredefinedCodeRefactoringProviderNames.cs index a730f074999a3..0e3d352d2874d 100644 --- a/src/Tools/ExternalAccess/Razor/RazorPredefinedCodeRefactoringProviderNames.cs +++ b/src/Tools/ExternalAccess/Razor/RazorPredefinedCodeRefactoringProviderNames.cs @@ -23,7 +23,7 @@ internal static class RazorPredefinedCodeRefactoringProviderNames public static string ExtractInterface => PredefinedCodeRefactoringProviderNames.ExtractInterface; public static string ExtractMethod => PredefinedCodeRefactoringProviderNames.ExtractMethod; public static string GenerateConstructorFromMembers => PredefinedCodeRefactoringProviderNames.GenerateConstructorFromMembers; - public static string GenerateDefaultConstructors => PredefinedCodeRefactoringProviderNames.GenerateDefaultConstructors; + public static string GenerateDefaultConstructors => nameof(GenerateDefaultConstructors); public static string GenerateEqualsAndGetHashCodeFromMembers => PredefinedCodeRefactoringProviderNames.GenerateEqualsAndGetHashCodeFromMembers; public static string GenerateOverrides => PredefinedCodeRefactoringProviderNames.GenerateOverrides; public static string InlineTemporary => PredefinedCodeRefactoringProviderNames.InlineTemporary; diff --git a/src/Tools/ExternalAccess/Razor/RazorProjectExtensions.cs b/src/Tools/ExternalAccess/Razor/RazorProjectExtensions.cs index 7603f875f31e9..25ec3e65f3f4d 100644 --- a/src/Tools/ExternalAccess/Razor/RazorProjectExtensions.cs +++ b/src/Tools/ExternalAccess/Razor/RazorProjectExtensions.cs @@ -17,5 +17,13 @@ internal static class RazorProjectExtensions { return project.GetSourceGeneratorRunResultAsync(cancellationToken); } + + internal static async ValueTask> GetSourceGeneratedDocumentsForGeneratorAsync(this Project project, string assemblyName, string assemblyPath, Version assemblyVersion, string typeName, CancellationToken cancellationToken) + { + var results = await project.GetSourceGeneratedDocumentsAsync(cancellationToken).ConfigureAwait(false); + + var generatorIdentity = new SourceGeneratorIdentity(assemblyName, assemblyPath, assemblyVersion, typeName); + return results.Where(s => s.Identity.Generator == generatorIdentity); + } } } diff --git a/src/Tools/IdeCoreBenchmarks/ProjectOperationBenchmarks.cs b/src/Tools/IdeCoreBenchmarks/ProjectOperationBenchmarks.cs index e67f5aa80c5c0..107a1989f0715 100644 --- a/src/Tools/IdeCoreBenchmarks/ProjectOperationBenchmarks.cs +++ b/src/Tools/IdeCoreBenchmarks/ProjectOperationBenchmarks.cs @@ -12,7 +12,7 @@ namespace IdeCoreBenchmarks { - public class ProjectOperationBenchmarks + public static class ProjectOperationBenchmarks { private static readonly SourceText s_newText = SourceText.From("text"); diff --git a/src/Tools/Source/RunTests/RunTests.csproj b/src/Tools/Source/RunTests/RunTests.csproj index c3c7c14e08d87..f88b6a17d7dff 100644 --- a/src/Tools/Source/RunTests/RunTests.csproj +++ b/src/Tools/Source/RunTests/RunTests.csproj @@ -10,11 +10,9 @@ - - diff --git a/src/Tools/TestDiscoveryWorker/Program.cs b/src/Tools/TestDiscoveryWorker/Program.cs index 882ab62b3db1c..4d1289b3e9e7c 100644 --- a/src/Tools/TestDiscoveryWorker/Program.cs +++ b/src/Tools/TestDiscoveryWorker/Program.cs @@ -65,7 +65,7 @@ await Console.Out.WriteLineAsync($"Discovering tests in {testDescriptor}...").ConfigureAwait(false); using var xunit = new XunitFrontController(AppDomainSupport.IfAvailable, assemblyFileName, shadowCopy: false); - var configuration = ConfigReader.Load(assemblyFileName); + var configuration = ConfigReader.Load(assemblyFileName, configFileName: null); var sink = new Sink(); xunit.Find(includeSourceInformation: false, messageSink: sink, diff --git a/src/Tools/TestDiscoveryWorker/TestDiscoveryWorker.csproj b/src/Tools/TestDiscoveryWorker/TestDiscoveryWorker.csproj index 84032b5202050..1d6c65bf6d8ec 100644 --- a/src/Tools/TestDiscoveryWorker/TestDiscoveryWorker.csproj +++ b/src/Tools/TestDiscoveryWorker/TestDiscoveryWorker.csproj @@ -10,8 +10,6 @@ - - diff --git a/src/VisualStudio/CSharp/Impl/CSharpExtension.cs b/src/VisualStudio/CSharp/Impl/CSharpExtension.cs index 86969cdd5f05e..bb5c514ea67d9 100644 --- a/src/VisualStudio/CSharp/Impl/CSharpExtension.cs +++ b/src/VisualStudio/CSharp/Impl/CSharpExtension.cs @@ -22,9 +22,9 @@ internal sealed class CSharpExtension : Extension public static CommandGroupConfiguration ProjectCommandGroupWithPlacement => new(GroupPlacement.VsctParent(new Guid(VSConstants.CMDSETID.ShellMainMenu_string), VsMenus.IDM_VS_CTXT_PROJNODE, priority: 0x0400)) { - Children = new[] - { + Children = + [ GroupChild.Command() - } + ] }; } diff --git a/src/VisualStudio/CSharp/Impl/CSharpVSResources.resx b/src/VisualStudio/CSharp/Impl/CSharpVSResources.resx index c4670e718b663..1294054572933 100644 --- a/src/VisualStudio/CSharp/Impl/CSharpVSResources.resx +++ b/src/VisualStudio/CSharp/Impl/CSharpVSResources.resx @@ -126,9 +126,6 @@ Surround With - - Insert Snippet - Automatically format _block on } @@ -313,57 +310,21 @@ New line options for keywords - - _Show procedure line separators - - - Editor Help - - - Highlight related _keywords under cursor - - - _Highlight references to symbol under cursor - Enter _outlining mode when files open - - Extract Method - _Generate XML documentation comments for /// - - Highlighting - _Insert * at the start of new lines when writing /* */ comments - - Optimize for solution size - - - Large - - - Regular - - - Small - Using Directives - - Performance - _Place 'System' directives first when sorting usings - - _Show completion list after a character is typed - Place _keywords in completion lists @@ -376,9 +337,6 @@ Selection In Completion List - - Show preview for rename _tracking - Place open brace on new line for property, indexer, and event accessors @@ -436,39 +394,12 @@ Split string literals on _enter - - _Highlight matching portions of completion list items - - - Show completion item _filters - - - Enter key behavior: - - - _Only add new line on enter after end of fully typed word - - - _Always add new line on enter - - - _Never add new line on enter - Always include snippets Include snippets when ?-Tab is typed after an identifier - - Never include snippets - - - Snippets behavior - - - Show completion list after a character is _deleted - 'null' checking: @@ -493,9 +424,6 @@ Automatically format when typing - - Never - When on single line @@ -508,10 +436,6 @@ Fade out unused usings - - Prefer 'is null' for reference equality checks - 'is null' is a C# string and should not be localized. - Report invalid placeholders in 'string.Format' calls @@ -525,11 +449,11 @@ In other binary operators: && || ?? and or 'and' and 'or' are C# keywords and should not be localized - + Show name s_uggestions - - Remove unnecessary usings + + Show name suggestions In relational operators: < > <= >= is as == != @@ -538,23 +462,13 @@ Discard - - Unused local - When on multiple lines - - Show items from unimported namespaces - Inside namespace 'namespace' is a C# keyword and should not be localized - - Outside namespace - 'namespace' is a C# keyword and should not be localized - Preferred 'using' directive placement 'using' is a C# keyword and should not be localized @@ -573,9 +487,6 @@ Automatically show completion list in argument lists - - Show remarks in Quick Info - Pattern matching preferences: @@ -610,9 +521,6 @@ Automatically complete statement on semicolon - - Prefer 'null' check over type check - Block scoped @@ -628,15 +536,15 @@ Show new snippet experience (experimental) + + Show new snippet experience + Allow blank line after token in conditional expression Allow blank line after token in arrow expression clause - - Semantic Search - Run Query diff --git a/src/VisualStudio/CSharp/Impl/CodeModel/CSharpCodeModelService.cs b/src/VisualStudio/CSharp/Impl/CodeModel/CSharpCodeModelService.cs index 39bcd183ae1fe..78eed0f07570c 100644 --- a/src/VisualStudio/CSharp/Impl/CodeModel/CSharpCodeModelService.cs +++ b/src/VisualStudio/CSharp/Impl/CodeModel/CSharpCodeModelService.cs @@ -1280,7 +1280,7 @@ public override SyntaxNode SetComment(SyntaxNode node, string value) { var builder = new StringBuilder(); - foreach (var line in value.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries)) + foreach (var line in value.Split(['\r', '\n'], StringSplitOptions.RemoveEmptyEntries)) { builder.Append("// "); builder.Append(line); @@ -1354,7 +1354,7 @@ public override string GetDocComment(SyntaxNode node) var text = memberDeclaration.SyntaxTree.GetText(CancellationToken.None); var newLine = GetNewLineCharacter(text); - var lines = documentationComment.ToString().Split(new[] { newLine }, StringSplitOptions.None); + var lines = documentationComment.ToString().Split([newLine], StringSplitOptions.None); // trim off leading whitespace and exterior trivia. var lengthToStrip = lines[0].GetLeadingWhitespace().Length; @@ -1415,7 +1415,7 @@ public override SyntaxNode SetDocComment(SyntaxNode node, string value) foreach (var child in docElement.Elements()) { - foreach (var line in child.ToString().Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries)) + foreach (var line in child.ToString().Split(['\r', '\n'], StringSplitOptions.RemoveEmptyEntries)) { builder.Append("/// "); builder.Append(line); @@ -3673,7 +3673,7 @@ public override object GetExternalTypeExtender(string name, string externalLocat } public override string[] GetTypeExtenderNames() - => Array.Empty(); + => []; public override object GetTypeExtender(string name, AbstractCodeType symbol) => throw Exceptions.ThrowEFail(); diff --git a/src/VisualStudio/CSharp/Impl/EditorConfigSettings/DataProvider/CodeStyle/CSharpCodeStyleSettingsProvider.cs b/src/VisualStudio/CSharp/Impl/EditorConfigSettings/DataProvider/CodeStyle/CSharpCodeStyleSettingsProvider.cs index c2bcace02d039..90b03e02d0973 100644 --- a/src/VisualStudio/CSharp/Impl/EditorConfigSettings/DataProvider/CodeStyle/CSharpCodeStyleSettingsProvider.cs +++ b/src/VisualStudio/CSharp/Impl/EditorConfigSettings/DataProvider/CodeStyle/CSharpCodeStyleSettingsProvider.cs @@ -7,7 +7,9 @@ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.AddImport; using Microsoft.CodeAnalysis.CodeStyle; +using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.CodeStyle; +using Microsoft.CodeAnalysis.Editor.CSharp; using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Data; using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.DataProvider; using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Updater; @@ -70,14 +72,14 @@ private static IEnumerable GetUsingsCodeStyleOptions(TieredAna { yield return CodeStyleSetting.Create(CSharpCodeStyleOptions.PreferredUsingDirectivePlacement, CSharpVSResources.Preferred_using_directive_placement, options, updater, enumValues: [AddImportPlacement.InsideNamespace, AddImportPlacement.OutsideNamespace], - valueDescriptions: [CSharpVSResources.Inside_namespace, CSharpVSResources.Outside_namespace]); + valueDescriptions: [CSharpVSResources.Inside_namespace, CSharpEditorResources.Outside_namespace]); } private static IEnumerable GetNullCheckingCodeStyleOptions(TieredAnalyzerConfigOptions options, OptionUpdater updater) { yield return CodeStyleSetting.Create(CSharpCodeStyleOptions.PreferThrowExpression, CSharpVSResources.Prefer_throw_expression, options, updater); yield return CodeStyleSetting.Create(CSharpCodeStyleOptions.PreferConditionalDelegateCall, CSharpVSResources.Prefer_conditional_delegate_call, options, updater); - yield return CodeStyleSetting.Create(CSharpCodeStyleOptions.PreferNullCheckOverTypeCheck, CSharpVSResources.Prefer_null_check_over_type_check, options, updater); + yield return CodeStyleSetting.Create(CSharpCodeStyleOptions.PreferNullCheckOverTypeCheck, CSharpAnalyzersResources.Prefer_null_check_over_type_check, options, updater); } private static IEnumerable GetModifierCodeStyleOptions(TieredAnalyzerConfigOptions options, OptionUpdater updater) @@ -93,7 +95,7 @@ private static IEnumerable GetCodeBlockCodeStyleOptions(Tiered yield return CodeStyleSetting.Create(CSharpCodeStyleOptions.PreferSimpleUsingStatement, ServicesVSResources.Prefer_simple_using_statement, options, updater); yield return CodeStyleSetting.Create(CSharpCodeStyleOptions.PreferBraces, ServicesVSResources.Prefer_braces, options, updater, enumValues: [PreferBracesPreference.Always, PreferBracesPreference.None, PreferBracesPreference.WhenMultiline], - valueDescriptions: [ServicesVSResources.Yes, ServicesVSResources.No, CSharpVSResources.When_on_multiple_lines]); + valueDescriptions: [EditorFeaturesResources.Yes, EditorFeaturesResources.No, CSharpVSResources.When_on_multiple_lines]); yield return CodeStyleSetting.Create(CSharpCodeStyleOptions.NamespaceDeclarations, ServicesVSResources.Namespace_declarations, options, updater, enumValues: [NamespaceDeclarationPreference.BlockScoped, NamespaceDeclarationPreference.FileScoped], @@ -136,7 +138,7 @@ private static IEnumerable GetVariableCodeStyleOptions(TieredA private static IEnumerable GetExpressionBodyCodeStyleOptions(TieredAnalyzerConfigOptions options, OptionUpdater updater) { var enumValues = new[] { ExpressionBodyPreference.Never, ExpressionBodyPreference.WhenPossible, ExpressionBodyPreference.WhenOnSingleLine }; - var valueDescriptions = new[] { CSharpVSResources.Never, CSharpVSResources.When_possible, CSharpVSResources.When_on_single_line }; + var valueDescriptions = new[] { ServicesVSResources.Never, CSharpVSResources.When_possible, CSharpVSResources.When_on_single_line }; yield return CodeStyleSetting.Create(CSharpCodeStyleOptions.PreferExpressionBodiedMethods, ServicesVSResources.Use_expression_body_for_methods, options, updater, enumValues, valueDescriptions); yield return CodeStyleSetting.Create(CSharpCodeStyleOptions.PreferExpressionBodiedConstructors, ServicesVSResources.Use_expression_body_for_constructors, options, updater, enumValues, valueDescriptions); @@ -151,7 +153,7 @@ private static IEnumerable GetExpressionBodyCodeStyleOptions(T private static IEnumerable GetUnusedValueCodeStyleOptions(TieredAnalyzerConfigOptions options, OptionUpdater updater) { var enumValues = new[] { UnusedValuePreference.UnusedLocalVariable, UnusedValuePreference.DiscardVariable }; - var valueDescriptions = new[] { CSharpVSResources.Unused_local, CSharpVSResources.Discard }; + var valueDescriptions = new[] { ServicesVSResources.Unused_local, CSharpVSResources.Discard }; yield return CodeStyleSetting.Create(CSharpCodeStyleOptions.UnusedValueAssignment, ServicesVSResources.Avoid_unused_value_assignments, options, updater, enumValues, valueDescriptions); yield return CodeStyleSetting.Create(CSharpCodeStyleOptions.UnusedValueExpressionStatement, ServicesVSResources.Avoid_expression_statements_that_implicitly_ignore_value, options, updater, enumValues, valueDescriptions); diff --git a/src/VisualStudio/CSharp/Impl/Interactive/CSharpVsInteractiveWindowProvider.cs b/src/VisualStudio/CSharp/Impl/Interactive/CSharpVsInteractiveWindowProvider.cs index 53b16a0239d57..c0f0e8f5271c9 100644 --- a/src/VisualStudio/CSharp/Impl/Interactive/CSharpVsInteractiveWindowProvider.cs +++ b/src/VisualStudio/CSharp/Impl/Interactive/CSharpVsInteractiveWindowProvider.cs @@ -10,7 +10,6 @@ using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Interactive; using Microsoft.CodeAnalysis.Internal.Log; -using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Shared.TestHooks; using Microsoft.VisualStudio.InteractiveWindow.Commands; using Microsoft.VisualStudio.InteractiveWindow.Shell; @@ -29,7 +28,6 @@ internal sealed class CSharpVsInteractiveWindowProvider : VsInteractiveWindowPro private readonly IThreadingContext _threadingContext; private readonly IAsynchronousOperationListener _listener; private readonly ITextDocumentFactoryService _textDocumentFactoryService; - private readonly EditorOptionsService _editorOptionsService; [ImportingConstructor] [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] @@ -43,14 +41,12 @@ public CSharpVsInteractiveWindowProvider( IInteractiveWindowCommandsFactory commandsFactory, [ImportMany] IInteractiveWindowCommand[] commands, ITextDocumentFactoryService textDocumentFactoryService, - EditorOptionsService editorOptionsService, VisualStudioWorkspace workspace) : base(serviceProvider, interactiveWindowFactory, classifierAggregator, contentTypeRegistry, commandsFactory, commands, workspace) { _threadingContext = threadingContext; _listener = listenerProvider.GetListener(FeatureAttribute.InteractiveEvaluator); _textDocumentFactoryService = textDocumentFactoryService; - _editorOptionsService = editorOptionsService; } protected override Guid LanguageServiceGuid => LanguageServiceGuids.CSharpLanguageServiceId; @@ -76,7 +72,6 @@ protected override CSharpInteractiveEvaluator CreateInteractiveEvaluator( CommandsFactory, Commands, _textDocumentFactoryService, - _editorOptionsService, CSharpInteractiveEvaluatorLanguageInfoProvider.Instance, Environment.GetFolderPath(Environment.SpecialFolder.UserProfile)); } diff --git a/src/VisualStudio/CSharp/Impl/Interactive/OpenInteractiveWindowCommand.cs b/src/VisualStudio/CSharp/Impl/Interactive/OpenInteractiveWindowCommand.cs index b4fbcea6b22f6..13ff7766f5e66 100644 --- a/src/VisualStudio/CSharp/Impl/Interactive/OpenInteractiveWindowCommand.cs +++ b/src/VisualStudio/CSharp/Impl/Interactive/OpenInteractiveWindowCommand.cs @@ -21,7 +21,7 @@ internal class OpenInteractiveWindowCommand( { public override CommandConfiguration CommandConfiguration => new("%CSharpLanguageServiceExtension.OpenInteractiveWindow.DisplayName%") { - Placements = new[] { CommandPlacement.KnownPlacements.ViewOtherWindowsMenu.WithPriority(0x8000) }, + Placements = [CommandPlacement.KnownPlacements.ViewOtherWindowsMenu.WithPriority(0x8000)], // TODO: Shortcuts https://github.com/dotnet/roslyn/issues/3941 }; diff --git a/src/VisualStudio/CSharp/Impl/LanguageService/CSharpHelpContextService.cs b/src/VisualStudio/CSharp/Impl/LanguageService/CSharpHelpContextService.cs index 20e4dd353019b..e2b7896924e72 100644 --- a/src/VisualStudio/CSharp/Impl/LanguageService/CSharpHelpContextService.cs +++ b/src/VisualStudio/CSharp/Impl/LanguageService/CSharpHelpContextService.cs @@ -23,568 +23,566 @@ using Microsoft.VisualStudio.LanguageServices.Implementation.F1Help; using Roslyn.Utilities; -namespace Microsoft.VisualStudio.LanguageServices.CSharp.LanguageService +namespace Microsoft.VisualStudio.LanguageServices.CSharp.LanguageService; + +[ExportLanguageService(typeof(IHelpContextService), LanguageNames.CSharp), Shared] +[method: ImportingConstructor] +[method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] +internal sealed class CSharpHelpContextService() : AbstractHelpContextService { - [ExportLanguageService(typeof(IHelpContextService), LanguageNames.CSharp), Shared] - internal class CSharpHelpContextService : AbstractHelpContextService + // This redirects to https://docs.microsoft.com/visualstudio/ide/not-in-toc/default, indicating nothing is found. + private const string NotFoundHelpTerm = "vs.texteditor"; + + public override string Language => "csharp"; + public override string Product => "csharp"; + + private static string Keyword(string text) + => text + "_CSharpKeyword"; + + public override async Task GetHelpTermAsync(Document document, TextSpan span, CancellationToken cancellationToken) { - // This redirects to https://docs.microsoft.com/visualstudio/ide/not-in-toc/default, indicating nothing is found. - private const string NotFoundHelpTerm = "vs.texteditor"; + // For now, find the token under the start of the selection. + var syntaxTree = await document.GetRequiredSyntaxTreeAsync(cancellationToken).ConfigureAwait(false); + var token = await syntaxTree.GetTouchingTokenAsync(span.Start, cancellationToken, findInsideTrivia: true).ConfigureAwait(false); - [ImportingConstructor] - [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - public CSharpHelpContextService() + if (token.Span.IntersectsWith(span)) { - } + var semanticModel = await document.ReuseExistingSpeculativeModelAsync(span, cancellationToken).ConfigureAwait(false); - public override string Language => "csharp"; - public override string Product => "csharp"; + var result = TryGetText(token, semanticModel, document, cancellationToken); + if (result is null) + { + var previousToken = token.GetPreviousToken(); + if (previousToken.Span.IntersectsWith(span)) + result = TryGetText(previousToken, semanticModel, document, cancellationToken); + } - private static string Keyword(string text) - => text + "_CSharpKeyword"; + return result ?? NotFoundHelpTerm; + } - public override async Task GetHelpTermAsync(Document document, TextSpan span, CancellationToken cancellationToken) + var root = await syntaxTree.GetRootAsync(cancellationToken).ConfigureAwait(false); + var trivia = root.FindTrivia(span.Start, findInsideTrivia: true); + if (trivia.Span.IntersectsWith(span) && trivia.Kind() == SyntaxKind.PreprocessingMessageTrivia && + trivia.Token.GetAncestor() != null) { - // For now, find the token under the start of the selection. - var syntaxTree = await document.GetRequiredSyntaxTreeAsync(cancellationToken).ConfigureAwait(false); - var token = await syntaxTree.GetTouchingTokenAsync(span.Start, cancellationToken, findInsideTrivia: true).ConfigureAwait(false); + return "#region"; + } - if (token.Span.IntersectsWith(span)) - { - var semanticModel = await document.ReuseExistingSpeculativeModelAsync(span, cancellationToken).ConfigureAwait(false); + if (trivia.IsRegularOrDocComment()) + { + // just find the first "word" that intersects with our position + var text = await syntaxTree.GetTextAsync(cancellationToken).ConfigureAwait(false); + var start = span.Start; + var end = span.Start; - var result = TryGetText(token, semanticModel, document, cancellationToken); - if (result is null) - { - var previousToken = token.GetPreviousToken(); - if (previousToken.Span.IntersectsWith(span)) - result = TryGetText(previousToken, semanticModel, document, cancellationToken); - } + var syntaxFacts = document.GetRequiredLanguageService(); + while (start > 0 && syntaxFacts.IsIdentifierPartCharacter(text[start - 1])) + start--; - return result ?? NotFoundHelpTerm; - } + while (end < text.Length - 1 && syntaxFacts.IsIdentifierPartCharacter(text[end])) + end++; - var root = await syntaxTree.GetRootAsync(cancellationToken).ConfigureAwait(false); - var trivia = root.FindTrivia(span.Start, findInsideTrivia: true); - if (trivia.Span.IntersectsWith(span) && trivia.Kind() == SyntaxKind.PreprocessingMessageTrivia && - trivia.Token.GetAncestor() != null) - { - return "#region"; - } + return text.GetSubText(TextSpan.FromBounds(start, end)).ToString(); + } - if (trivia.IsRegularOrDocComment()) - { - // just find the first "word" that intersects with our position - var text = await syntaxTree.GetTextAsync(cancellationToken).ConfigureAwait(false); - var start = span.Start; - var end = span.Start; + return NotFoundHelpTerm; + } - var syntaxFacts = document.GetRequiredLanguageService(); - while (start > 0 && syntaxFacts.IsIdentifierPartCharacter(text[start - 1])) - start--; + private string? TryGetText(SyntaxToken token, SemanticModel semanticModel, Document document, CancellationToken cancellationToken) + { + if (TryGetTextForSpecialCharacters(token, out var text) || + TryGetTextForContextualKeyword(token, out text) || + TryGetTextForCombinationKeyword(token, out text) || + TryGetTextForPreProcessor(token, out text) || + TryGetTextForKeyword(token, out text) || + TryGetTextForOperator(token, document, out text) || + TryGetTextForSymbol(token, semanticModel, document, cancellationToken, out text)) + { + return text; + } - while (end < text.Length - 1 && syntaxFacts.IsIdentifierPartCharacter(text[end])) - end++; + return null; + } - return text.GetSubText(TextSpan.FromBounds(start, end)).ToString(); - } + private static bool TryGetTextForSpecialCharacters(SyntaxToken token, [NotNullWhen(true)] out string? text) + { + if (token.Kind() + is SyntaxKind.InterpolatedStringStartToken + or SyntaxKind.InterpolatedStringEndToken + or SyntaxKind.InterpolatedRawStringEndToken + or SyntaxKind.InterpolatedStringTextToken + or SyntaxKind.InterpolatedSingleLineRawStringStartToken + or SyntaxKind.InterpolatedMultiLineRawStringStartToken) + { + text = Keyword("$"); + return true; + } - return NotFoundHelpTerm; + if (token.IsVerbatimStringLiteral()) + { + text = Keyword("@"); + return true; } - private string? TryGetText(SyntaxToken token, SemanticModel semanticModel, Document document, CancellationToken cancellationToken) + if (token.IsKind(SyntaxKind.InterpolatedVerbatimStringStartToken)) { - if (TryGetTextForSpecialCharacters(token, out var text) || - TryGetTextForContextualKeyword(token, out text) || - TryGetTextForCombinationKeyword(token, out text) || - TryGetTextForPreProcessor(token, out text) || - TryGetTextForKeyword(token, out text) || - TryGetTextForOperator(token, document, out text) || - TryGetTextForSymbol(token, semanticModel, document, cancellationToken, out text)) - { - return text; - } + text = Keyword("@$"); + return true; + } - return null; + if (token.Kind() + is SyntaxKind.Utf8StringLiteralToken + or SyntaxKind.Utf8SingleLineRawStringLiteralToken + or SyntaxKind.Utf8MultiLineRawStringLiteralToken) + { + text = Keyword("Utf8StringLiteral"); + return true; } - private static bool TryGetTextForSpecialCharacters(SyntaxToken token, [NotNullWhen(true)] out string? text) + if (token.Kind() is SyntaxKind.SingleLineRawStringLiteralToken or SyntaxKind.MultiLineRawStringLiteralToken) { - if (token.Kind() - is SyntaxKind.InterpolatedStringStartToken - or SyntaxKind.InterpolatedStringEndToken - or SyntaxKind.InterpolatedRawStringEndToken - or SyntaxKind.InterpolatedStringTextToken - or SyntaxKind.InterpolatedSingleLineRawStringStartToken - or SyntaxKind.InterpolatedMultiLineRawStringStartToken) - { - text = Keyword("$"); - return true; - } + text = Keyword("RawStringLiteral"); + return true; + } - if (token.IsVerbatimStringLiteral()) - { - text = Keyword("@"); - return true; - } + text = null; + return false; + } - if (token.IsKind(SyntaxKind.InterpolatedVerbatimStringStartToken)) - { - text = Keyword("@$"); - return true; - } + private bool TryGetTextForSymbol( + SyntaxToken token, SemanticModel semanticModel, Document document, CancellationToken cancellationToken, + [NotNullWhen(true)] out string? text) + { + ISymbol? symbol = null; + if (token.Parent is TypeArgumentListSyntax) + { + var genericName = token.GetAncestor(); + if (genericName != null) + symbol = semanticModel.GetSymbolInfo(genericName, cancellationToken).Symbol ?? semanticModel.GetTypeInfo(genericName, cancellationToken).Type; + } + else if (token.Parent is NullableTypeSyntax && token.IsKind(SyntaxKind.QuestionToken)) + { + text = "System.Nullable`1"; + return true; + } + else + { + symbol = semanticModel.GetSemanticInfo(token, document.Project.Solution.Services, cancellationToken) + .GetAnySymbol(includeType: true); - if (token.Kind() - is SyntaxKind.Utf8StringLiteralToken - or SyntaxKind.Utf8SingleLineRawStringLiteralToken - or SyntaxKind.Utf8MultiLineRawStringLiteralToken) + if (symbol == null) { - text = Keyword("Utf8StringLiteral"); - return true; + var bindableParent = document.GetRequiredLanguageService().TryGetBindableParent(token); + var overloads = bindableParent != null ? semanticModel.GetMemberGroup(bindableParent) : []; + symbol = overloads.FirstOrDefault(); } + } - if (token.Kind() is SyntaxKind.SingleLineRawStringLiteralToken or SyntaxKind.MultiLineRawStringLiteralToken) - { - text = Keyword("RawStringLiteral"); - return true; - } + // Local: return the name if it's the declaration, otherwise the type + if (symbol is ILocalSymbol localSymbol && !symbol.DeclaringSyntaxReferences.Any(static (d, token) => d.GetSyntax().DescendantTokens().Contains(token), token)) + { + symbol = localSymbol.Type; + } + + // Range variable: use the type + if (symbol is IRangeVariableSymbol) + { + var info = semanticModel.GetTypeInfo(token.GetRequiredParent(), cancellationToken); + symbol = info.Type; + } + // Just use syntaxfacts for operators + if (symbol is IMethodSymbol method && method.MethodKind == MethodKind.BuiltinOperator) + { text = null; return false; } - private bool TryGetTextForSymbol( - SyntaxToken token, SemanticModel semanticModel, Document document, CancellationToken cancellationToken, - [NotNullWhen(true)] out string? text) + if (symbol is IDiscardSymbol) { - ISymbol? symbol = null; - if (token.Parent is TypeArgumentListSyntax) - { - var genericName = token.GetAncestor(); - if (genericName != null) - symbol = semanticModel.GetSymbolInfo(genericName, cancellationToken).Symbol ?? semanticModel.GetTypeInfo(genericName, cancellationToken).Type; - } - else if (token.Parent is NullableTypeSyntax && token.IsKind(SyntaxKind.QuestionToken)) - { - text = "System.Nullable`1"; - return true; - } - else - { - symbol = semanticModel.GetSemanticInfo(token, document.Project.Solution.Services, cancellationToken) - .GetAnySymbol(includeType: true); - - if (symbol == null) - { - var bindableParent = document.GetRequiredLanguageService().TryGetBindableParent(token); - var overloads = bindableParent != null ? semanticModel.GetMemberGroup(bindableParent) : ImmutableArray.Empty; - symbol = overloads.FirstOrDefault(); - } - } - - // Local: return the name if it's the declaration, otherwise the type - if (symbol is ILocalSymbol localSymbol && !symbol.DeclaringSyntaxReferences.Any(static (d, token) => d.GetSyntax().DescendantTokens().Contains(token), token)) - { - symbol = localSymbol.Type; - } - - // Range variable: use the type - if (symbol is IRangeVariableSymbol) - { - var info = semanticModel.GetTypeInfo(token.GetRequiredParent(), cancellationToken); - symbol = info.Type; - } - - // Just use syntaxfacts for operators - if (symbol is IMethodSymbol method && method.MethodKind == MethodKind.BuiltinOperator) - { - text = null; - return false; - } + text = Keyword("discard"); + return true; + } - if (symbol is IDiscardSymbol) - { - text = Keyword("discard"); - return true; - } + if (symbol is IPreprocessingSymbol) + { + Debug.Fail("We should have handled that in the preprocessor directive."); + } - if (symbol is IPreprocessingSymbol) - { - Debug.Fail("We should have handled that in the preprocessor directive."); - } + text = FormatSymbol(symbol); + return text != null; + } - text = FormatSymbol(symbol); - return text != null; + private static bool TryGetTextForOperator(SyntaxToken token, Document document, [NotNullWhen(true)] out string? text) + { + if (token.IsKind(SyntaxKind.ExclamationToken) && + token.Parent.IsKind(SyntaxKind.SuppressNullableWarningExpression)) + { + text = Keyword("nullForgiving"); + return true; } - private static bool TryGetTextForOperator(SyntaxToken token, Document document, [NotNullWhen(true)] out string? text) + var syntaxFacts = document.GetRequiredLanguageService(); + if (syntaxFacts.IsOperator(token)) { - if (token.IsKind(SyntaxKind.ExclamationToken) && - token.Parent.IsKind(SyntaxKind.SuppressNullableWarningExpression)) - { - text = Keyword("nullForgiving"); - return true; - } - - var syntaxFacts = document.GetRequiredLanguageService(); - if (syntaxFacts.IsOperator(token)) - { - text = Keyword(syntaxFacts.GetText(token.RawKind)); - return true; - } + text = Keyword(syntaxFacts.GetText(token.RawKind)); + return true; + } - if (token.IsKind(SyntaxKind.ColonColonToken)) - { - text = Keyword("::"); - return true; - } + if (token.IsKind(SyntaxKind.ColonColonToken)) + { + text = Keyword("::"); + return true; + } - if (token.IsKind(SyntaxKind.ColonToken) && token.Parent is NameColonSyntax) - { - text = Keyword("namedParameter"); - return true; - } + if (token.IsKind(SyntaxKind.ColonToken) && token.Parent is NameColonSyntax) + { + text = Keyword("namedParameter"); + return true; + } - if (token.IsKind(SyntaxKind.EqualsToken)) + if (token.IsKind(SyntaxKind.EqualsToken)) + { + if (token.Parent.IsKind(SyntaxKind.EqualsValueClause)) { - if (token.Parent.IsKind(SyntaxKind.EqualsValueClause)) + if (token.Parent.Parent.IsKind(SyntaxKind.Parameter)) { - if (token.Parent.Parent.IsKind(SyntaxKind.Parameter)) - { - text = Keyword("optionalParameter"); - return true; - } - else if (token.Parent.Parent.IsKind(SyntaxKind.PropertyDeclaration)) - { - text = Keyword("propertyInitializer"); - return true; - } - else if (token.Parent.Parent.IsKind(SyntaxKind.EnumMemberDeclaration)) - { - text = Keyword("enum"); - return true; - } - else if (token.Parent.Parent.IsKind(SyntaxKind.VariableDeclarator)) - { - text = Keyword("="); - return true; - } + text = Keyword("optionalParameter"); + return true; } - else if (token.Parent.IsKind(SyntaxKind.NameEquals)) + else if (token.Parent.Parent.IsKind(SyntaxKind.PropertyDeclaration)) { - if (token.Parent.Parent.IsKind(SyntaxKind.AnonymousObjectMemberDeclarator)) - { - text = Keyword("anonymousObject"); - return true; - } - else if (token.Parent.Parent.IsKind(SyntaxKind.UsingDirective)) - { - text = Keyword("using"); - return true; - } - else if (token.Parent.Parent.IsKind(SyntaxKind.AttributeArgument)) - { - text = Keyword("attributeNamedArgument"); - return true; - } + text = Keyword("propertyInitializer"); + return true; } - else if (token.Parent.IsKind(SyntaxKind.LetClause)) + else if (token.Parent.Parent.IsKind(SyntaxKind.EnumMemberDeclaration)) { - text = Keyword("let"); + text = Keyword("enum"); return true; } - else if (token.Parent is XmlAttributeSyntax) + else if (token.Parent.Parent.IsKind(SyntaxKind.VariableDeclarator)) { - // redirects to https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/xmldoc/recommended-tags - text = "see"; + text = Keyword("="); return true; } - - // EqualsToken in assignment expression is handled by syntaxFacts.IsOperator call above. - // Here we try to handle other contexts of EqualsToken. - // If we hit this assert, there is a context of the EqualsToken that's not handled. - // In this case, we currently fallback to https://docs.microsoft.com/dotnet/csharp/language-reference/operators/assignment-operator - Debug.Fail("Falling back to F1 keyword for assignment token."); - text = Keyword("="); - return true; } - - if (token.Kind() is SyntaxKind.LessThanToken or SyntaxKind.GreaterThanToken) + else if (token.Parent.IsKind(SyntaxKind.NameEquals)) { - if (token.Parent.IsKind(SyntaxKind.FunctionPointerParameterList)) + if (token.Parent.Parent.IsKind(SyntaxKind.AnonymousObjectMemberDeclarator)) + { + text = Keyword("anonymousObject"); + return true; + } + else if (token.Parent.Parent.IsKind(SyntaxKind.UsingDirective)) { - text = Keyword("functionPointer"); + text = Keyword("using"); + return true; + } + else if (token.Parent.Parent.IsKind(SyntaxKind.AttributeArgument)) + { + text = Keyword("attributeNamedArgument"); return true; } } - - if (token.IsKind(SyntaxKind.QuestionToken) && token.Parent is ConditionalExpressionSyntax) + else if (token.Parent.IsKind(SyntaxKind.LetClause)) { - text = Keyword("?"); + text = Keyword("let"); return true; } - - if (token.IsKind(SyntaxKind.EqualsGreaterThanToken)) + else if (token.Parent is XmlAttributeSyntax) { - text = Keyword("=>"); + // redirects to https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/xmldoc/recommended-tags + text = "see"; return true; } - if (token.Kind() is SyntaxKind.LessThanToken or SyntaxKind.GreaterThanToken && - token.Parent is (kind: SyntaxKind.TypeParameterList or SyntaxKind.TypeArgumentList)) + // EqualsToken in assignment expression is handled by syntaxFacts.IsOperator call above. + // Here we try to handle other contexts of EqualsToken. + // If we hit this assert, there is a context of the EqualsToken that's not handled. + // In this case, we currently fallback to https://docs.microsoft.com/dotnet/csharp/language-reference/operators/assignment-operator + Debug.Fail("Falling back to F1 keyword for assignment token."); + text = Keyword("="); + return true; + } + + if (token.Kind() is SyntaxKind.LessThanToken or SyntaxKind.GreaterThanToken) + { + if (token.Parent.IsKind(SyntaxKind.FunctionPointerParameterList)) { - text = Keyword("generics"); + text = Keyword("functionPointer"); return true; } - - text = null; - return false; } - private static bool TryGetTextForPreProcessor(SyntaxToken token, [NotNullWhen(true)] out string? text) + if (token.IsKind(SyntaxKind.QuestionToken) && token.Parent is ConditionalExpressionSyntax) { - var syntaxFacts = CSharpSyntaxFacts.Instance; + text = Keyword("?"); + return true; + } - // Several keywords are both normal keywords and preprocessor keywords. So only consider this token a - // pp-keyword if we're actually in a directive. - var directive = token.GetAncestor(); - if (directive != null) - { - if (token.IsKind(SyntaxKind.DefaultKeyword) && token.Parent is LineDirectiveTriviaSyntax) - { - text = Keyword("defaultline"); - return true; - } + if (token.IsKind(SyntaxKind.EqualsGreaterThanToken)) + { + text = Keyword("=>"); + return true; + } - if (syntaxFacts.IsPreprocessorKeyword(token)) - { - text = $"#{token.Text}"; - return true; - } + if (token.Kind() is SyntaxKind.LessThanToken or SyntaxKind.GreaterThanToken && + token.Parent is (kind: SyntaxKind.TypeParameterList or SyntaxKind.TypeArgumentList)) + { + text = Keyword("generics"); + return true; + } - if (token.Kind() is SyntaxKind.IdentifierToken or SyntaxKind.EndOfDirectiveToken) - { - text = $"#{directive.HashToken.GetNextToken(includeDirectives: true).Text}"; - return true; - } - } + text = null; + return false; + } - text = null; - return false; - } + private static bool TryGetTextForPreProcessor(SyntaxToken token, [NotNullWhen(true)] out string? text) + { + var syntaxFacts = CSharpSyntaxFacts.Instance; - private static bool TryGetTextForContextualKeyword(SyntaxToken token, [NotNullWhen(true)] out string? text) + // Several keywords are both normal keywords and preprocessor keywords. So only consider this token a + // pp-keyword if we're actually in a directive. + var directive = token.GetAncestor(); + if (directive != null) { - if (token.Text == "nameof") + if (token.IsKind(SyntaxKind.DefaultKeyword) && token.Parent is LineDirectiveTriviaSyntax) { - text = Keyword("nameof"); + text = Keyword("defaultline"); return true; } - if (token.IsContextualKeyword()) + if (syntaxFacts.IsPreprocessorKeyword(token)) { - switch (token.Kind()) - { - case SyntaxKind.PartialKeyword: - if (token.Parent.GetAncestorOrThis() != null) - { - text = Keyword("partialmethod"); - return true; - } - else if (token.Parent.GetAncestorOrThis() != null) - { - text = Keyword("partialtype"); - return true; - } - - break; - - case SyntaxKind.WhereKeyword: - text = token.Parent.GetAncestorOrThis() != null - ? Keyword("whereconstraint") - : Keyword("whereclause"); - - return true; - - case SyntaxKind.RequiredKeyword: - text = Keyword("required"); - return true; - } + text = $"#{token.Text}"; + return true; } - else if (token.ValueText is "notnull" or "unmanaged") + + if (token.Kind() is SyntaxKind.IdentifierToken or SyntaxKind.EndOfDirectiveToken) { - if (token.Parent is IdentifierNameSyntax { Parent: TypeConstraintSyntax { Parent: TypeParameterConstraintClauseSyntax } }) - { - text = Keyword(token.ValueText); - return true; - } + text = $"#{directive.HashToken.GetNextToken(includeDirectives: true).Text}"; + return true; } + } - text = null; - return false; + text = null; + return false; + } + + private static bool TryGetTextForContextualKeyword(SyntaxToken token, [NotNullWhen(true)] out string? text) + { + if (token.Text == "nameof") + { + text = Keyword("nameof"); + return true; } - private static bool TryGetTextForCombinationKeyword(SyntaxToken token, [NotNullWhen(true)] out string? text) + + if (token.IsContextualKeyword()) { switch (token.Kind()) { - case SyntaxKind.PrivateKeyword when ModifiersContains(token, SyntaxKind.ProtectedKeyword): - case SyntaxKind.ProtectedKeyword when ModifiersContains(token, SyntaxKind.PrivateKeyword): - text = Keyword("privateprotected"); - return true; + case SyntaxKind.PartialKeyword: + if (token.Parent.GetAncestorOrThis() != null) + { + text = Keyword("partialmethod"); + return true; + } + else if (token.Parent.GetAncestorOrThis() != null) + { + text = Keyword("partialtype"); + return true; + } - case SyntaxKind.ProtectedKeyword when ModifiersContains(token, SyntaxKind.InternalKeyword): - case SyntaxKind.InternalKeyword when ModifiersContains(token, SyntaxKind.ProtectedKeyword): - text = Keyword("protectedinternal"); - return true; + break; + + case SyntaxKind.WhereKeyword: + text = token.Parent.GetAncestorOrThis() != null + ? Keyword("whereconstraint") + : Keyword("whereclause"); - case SyntaxKind.UsingKeyword when token.Parent is UsingDirectiveSyntax: - text = token.GetNextToken().IsKind(SyntaxKind.StaticKeyword) - ? Keyword("using-static") - : Keyword("using"); - return true; - case SyntaxKind.StaticKeyword when token.Parent is UsingDirectiveSyntax: - text = Keyword("using-static"); return true; - case SyntaxKind.ReturnKeyword when token.Parent.IsKind(SyntaxKind.YieldReturnStatement): - case SyntaxKind.BreakKeyword when token.Parent.IsKind(SyntaxKind.YieldBreakStatement): - text = Keyword("yield"); + + case SyntaxKind.RequiredKeyword: + text = Keyword("required"); return true; } - - text = null; - return false; - - static bool ModifiersContains(SyntaxToken token, SyntaxKind kind) + } + else if (token.ValueText is "notnull" or "unmanaged") + { + if (token.Parent is IdentifierNameSyntax { Parent: TypeConstraintSyntax { Parent: TypeParameterConstraintClauseSyntax } }) { - return CSharpSyntaxFacts.Instance.GetModifiers(token.Parent).Any(t => t.IsKind(kind)); + text = Keyword(token.ValueText); + return true; } } - private static bool TryGetTextForKeyword(SyntaxToken token, [NotNullWhen(true)] out string? text) + text = null; + return false; + } + private static bool TryGetTextForCombinationKeyword(SyntaxToken token, [NotNullWhen(true)] out string? text) + { + switch (token.Kind()) { - if (token.IsKind(SyntaxKind.InKeyword)) - { - if (token.GetAncestor() != null) - { - text = Keyword("from"); - return true; - } + case SyntaxKind.PrivateKeyword when ModifiersContains(token, SyntaxKind.ProtectedKeyword): + case SyntaxKind.ProtectedKeyword when ModifiersContains(token, SyntaxKind.PrivateKeyword): + text = Keyword("privateprotected"); + return true; - if (token.GetAncestor() != null) - { - text = Keyword("join"); - return true; - } - } + case SyntaxKind.ProtectedKeyword when ModifiersContains(token, SyntaxKind.InternalKeyword): + case SyntaxKind.InternalKeyword when ModifiersContains(token, SyntaxKind.ProtectedKeyword): + text = Keyword("protectedinternal"); + return true; - if (token.IsKind(SyntaxKind.DefaultKeyword)) - { - if (token.Parent is DefaultConstraintSyntax) - { - text = Keyword("defaultconstraint"); - return true; - } + case SyntaxKind.UsingKeyword when token.Parent is UsingDirectiveSyntax: + text = token.GetNextToken().IsKind(SyntaxKind.StaticKeyword) + ? Keyword("using-static") + : Keyword("using"); + return true; + case SyntaxKind.StaticKeyword when token.Parent is UsingDirectiveSyntax: + text = Keyword("using-static"); + return true; + case SyntaxKind.GlobalKeyword when token.Parent is UsingDirectiveSyntax: + text = Keyword("global-using"); + return true; + case SyntaxKind.ReturnKeyword when token.Parent.IsKind(SyntaxKind.YieldReturnStatement): + case SyntaxKind.BreakKeyword when token.Parent.IsKind(SyntaxKind.YieldBreakStatement): + text = Keyword("yield"); + return true; + } - if (token.Parent is DefaultSwitchLabelSyntax or GotoStatementSyntax) - { - text = Keyword("defaultcase"); - return true; - } - } + text = null; + return false; - if (token.IsKind(SyntaxKind.ClassKeyword) && token.Parent is ClassOrStructConstraintSyntax) - { - text = Keyword("classconstraint"); - return true; - } + static bool ModifiersContains(SyntaxToken token, SyntaxKind kind) + { + return CSharpSyntaxFacts.Instance.GetModifiers(token.Parent).Any(t => t.IsKind(kind)); + } + } - if (token.IsKind(SyntaxKind.StructKeyword) && token.Parent is ClassOrStructConstraintSyntax) + private static bool TryGetTextForKeyword(SyntaxToken token, [NotNullWhen(true)] out string? text) + { + if (token.IsKind(SyntaxKind.InKeyword)) + { + if (token.GetAncestor() != null) { - text = Keyword("structconstraint"); + text = Keyword("from"); return true; } - if (token.IsKind(SyntaxKind.UsingKeyword) && token.Parent is UsingStatementSyntax or LocalDeclarationStatementSyntax) + if (token.GetAncestor() != null) { - text = Keyword("using-statement"); + text = Keyword("join"); return true; } + } - if (token.IsKind(SyntaxKind.SwitchKeyword) && token.Parent is SwitchExpressionSyntax) + if (token.IsKind(SyntaxKind.DefaultKeyword)) + { + if (token.Parent is DefaultConstraintSyntax) { - text = Keyword("switch-expression"); + text = Keyword("defaultconstraint"); return true; } - if (token.IsKeyword()) + if (token.Parent is DefaultSwitchLabelSyntax or GotoStatementSyntax) { - text = Keyword(token.Text); + text = Keyword("defaultcase"); return true; } + } - if (token.ValueText == "var" && token.IsKind(SyntaxKind.IdentifierToken) && - token.Parent?.Parent is VariableDeclarationSyntax declaration && token.Parent == declaration.Type) - { - text = Keyword("var"); - return true; - } + if (token.IsKind(SyntaxKind.ClassKeyword) && token.Parent is ClassOrStructConstraintSyntax) + { + text = Keyword("classconstraint"); + return true; + } - if (token.IsTypeNamedDynamic()) - { - text = Keyword("dynamic"); - return true; - } + if (token.IsKind(SyntaxKind.StructKeyword) && token.Parent is ClassOrStructConstraintSyntax) + { + text = Keyword("structconstraint"); + return true; + } - text = null; - return false; + if (token.IsKind(SyntaxKind.UsingKeyword) && token.Parent is UsingStatementSyntax or LocalDeclarationStatementSyntax) + { + text = Keyword("using-statement"); + return true; } - private static string FormatNamespaceOrTypeSymbol(INamespaceOrTypeSymbol symbol) + if (token.IsKind(SyntaxKind.SwitchKeyword) && token.Parent is SwitchExpressionSyntax) { - var displayString = symbol.ToDisplayString(TypeFormat); + text = Keyword("switch-expression"); + return true; + } - if (symbol is ITypeSymbol type && type.OriginalDefinition.SpecialType == SpecialType.System_Nullable_T) - { - return "System.Nullable`1"; - } + if (token.IsKeyword()) + { + text = Keyword(token.Text); + return true; + } - if (symbol.GetTypeArguments().Any()) - { - return $"{displayString}`{symbol.GetTypeArguments().Length}"; - } + if (token.ValueText == "var" && token.IsKind(SyntaxKind.IdentifierToken) && + token.Parent?.Parent is VariableDeclarationSyntax declaration && token.Parent == declaration.Type) + { + text = Keyword("var"); + return true; + } - return displayString; + if (token.IsTypeNamedDynamic()) + { + text = Keyword("dynamic"); + return true; } - public override string? FormatSymbol(ISymbol? symbol) + text = null; + return false; + } + + private static string FormatNamespaceOrTypeSymbol(INamespaceOrTypeSymbol symbol) + { + var displayString = symbol.ToDisplayString(TypeFormat); + + if (symbol is ITypeSymbol type && type.OriginalDefinition.SpecialType == SpecialType.System_Nullable_T) { - if (symbol == null) - return null; + return "System.Nullable`1"; + } - if (symbol is ITypeSymbol or INamespaceSymbol) - { - return FormatNamespaceOrTypeSymbol((INamespaceOrTypeSymbol)symbol); - } + if (symbol.GetTypeArguments().Any()) + { + return $"{displayString}`{symbol.GetTypeArguments().Length}"; + } - if (symbol.MatchesKind(SymbolKind.Alias, SymbolKind.Local, SymbolKind.Parameter)) - { - return FormatSymbol(symbol.GetSymbolType()); - } + return displayString; + } - var containingType = FormatNamespaceOrTypeSymbol(symbol.ContainingType); - var name = symbol.ToDisplayString(NameFormat); + public override string? FormatSymbol(ISymbol? symbol) + { + if (symbol == null) + return null; - if (symbol.IsConstructor()) - { - return $"{containingType}.#ctor"; - } + if (symbol is ITypeSymbol or INamespaceSymbol) + { + return FormatNamespaceOrTypeSymbol((INamespaceOrTypeSymbol)symbol); + } - if (symbol.GetTypeArguments().Any()) - { - return $"{containingType}.{name}``{symbol.GetTypeArguments().Length}"; - } + if (symbol.MatchesKind(SymbolKind.Alias, SymbolKind.Local, SymbolKind.Parameter)) + { + return FormatSymbol(symbol.GetSymbolType()); + } - return $"{containingType}.{name}"; + var containingType = FormatNamespaceOrTypeSymbol(symbol.ContainingType); + var name = symbol.ToDisplayString(NameFormat); + + if (symbol.IsConstructor()) + { + return $"{containingType}.#ctor"; } + + if (symbol.GetTypeArguments().Any()) + { + return $"{containingType}.{name}``{symbol.GetTypeArguments().Length}"; + } + + return $"{containingType}.{name}"; } } diff --git a/src/VisualStudio/CSharp/Impl/Microsoft.VisualStudio.LanguageServices.CSharp.csproj b/src/VisualStudio/CSharp/Impl/Microsoft.VisualStudio.LanguageServices.CSharp.csproj index 6ff52d800af00..151a0533819f1 100644 --- a/src/VisualStudio/CSharp/Impl/Microsoft.VisualStudio.LanguageServices.CSharp.csproj +++ b/src/VisualStudio/CSharp/Impl/Microsoft.VisualStudio.LanguageServices.CSharp.csproj @@ -51,10 +51,11 @@ + - + true VSPackage Designer diff --git a/src/VisualStudio/CSharp/Impl/ObjectBrowser/DescriptionBuilder.cs b/src/VisualStudio/CSharp/Impl/ObjectBrowser/DescriptionBuilder.cs index edd849ed6bc61..8b1ab58d4b13b 100644 --- a/src/VisualStudio/CSharp/Impl/ObjectBrowser/DescriptionBuilder.cs +++ b/src/VisualStudio/CSharp/Impl/ObjectBrowser/DescriptionBuilder.cs @@ -6,538 +6,531 @@ using System.Collections.Immutable; using System.Diagnostics; +using System.Threading; +using System.Threading.Tasks; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.VisualStudio.LanguageServices.Implementation.Library.ObjectBrowser; using Microsoft.VisualStudio.Shell.Interop; -namespace Microsoft.VisualStudio.LanguageServices.CSharp.ObjectBrowser +namespace Microsoft.VisualStudio.LanguageServices.CSharp.ObjectBrowser; + +internal sealed class DescriptionBuilder( + IVsObjectBrowserDescription3 description, + ObjectBrowserLibraryManager libraryManager, + ObjectListItem listItem, + Project project) : AbstractDescriptionBuilder(description, libraryManager, listItem, project) { - internal class DescriptionBuilder : AbstractDescriptionBuilder + protected override void BuildNamespaceDeclaration(INamespaceSymbol namespaceSymbol, _VSOBJDESCOPTIONS options) { - public DescriptionBuilder( - IVsObjectBrowserDescription3 description, - ObjectBrowserLibraryManager libraryManager, - ObjectListItem listItem, - Project project) - : base(description, libraryManager, listItem, project) - { - } + AddText("namespace "); + AddName(namespaceSymbol.ToDisplayString()); + } - protected override void BuildNamespaceDeclaration(INamespaceSymbol namespaceSymbol, _VSOBJDESCOPTIONS options) - { - AddText("namespace "); - AddName(namespaceSymbol.ToDisplayString()); - } + protected override async Task BuildDelegateDeclarationAsync( + INamedTypeSymbol typeSymbol, _VSOBJDESCOPTIONS options, CancellationToken cancellationToken) + { + Debug.Assert(typeSymbol.TypeKind == TypeKind.Delegate); - protected override void BuildDelegateDeclaration(INamedTypeSymbol typeSymbol, _VSOBJDESCOPTIONS options) - { - Debug.Assert(typeSymbol.TypeKind == TypeKind.Delegate); + BuildTypeModifiers(typeSymbol); + AddText("delegate "); - BuildTypeModifiers(typeSymbol); - AddText("delegate "); + var delegateInvokeMethod = typeSymbol.DelegateInvokeMethod; - var delegateInvokeMethod = typeSymbol.DelegateInvokeMethod; + await AddTypeLinkAsync(delegateInvokeMethod.ReturnType, LinkFlags.None, cancellationToken).ConfigureAwait(true); + AddText(" "); - AddTypeLink(delegateInvokeMethod.ReturnType, LinkFlags.None); - AddText(" "); + var typeQualificationStyle = (options & _VSOBJDESCOPTIONS.ODO_USEFULLNAME) != 0 + ? SymbolDisplayTypeQualificationStyle.NameAndContainingTypesAndNamespaces + : SymbolDisplayTypeQualificationStyle.NameOnly; - var typeQualificationStyle = (options & _VSOBJDESCOPTIONS.ODO_USEFULLNAME) != 0 - ? SymbolDisplayTypeQualificationStyle.NameAndContainingTypesAndNamespaces - : SymbolDisplayTypeQualificationStyle.NameOnly; + var typeNameFormat = new SymbolDisplayFormat( + typeQualificationStyle: typeQualificationStyle, + genericsOptions: SymbolDisplayGenericsOptions.IncludeTypeParameters | SymbolDisplayGenericsOptions.IncludeVariance); - var typeNameFormat = new SymbolDisplayFormat( - typeQualificationStyle: typeQualificationStyle, - genericsOptions: SymbolDisplayGenericsOptions.IncludeTypeParameters | SymbolDisplayGenericsOptions.IncludeVariance); + AddName(typeSymbol.ToDisplayString(typeNameFormat)); - AddName(typeSymbol.ToDisplayString(typeNameFormat)); + AddText("("); + await BuildParameterListAsync(delegateInvokeMethod.Parameters, cancellationToken).ConfigureAwait(true); + AddText(")"); - AddText("("); - BuildParameterList(delegateInvokeMethod.Parameters); - AddText(")"); + if (typeSymbol.IsGenericType) + await BuildGenericConstraintsAsync(typeSymbol, cancellationToken).ConfigureAwait(true); + } - if (typeSymbol.IsGenericType) - { - BuildGenericConstraints(typeSymbol); - } - } + protected override async Task BuildTypeDeclarationAsync( + INamedTypeSymbol typeSymbol, _VSOBJDESCOPTIONS options, CancellationToken cancellationToken) + { + BuildTypeModifiers(typeSymbol); - protected override void BuildTypeDeclaration(INamedTypeSymbol typeSymbol, _VSOBJDESCOPTIONS options) + switch (typeSymbol.TypeKind) { - BuildTypeModifiers(typeSymbol); + case TypeKind.Enum: + AddText("enum "); + break; - switch (typeSymbol.TypeKind) - { - case TypeKind.Enum: - AddText("enum "); - break; - - case TypeKind.Struct: - AddText("struct "); - break; + case TypeKind.Struct: + AddText("struct "); + break; - case TypeKind.Interface: - AddText("interface "); - break; + case TypeKind.Interface: + AddText("interface "); + break; - case TypeKind.Class: - AddText("class "); - break; + case TypeKind.Class: + AddText("class "); + break; - default: - Debug.Fail("Invalid type kind encountered: " + typeSymbol.TypeKind.ToString()); - break; - } + default: + Debug.Fail("Invalid type kind encountered: " + typeSymbol.TypeKind.ToString()); + break; + } - var typeNameFormat = new SymbolDisplayFormat( - genericsOptions: SymbolDisplayGenericsOptions.IncludeTypeParameters | SymbolDisplayGenericsOptions.IncludeVariance); + var typeNameFormat = new SymbolDisplayFormat( + genericsOptions: SymbolDisplayGenericsOptions.IncludeTypeParameters | SymbolDisplayGenericsOptions.IncludeVariance); - AddName(typeSymbol.ToDisplayString(typeNameFormat)); + AddName(typeSymbol.ToDisplayString(typeNameFormat)); - if (typeSymbol.TypeKind == TypeKind.Enum) + if (typeSymbol.TypeKind == TypeKind.Enum) + { + var underlyingType = typeSymbol.EnumUnderlyingType; + if (underlyingType != null) { - var underlyingType = typeSymbol.EnumUnderlyingType; - if (underlyingType != null) + if (underlyingType.SpecialType != SpecialType.System_Int32) { - if (underlyingType.SpecialType != SpecialType.System_Int32) - { - AddText(" : "); - AddTypeLink(underlyingType, LinkFlags.None); - } + AddText(" : "); + await AddTypeLinkAsync(underlyingType, LinkFlags.None, cancellationToken).ConfigureAwait(true); } } - else - { - var baseType = typeSymbol.BaseType; - if (baseType != null) + } + else + { + var baseType = typeSymbol.BaseType; + if (baseType != null) + { + if (baseType.SpecialType is not SpecialType.System_Object and + not SpecialType.System_Delegate and + not SpecialType.System_MulticastDelegate and + not SpecialType.System_Enum and + not SpecialType.System_ValueType) { - if (baseType.SpecialType is not SpecialType.System_Object and - not SpecialType.System_Delegate and - not SpecialType.System_MulticastDelegate and - not SpecialType.System_Enum and - not SpecialType.System_ValueType) - { - AddText(" : "); - AddTypeLink(baseType, LinkFlags.None); - } + AddText(" : "); + await AddTypeLinkAsync(baseType, LinkFlags.None, cancellationToken).ConfigureAwait(true); } } + } - if (typeSymbol.IsGenericType) - { - BuildGenericConstraints(typeSymbol); - } + if (typeSymbol.IsGenericType) + await BuildGenericConstraintsAsync(typeSymbol, cancellationToken).ConfigureAwait(true); + } + + private void BuildAccessibility(ISymbol symbol) + { + switch (symbol.DeclaredAccessibility) + { + case Accessibility.Public: + AddText("public "); + break; + + case Accessibility.Private: + AddText("private "); + break; + + case Accessibility.Protected: + AddText("protected "); + break; + + case Accessibility.Internal: + AddText("internal "); + break; + + case Accessibility.ProtectedOrInternal: + AddText("protected internal "); + break; + + case Accessibility.ProtectedAndInternal: + AddText("private protected "); + break; + + default: + AddText("internal "); + break; } + } + + private void BuildTypeModifiers(INamedTypeSymbol typeSymbol) + { + BuildAccessibility(typeSymbol); - private void BuildAccessibility(ISymbol symbol) + if (typeSymbol.IsStatic) { - switch (symbol.DeclaredAccessibility) - { - case Accessibility.Public: - AddText("public "); - break; + AddText("static "); + } - case Accessibility.Private: - AddText("private "); - break; + if (typeSymbol.IsAbstract && + typeSymbol.TypeKind != TypeKind.Interface) + { + AddText("abstract "); + } - case Accessibility.Protected: - AddText("protected "); - break; + if (typeSymbol.IsSealed && + typeSymbol.TypeKind != TypeKind.Struct && + typeSymbol.TypeKind != TypeKind.Enum && + typeSymbol.TypeKind != TypeKind.Delegate) + { + AddText("sealed "); + } + } - case Accessibility.Internal: - AddText("internal "); - break; + protected override async Task BuildMethodDeclarationAsync( + IMethodSymbol methodSymbol, _VSOBJDESCOPTIONS options, CancellationToken cancellationToken) + { + BuildMemberModifiers(methodSymbol); - case Accessibility.ProtectedOrInternal: - AddText("protected internal "); - break; + if (methodSymbol.MethodKind is not MethodKind.Constructor and + not MethodKind.Destructor and + not MethodKind.StaticConstructor and + not MethodKind.Conversion) + { + await AddTypeLinkAsync(methodSymbol.ReturnType, LinkFlags.None, cancellationToken).ConfigureAwait(true); + AddText(" "); + } - case Accessibility.ProtectedAndInternal: - AddText("private protected "); + if (methodSymbol.MethodKind == MethodKind.Conversion) + { + switch (methodSymbol.Name) + { + case WellKnownMemberNames.ImplicitConversionName: + AddName("implicit operator "); break; - default: - AddText("internal "); + case WellKnownMemberNames.ExplicitConversionName: + AddName("explicit operator "); break; } + + await AddTypeLinkAsync(methodSymbol.ReturnType, LinkFlags.None, cancellationToken).ConfigureAwait(true); } + else + { + var methodNameFormat = new SymbolDisplayFormat( + genericsOptions: SymbolDisplayGenericsOptions.IncludeTypeParameters | SymbolDisplayGenericsOptions.IncludeVariance); - private void BuildTypeModifiers(INamedTypeSymbol typeSymbol) + AddName(methodSymbol.ToDisplayString(methodNameFormat)); + } + + AddText("("); + + if (methodSymbol.IsExtensionMethod) { - BuildAccessibility(typeSymbol); + AddText("this "); + } - if (typeSymbol.IsStatic) - { - AddText("static "); - } + await BuildParameterListAsync(methodSymbol.Parameters, cancellationToken).ConfigureAwait(true); + AddText(")"); - if (typeSymbol.IsAbstract && - typeSymbol.TypeKind != TypeKind.Interface) - { - AddText("abstract "); - } + if (methodSymbol.IsGenericMethod) + await BuildGenericConstraintsAsync(methodSymbol, cancellationToken).ConfigureAwait(true); + } - if (typeSymbol.IsSealed && - typeSymbol.TypeKind != TypeKind.Struct && - typeSymbol.TypeKind != TypeKind.Enum && - typeSymbol.TypeKind != TypeKind.Delegate) - { - AddText("sealed "); - } + private void BuildMemberModifiers(ISymbol memberSymbol) + { + if (memberSymbol.ContainingType != null && memberSymbol.ContainingType.TypeKind == TypeKind.Interface) + { + return; } - protected override void BuildMethodDeclaration(IMethodSymbol methodSymbol, _VSOBJDESCOPTIONS options) + var methodSymbol = memberSymbol as IMethodSymbol; + var fieldSymbol = memberSymbol as IFieldSymbol; + + if (methodSymbol != null && + methodSymbol.MethodKind == MethodKind.Destructor) { - BuildMemberModifiers(methodSymbol); + return; + } - if (methodSymbol.MethodKind is not MethodKind.Constructor and - not MethodKind.Destructor and - not MethodKind.StaticConstructor and - not MethodKind.Conversion) - { - AddTypeLink(methodSymbol.ReturnType, LinkFlags.None); - AddText(" "); - } + if (fieldSymbol != null && + fieldSymbol.ContainingType.TypeKind == TypeKind.Enum) + { + return; + } - if (methodSymbol.MethodKind == MethodKind.Conversion) - { - switch (methodSymbol.Name) - { - case WellKnownMemberNames.ImplicitConversionName: - AddName("implicit operator "); - break; + // TODO: 'new' modifier isn't exposed on symbols. Do we need it? - case WellKnownMemberNames.ExplicitConversionName: - AddName("explicit operator "); - break; - } + // Note: we don't display the access modifier for static constructors + if (methodSymbol == null || + methodSymbol.MethodKind != MethodKind.StaticConstructor) + { + BuildAccessibility(memberSymbol); + } - AddTypeLink(methodSymbol.ReturnType, LinkFlags.None); - } - else - { - var methodNameFormat = new SymbolDisplayFormat( - genericsOptions: SymbolDisplayGenericsOptions.IncludeTypeParameters | SymbolDisplayGenericsOptions.IncludeVariance); + if (memberSymbol.RequiresUnsafeModifier()) + { + AddText("unsafe "); + } - AddName(methodSymbol.ToDisplayString(methodNameFormat)); - } + // Note: we don't display 'static' for constant fields + if (memberSymbol.IsStatic && + (fieldSymbol == null || !fieldSymbol.IsConst)) + { + AddText("static "); + } - AddText("("); + if (memberSymbol.IsExtern) + { + AddText("extern "); + } - if (methodSymbol.IsExtensionMethod) - { - AddText("this "); - } + if (fieldSymbol != null && fieldSymbol.IsReadOnly) + { + AddText("readonly "); + } - BuildParameterList(methodSymbol.Parameters); - AddText(")"); + if (fieldSymbol != null && fieldSymbol.IsConst) + { + AddText("const "); + } - if (methodSymbol.IsGenericMethod) - { - BuildGenericConstraints(methodSymbol); - } + if (fieldSymbol != null && fieldSymbol.IsVolatile) + { + AddText("volatile "); } - private void BuildMemberModifiers(ISymbol memberSymbol) + if (memberSymbol.IsAbstract) + { + AddText("abstract "); + } + else if (memberSymbol.IsOverride) { - if (memberSymbol.ContainingType != null && memberSymbol.ContainingType.TypeKind == TypeKind.Interface) + if (memberSymbol.IsSealed) { - return; + AddText("sealed "); } - var methodSymbol = memberSymbol as IMethodSymbol; - var fieldSymbol = memberSymbol as IFieldSymbol; + AddText("override "); + } + else if (memberSymbol.IsVirtual) + { + AddText("virtual "); + } + } - if (methodSymbol != null && - methodSymbol.MethodKind == MethodKind.Destructor) - { - return; - } + private async Task BuildGenericConstraintsAsync(INamedTypeSymbol typeSymbol, CancellationToken cancellationToken) + { + foreach (var typeParameterSymbol in typeSymbol.TypeParameters) + await BuildConstraintsAsync(typeParameterSymbol, cancellationToken).ConfigureAwait(true); + } - if (fieldSymbol != null && - fieldSymbol.ContainingType.TypeKind == TypeKind.Enum) - { - return; - } + private async Task BuildGenericConstraintsAsync(IMethodSymbol methodSymbol, CancellationToken cancellationToken) + { + foreach (var typeParameterSymbol in methodSymbol.TypeParameters) + await BuildConstraintsAsync(typeParameterSymbol, cancellationToken).ConfigureAwait(true); + } - // TODO: 'new' modifier isn't exposed on symbols. Do we need it? + private async Task BuildConstraintsAsync(ITypeParameterSymbol typeParameterSymbol, CancellationToken cancellationToken) + { + if (typeParameterSymbol.ConstraintTypes.Length == 0 && + !typeParameterSymbol.HasConstructorConstraint && + !typeParameterSymbol.HasReferenceTypeConstraint && + !typeParameterSymbol.HasValueTypeConstraint && + !typeParameterSymbol.AllowsRefLikeType) + { + return; + } - // Note: we don't display the access modifier for static constructors - if (methodSymbol == null || - methodSymbol.MethodKind != MethodKind.StaticConstructor) - { - BuildAccessibility(memberSymbol); - } + AddLineBreak(); + AddText("\t"); + AddText("where "); + AddName(typeParameterSymbol.Name); + AddText(" : "); - if (memberSymbol.RequiresUnsafeModifier()) - { - AddText("unsafe "); - } + var isFirst = true; - // Note: we don't display 'static' for constant fields - if (memberSymbol.IsStatic && - (fieldSymbol == null || !fieldSymbol.IsConst)) + if (typeParameterSymbol.HasReferenceTypeConstraint) + { + if (!isFirst) { - AddText("static "); + AddComma(); } - if (memberSymbol.IsExtern) - { - AddText("extern "); - } + AddText("class"); + isFirst = false; + } - if (fieldSymbol != null && fieldSymbol.IsReadOnly) + if (typeParameterSymbol.HasValueTypeConstraint) + { + if (!isFirst) { - AddText("readonly "); + AddComma(); } - if (fieldSymbol != null && fieldSymbol.IsConst) - { - AddText("const "); - } + AddText("struct"); + isFirst = false; + } - if (fieldSymbol != null && fieldSymbol.IsVolatile) + foreach (var constraintType in typeParameterSymbol.ConstraintTypes) + { + if (!isFirst) { - AddText("volatile "); + AddComma(); } - if (memberSymbol.IsAbstract) - { - AddText("abstract "); - } - else if (memberSymbol.IsOverride) - { - if (memberSymbol.IsSealed) - { - AddText("sealed "); - } + await AddTypeLinkAsync(constraintType, LinkFlags.None, cancellationToken).ConfigureAwait(true); + isFirst = false; + } - AddText("override "); - } - else if (memberSymbol.IsVirtual) + if (typeParameterSymbol.HasConstructorConstraint) + { + if (!isFirst) { - AddText("virtual "); + AddComma(); } + + AddText("new()"); + isFirst = false; } - private void BuildGenericConstraints(INamedTypeSymbol typeSymbol) + if (typeParameterSymbol.AllowsRefLikeType) { - foreach (var typeParameterSymbol in typeSymbol.TypeParameters) + if (!isFirst) { - BuildConstraints(typeParameterSymbol); + AddComma(); } + + AddText("allows ref struct"); } + } - private void BuildGenericConstraints(IMethodSymbol methodSymbol) + private async Task BuildParameterListAsync( + ImmutableArray parameters, CancellationToken cancellationToken) + { + var count = parameters.Length; + if (count == 0) { - foreach (var typeParameterSymbol in methodSymbol.TypeParameters) - { - BuildConstraints(typeParameterSymbol); - } + return; } - private void BuildConstraints(ITypeParameterSymbol typeParameterSymbol) + for (var i = 0; i < count; i++) { - if (typeParameterSymbol.ConstraintTypes.Length == 0 && - !typeParameterSymbol.HasConstructorConstraint && - !typeParameterSymbol.HasReferenceTypeConstraint && - !typeParameterSymbol.HasValueTypeConstraint && - !typeParameterSymbol.AllowsRefLikeType) + if (i > 0) { - return; + AddComma(); } - AddLineBreak(); - AddText("\t"); - AddText("where "); - AddName(typeParameterSymbol.Name); - AddText(" : "); - - var isFirst = true; + var current = parameters[i]; - if (typeParameterSymbol.HasReferenceTypeConstraint) + if (current.IsOptional) { - if (!isFirst) - { - AddComma(); - } - - AddText("class"); - isFirst = false; + AddText("["); } - if (typeParameterSymbol.HasValueTypeConstraint) + if (current.RefKind == RefKind.Ref) { - if (!isFirst) - { - AddComma(); - } - - AddText("struct"); - isFirst = false; + AddText("ref "); } - - foreach (var constraintType in typeParameterSymbol.ConstraintTypes) + else if (current.RefKind == RefKind.Out) { - if (!isFirst) - { - AddComma(); - } - - AddTypeLink(constraintType, LinkFlags.None); - isFirst = false; + AddText("out "); } - if (typeParameterSymbol.HasConstructorConstraint) + if (current.IsParams) { - if (!isFirst) - { - AddComma(); - } - - AddText("new()"); - isFirst = false; + AddText("params "); } - if (typeParameterSymbol.AllowsRefLikeType) + await AddTypeLinkAsync(current.Type, LinkFlags.None, cancellationToken).ConfigureAwait(true); + AddText(" "); + AddParam(current.Name); + + if (current.HasExplicitDefaultValue) { - if (!isFirst) + AddText(" = "); + if (current.ExplicitDefaultValue == null) { - AddComma(); + AddText("null"); + } + else + { + AddText(current.ExplicitDefaultValue.ToString()); } - - AddText("allows ref struct"); } - } - private void BuildParameterList(ImmutableArray parameters) - { - var count = parameters.Length; - if (count == 0) + if (current.IsOptional) { - return; + AddText("]"); } + } + } - for (var i = 0; i < count; i++) - { - if (i > 0) - { - AddComma(); - } - - var current = parameters[i]; - - if (current.IsOptional) - { - AddText("["); - } - - if (current.RefKind == RefKind.Ref) - { - AddText("ref "); - } - else if (current.RefKind == RefKind.Out) - { - AddText("out "); - } + protected override async Task BuildFieldDeclarationAsync( + IFieldSymbol fieldSymbol, _VSOBJDESCOPTIONS options, CancellationToken cancellationToken) + { + BuildMemberModifiers(fieldSymbol); - if (current.IsParams) - { - AddText("params "); - } + if (fieldSymbol.ContainingType.TypeKind != TypeKind.Enum) + { + await AddTypeLinkAsync(fieldSymbol.Type, LinkFlags.None, cancellationToken).ConfigureAwait(true); + AddText(" "); + } - AddTypeLink(current.Type, LinkFlags.None); - AddText(" "); - AddParam(current.Name); + AddName(fieldSymbol.Name); + } - if (current.HasExplicitDefaultValue) - { - AddText(" = "); - if (current.ExplicitDefaultValue == null) - { - AddText("null"); - } - else - { - AddText(current.ExplicitDefaultValue.ToString()); - } - } + protected override async Task BuildPropertyDeclarationAsync( + IPropertySymbol propertySymbol, _VSOBJDESCOPTIONS options, CancellationToken cancellationToken) + { + BuildMemberModifiers(propertySymbol); - if (current.IsOptional) - { - AddText("]"); - } - } - } + await AddTypeLinkAsync(propertySymbol.Type, LinkFlags.None, cancellationToken).ConfigureAwait(true); + AddText(" "); - protected override void BuildFieldDeclaration(IFieldSymbol fieldSymbol, _VSOBJDESCOPTIONS options) + if (propertySymbol.IsIndexer) { - BuildMemberModifiers(fieldSymbol); - - if (fieldSymbol.ContainingType.TypeKind != TypeKind.Enum) - { - AddTypeLink(fieldSymbol.Type, LinkFlags.None); - AddText(" "); - } - - AddName(fieldSymbol.Name); + AddName("this"); + AddText("["); + await BuildParameterListAsync(propertySymbol.Parameters, cancellationToken).ConfigureAwait(true); + AddText("]"); } - - protected override void BuildPropertyDeclaration(IPropertySymbol propertySymbol, _VSOBJDESCOPTIONS options) + else { - BuildMemberModifiers(propertySymbol); + AddName(propertySymbol.Name); + } - AddTypeLink(propertySymbol.Type, LinkFlags.None); - AddText(" "); + AddText(" { "); - if (propertySymbol.IsIndexer) - { - AddName("this"); - AddText("["); - BuildParameterList(propertySymbol.Parameters); - AddText("]"); - } - else + if (propertySymbol.GetMethod != null) + { + if (propertySymbol.GetMethod.DeclaredAccessibility != propertySymbol.DeclaredAccessibility) { - AddName(propertySymbol.Name); + BuildAccessibility(propertySymbol.GetMethod); } - AddText(" { "); - - if (propertySymbol.GetMethod != null) - { - if (propertySymbol.GetMethod.DeclaredAccessibility != propertySymbol.DeclaredAccessibility) - { - BuildAccessibility(propertySymbol.GetMethod); - } - - AddText("get; "); - } + AddText("get; "); + } - if (propertySymbol.SetMethod != null) + if (propertySymbol.SetMethod != null) + { + if (propertySymbol.SetMethod.DeclaredAccessibility != propertySymbol.DeclaredAccessibility) { - if (propertySymbol.SetMethod.DeclaredAccessibility != propertySymbol.DeclaredAccessibility) - { - BuildAccessibility(propertySymbol.SetMethod); - } - - AddText("set; "); + BuildAccessibility(propertySymbol.SetMethod); } - AddText("}"); + AddText("set; "); } - protected override void BuildEventDeclaration(IEventSymbol eventSymbol, _VSOBJDESCOPTIONS options) - { - BuildMemberModifiers(eventSymbol); + AddText("}"); + } - AddText("event "); + protected override async Task BuildEventDeclarationAsync( + IEventSymbol eventSymbol, _VSOBJDESCOPTIONS options, CancellationToken cancellationToken) + { + BuildMemberModifiers(eventSymbol); - AddTypeLink(eventSymbol.Type, LinkFlags.None); - AddText(" "); + AddText("event "); - AddName(eventSymbol.Name); - } + await AddTypeLinkAsync(eventSymbol.Type, LinkFlags.None, cancellationToken).ConfigureAwait(true); + AddText(" "); + + AddName(eventSymbol.Name); } } diff --git a/src/VisualStudio/CSharp/Impl/ObjectBrowser/ObjectBrowserLibraryManager.cs b/src/VisualStudio/CSharp/Impl/ObjectBrowser/ObjectBrowserLibraryManager.cs index d3dcae31f60a1..bf0edb729257e 100644 --- a/src/VisualStudio/CSharp/Impl/ObjectBrowser/ObjectBrowserLibraryManager.cs +++ b/src/VisualStudio/CSharp/Impl/ObjectBrowser/ObjectBrowserLibraryManager.cs @@ -10,27 +10,22 @@ using Microsoft.VisualStudio.LanguageServices.Implementation.Library.ObjectBrowser; using Microsoft.VisualStudio.Shell.Interop; -namespace Microsoft.VisualStudio.LanguageServices.CSharp.ObjectBrowser +namespace Microsoft.VisualStudio.LanguageServices.CSharp.ObjectBrowser; + +internal sealed class ObjectBrowserLibraryManager( + IServiceProvider serviceProvider, + IComponentModel componentModel, + VisualStudioWorkspace workspace) : AbstractObjectBrowserLibraryManager( + LanguageNames.CSharp, Guids.CSharpLibraryId, serviceProvider, componentModel, workspace) { - internal class ObjectBrowserLibraryManager : AbstractObjectBrowserLibraryManager + internal override AbstractDescriptionBuilder CreateDescriptionBuilder( + IVsObjectBrowserDescription3 description, + ObjectListItem listItem, + Project project) { - public ObjectBrowserLibraryManager( - IServiceProvider serviceProvider, - IComponentModel componentModel, - VisualStudioWorkspace workspace) - : base(LanguageNames.CSharp, Guids.CSharpLibraryId, serviceProvider, componentModel, workspace) - { - } - - internal override AbstractDescriptionBuilder CreateDescriptionBuilder( - IVsObjectBrowserDescription3 description, - ObjectListItem listItem, - Project project) - { - return new DescriptionBuilder(description, this, listItem, project); - } - - internal override AbstractListItemFactory CreateListItemFactory() - => new ListItemFactory(); + return new DescriptionBuilder(description, this, listItem, project); } + + internal override AbstractListItemFactory CreateListItemFactory() + => new ListItemFactory(); } diff --git a/src/VisualStudio/CSharp/Impl/Options/AdvancedOptionPage.cs b/src/VisualStudio/CSharp/Impl/Options/AdvancedOptionPage.cs index 84e0410e47e1c..008b57296030f 100644 --- a/src/VisualStudio/CSharp/Impl/Options/AdvancedOptionPage.cs +++ b/src/VisualStudio/CSharp/Impl/Options/AdvancedOptionPage.cs @@ -4,7 +4,6 @@ using System; using System.Runtime.InteropServices; -using Microsoft.VisualStudio.ComponentModelHost; using Microsoft.VisualStudio.LanguageServices.Implementation.Options; namespace Microsoft.VisualStudio.LanguageServices.CSharp.Options @@ -14,8 +13,7 @@ internal class AdvancedOptionPage : AbstractOptionPage { protected override AbstractOptionPageControl CreateOptionPage(IServiceProvider serviceProvider, OptionStore optionStore) { - var componentModel = (IComponentModel)this.Site.GetService(typeof(SComponentModel)); - return new AdvancedOptionPageControl(optionStore, componentModel); + return new AdvancedOptionPageControl(optionStore); } } } diff --git a/src/VisualStudio/CSharp/Impl/Options/AdvancedOptionPageControl.xaml b/src/VisualStudio/CSharp/Impl/Options/AdvancedOptionPageControl.xaml index f4e39446c5180..8ef4c9be0c53c 100644 --- a/src/VisualStudio/CSharp/Impl/Options/AdvancedOptionPageControl.xaml +++ b/src/VisualStudio/CSharp/Impl/Options/AdvancedOptionPageControl.xaml @@ -62,8 +62,8 @@ Content="{x:Static local:AdvancedOptionPageStrings.Option_Automatically_reload_updated_analyzers_and_generators}" /> - + @@ -105,8 +105,6 @@ Content="{x:Static local:AdvancedOptionPageStrings.Option_Enable_navigation_to_decompiled_sources}" /> - @@ -196,6 +194,8 @@ + @@ -272,21 +272,13 @@ - - - diff --git a/src/VisualStudio/CSharp/Impl/Options/AdvancedOptionPageControl.xaml.cs b/src/VisualStudio/CSharp/Impl/Options/AdvancedOptionPageControl.xaml.cs index 25cea26602dc9..4b2884545023b 100644 --- a/src/VisualStudio/CSharp/Impl/Options/AdvancedOptionPageControl.xaml.cs +++ b/src/VisualStudio/CSharp/Impl/Options/AdvancedOptionPageControl.xaml.cs @@ -23,7 +23,6 @@ using Microsoft.CodeAnalysis.Editor.InlineHints; using Microsoft.CodeAnalysis.Editor.InlineRename; using Microsoft.CodeAnalysis.Editor.Shared.Options; -using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.Features.EmbeddedLanguages.Json.LanguageServices; using Microsoft.CodeAnalysis.Features.EmbeddedLanguages.RegularExpressions.LanguageServices; using Microsoft.CodeAnalysis.Host; @@ -43,7 +42,6 @@ using Microsoft.CodeAnalysis.Structure; using Microsoft.CodeAnalysis.SymbolSearch; using Microsoft.CodeAnalysis.ValidateFormatString; -using Microsoft.VisualStudio.ComponentModelHost; using Microsoft.VisualStudio.LanguageServices.DocumentOutline; using Microsoft.VisualStudio.LanguageServices.Implementation.Options; @@ -51,14 +49,8 @@ namespace Microsoft.VisualStudio.LanguageServices.CSharp.Options { internal partial class AdvancedOptionPageControl : AbstractOptionPageControl { - private readonly IThreadingContext _threadingContext; - private readonly ColorSchemeApplier _colorSchemeApplier; - - public AdvancedOptionPageControl(OptionStore optionStore, IComponentModel componentModel) : base(optionStore) + public AdvancedOptionPageControl(OptionStore optionStore) : base(optionStore) { - _threadingContext = componentModel.GetService(); - _colorSchemeApplier = componentModel.GetService(); - InitializeComponent(); // Analysis @@ -78,12 +70,7 @@ public AdvancedOptionPageControl(OptionStore optionStore, IComponentModel compon BindToOption(Enable_file_logging_for_diagnostics, VisualStudioLoggingOptionsStorage.EnableFileLoggingForDiagnostics); BindToOption(Skip_analyzers_for_implicitly_triggered_builds, FeatureOnOffOptions.SkipAnalyzersForImplicitlyTriggeredBuilds); - BindToOption(Show_Remove_Unused_References_command_in_Solution_Explorer_experimental, FeatureOnOffOptions.OfferRemoveUnusedReferences, () => - { - // If the option has not been set by the user, check if the option to remove unused references - // is enabled from experimentation. If so, default to that. - return optionStore.GetOption(FeatureOnOffOptions.OfferRemoveUnusedReferencesFeatureFlag); - }); + BindToOption(Show_Remove_Unused_References_command_in_Solution_Explorer, FeatureOnOffOptions.OfferRemoveUnusedReferences, () => true); // Source Generators BindToOption(Automatic_Run_generators_after_any_change, WorkspaceConfigurationOptionsStorage.SourceGeneratorExecution, SourceGeneratorExecutionPreference.Automatic, () => @@ -142,6 +129,7 @@ public AdvancedOptionPageControl(OptionStore optionStore, IComponentModel compon // Fading BindToOption(Fade_out_unused_usings, FadingOptions.FadeOutUnusedImports, LanguageNames.CSharp); + BindToOption(Fade_out_unused_members, FadingOptions.FadeOutUnusedMembers, LanguageNames.CSharp); BindToOption(Fade_out_unreachable_code, FadingOptions.FadeOutUnreachableCode, LanguageNames.CSharp); // Block Structure Guides @@ -224,15 +212,6 @@ public AdvancedOptionPageControl(OptionStore optionStore, IComponentModel compon // we need to update the visibility of our combobox and warnings based on the current VS theme before being rendered. internal override void OnLoad() { - var cancellationToken = _threadingContext.DisposalToken; - var (isSupportedTheme, isThemeCustomized) = _threadingContext.JoinableTaskFactory.Run(async () => - (await _colorSchemeApplier.IsSupportedThemeAsync(cancellationToken).ConfigureAwait(false), - await _colorSchemeApplier.IsThemeCustomizedAsync(cancellationToken).ConfigureAwait(false))); - - Editor_color_scheme.IsEnabled = isSupportedTheme; - Customized_Theme_Warning.Visibility = isSupportedTheme && isThemeCustomized ? Visibility.Visible : Visibility.Collapsed; - Custom_VS_Theme_Warning.Visibility = isSupportedTheme ? Visibility.Collapsed : Visibility.Visible; - UpdateInlineHintsOptions(); base.OnLoad(); diff --git a/src/VisualStudio/CSharp/Impl/Options/AdvancedOptionPageStrings.cs b/src/VisualStudio/CSharp/Impl/Options/AdvancedOptionPageStrings.cs index 1e53f112ce666..697627e5c57b5 100644 --- a/src/VisualStudio/CSharp/Impl/Options/AdvancedOptionPageStrings.cs +++ b/src/VisualStudio/CSharp/Impl/Options/AdvancedOptionPageStrings.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 Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.ColorSchemes; using Microsoft.CodeAnalysis.SolutionCrawler; @@ -16,7 +17,7 @@ public static string Option_Run_background_code_analysis_for => ServicesVSResources.Run_background_code_analysis_for_colon; public static string Option_Background_Analysis_Scope_None - => ServicesVSResources.None; + => WorkspacesResources.None; public static string Option_Background_Analysis_Scope_Active_File => ServicesVSResources.Current_document; @@ -43,7 +44,7 @@ public static string Option_Show_compiler_errors_and_warnings_for => ServicesVSResources.Show_compiler_errors_and_warnings_for_colon; public static string Option_Compiler_Diagnostics_Scope_None - => ServicesVSResources.None; + => WorkspacesResources.None; public static string Option_Compiler_Diagnostics_Scope_Visible_Files => ServicesVSResources.Current_document; // We show "Current document" to users for consistency with term used elsewhere. @@ -82,7 +83,7 @@ public static string Option_analyze_source_generated_files => ServicesVSResources.Analyze_source_generated_files; public static string Option_Inline_Hints - => ServicesVSResources.Inline_Hints; + => EditorFeaturesResources.Inline_Hints; public static string Option_Display_all_hints_while_pressing_Alt_F1 => ServicesVSResources.Display_all_hints_while_pressing_Alt_F1; @@ -139,13 +140,13 @@ public static string Option_on_the_right_edge_of_the_editor_window => ServicesVSResources.on_the_right_edge_of_the_editor_window; public static string Option_RenameTrackingPreview - => CSharpVSResources.Show_preview_for_rename_tracking; + => ServicesVSResources.Show_preview_for_rename_tracking; public static string Option_Split_string_literals_on_enter => CSharpVSResources.Split_string_literals_on_enter; public static string Option_DisplayLineSeparators - => CSharpVSResources.Show_procedure_line_separators; + => ServicesVSResources.Show_procedure_line_separators; public static string Option_Underline_reassigned_variables => ServicesVSResources.Underline_reassigned_variables; @@ -154,13 +155,13 @@ public static string Option_Strike_out_obsolete_symbols => ServicesVSResources.Strike_out_obsolete_symbols; public static string Option_EditorHelp - => CSharpVSResources.Editor_Help; + => ServicesVSResources.Editor_Help; public static string Option_EnableHighlightKeywords - => CSharpVSResources.Highlight_related_keywords_under_cursor; + => ServicesVSResources.Highlight_related_keywords_under_cursor; public static string Option_EnableHighlightReferences - => CSharpVSResources.Highlight_references_to_symbol_under_cursor; + => ServicesVSResources.Highlight_references_to_symbol_under_cursor; public static string Option_EnterOutliningMode => CSharpVSResources.Enter_outlining_mode_when_files_open; @@ -199,28 +200,28 @@ public static string Option_InsertAsteriskAtTheStartOfNewLinesWhenWritingBlockCo => CSharpVSResources.Insert_at_the_start_of_new_lines_when_writing_comments; public static string Option_ShowRemarksInQuickInfo - => CSharpVSResources.Show_remarks_in_Quick_Info; + => ServicesVSResources.Show_remarks_in_Quick_Info; public static string Option_Highlighting - => CSharpVSResources.Highlighting; + => ServicesVSResources.Highlighting; public static string Option_OptimizeForSolutionSize - => CSharpVSResources.Optimize_for_solution_size; + => ServicesVSResources.Optimize_for_solution_size; public static string Option_OptimizeForSolutionSize_Large - => CSharpVSResources.Large; + => ServicesVSResources.Large; public static string Option_OptimizeForSolutionSize_Regular - => CSharpVSResources.Regular; + => ServicesVSResources.Regular; public static string Option_OptimizeForSolutionSize_Small - => CSharpVSResources.Small; + => ServicesVSResources.Small; public static string Option_Quick_Actions => ServicesVSResources.Quick_Actions; public static string Option_Outlining - => ServicesVSResources.Outlining; + => EditorFeaturesResources.Outlining; public static string Option_Collapse_regions_on_file_open => ServicesVSResources.Collapse_regions_on_file_open; @@ -267,11 +268,14 @@ public static string Option_Fading public static string Option_Fade_out_unused_usings => CSharpVSResources.Fade_out_unused_usings; + public static string Option_Fade_out_unused_members + => ServicesVSResources.Fade_out_unused_members; + public static string Option_Fade_out_unreachable_code => ServicesVSResources.Fade_out_unreachable_code; public static string Option_Performance - => CSharpVSResources.Performance; + => ServicesVSResources.Performance; public static string Option_PlaceSystemNamespaceFirst => CSharpVSResources.Place_System_directives_first_when_sorting_usings; @@ -312,12 +316,6 @@ public static string Option_Show_completion_list public static string Option_Editor_Color_Scheme => ServicesVSResources.Editor_Color_Scheme; - public static string Editor_color_scheme_options_are_only_available_when_using_a_color_theme_bundled_with_Visual_Studio_The_color_theme_can_be_configured_from_the_Environment_General_options_page - => ServicesVSResources.Editor_color_scheme_options_are_only_available_when_using_a_color_theme_bundled_with_Visual_Studio_The_color_theme_can_be_configured_from_the_Environment_General_options_page; - - public static string Some_color_scheme_colors_are_being_overridden_by_changes_made_in_the_Environment_Fonts_and_Colors_options_page_Choose_Use_Defaults_in_the_Fonts_and_Colors_page_to_revert_all_customizations - => ServicesVSResources.Some_color_scheme_colors_are_being_overridden_by_changes_made_in_the_Environment_Fonts_and_Colors_options_page_Choose_Use_Defaults_in_the_Fonts_and_Colors_page_to_revert_all_customizations; - public static string Edit_color_scheme => ServicesVSResources.Editor_Color_Scheme; @@ -333,8 +331,8 @@ public static ColorSchemeName Color_Scheme_VisualStudio2019_Tag public static ColorSchemeName Color_Scheme_VisualStudio2017_Tag => ColorSchemeName.VisualStudio2017; - public static string Option_Show_Remove_Unused_References_command_in_Solution_Explorer_experimental - => ServicesVSResources.Show_Remove_Unused_References_command_in_Solution_Explorer_experimental; + public static string Option_Show_Remove_Unused_References_command_in_Solution_Explorer + => ServicesVSResources.Show_Remove_Unused_References_command_in_Solution_Explorer; public static string Option_Enable_file_logging_for_diagnostics => ServicesVSResources.Enable_file_logging_for_diagnostics; @@ -375,11 +373,8 @@ public static string Option_Fix_text_pasted_into_string_literals_experimental public static string Option_Go_To_Definition => ServicesVSResources.Go_To_Definition; - public static string Option_Navigate_asynchronously_exerimental - => ServicesVSResources.Navigate_asynchronously_exerimental; - public static string Option_Rename - => ServicesVSResources.Rename; + => EditorFeaturesResources.Rename; public static string Option_Rename_asynchronously_experimental => ServicesVSResources.Rename_asynchronously_experimental; diff --git a/src/VisualStudio/CSharp/Impl/Options/AutomationObject/AutomationObject.Fading.cs b/src/VisualStudio/CSharp/Impl/Options/AutomationObject/AutomationObject.Fading.cs index 4bc88fcb88ff4..bf8721627a36e 100644 --- a/src/VisualStudio/CSharp/Impl/Options/AutomationObject/AutomationObject.Fading.cs +++ b/src/VisualStudio/CSharp/Impl/Options/AutomationObject/AutomationObject.Fading.cs @@ -4,20 +4,25 @@ using Microsoft.CodeAnalysis.CodeStyle; -namespace Microsoft.VisualStudio.LanguageServices.CSharp.Options +namespace Microsoft.VisualStudio.LanguageServices.CSharp.Options; + +public partial class AutomationObject { - public partial class AutomationObject + public int Fading_FadeOutUnreachableCode + { + get { return GetBooleanOption(FadingOptions.FadeOutUnreachableCode); } + set { SetBooleanOption(FadingOptions.FadeOutUnreachableCode, value); } + } + + public int Fading_FadeOutUnusedImports { - public int Fading_FadeOutUnreachableCode - { - get { return GetBooleanOption(FadingOptions.FadeOutUnreachableCode); } - set { SetBooleanOption(FadingOptions.FadeOutUnreachableCode, value); } - } + get { return GetBooleanOption(FadingOptions.FadeOutUnusedImports); } + set { SetBooleanOption(FadingOptions.FadeOutUnusedImports, value); } + } - public int Fading_FadeOutUnusedImports - { - get { return GetBooleanOption(FadingOptions.FadeOutUnusedImports); } - set { SetBooleanOption(FadingOptions.FadeOutUnusedImports, value); } - } + public int Fading_FadeOutUnusedMembers + { + get { return GetBooleanOption(FadingOptions.FadeOutUnusedMembers); } + set { SetBooleanOption(FadingOptions.FadeOutUnusedMembers, value); } } } diff --git a/src/VisualStudio/CSharp/Impl/Options/AutomationObject/AutomationObject.cs b/src/VisualStudio/CSharp/Impl/Options/AutomationObject/AutomationObject.cs index 4320c664485ad..e9e2a3c5e5281 100644 --- a/src/VisualStudio/CSharp/Impl/Options/AutomationObject/AutomationObject.cs +++ b/src/VisualStudio/CSharp/Impl/Options/AutomationObject/AutomationObject.cs @@ -11,7 +11,7 @@ namespace Microsoft.VisualStudio.LanguageServices.CSharp.Options { [ComVisible(true)] - public partial class AutomationObject : AbstractAutomationObject + public sealed partial class AutomationObject : AbstractAutomationObject { internal AutomationObject(ILegacyGlobalOptionService legacyGlobalOptions) : base(legacyGlobalOptions, LanguageNames.CSharp) diff --git a/src/VisualStudio/CSharp/Impl/Options/CSharpVisualStudioOptionStorageReadFallbacks.cs b/src/VisualStudio/CSharp/Impl/Options/CSharpVisualStudioOptionStorageReadFallbacks.cs index 1f541870e76f8..f25d411c52b2a 100644 --- a/src/VisualStudio/CSharp/Impl/Options/CSharpVisualStudioOptionStorageReadFallbacks.cs +++ b/src/VisualStudio/CSharp/Impl/Options/CSharpVisualStudioOptionStorageReadFallbacks.cs @@ -17,10 +17,12 @@ internal static class CSharpVisualStudioOptionStorageReadFallbacks [ExportVisualStudioStorageReadFallback("csharp_space_between_parentheses"), Shared] internal sealed class SpaceBetweenParentheses : IVisualStudioStorageReadFallback { - private static readonly ImmutableArray<(string key, int flag)> s_storages = ImmutableArray.Create( + private static readonly ImmutableArray<(string key, int flag)> s_storages = + [ ("TextEditor.CSharp.Specific.SpaceWithinExpressionParentheses", (int)SpacePlacementWithinParentheses.Expressions), ("TextEditor.CSharp.Specific.SpaceWithinCastParentheses", (int)SpacePlacementWithinParentheses.TypeCasts), - ("TextEditor.CSharp.Specific.SpaceWithinOtherParentheses", (int)SpacePlacementWithinParentheses.ControlFlowStatements)); + ("TextEditor.CSharp.Specific.SpaceWithinOtherParentheses", (int)SpacePlacementWithinParentheses.ControlFlowStatements), + ]; [ImportingConstructor] [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] @@ -35,7 +37,8 @@ public SpaceBetweenParentheses() [ExportVisualStudioStorageReadFallback("csharp_new_line_before_open_brace"), Shared] internal sealed class NewLinesForBraces : IVisualStudioStorageReadFallback { - private static readonly ImmutableArray<(string key, int flag)> s_storages = ImmutableArray.Create( + private static readonly ImmutableArray<(string key, int flag)> s_storages = + [ ("TextEditor.CSharp.Specific.NewLinesForBracesInTypes", (int)NewLineBeforeOpenBracePlacement.Types), ("TextEditor.CSharp.Specific.NewLinesForBracesInAnonymousTypes", (int)NewLineBeforeOpenBracePlacement.AnonymousTypes), ("TextEditor.CSharp.Specific.NewLinesForBracesInObjectCollectionArrayInitializers", (int)NewLineBeforeOpenBracePlacement.ObjectCollectionArrayInitializers), @@ -44,7 +47,8 @@ internal sealed class NewLinesForBraces : IVisualStudioStorageReadFallback ("TextEditor.CSharp.Specific.NewLinesForBracesInAccessors", (int)NewLineBeforeOpenBracePlacement.Accessors), ("TextEditor.CSharp.Specific.NewLinesForBracesInAnonymousMethods", (int)NewLineBeforeOpenBracePlacement.AnonymousMethods), ("TextEditor.CSharp.Specific.NewLinesForBracesInLambdaExpressionBody", (int)NewLineBeforeOpenBracePlacement.LambdaExpressionBody), - ("TextEditor.CSharp.Specific.NewLinesForBracesInControlBlocks", (int)NewLineBeforeOpenBracePlacement.ControlBlocks)); + ("TextEditor.CSharp.Specific.NewLinesForBracesInControlBlocks", (int)NewLineBeforeOpenBracePlacement.ControlBlocks), + ]; [ImportingConstructor] [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] diff --git a/src/VisualStudio/CSharp/Impl/Options/Formatting/StyleViewModel.cs b/src/VisualStudio/CSharp/Impl/Options/Formatting/StyleViewModel.cs index 7b7dfdecfe67e..4136ea53e015a 100644 --- a/src/VisualStudio/CSharp/Impl/Options/Formatting/StyleViewModel.cs +++ b/src/VisualStudio/CSharp/Impl/Options/Formatting/StyleViewModel.cs @@ -10,7 +10,9 @@ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.AddImport; using Microsoft.CodeAnalysis.CodeStyle; +using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.CodeStyle; +using Microsoft.CodeAnalysis.Editor.CSharp; using Microsoft.VisualStudio.LanguageServices.Implementation.Options; namespace Microsoft.VisualStudio.LanguageServices.CSharp.Options.Formatting @@ -1489,7 +1491,7 @@ class Customer }} //]", $@" //[ - // {CSharpVSResources.Outside_namespace} + // {CSharpEditorResources.Outside_namespace} using System; using System.Linq; @@ -2208,7 +2210,7 @@ internal StyleViewModel(OptionStore optionStore, IServiceProvider serviceProvide var usingDirectivePlacementPreferences = new List { new CodeStylePreference(CSharpVSResources.Inside_namespace, isChecked: false), - new CodeStylePreference(CSharpVSResources.Outside_namespace, isChecked: false), + new CodeStylePreference(CSharpEditorResources.Outside_namespace, isChecked: false), }; var qualifyMemberAccessPreferences = new List @@ -2291,8 +2293,8 @@ internal StyleViewModel(OptionStore optionStore, IServiceProvider serviceProvide CodeStyleItems.Add(new BooleanCodeStyleOptionViewModel(CSharpCodeStyleOptions.PreferConditionalDelegateCall, CSharpVSResources.Prefer_conditional_delegate_call, s_preferConditionalDelegateCall, s_preferConditionalDelegateCall, this, optionStore, nullCheckingGroupTitle)); CodeStyleItems.Add(new BooleanCodeStyleOptionViewModel(CodeStyleOptions2.PreferCoalesceExpression, ServicesVSResources.Prefer_coalesce_expression, s_preferCoalesceExpression, s_preferCoalesceExpression, this, optionStore, nullCheckingGroupTitle)); CodeStyleItems.Add(new BooleanCodeStyleOptionViewModel(CodeStyleOptions2.PreferNullPropagation, ServicesVSResources.Prefer_null_propagation, s_preferNullPropagation, s_preferNullPropagation, this, optionStore, nullCheckingGroupTitle)); - CodeStyleItems.Add(new BooleanCodeStyleOptionViewModel(CodeStyleOptions2.PreferIsNullCheckOverReferenceEqualityMethod, CSharpVSResources.Prefer_is_null_for_reference_equality_checks, s_preferIsNullOverReferenceEquals, s_preferIsNullOverReferenceEquals, this, optionStore, nullCheckingGroupTitle)); - CodeStyleItems.Add(new BooleanCodeStyleOptionViewModel(CSharpCodeStyleOptions.PreferNullCheckOverTypeCheck, CSharpVSResources.Prefer_null_check_over_type_check, s_preferNullcheckOverTypeCheck, s_preferNullcheckOverTypeCheck, this, optionStore, nullCheckingGroupTitle)); + CodeStyleItems.Add(new BooleanCodeStyleOptionViewModel(CodeStyleOptions2.PreferIsNullCheckOverReferenceEqualityMethod, EditorFeaturesResources.Prefer_is_null_for_reference_equality_checks, s_preferIsNullOverReferenceEquals, s_preferIsNullOverReferenceEquals, this, optionStore, nullCheckingGroupTitle)); + CodeStyleItems.Add(new BooleanCodeStyleOptionViewModel(CSharpCodeStyleOptions.PreferNullCheckOverTypeCheck, CSharpAnalyzersResources.Prefer_null_check_over_type_check, s_preferNullcheckOverTypeCheck, s_preferNullcheckOverTypeCheck, this, optionStore, nullCheckingGroupTitle)); // Using directive preferences. CodeStyleItems.Add(new EnumCodeStyleOptionViewModel( @@ -2350,8 +2352,8 @@ private void AddBracesOptions(OptionStore optionStore, string bracesPreferenceGr { var bracesPreferences = new List { - new CodeStylePreference(ServicesVSResources.Yes, isChecked: false), - new CodeStylePreference(ServicesVSResources.No, isChecked: false), + new CodeStylePreference(EditorFeaturesResources.Yes, isChecked: false), + new CodeStylePreference(EditorFeaturesResources.No, isChecked: false), new CodeStylePreference(CSharpVSResources.When_on_multiple_lines, isChecked: false), }; @@ -2387,7 +2389,7 @@ private void AddExpressionBodyOptions(OptionStore optionStore, string expression { var expressionBodyPreferences = new List { - new CodeStylePreference(CSharpVSResources.Never, isChecked: false), + new CodeStylePreference(ServicesVSResources.Never, isChecked: false), new CodeStylePreference(CSharpVSResources.When_possible, isChecked: false), new CodeStylePreference(CSharpVSResources.When_on_single_line, isChecked: false), }; @@ -2455,7 +2457,7 @@ private void AddUnusedValueOptions(OptionStore optionStore, string expressionPre { var unusedValuePreferences = new List { - new CodeStylePreference(CSharpVSResources.Unused_local, isChecked: false), + new CodeStylePreference(ServicesVSResources.Unused_local, isChecked: false), new CodeStylePreference(CSharpVSResources.Discard, isChecked: true), }; diff --git a/src/VisualStudio/CSharp/Impl/Options/IntelliSenseOptionPageControl.xaml b/src/VisualStudio/CSharp/Impl/Options/IntelliSenseOptionPageControl.xaml index a44181d87df24..e1072c383a688 100644 --- a/src/VisualStudio/CSharp/Impl/Options/IntelliSenseOptionPageControl.xaml +++ b/src/VisualStudio/CSharp/Impl/Options/IntelliSenseOptionPageControl.xaml @@ -68,7 +68,7 @@ + Content="{x:Static local:IntelliSenseOptionPageStrings.Option_Show_name_s_uggestions}" /> + Content="{x:Static local:IntelliSenseOptionPageStrings.Option_Tab_twice_to_insert_arguments_experimental}" /> CSharpVSResources.Show_completion_list_after_a_character_is_typed; + => ServicesVSResources._Show_completion_list_after_a_character_is_typed; public static string Option_Show_completion_list_after_a_character_is_deleted - => CSharpVSResources.Show_completion_list_after_a_character_is_deleted; + => ServicesVSResources.Show_completion_list_after_a_character_is__deleted; public static string Option_Completion { @@ -35,30 +35,30 @@ public static string Option_ShowSnippets } public static string Option_Highlight_matching_portions_of_completion_list_items - => CSharpVSResources.Highlight_matching_portions_of_completion_list_items; + => ServicesVSResources._Highlight_matching_portions_of_completion_list_items; public static string Option_Show_completion_item_filters - => CSharpVSResources.Show_completion_item_filters; + => ServicesVSResources.Show_completion_item__filters; public static string Option_Automatically_complete_statement_on_semicolon => CSharpVSResources.Automatically_complete_statement_on_semicolon; public static string Enter_key_behavior_Title - => CSharpVSResources.Enter_key_behavior_colon; + => ServicesVSResources.Enter_key_behavior_colon; public static string Option_Never_add_new_line_on_enter - => CSharpVSResources.Never_add_new_line_on_enter; + => ServicesVSResources.Never_add_new_line_on_enter; public static string Option_Only_add_new_line_on_enter_with_whole_word - => CSharpVSResources.Only_add_new_line_on_enter_after_end_of_fully_typed_word; + => ServicesVSResources._Only_add_new_line_on_enter_after_end_of_fully_typed_word; public static string Option_Always_add_new_line_on_enter - => CSharpVSResources.Always_add_new_line_on_enter; + => ServicesVSResources.Always_add_new_line_on_enter; public static string Snippets_behavior - => CSharpVSResources.Snippets_behavior; + => ServicesVSResources.Snippets_behavior; public static string Option_Never_include_snippets - => CSharpVSResources.Never_include_snippets; + => ServicesVSResources.Never_include_snippets; public static string Option_Always_include_snippets => CSharpVSResources.Always_include_snippets; @@ -66,14 +66,14 @@ public static string Option_Always_include_snippets public static string Option_Include_snippets_when_question_Tab_is_typed_after_an_identifier => CSharpVSResources.Include_snippets_when_Tab_is_typed_after_an_identifier; - public static string Option_Show_name_suggestions - => CSharpVSResources.Show_name_suggestions; + public static string Option_Show_name_s_uggestions + => CSharpVSResources.Show_name_s_uggestions; public static string Option_Show_items_from_unimported_namespaces - => CSharpVSResources.Show_items_from_unimported_namespaces; + => ServicesVSResources.Show_items_from_unimported_namespaces; - public static string Option_Tab_twice_to_insert_arguments - => ServicesVSResources.Tab_twice_to_insert_arguments; + public static string Option_Tab_twice_to_insert_arguments_experimental + => ServicesVSResources.Tab_twice_to_insert_arguments_experimental; public static string Automatically_show_completion_list_in_argument_lists => CSharpVSResources.Automatically_show_completion_list_in_argument_lists; diff --git a/src/VisualStudio/CSharp/Impl/PackageRegistration.pkgdef b/src/VisualStudio/CSharp/Impl/PackageRegistration.pkgdef index 852593e3f17a3..1a5637a51aad2 100644 --- a/src/VisualStudio/CSharp/Impl/PackageRegistration.pkgdef +++ b/src/VisualStudio/CSharp/Impl/PackageRegistration.pkgdef @@ -198,4 +198,4 @@ [$RootKey$\SettingsManifests\{13c3bbb4-f18f-4111-9f54-a0fb010d9194}] @="Microsoft.VisualStudio.LanguageServices.CSharp.LanguageService.CSharpPackage" "ManifestPath"="$PackageFolder$\UnifiedSettings\csharpSettings.registration.json" -"CacheTag"=qword:CE76341698AB8CD3 +"CacheTag"=qword:18C11F0A543B8AD0 diff --git a/src/VisualStudio/CSharp/Impl/ProjectSystemShim/CSharpProjectShim.ICSharpProjectSite.cs b/src/VisualStudio/CSharp/Impl/ProjectSystemShim/CSharpProjectShim.ICSharpProjectSite.cs index 7992e546c7411..11fa561e1bdd4 100644 --- a/src/VisualStudio/CSharp/Impl/ProjectSystemShim/CSharpProjectShim.ICSharpProjectSite.cs +++ b/src/VisualStudio/CSharp/Impl/ProjectSystemShim/CSharpProjectShim.ICSharpProjectSite.cs @@ -6,6 +6,7 @@ using System.Linq; using System.Runtime.InteropServices; using System.Threading; +using System.Threading.Tasks; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.VisualStudio.LanguageServices.CSharp.ProjectSystemShim.Interop; @@ -120,48 +121,50 @@ public void OnModuleRemoved(string filename) public int GetValidStartupClasses(IntPtr[] classNames, ref int count) { - var project = Workspace.CurrentSolution.GetRequiredProject(ProjectSystemProject.Id); - var compilation = project.GetRequiredCompilationAsync(CancellationToken.None).WaitAndGetResult(CancellationToken.None); - var entryPoints = CSharpEntryPointFinder.FindEntryPoints(compilation); + var (result, newCount) = this.ThreadingContext.JoinableTaskFactory.Run(GetValidStartupClassesAsync); + if (newCount.HasValue) + count = newCount.Value; - // If classNames is NULL, then we need to populate the number of valid startup - // classes only - if (classNames == null) - { - count = entryPoints.Count(); - return VSConstants.S_OK; - } - else + return result; + + async Task<(int result, int? newCount)> GetValidStartupClassesAsync() { - // We return S_FALSE if we have more entrypoints than places in the array. - var entryPointNames = entryPoints.Select(e => e.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat.WithGlobalNamespaceStyle(SymbolDisplayGlobalNamespaceStyle.Omitted))).ToArray(); + var project = Workspace.CurrentSolution.GetRequiredProject(ProjectSystemProject.Id); + var compilation = await project.GetRequiredCompilationAsync(CancellationToken.None).ConfigureAwait(true); + var entryPoints = CSharpEntryPointFinder.FindEntryPoints(compilation); - if (entryPointNames.Length > classNames.Length) + // If classNames is NULL, then we need to populate the number of valid startup + // classes only + if (classNames == null) { - return VSConstants.S_FALSE; + return (VSConstants.S_OK, entryPoints.Count()); } - - // The old language service stored startup class names in its string table, - // so the property page never freed them. To avoid leaking memory, we're - // going to allocate our strings on the native heap and keep the pointers to them. - // Subsequent calls to this function will free the old strings and allocate the - // new ones. The last set of marshalled strings is freed in the destructor. - if (_startupClasses != null) + else { - foreach (var @class in _startupClasses) + // We return S_FALSE if we have more entrypoints than places in the array. + var entryPointNames = entryPoints.Select(e => e.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat.WithGlobalNamespaceStyle(SymbolDisplayGlobalNamespaceStyle.Omitted))).ToArray(); + + if (entryPointNames.Length > classNames.Length) + return (VSConstants.S_FALSE, null); + + // The old language service stored startup class names in its string table, + // so the property page never freed them. To avoid leaking memory, we're + // going to allocate our strings on the native heap and keep the pointers to them. + // Subsequent calls to this function will free the old strings and allocate the + // new ones. The last set of marshalled strings is freed in the destructor. + if (_startupClasses != null) { - Marshal.FreeHGlobal(@class); + foreach (var @class in _startupClasses) + Marshal.FreeHGlobal(@class); } - } - _startupClasses = entryPointNames.Select(Marshal.StringToHGlobalUni).ToArray(); - Array.Copy(_startupClasses, classNames, _startupClasses.Length); + _startupClasses = [.. entryPointNames.Select(Marshal.StringToHGlobalUni)]; + Array.Copy(_startupClasses, classNames, _startupClasses.Length); - count = entryPointNames.Length; - return VSConstants.S_OK; + return (VSConstants.S_OK, entryPointNames.Length); + } } } - public void OnAliasesChanged(string file, string project, int previousAliasesCount, string[] previousAliases, int currentAliasesCount, string[] currentAliases) { using (ProjectSystemProject.CreateBatchScope()) diff --git a/src/VisualStudio/CSharp/Impl/ProjectSystemShim/CSharpProjectShim.OptionsProcessor.cs b/src/VisualStudio/CSharp/Impl/ProjectSystemShim/CSharpProjectShim.OptionsProcessor.cs index f7748a5f1aa0e..ecd124d10017d 100644 --- a/src/VisualStudio/CSharp/Impl/ProjectSystemShim/CSharpProjectShim.OptionsProcessor.cs +++ b/src/VisualStudio/CSharp/Impl/ProjectSystemShim/CSharpProjectShim.OptionsProcessor.cs @@ -160,7 +160,7 @@ compilerOptions is CompilerOptions.OPTID_NOWARNLIST or CompilerOptions.OPTID_WARNASERRORLIST or CompilerOptions.OPTID_WARNNOTASERRORLIST); - foreach (var warning in GetStringOption(compilerOptions, defaultValue: "").Split(new[] { ' ', ',', ';' }, StringSplitOptions.RemoveEmptyEntries)) + foreach (var warning in GetStringOption(compilerOptions, defaultValue: "").Split([' ', ',', ';'], StringSplitOptions.RemoveEmptyEntries)) { var warningStringID = warning; if (int.TryParse(warning, out var warningId)) @@ -214,7 +214,7 @@ private bool GetBooleanOption(CompilerOptions optionID) protected override ParseOptions ComputeParseOptionsWithHostValues(ParseOptions parseOptions) { - var symbols = GetStringOption(CompilerOptions.OPTID_CCSYMBOLS, defaultValue: "").Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries); + var symbols = GetStringOption(CompilerOptions.OPTID_CCSYMBOLS, defaultValue: "").Split([';'], StringSplitOptions.RemoveEmptyEntries); // The base implementation of OptionsProcessor already tried this, but it didn't have the real documentation // path so we have to do it a second time diff --git a/src/VisualStudio/CSharp/Impl/ProjectSystemShim/TempPECompilerService.cs b/src/VisualStudio/CSharp/Impl/ProjectSystemShim/TempPECompilerService.cs index ae2a7a29f28e0..02f811eb9514b 100644 --- a/src/VisualStudio/CSharp/Impl/ProjectSystemShim/TempPECompilerService.cs +++ b/src/VisualStudio/CSharp/Impl/ProjectSystemShim/TempPECompilerService.cs @@ -51,7 +51,7 @@ public int CompileTempPE(string pszOutputFileName, int sourceCount, string[] fil var metadataResolver = new WorkspaceMetadataFileReferenceResolver( _metadataService, - new RelativePathResolver(ImmutableArray.Empty, baseDirectory: null)); + new RelativePathResolver([], baseDirectory: null)); var compilation = CSharpCompilation.Create( Path.GetFileName(pszOutputFileName), @@ -82,7 +82,7 @@ private static CSharpCommandLineArguments ParseCommandLineArguments(string baseD if (optionName == "r") { // We get a pipe-delimited list of references, so split them back apart - foreach (var reference in ((string)optionValue).Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries)) + foreach (var reference in ((string)optionValue).Split(['|'], StringSplitOptions.RemoveEmptyEntries)) { arguments.Add(string.Format("/r:\"{0}\"", reference)); } diff --git a/src/VisualStudio/CSharp/Impl/SemanticSearch/OpenSemanticSearchWindowCommand.cs b/src/VisualStudio/CSharp/Impl/SemanticSearch/OpenSemanticSearchWindowCommand.cs index 53096f1cefd6a..0b29e070ab5bd 100644 --- a/src/VisualStudio/CSharp/Impl/SemanticSearch/OpenSemanticSearchWindowCommand.cs +++ b/src/VisualStudio/CSharp/Impl/SemanticSearch/OpenSemanticSearchWindowCommand.cs @@ -19,7 +19,7 @@ internal sealed class OpenSemanticSearchWindowCommand : Command public override CommandConfiguration CommandConfiguration => new("%CSharpLanguageServiceExtension.OpenSemanticSearchWindow.DisplayName%") { Icon = new(ImageMoniker.KnownValues.FindSymbol, IconSettings.IconAndText), - Placements = new[] { CommandPlacement.KnownPlacements.ViewOtherWindowsMenu.WithPriority(0x8010) }, + Placements = [CommandPlacement.KnownPlacements.ViewOtherWindowsMenu.WithPriority(0x8010)], VisibleWhen = ActivationConstraint.UIContext(Guid.Parse(SemanticSearchFeatureFlag.UIContextId)) }; diff --git a/src/VisualStudio/CSharp/Impl/SemanticSearch/SemanticSearchToolWindowImpl.cs b/src/VisualStudio/CSharp/Impl/SemanticSearch/SemanticSearchToolWindowImpl.cs index 7c4a4ccee01ee..d51c7b44a8e87 100644 --- a/src/VisualStudio/CSharp/Impl/SemanticSearch/SemanticSearchToolWindowImpl.cs +++ b/src/VisualStudio/CSharp/Impl/SemanticSearch/SemanticSearchToolWindowImpl.cs @@ -222,6 +222,7 @@ private static ControlTemplate CreateButtonTemplate() context.XmlnsDictionary.Add("x", "http://schemas.microsoft.com/winfx/2006/xaml"); context.XmlnsDictionary.Add("vsui", "clr-namespace:Microsoft.VisualStudio.PlatformUI;assembly=Microsoft.VisualStudio.Shell.15.0"); + // CodeQL [SM02229] The string being passed to the deserialize method is practically constant and all the types listed are controlled by the VS platform. return (ControlTemplate)XamlReader.Parse($$$""" diff --git a/src/VisualStudio/CSharp/Impl/Snippets/CSharpSnippetExpansionLanguageHelper.cs b/src/VisualStudio/CSharp/Impl/Snippets/CSharpSnippetExpansionLanguageHelper.cs index 27b49fa8185d1..2fee5a7250058 100644 --- a/src/VisualStudio/CSharp/Impl/Snippets/CSharpSnippetExpansionLanguageHelper.cs +++ b/src/VisualStudio/CSharp/Impl/Snippets/CSharpSnippetExpansionLanguageHelper.cs @@ -7,6 +7,7 @@ using System.Composition; using System.Linq; using System.Threading; +using System.Threading.Tasks; using System.Xml.Linq; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.AddImport; @@ -15,6 +16,7 @@ using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Editing; using Microsoft.CodeAnalysis.Editor.Shared.Extensions; +using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Shared.Extensions; @@ -25,133 +27,123 @@ using Roslyn.Utilities; using VsTextSpan = Microsoft.VisualStudio.TextManager.Interop.TextSpan; -namespace Microsoft.VisualStudio.LanguageServices.CSharp.Snippets +namespace Microsoft.VisualStudio.LanguageServices.CSharp.Snippets; + +using static CSharpSyntaxTokens; + +[ExportLanguageService(typeof(ISnippetExpansionLanguageHelper), LanguageNames.CSharp), Shared] +[method: ImportingConstructor] +[method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] +internal sealed class CSharpSnippetExpansionLanguageHelper( + IThreadingContext threadingContext) + : AbstractSnippetExpansionLanguageHelper(threadingContext) { - using static CSharpSyntaxTokens; + public override Guid LanguageServiceGuid => Guids.CSharpLanguageServiceId; + public override string FallbackDefaultLiteral => "default"; - [ExportLanguageService(typeof(ISnippetExpansionLanguageHelper), LanguageNames.CSharp)] - [Shared] - internal class CSharpSnippetExpansionLanguageHelper : AbstractSnippetExpansionLanguageHelper + /// The tracking span of the inserted "/**/" if there is an $end$ location, null + /// otherwise. + public override ITrackingSpan? InsertEmptyCommentAndGetEndPositionTrackingSpan(IVsExpansionSession expansionSession, ITextView textView, ITextBuffer subjectBuffer) { - [ImportingConstructor] - [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - public CSharpSnippetExpansionLanguageHelper() + RoslynDebug.AssertNotNull(expansionSession); + + var endSpanInSurfaceBuffer = new VsTextSpan[1]; + if (expansionSession.GetEndSpan(endSpanInSurfaceBuffer) != VSConstants.S_OK) { + return null; } - public override Guid LanguageServiceGuid => Guids.CSharpLanguageServiceId; - public override string FallbackDefaultLiteral => "default"; - - /// The tracking span of the inserted "/**/" if there is an $end$ location, null - /// otherwise. - public override ITrackingSpan? InsertEmptyCommentAndGetEndPositionTrackingSpan(IVsExpansionSession expansionSession, ITextView textView, ITextBuffer subjectBuffer) + if (!TryGetSubjectBufferSpan(textView, subjectBuffer, endSpanInSurfaceBuffer[0], out var subjectBufferEndSpan)) { - RoslynDebug.AssertNotNull(expansionSession); + return null; + } - var endSpanInSurfaceBuffer = new VsTextSpan[1]; - if (expansionSession.GetEndSpan(endSpanInSurfaceBuffer) != VSConstants.S_OK) - { - return null; - } + var endPosition = subjectBufferEndSpan.Start.Position; - if (!TryGetSubjectBufferSpan(textView, subjectBuffer, endSpanInSurfaceBuffer[0], out var subjectBufferEndSpan)) - { - return null; - } + var commentString = "/**/"; + subjectBuffer.Insert(endPosition, commentString); - var endPosition = subjectBufferEndSpan.Start.Position; + var commentSpan = new Span(endPosition, commentString.Length); + return subjectBuffer.CurrentSnapshot.CreateTrackingSpan(commentSpan, SpanTrackingMode.EdgeExclusive); + } - var commentString = "/**/"; - subjectBuffer.Insert(endPosition, commentString); + public override async Task AddImportsAsync( + Document document, + AddImportPlacementOptions addImportOptions, + SyntaxFormattingOptions formattingOptions, + int position, + XElement snippetNode, + CancellationToken cancellationToken) + { + var importsNode = snippetNode.Element(XName.Get("Imports", snippetNode.Name.NamespaceName)); + if (importsNode == null || !importsNode.HasElements) + return document; - var commentSpan = new Span(endPosition, commentString.Length); - return subjectBuffer.CurrentSnapshot.CreateTrackingSpan(commentSpan, SpanTrackingMode.EdgeExclusive); - } + var root = document.GetRequiredSyntaxRootSynchronously(cancellationToken); + var contextLocation = root.FindToken(position).GetRequiredParent(); - public override Document AddImports( - Document document, - AddImportPlacementOptions addImportOptions, - SyntaxFormattingOptions formattingOptions, - int position, - XElement snippetNode, - CancellationToken cancellationToken) - { - var importsNode = snippetNode.Element(XName.Get("Imports", snippetNode.Name.NamespaceName)); - if (importsNode == null || - !importsNode.HasElements) - { - return document; - } + var newUsingDirectives = GetUsingDirectivesToAdd(contextLocation, snippetNode, importsNode); + if (newUsingDirectives.Count == 0) + return document; - var root = document.GetRequiredSyntaxRootSynchronously(cancellationToken); - var contextLocation = root.FindToken(position).GetRequiredParent(); + // In Venus/Razor, inserting imports statements into the subject buffer does not work. + // Instead, we add the imports through the contained language host. + if (TryAddImportsToContainedDocument(document, newUsingDirectives.Where(u => u.Alias == null).Select(u => u.Name!.ToString()))) + return document; - var newUsingDirectives = GetUsingDirectivesToAdd(contextLocation, snippetNode, importsNode); - if (!newUsingDirectives.Any()) - { - return document; - } + var addImportService = document.GetRequiredLanguageService(); + var generator = document.GetRequiredLanguageService(); + var compilation = await document.Project.GetRequiredCompilationAsync(cancellationToken).ConfigureAwait(true); + var newRoot = addImportService.AddImports(compilation, root, contextLocation, newUsingDirectives, generator, addImportOptions, cancellationToken); - // In Venus/Razor, inserting imports statements into the subject buffer does not work. - // Instead, we add the imports through the contained language host. - if (TryAddImportsToContainedDocument(document, newUsingDirectives.Where(u => u.Alias == null).Select(u => u.Name!.ToString()))) - { - return document; - } + var newDocument = document.WithSyntaxRoot(newRoot); - var addImportService = document.GetRequiredLanguageService(); - var generator = document.GetRequiredLanguageService(); - var compilation = document.Project.GetRequiredCompilationAsync(cancellationToken).WaitAndGetResult(cancellationToken); - var newRoot = addImportService.AddImports(compilation, root, contextLocation, newUsingDirectives, generator, addImportOptions, cancellationToken); + var formattedDocument = await Formatter.FormatAsync(newDocument, Formatter.Annotation, formattingOptions, cancellationToken).ConfigureAwait(true); + await document.Project.Solution.Workspace.ApplyDocumentChangesAsync( + this.ThreadingContext, formattedDocument, cancellationToken).ConfigureAwait(true); - var newDocument = document.WithSyntaxRoot(newRoot); - - var formattedDocument = Formatter.FormatAsync(newDocument, Formatter.Annotation, formattingOptions, cancellationToken).WaitAndGetResult(cancellationToken); - document.Project.Solution.Workspace.ApplyDocumentChanges(formattedDocument, cancellationToken); + return formattedDocument; + } - return formattedDocument; - } + private static List GetUsingDirectivesToAdd( + SyntaxNode contextLocation, XElement snippetNode, XElement importsNode) + { + var namespaceXmlName = XName.Get("Namespace", snippetNode.Name.NamespaceName); + var existingUsings = contextLocation.GetEnclosingUsingDirectives(); + var newUsings = new List(); - private static List GetUsingDirectivesToAdd( - SyntaxNode contextLocation, XElement snippetNode, XElement importsNode) + foreach (var import in importsNode.Elements(XName.Get("Import", snippetNode.Name.NamespaceName))) { - var namespaceXmlName = XName.Get("Namespace", snippetNode.Name.NamespaceName); - var existingUsings = contextLocation.GetEnclosingUsingDirectives(); - var newUsings = new List(); + var namespaceElement = import.Element(namespaceXmlName); + if (namespaceElement == null) + { + continue; + } - foreach (var import in importsNode.Elements(XName.Get("Import", snippetNode.Name.NamespaceName))) + var namespaceToImport = namespaceElement.Value.Trim(); + if (string.IsNullOrEmpty(namespaceToImport)) { - var namespaceElement = import.Element(namespaceXmlName); - if (namespaceElement == null) - { - continue; - } - - var namespaceToImport = namespaceElement.Value.Trim(); - if (string.IsNullOrEmpty(namespaceToImport)) - { - continue; - } - - var candidateUsing = SyntaxFactory.ParseCompilationUnit("using " + namespaceToImport + ";").DescendantNodes().OfType().FirstOrDefault(); - if (candidateUsing == null) - { - continue; - } - else if (candidateUsing.ContainsDiagnostics && !namespaceToImport.Contains("=")) - { - // Retry by parsing the namespace as a name and constructing a using directive from it - candidateUsing = SyntaxFactory.UsingDirective(SyntaxFactory.ParseName(namespaceToImport)) - .WithUsingKeyword(UsingKeyword.WithTrailingTrivia(SyntaxFactory.Space)); - } - - if (!existingUsings.Any(u => u.IsEquivalentTo(candidateUsing, topLevel: false))) - { - newUsings.Add(candidateUsing.WithAdditionalAnnotations(Formatter.Annotation).WithAppendedTrailingTrivia(SyntaxFactory.CarriageReturnLineFeed)); - } + continue; } - return newUsings; + var candidateUsing = SyntaxFactory.ParseCompilationUnit("using " + namespaceToImport + ";").DescendantNodes().OfType().FirstOrDefault(); + if (candidateUsing == null) + { + continue; + } + else if (candidateUsing.ContainsDiagnostics && !namespaceToImport.Contains("=")) + { + // Retry by parsing the namespace as a name and constructing a using directive from it + candidateUsing = SyntaxFactory.UsingDirective(SyntaxFactory.ParseName(namespaceToImport)) + .WithUsingKeyword(UsingKeyword.WithTrailingTrivia(SyntaxFactory.Space)); + } + + if (!existingUsings.Any(u => u.IsEquivalentTo(candidateUsing, topLevel: false))) + { + newUsings.Add(candidateUsing.WithAdditionalAnnotations(Formatter.Annotation).WithAppendedTrailingTrivia(SyntaxFactory.CarriageReturnLineFeed)); + } } + + return newUsings; } } diff --git a/src/VisualStudio/CSharp/Impl/Snippets/SnippetCommandHandler.cs b/src/VisualStudio/CSharp/Impl/Snippets/SnippetCommandHandler.cs index 1cebb71413754..821c0869fedd3 100644 --- a/src/VisualStudio/CSharp/Impl/Snippets/SnippetCommandHandler.cs +++ b/src/VisualStudio/CSharp/Impl/Snippets/SnippetCommandHandler.cs @@ -120,7 +120,7 @@ protected override bool TryInvokeInsertionUI(ITextView textView, ITextBuffer sub bstrKinds: null, iCountKinds: 0, fIncludeNULLKind: 0, - bstrPrefixText: surroundWith ? CSharpVSResources.Surround_With : CSharpVSResources.Insert_Snippet, + bstrPrefixText: surroundWith ? CSharpVSResources.Surround_With : ServicesVSResources.Insert_Snippet, bstrCompletionChar: null); return true; diff --git a/src/VisualStudio/CSharp/Impl/UnifiedSettings/csharpSettings.registration.json b/src/VisualStudio/CSharp/Impl/UnifiedSettings/csharpSettings.registration.json index a5a62ad827f35..627bd2ab30446 100644 --- a/src/VisualStudio/CSharp/Impl/UnifiedSettings/csharpSettings.registration.json +++ b/src/VisualStudio/CSharp/Impl/UnifiedSettings/csharpSettings.registration.json @@ -6,7 +6,7 @@ "properties": { // CompletionOptionsStorage.TriggerOnTypingLetters "textEditor.csharp.intellisense.triggerCompletionOnTypingLetters": { - "title": "@Show_completion_list_after_a_character_is_typed;..\\Microsoft.VisualStudio.LanguageServices.CSharp.dll", + "title": "@Show_completion_list_after_a_character_is_typed;..\\Microsoft.VisualStudio.LanguageServices.dll", "type": "boolean", "default": true, "order": 0, @@ -21,7 +21,7 @@ }, // CompletionOptionsStorage.TriggerOnDeletion "textEditor.csharp.intellisense.triggerCompletionOnDeletion": { - "title": "@Show_completion_list_after_a_character_is_deleted;..\\Microsoft.VisualStudio.LanguageServices.CSharp.dll", + "title": "@Show_completion_list_after_a_character_is_deleted;..\\Microsoft.VisualStudio.LanguageServices.dll", "type": "boolean", "default": false, "order": 1, @@ -52,7 +52,7 @@ }, // CompletionViewOptionsStorage.HighlightMatchingPortionsOfCompletionListItems "textEditor.csharp.intellisense.highlightMatchingPortionsOfCompletionListItems": { - "title": "@Highlight_matching_portions_of_completion_list_items;..\\Microsoft.VisualStudio.LanguageServices.CSharp.dll", + "title": "@Highlight_matching_portions_of_completion_list_items;..\\Microsoft.VisualStudio.LanguageServices.dll", "type": "boolean", "default": true, "order": 20, @@ -67,7 +67,7 @@ }, // CompletionViewOptionsStorage.ShowCompletionItemFilters "textEditor.csharp.intellisense.showCompletionItemFilters": { - "title": "@Show_completion_item_filters;..\\Microsoft.VisualStudio.LanguageServices.CSharp.dll", + "title": "@Show_completion_item_filters;..\\Microsoft.VisualStudio.LanguageServices.dll", "type": "boolean", "default": true, "order": 30, @@ -97,10 +97,10 @@ }, // CompletionOptionsStorage.SnippetsBehavior "textEditor.csharp.intellisense.snippetsBehavior": { - "title": "@Snippets_behavior;..\\Microsoft.VisualStudio.LanguageServices.CSharp.dll", + "title": "@Snippets_behavior;..\\Microsoft.VisualStudio.LanguageServices.dll", "type": "string", "enum": [ "neverInclude", "alwaysInclude", "includeAfterTypingIdentifierQuestionTab" ], - "enumItemLabels": [ "@Never_include_snippets;{13c3bbb4-f18f-4111-9f54-a0fb010d9194}", "@Always_include_snippets;{13c3bbb4-f18f-4111-9f54-a0fb010d9194}", "@Include_snippets_when_Tab_is_typed_after_an_identifier;{13c3bbb4-f18f-4111-9f54-a0fb010d9194}" ], + "enumItemLabels": [ "@Never_include_snippets;..\\Microsoft.VisualStudio.LanguageServices.dll", "@Always_include_snippets;..\\Microsoft.VisualStudio.LanguageServices.CSharp.dll", "@Include_snippets_when_Tab_is_typed_after_an_identifier;..\\Microsoft.VisualStudio.LanguageServices.CSharp.dll" ], "default": "alwaysInclude", "order": 50, "migration": { @@ -136,10 +136,10 @@ }, // CompletionOptionsStorage.EnterKeyBehavior "textEditor.csharp.intellisense.returnKeyCompletionBehavior": { - "title": "@Enter_key_behavior_colon;..\\Microsoft.VisualStudio.LanguageServices.CSharp.dll", + "title": "@Enter_key_behavior;..\\Microsoft.VisualStudio.LanguageServices.dll", "type": "string", "enum": [ "never", "afterFullyTypedWord", "always" ], - "enumItemLabels": [ "@Never_add_new_line_on_enter;{13c3bbb4-f18f-4111-9f54-a0fb010d9194}", "@Only_add_new_line_on_enter_after_end_of_fully_typed_word;{13c3bbb4-f18f-4111-9f54-a0fb010d9194}", "@Always_add_new_line_on_enter;{13c3bbb4-f18f-4111-9f54-a0fb010d9194}" ], + "enumItemLabels": [ "@Never_add_new_line_on_enter;{13c3bbb4-f18f-4111-9f54-a0fb010d9194}", "@Only_add_new_line_on_enter_after_end_of_fully_typed_word;..\\Microsoft.VisualStudio.LanguageServices.dll", "@Always_add_new_line_on_enter;{13c3bbb4-f18f-4111-9f54-a0fb010d9194}" ], "default": "never", "order": 60, "migration": { @@ -190,7 +190,7 @@ }, // CompletionOptionsStorage.ShowItemsFromUnimportedNamespaces "textEditor.csharp.intellisense.showCompletionItemsFromUnimportedNamespaces": { - "title": "@Show_items_from_unimported_namespaces;..\\Microsoft.VisualStudio.LanguageServices.CSharp.dll", + "title": "@Show_items_from_unimported_namespaces;..\\Microsoft.VisualStudio.LanguageServices.dll", "type": "boolean", "default": true, "order": 80, @@ -209,6 +209,11 @@ "type": "boolean", "default": false, "order": 90, + "messages": [ + { + "text": "@Experimental_feature;..\\Microsoft.VisualStudio.LanguageServices.dll" + } + ], "migration": { "pass": { "input": { @@ -220,9 +225,14 @@ }, // CompletionOptionsStorage.ShowNewSnippetExperienceUserOption "textEditor.csharp.intellisense.showNewSnippetExperience": { - "title": "@Show_new_snippet_experience_experimental;..\\Microsoft.VisualStudio.LanguageServices.CSharp.dll", + "title": "@Show_new_snippet_experience;..\\Microsoft.VisualStudio.LanguageServices.CSharp.dll", "type": "boolean", "default": false, + "messages": [ + { + "text": "@Experimental_feature;..\\Microsoft.VisualStudio.LanguageServices.dll" + } + ], "alternateDefault": { // CompletionOptionsStorage.ShowNewSnippetExperienceFeatureFlag "flagName": "Roslyn.SnippetCompletion", @@ -241,7 +251,7 @@ }, "categories": { "textEditor.csharp":{ - "title": "C#" + "title": "@101;{13c3bbb4-f18f-4111-9f54-a0fb010d9194}" }, "textEditor.csharp.intellisense": { "title": "@103;{13c3bbb4-f18f-4111-9f54-a0fb010d9194}", diff --git a/src/VisualStudio/CSharp/Impl/VSPackage.resx b/src/VisualStudio/CSharp/Impl/VSPackage.resx index 07f156ef5855f..46dd42a04b2b4 100644 --- a/src/VisualStudio/CSharp/Impl/VSPackage.resx +++ b/src/VisualStudio/CSharp/Impl/VSPackage.resx @@ -375,7 +375,4 @@ Show items from unimported namespaces (experimental); Never include snippets - - Only add new line on enter after end of fully typed word - \ No newline at end of file diff --git a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.cs.xlf b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.cs.xlf index ebdf4bb147878..e1c4cc4776bb8 100644 --- a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.cs.xlf +++ b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.cs.xlf @@ -122,11 +122,6 @@ Uvnitř namespace 'namespace' is a C# keyword and should not be localized - - Outside namespace - Vně namespace - 'namespace' is a C# keyword and should not be localized - Pattern matching preferences: Předvolby porovnávání vzorů: @@ -147,16 +142,6 @@ Upřednostňovat implicitní vytvoření objektu, pokud je typ zřejmý - - Prefer 'is null' for reference equality checks - U kontrol rovnosti odkazů dávat přednost možnosti is null - 'is null' is a C# string and should not be localized. - - - Prefer 'null' check over type check - Upřednostňovat kontrolu hodnoty null před kontrolou typu - - Prefer pattern matching Upřednostňovat porovnávání vzorů @@ -177,11 +162,6 @@ Preferované umístění direktivy using 'using' is a C# keyword and should not be localized - - Remove unnecessary usings - Odebrat nepotřebné direktivy using - - Run Query Spustit dotaz @@ -192,19 +172,19 @@ Spustit (Ctrl+Enter) - - Semantic Search - Sémantické vyhledávání - - Show hints for 'new' expressions Zobrazit nápovědy pro výrazy new - - Show items from unimported namespaces - Zobrazit položky z neimportovaných oborů názvů + + Show name s_uggestions + Show name s_uggestions + + + + Show new snippet experience + Show new snippet experience @@ -212,11 +192,6 @@ Zobrazit nové prostředí fragmentů kódu (experimentální) - - Show remarks in Quick Info - Zobrazit poznámky v Rychlých informacích - - Suggest usings for types in .NET Framework assemblies Navrhnout použití typů v sestaveních .NET Framework @@ -227,11 +202,6 @@ Obklopit s - - Insert Snippet - Vložit fragment - - Automatically format _block on } Automaticky formátovat _blok při znaku } @@ -522,96 +492,31 @@ Možnosti nových řádků pro klíčová slova - - Unused local - Nepoužitá místní - - - - _Show procedure line separators - Zob_razit oddělovače řádků procedur - - - - Editor Help - Nápověda k editoru - - - - Highlight related _keywords under cursor - Zvýrazňovat související _klíčová slova pod kurzorem - - - - _Highlight references to symbol under cursor - Z_výrazňovat odkazy na symbol pod kurzorem - - Enter _outlining mode when files open P_o otevření souborů vejít do režimu osnovy - - Extract Method - Extrahovat metodu - - _Generate XML documentation comments for /// _Generovat komentáře dokumentace XML pro /// - - Highlighting - Zvýraznění - - _Insert * at the start of new lines when writing /* */ comments Při psaní _komentářů /* */ vkládat na začátek nových řádků hvězdičku (*) - - Optimize for solution size - Optimalizovat pro velikost řešení - - - - Large - Velké - - - - Regular - Normální - - - - Small - Malé - - Using Directives Direktivy using - - Performance - Výkon - - _Place 'System' directives first when sorting usings _Při řazení direktiv using umístit nejdřív direktivy System - - _Show completion list after a character is typed - _Zobrazovat seznam dokončení po zadání znaku - - Place _keywords in completion lists Umístit _klíčová slova do seznamů dokončení @@ -627,11 +532,6 @@ Výběr v seznamu dokončení - - Show preview for rename _tracking - Zobrazit náhled pro sledování _rename - - Place open brace on new line for property, indexer, and event accessors Vloží levou složenou závorku na nový řádek pro přistupující objekty vlastností, indexerů a událostí. @@ -732,36 +632,6 @@ Rozdělit literály řetězců u _enter - - _Highlight matching portions of completion list items - _Zvýraznit odpovídající části položek seznamu dokončení - - - - Show completion item _filters - Zobrazit _filtry položek dokončení - - - - Enter key behavior: - Chování klávesy Enter: - - - - _Only add new line on enter after end of fully typed word - _Při stisku Enter přidat nový řádek jenom po dopsání celého slova - - - - _Always add new line on enter - _Při stisku Enter vždy přidat nový řádek - - - - _Never add new line on enter - _Při stisku Enter nikdy nepřidávat nový řádek - - Always include snippets Vždy zahrnovat fragmenty @@ -772,21 +642,6 @@ Zahrnovat fragmenty po zadání ?-Tab za identifikátor - - Never include snippets - Nikdy nezahrnovat fragmenty - - - - Snippets behavior - Chování fragmentů - - - - Show completion list after a character is _deleted - _Zobrazit seznam dokončení po odstranění znaku - - 'null' checking: 'Kontrola hodnoty null: @@ -822,11 +677,6 @@ Automaticky formátovat při psaní - - Never - Nikdy - - When on single line Pokud je na jednom řádku @@ -858,8 +708,8 @@ - Show name s_uggestions - Zobrazovat návr_hy názvů + Show name suggestions + Zobrazovat návr_hy názvů diff --git a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.de.xlf b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.de.xlf index bc402bd61e86c..dd26b273bb22c 100644 --- a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.de.xlf +++ b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.de.xlf @@ -122,11 +122,6 @@ Innerhalb des Namespaces 'namespace' is a C# keyword and should not be localized - - Outside namespace - Außerhalb des Namespaces - 'namespace' is a C# keyword and should not be localized - Pattern matching preferences: Einstellungen für den Musterabgleich: @@ -147,16 +142,6 @@ Implizite Objekterstellung bevorzugen, wenn der Typ offensichtlich ist - - Prefer 'is null' for reference equality checks - "is null" für Verweisübereinstimmungsprüfungen vorziehen - 'is null' is a C# string and should not be localized. - - - Prefer 'null' check over type check - "NULL"-Überprüfung vor Typüberprüfung bevorzugen - - Prefer pattern matching Musterabgleich bevorzugen @@ -177,11 +162,6 @@ Bevorzugte Platzierung der using-Anweisung 'using' is a C# keyword and should not be localized - - Remove unnecessary usings - Nicht benötigte Using-Direktiven entfernen - - Run Query Abfrage ausführen @@ -192,19 +172,19 @@ Ausführen (STRG+EINGABE) - - Semantic Search - Semantische Suche - - Show hints for 'new' expressions Hinweise für new-Ausdrücke anzeigen - - Show items from unimported namespaces - Elemente aus nicht importierten Namespaces anzeigen + + Show name s_uggestions + Show name s_uggestions + + + + Show new snippet experience + Show new snippet experience @@ -212,11 +192,6 @@ Neue Ausschnittsoberfläche anzeigen (experimentell) - - Show remarks in Quick Info - Hinweise in QuickInfo anzeigen - - Suggest usings for types in .NET Framework assemblies Using-Anweisungen für Typen in .NET Framework-Assemblys vorschlagen @@ -227,11 +202,6 @@ Umschließen mit - - Insert Snippet - Schnipsel einfügen - - Automatically format _block on } Beim Eingeben von } _Block automatisch formatieren @@ -522,96 +492,31 @@ Zeilenwechseloptionen für Schlüsselwörter - - Unused local - Nicht verwendete lokale Variable - - - - _Show procedure line separators - _Zeilentrennzeichen in Prozeduren anzeigen - - - - Editor Help - Editor-Hilfe - - - - Highlight related _keywords under cursor - Verwandte _Schlüsselbegriffe unter Cursor anzeigen - - - - _Highlight references to symbol under cursor - _Verweise auf Symbol unter Cursor hervorheben - - Enter _outlining mode when files open _Gliederungsmodus eingeben, wenn Dateien offen sind - - Extract Method - Methode extrahieren - - _Generate XML documentation comments for /// _XML-Dokumentationskommentare für /// eingeben - - Highlighting - Hervorheben - - _Insert * at the start of new lines when writing /* */ comments Be_im Schreiben von Kommentaren (/* */) * am Beginn neuer Zeilen einfügen - - Optimize for solution size - Für Lösungsgröße optimieren - - - - Large - Groß - - - - Regular - Regulär - - - - Small - Klein - - Using Directives Using-Direktiven - - Performance - Leistung - - _Place 'System' directives first when sorting usings System-Anweisungen beim Sortieren von using-Anweisungen an erster Stelle _platzieren - - _Show completion list after a character is typed - _Vervoll­ständigungsliste nach Eingabe eines Zeichens anzeigen - - Place _keywords in completion lists _Schlüsselwörter ebenfalls in Vervollständigungslisten aufnehmen @@ -627,11 +532,6 @@ Auswahl in Vervollständigungsliste - - Show preview for rename _tracking - Vorschau für Nachverfolgung beim _Umbenennen anzeigen - - Place open brace on new line for property, indexer, and event accessors Fügt eine öffnende geschweifte Klammer für eine Eigenschaft, den Indexer und Ereignisaccessor in einer neuen Zeile ein. @@ -732,36 +632,6 @@ _Zeichenfolgenliterale bei Eingabe teilen - - _Highlight matching portions of completion list items - _Übereinstimmende Teile der Vervollständigungslistenelemente anzeigen - - - - Show completion item _filters - Vervollständigungselement_filter anzeigen - - - - Enter key behavior: - Verhalten der EINGABETASTE: - - - - _Only add new line on enter after end of fully typed word - Neue _Zeile beim Drücken der EINGABETASTE nur nach einem vollständig eingegebenen Wort einfügen - - - - _Always add new line on enter - _Immer neue Zeile beim Drücken der EINGABETASTE einfügen - - - - _Never add new line on enter - _Nie neue Zeile beim Drücken der EINGABETASTE einfügen - - Always include snippets Schnipsel immer einschließen @@ -772,21 +642,6 @@ Schnipsel einschließen, wenn ?-TAB nach einem Bezeichner eingegeben wird - - Never include snippets - Schnipsel nie einschließen - - - - Snippets behavior - Schnipselverhalten - - - - Show completion list after a character is _deleted - Vervollstän_digungsliste nach Löschen eines Zeichens anzeigen - - 'null' checking: 'NULL-Überprüfung: @@ -822,11 +677,6 @@ Automatisch während der Eingabe formatieren - - Never - Nie - - When on single line In einzelner Zeile @@ -858,8 +708,8 @@ - Show name s_uggestions - Namensv_orschläge anzeigen + Show name suggestions + Namensv_orschläge anzeigen diff --git a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.es.xlf b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.es.xlf index d5180719b4295..f1a6af39bdd90 100644 --- a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.es.xlf +++ b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.es.xlf @@ -122,11 +122,6 @@ namespace interior 'namespace' is a C# keyword and should not be localized - - Outside namespace - namespace exterior - 'namespace' is a C# keyword and should not be localized - Pattern matching preferences: Preferencias de coincidencia de patrón: @@ -147,16 +142,6 @@ Preferir la creación implícita de objetos cuando el tipo sea aparente - - Prefer 'is null' for reference equality checks - Preferir “is null” para comprobaciones de igualdad de referencias - 'is null' is a C# string and should not be localized. - - - Prefer 'null' check over type check - Preferir comprobación "null' sobre comprobación de tipo - - Prefer pattern matching Preferir coincidencia de patrones @@ -177,11 +162,6 @@ Selección de ubicación de directiva "using" preferida 'using' is a C# keyword and should not be localized - - Remove unnecessary usings - Eliminar instrucciones Using innecesarias - - Run Query Ejecutar consulta @@ -192,19 +172,19 @@ Ejecutar (Ctrl+Entrar) - - Semantic Search - Búsqueda semántica - - Show hints for 'new' expressions Mostrar sugerencias para las expresiones "new" - - Show items from unimported namespaces - Mostrar elementos de espacios de nombres no importados + + Show name s_uggestions + Show name s_uggestions + + + + Show new snippet experience + Show new snippet experience @@ -212,11 +192,6 @@ Mostrar nueva experiencia de fragmento de código (experimental) - - Show remarks in Quick Info - Mostrar comentarios en Información rápida - - Suggest usings for types in .NET Framework assemblies Sugerir usos para tipos en ensamblados .NET Framework @@ -227,11 +202,6 @@ Rodear con - - Insert Snippet - Insertar fragmento de código - - Automatically format _block on } Dar formato automáticamente al _bloque al introducir } @@ -522,96 +492,31 @@ Opciones de nueva línea para palabras clave - - Unused local - Local sin uso - - - - _Show procedure line separators - Mo_strar separadores de líneas de procedimientos - - - - Editor Help - Ayuda de editor - - - - Highlight related _keywords under cursor - Resaltar palabras cla_ve relacionadas bajo el cursor - - - - _Highlight references to symbol under cursor - _Resaltar referencias al símbolo bajo el cursor - - Enter _outlining mode when files open Entrar en m_odo de esquematización al abrir archivos - - Extract Method - Extraer método - - _Generate XML documentation comments for /// _Generar comentarios de documentación XML con /// - - Highlighting - Resaltar - - _Insert * at the start of new lines when writing /* */ comments _Insertar * al comienzo de nuevas líneas al escribir comentarios /* */ - - Optimize for solution size - Optimizar para tamaño de la solución - - - - Large - Grande - - - - Regular - Normal - - - - Small - Pequeño - - Using Directives Directivas Using - - Performance - Rendimiento - - _Place 'System' directives first when sorting usings Al ordenar instrucciones Using, _colocar primero las directivas 'System' - - _Show completion list after a character is typed - _Mostrar lista de finalización después de escribir un carácter - - Place _keywords in completion lists Colocar _palabras clave en listas de finalización @@ -627,11 +532,6 @@ Selección en la lista de finalización - - Show preview for rename _tracking - Mostrar vista previa para _seguimiento de cambio de nombre - - Place open brace on new line for property, indexer, and event accessors Colocar llave de apertura para descriptores de acceso de eventos, indizadores y propiedades en nueva línea @@ -732,36 +632,6 @@ Dividir literales de cadena al presionar _Entrar - - _Highlight matching portions of completion list items - _Resaltar partes coincidentes de elementos de lista de finalización - - - - Show completion item _filters - Mostrar _filtros de elementos de finalización - - - - Enter key behavior: - Comportamiento de la tecla Entrar: - - - - _Only add new line on enter after end of fully typed word - _Agregar solo una nueva línea con Entrar al final de palabras - - - - _Always add new line on enter - _Agregar siempre una nueva línea al presionar Entrar - - - - _Never add new line on enter - _No agregar nunca una nueva línea al presionar Entrar - - Always include snippets Incluir siempre fragmentos de código @@ -772,21 +642,6 @@ Incluir fragmentos de código cuando ?-Tab se escriba después de un identificador - - Never include snippets - No incluir nunca fragmentos de código - - - - Snippets behavior - Comportamiento de los fragmentos de código - - - - Show completion list after a character is _deleted - Mostrar lista de finalización después de _eliminar un carácter - - 'null' checking: 'Comprobación de "null": @@ -822,11 +677,6 @@ Dar formato automáticamente al escribir - - Never - Nunca - - When on single line Cuando esté en una sola línea @@ -858,8 +708,8 @@ - Show name s_uggestions - Mostrar s_ugerencias de nombres + Show name suggestions + Mostrar s_ugerencias de nombres diff --git a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.fr.xlf b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.fr.xlf index 0fbb92fd90ab2..1c01ddbc6d47e 100644 --- a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.fr.xlf +++ b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.fr.xlf @@ -122,11 +122,6 @@ Dans le namespace 'namespace' is a C# keyword and should not be localized - - Outside namespace - Hors du namespace - 'namespace' is a C# keyword and should not be localized - Pattern matching preferences: Préférences relatives aux critères spéciaux : @@ -147,16 +142,6 @@ Préférer la création d'objets implicites quand le type est apparent - - Prefer 'is null' for reference equality checks - Préférer 'is nul' pour les vérifications d'égalité de référence - 'is null' is a C# string and should not be localized. - - - Prefer 'null' check over type check - Préférer la vérification « null » à la vérification de type - - Prefer pattern matching Préférer les critères spéciaux @@ -177,11 +162,6 @@ Emplacement par défaut de la directive 'using' 'using' is a C# keyword and should not be localized - - Remove unnecessary usings - Supprimer les Usings inutiles - - Run Query Exécuter une requête @@ -192,19 +172,19 @@ Exécuter (Ctrl+Entrée) - - Semantic Search - Recherche sémantique - - Show hints for 'new' expressions Afficher les indicateurs pour les expressions 'new' - - Show items from unimported namespaces - Afficher les éléments des espaces de noms qui ne sont pas importés + + Show name s_uggestions + Show name s_uggestions + + + + Show new snippet experience + Show new snippet experience @@ -212,11 +192,6 @@ Afficher une nouvelle expérience d’extrait de code (expérimental) - - Show remarks in Quick Info - Afficher les notes dans Info express - - Suggest usings for types in .NET Framework assemblies Suggérer des using pour les types dans les assemblys .NET Framework @@ -227,11 +202,6 @@ Entourer de - - Insert Snippet - Insérer un extrait - - Automatically format _block on } Mise en forme automatique du _bloc lors de la saisie d'une } @@ -522,96 +492,31 @@ Nouvelles options de ligne pour les mots clés - - Unused local - Local inutilisé - - - - _Show procedure line separators - _Afficher les séparateurs de ligne de procédure - - - - Editor Help - Aide de l'éditeur - - - - Highlight related _keywords under cursor - Surligner les mots clés liés sous le _curseur - - - - _Highlight references to symbol under cursor - _Surligner les références jusqu'au symbole sous le curseur - - Enter _outlining mode when files open Passer en m_ode Plan à l'ouverture des fichiers - - Extract Method - Extraire la méthode - - _Generate XML documentation comments for /// _Générer des commentaires de documentation XML pour /// - - Highlighting - Mise en surbrillance - - _Insert * at the start of new lines when writing /* */ comments _Insérer * au début des nouvelles lignes pour l'écriture de commentaires /* */ - - Optimize for solution size - Optimiser pour la taille de la solution - - - - Large - Grande - - - - Regular - Normal - - - - Small - Petite - - Using Directives Directives Using - - Performance - Performances - - _Place 'System' directives first when sorting usings _Placer les directives 'System' en premier lors du tri des usings - - _Show completion list after a character is typed - _Afficher la liste de saisie semi-automatique après la saisie d'un caractère - - Place _keywords in completion lists Placer les mots _clés dans les listes de saisie semi-automatique @@ -627,11 +532,6 @@ Sélection dans la liste de saisie semi-automatique - - Show preview for rename _tracking - Affiche_r un aperçu pour le suivi des renommages - - Place open brace on new line for property, indexer, and event accessors Placer une accolade ouvrante sur une nouvelle ligne pour les accesseurs de propriété, d'indexeur et d'événement @@ -732,36 +632,6 @@ Fractionner les littéraux de chaîne avec _Entrée - - _Highlight matching portions of completion list items - _Mettre en surbrillance les parties correspondantes des éléments de liste de saisie semi-automatique - - - - Show completion item _filters - Afficher les _filtres d'éléments de saisie semi-automatique - - - - Enter key behavior: - Comportement de la touche Entrée : - - - - _Only add new line on enter after end of fully typed word - Aj_outer uniquement une nouvelle ligne après Entrée à la fin d'un mot complet tapé - - - - _Always add new line on enter - Toujours _ajouter une nouvelle ligne après Entrée - - - - _Never add new line on enter - _Ne jamais ajouter de nouvelle ligne après Entrée - - Always include snippets Toujours inclure les extraits de code @@ -772,21 +642,6 @@ Inclure les extraits de code quand ?-Tab est typé après un identificateur - - Never include snippets - Ne jamais inclure d'extrait de code - - - - Snippets behavior - Comportement des extraits de code - - - - Show completion list after a character is _deleted - Afficher la liste de saisie semi-automatique après la suppression d'un _caractère - - 'null' checking: 'vérification de valeur 'null' : @@ -822,11 +677,6 @@ Mise en forme automatique en cours de frappe - - Never - Jamais - - When on single line Sur une seule ligne @@ -858,8 +708,8 @@ - Show name s_uggestions - Afficher les s_uggestions de nom + Show name suggestions + Afficher les s_uggestions de nom diff --git a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.it.xlf b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.it.xlf index c80f034e857f9..cb563ea25c5b9 100644 --- a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.it.xlf +++ b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.it.xlf @@ -122,11 +122,6 @@ All'interno di namespace 'namespace' is a C# keyword and should not be localized - - Outside namespace - All'esterno di namespace - 'namespace' is a C# keyword and should not be localized - Pattern matching preferences: Preferenze per criteri di ricerca: @@ -147,16 +142,6 @@ Preferisci la creazione implicita di oggetti quando il tipo è apparente - - Prefer 'is null' for reference equality checks - Preferisci 'is null' per i controlli di uguaglianza dei riferimenti - 'is null' is a C# string and should not be localized. - - - Prefer 'null' check over type check - Preferisci il controllo 'null' al controllo del tipo - - Prefer pattern matching Preferisci i criteri di ricerca @@ -177,11 +162,6 @@ Posizione preferita della direttiva 'using' 'using' is a C# keyword and should not be localized - - Remove unnecessary usings - Rimuovi istruzioni using non necessarie - - Run Query Esegui query @@ -192,19 +172,19 @@ Esegui (CTRL+INVIO) - - Semantic Search - Ricerca semantica - - Show hints for 'new' expressions Mostra suggerimenti per le espressioni 'new' - - Show items from unimported namespaces - Mostra elementi da spazi dei nomi non importati + + Show name s_uggestions + Show name s_uggestions + + + + Show new snippet experience + Show new snippet experience @@ -212,11 +192,6 @@ Mostra nuova esperienza del frammento (sperimentale) - - Show remarks in Quick Info - Mostra i commenti in Informazioni rapide - - Suggest usings for types in .NET Framework assemblies Suggerisci le direttive using per i tipi in assembly .NET Framework @@ -227,11 +202,6 @@ Racchiudi tra - - Insert Snippet - Inserisci frammento - - Automatically format _block on } Formatta automaticamente _blocco dopo } @@ -522,96 +492,31 @@ Opzioni relative alla nuova riga per parole chiave - - Unused local - Variabile locale inutilizzata - - - - _Show procedure line separators - _Mostra separatori di riga routine - - - - Editor Help - Guida Editor - - - - Highlight related _keywords under cursor - Evidenzia _parole chiave correlate sotto il cursore - - - - _Highlight references to symbol under cursor - _Evidenzia riferimenti a simbolo sotto il cursore - - Enter _outlining mode when files open _Attiva modalità struttura all'apertura del file - - Extract Method - Estrai metodo - - _Generate XML documentation comments for /// _Genera commenti in formato documentazione XML per /// - - Highlighting - Evidenziazione - - _Insert * at the start of new lines when writing /* */ comments _Inserisci * all'inizio di nuove righe quando si scrivono commenti /* */ - - Optimize for solution size - Ottimizza in base alle dimensioni della soluzione - - - - Large - Grande - - - - Regular - Normale - - - - Small - Piccola - - Using Directives Direttive using - - Performance - Prestazioni - - _Place 'System' directives first when sorting usings _Inserisci prima le direttive 'System' durante l'ordinamento delle direttive using - - _Show completion list after a character is typed - Mo_stra elenco di completamento dopo la digitazione di un carattere - - Place _keywords in completion lists Inserisci parole c_hiave in elenchi di completamento @@ -627,11 +532,6 @@ Selezione in elenco di completamento - - Show preview for rename _tracking - Mostra anteprima per verifica _ridenominazione - - Place open brace on new line for property, indexer, and event accessors Inserisci parentesi graffa di apertura in una nuova riga per funzioni di accesso a proprietà, indicizzatori ed eventi @@ -732,36 +632,6 @@ Dividi valori letterali stringa dopo _INVIO - - _Highlight matching portions of completion list items - _Evidenzia le parti corrispondenti di voci dell'elenco di completamento - - - - Show completion item _filters - Mostra i _filtri per le voci di completamento - - - - Enter key behavior: - Comportamento del tasto INVIO: - - - - _Only add new line on enter after end of fully typed word - Aggi_ungi una nuova riga dopo INVIO alla fine della parola digitata - - - - _Always add new line on enter - _Aggiungi sempre una nuova riga dopo INVIO - - - - _Never add new line on enter - _Non aggiungere mai una nuova riga dopo INVIO - - Always include snippets Includi sempre i frammenti @@ -772,21 +642,6 @@ Includi i frammenti quando si digita ?+TAB dopo un identificatore - - Never include snippets - Non includere mai i frammenti - - - - Snippets behavior - Comportamento dei frammenti - - - - Show completion list after a character is _deleted - Mostra _elenco di completamento dopo l'eliminazione di un carattere - - 'null' checking: 'Controllo 'null': @@ -822,11 +677,6 @@ Formatta automaticamente durante la digitazione - - Never - Mai - - When on single line Se su riga singola @@ -858,8 +708,8 @@ - Show name s_uggestions - Mostra s_uggerimenti per nomi + Show name suggestions + Mostra s_uggerimenti per nomi diff --git a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.ja.xlf b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.ja.xlf index 1acf8e1d935c8..4ddb98d5b905e 100644 --- a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.ja.xlf +++ b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.ja.xlf @@ -122,11 +122,6 @@ namespace 内 'namespace' is a C# keyword and should not be localized - - Outside namespace - namespace 外 - 'namespace' is a C# keyword and should not be localized - Pattern matching preferences: パターン マッチング設定: @@ -147,16 +142,6 @@ 型が明白な場合に暗黙的なオブジェクトの作成を優先する - - Prefer 'is null' for reference equality checks - 参照の等値性のチェックには 'is null' を優先する - 'is null' is a C# string and should not be localized. - - - Prefer 'null' check over type check - 型のチェックよりも 'null 値' チェックを優先する - - Prefer pattern matching パターン マッチングを優先する @@ -177,11 +162,6 @@ 優先する 'using' ディレクティブの配置 'using' is a C# keyword and should not be localized - - Remove unnecessary usings - 不要な using の削除 - - Run Query クエリの実行 @@ -192,19 +172,19 @@ 実行 (Ctrl + Enter) - - Semantic Search - セマンティック検索 - - Show hints for 'new' expressions 'new' 式のヒントを表示する - - Show items from unimported namespaces - インポートされていない名前空間の項目を表示する + + Show name s_uggestions + Show name s_uggestions + + + + Show new snippet experience + Show new snippet experience @@ -212,11 +192,6 @@ 新しいスニペット エクスペリエンスの表示 (試験段階) - - Show remarks in Quick Info - クイック ヒントに注釈を表示する - - Suggest usings for types in .NET Framework assemblies .NET Framework アセンブリの型に using を提案する @@ -227,11 +202,6 @@ ブロックの挿入 - - Insert Snippet - スニペットの挿入 - - Automatically format _block on } } でブロックをオートフォーマットする(_B) @@ -522,96 +492,31 @@ キーワードの改行オプション - - Unused local - 未使用のローカル - - - - _Show procedure line separators - プロシージャ行の区切り記号を表示する(_S) - - - - Editor Help - エディターのヘルプ - - - - Highlight related _keywords under cursor - カーソルの下にあるキーワードの関連キーワードをハイライトする(_K) - - - - _Highlight references to symbol under cursor - カーソルの下にあるシンボルへの参照をハイライトする(_H) - - Enter _outlining mode when files open ファイルを開くときにアウトライン モードに入る(_O) - - Extract Method - メソッドの抽出 - - _Generate XML documentation comments for /// /// が入力されたとき、XML ドキュメント コメントを生成する(_G) - - Highlighting - 強調表示 - - _Insert * at the start of new lines when writing /* */ comments /* */ コメントを記述する際、新しい行の先頭に * を挿入する(_I) - - Optimize for solution size - ソリューションのサイズを最適化します - - - - Large - - - - - Regular - 標準 - - - - Small - - - Using Directives ディレクティブを使用する - - Performance - パフォーマンス - - _Place 'System' directives first when sorting usings using を並べ替える際に、'System' ディレクティブを先頭に配置する(_P) - - _Show completion list after a character is typed - 文字が入力された後に入力候補一覧を表示する(_S) - - Place _keywords in completion lists 入力候補一覧にキーワードを配置する(_K) @@ -627,11 +532,6 @@ 入力候補一覧からの選択 - - Show preview for rename _tracking - 名前変更追跡のプレビューの表示(_T) - - Place open brace on new line for property, indexer, and event accessors プロパティ、インデクサー、イベント アクセサーの新しい行に始めかっこを配置します @@ -732,36 +632,6 @@ Enter で文字列リテラルを分割する(_E) - - _Highlight matching portions of completion list items - 入力候補一覧の項目の一致している部分を強調表示する(_H) - - - - Show completion item _filters - 入力候補の項目フィルターを表示する(_F) - - - - Enter key behavior: - Enter キー入力時動作: - - - - _Only add new line on enter after end of fully typed word - 単語を完全に入力した後 Enter キーで新しい行のみを追加する(_O) - - - - _Always add new line on enter - Enter キーで常に新しい行を追加する(_A) - - - - _Never add new line on enter - Enter キーで新しい行を追加しない(_N) - - Always include snippets 常にスニペットを含める @@ -772,21 +642,6 @@ 識別子の後に ? Tab を入力したときにスニペットを含める - - Never include snippets - スニペットを含めない - - - - Snippets behavior - スニペットの動作 - - - - Show completion list after a character is _deleted - 文字が削除された後に入力候補一覧を表示する(_D) - - 'null' checking: 'null' チェック: @@ -822,11 +677,6 @@ 入力時にオートフォーマットする - - Never - 行わない - - When on single line 1 行の場合 @@ -858,8 +708,8 @@ - Show name s_uggestions - 名前の提案を表示(_U) + Show name suggestions + 名前の提案を表示(_U) diff --git a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.ko.xlf b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.ko.xlf index 362cda6918267..4869b58f2b810 100644 --- a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.ko.xlf +++ b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.ko.xlf @@ -122,11 +122,6 @@ namespace 내부 'namespace' is a C# keyword and should not be localized - - Outside namespace - 외부 namespace - 'namespace' is a C# keyword and should not be localized - Pattern matching preferences: 패턴 일치 기본 설정: @@ -147,16 +142,6 @@ 형식이 명백한 경우 암시적 개체 만들기 선호 - - Prefer 'is null' for reference equality checks - 참조 같음 검사에 대해 'is null' 선호 - 'is null' is a C# string and should not be localized. - - - Prefer 'null' check over type check - 형식 검사보다 'null' 검사 선호 - - Prefer pattern matching 패턴 일치 선호 @@ -177,11 +162,6 @@ 선호하는 'using' 지시문 배치 'using' is a C# keyword and should not be localized - - Remove unnecessary usings - 불필요한 Using 제거 - - Run Query 쿼리 실행 @@ -192,19 +172,19 @@ 보내기(Ctrl+Enter) - - Semantic Search - 의미 체계 검색 - - Show hints for 'new' expressions 'new' 식에 대한 힌트 표시 - - Show items from unimported namespaces - 가져오지 않은 네임스페이스의 항목 표시 + + Show name s_uggestions + Show name s_uggestions + + + + Show new snippet experience + Show new snippet experience @@ -212,11 +192,6 @@ 새 코드 조각 환경 표시(실험적) - - Show remarks in Quick Info - 요약 정보에 설명 표시 - - Suggest usings for types in .NET Framework assemblies .NET Framework 어셈블리의 형식에 using 제안 @@ -227,11 +202,6 @@ 코드 감싸기 - - Insert Snippet - 조각 삽입 - - Automatically format _block on } } 입력 시 블록 서식 자동 지정(_B) @@ -522,96 +492,31 @@ 키워드에 대한 줄 바꿈 옵션 - - Unused local - 사용하지 않는 로컬 - - - - _Show procedure line separators - 프로시저 줄 구분선 표시(_S) - - - - Editor Help - 편집기 도움말 - - - - Highlight related _keywords under cursor - 커서 아래의 관련 키워드 강조(_K) - - - - _Highlight references to symbol under cursor - 커서 아래의 기호에 대한 참조 강조(_H) - - Enter _outlining mode when files open 개요 모드로 파일 열기(_O) - - Extract Method - 메서드 추출 - - _Generate XML documentation comments for /// ///에 대해 XML 문서 주석 생성(_G) - - Highlighting - 강조 표시 - - _Insert * at the start of new lines when writing /* */ comments /* */ 주석을 작성할 때 새 줄의 시작 부분에 * 삽입(_I) - - Optimize for solution size - 솔루션 크기에 맞게 최적화 - - - - Large - 크게 - - - - Regular - 일반 - - - - Small - 작게 - - Using Directives Using 지시문 - - Performance - 성능 - - _Place 'System' directives first when sorting usings using 정렬 시 'System' 지시문 먼저 배치(_P) - - _Show completion list after a character is typed - 문자를 입력하면 완성 목록 표시(_S) - - Place _keywords in completion lists 완성 목록에 키워드 배치(_K) @@ -627,11 +532,6 @@ 완성 목록에서 선택 - - Show preview for rename _tracking - 이름 바꾸기 추적 미리 보기 표시(_T) - - Place open brace on new line for property, indexer, and event accessors 속성, 인덱서 및 이벤트 접근자의 여는 중괄호를 새 줄에 배치합니다. @@ -732,36 +632,6 @@ <Enter> 키를 누르면 문자열 리터럴 분할(_E) - - _Highlight matching portions of completion list items - 완성 목록 항목에서 일치하는 부분 강조 표시(_H) - - - - Show completion item _filters - 완성 항목 필터 표시(_F) - - - - Enter key behavior: - <Enter> 키 기능: - - - - _Only add new line on enter after end of fully typed word - 단어를 모두 입력한 후 <Enter> 키를 누르면 새 줄 추가(_O) - - - - _Always add new line on enter - <Enter> 키를 누르면 항상 새 줄 추가(_A) - - - - _Never add new line on enter - <Enter> 키를 누르면 새 줄 추가 안 함(_N) - - Always include snippets 코드 조각 항상 포함 @@ -772,21 +642,6 @@ 식별자 뒤에 ?-Tab을 입력하면 코드 조각 포함 - - Never include snippets - 코드 조각 포함 안 함 - - - - Snippets behavior - 코드 조각 동작 - - - - Show completion list after a character is _deleted - 문자를 삭제하면 완성 목록 표시(_D) - - 'null' checking: 'null' 확인: @@ -822,11 +677,6 @@ 입력할 때 서식 자동 지정 - - Never - 안 함 - - When on single line 한 줄에 있는 경우 @@ -858,8 +708,8 @@ - Show name s_uggestions - 이름 제안 표시(_U) + Show name suggestions + 이름 제안 표시(_U) diff --git a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.pl.xlf b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.pl.xlf index b54368597b997..3c8a0c83b66b0 100644 --- a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.pl.xlf +++ b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.pl.xlf @@ -122,11 +122,6 @@ W elemencie namespace 'namespace' is a C# keyword and should not be localized - - Outside namespace - Poza elementem namespace - 'namespace' is a C# keyword and should not be localized - Pattern matching preferences: Preferencje dopasowywania wzorca: @@ -147,16 +142,6 @@ Preferuj niejawne tworzenie obiektu, gdy typ jest oczywisty - - Prefer 'is null' for reference equality checks - Preferuj wyrażenie „is null” w przypadku sprawdzeń odwołań pod kątem równości - 'is null' is a C# string and should not be localized. - - - Prefer 'null' check over type check - Ustaw preferencje na sprawdzanie wartości „null” zamiast sprawdzania typu - - Prefer pattern matching Preferuj dopasowywanie do wzorca @@ -177,11 +162,6 @@ Preferowane położenie dyrektywy „using” 'using' is a C# keyword and should not be localized - - Remove unnecessary usings - Usuń niepotrzebne użycia - - Run Query Uruchom zapytanie @@ -192,19 +172,19 @@ Uruchom (Ctrl+Enter) - - Semantic Search - Wyszukiwanie semantyczne - - Show hints for 'new' expressions Pokaż wskazówki dla wyrażeń „new” - - Show items from unimported namespaces - Pokaż elementy z nieimportowanych przestrzeni nazw + + Show name s_uggestions + Show name s_uggestions + + + + Show new snippet experience + Show new snippet experience @@ -212,11 +192,6 @@ Pokaż nowe środowisko fragmentu kodu (eksperymentalne) - - Show remarks in Quick Info - Pokaż uwagi w szybkich podpowiedziach - - Suggest usings for types in .NET Framework assemblies Sugeruj dyrektywy using dla typów w zestawach platformy .NET Framework @@ -227,11 +202,6 @@ Otocz przez - - Insert Snippet - Wstaw fragment kodu - - Automatically format _block on } Automatycznie formatuj _blok w pozycji znaku } @@ -522,96 +492,31 @@ Opcje nowego wiersza dla słów kluczowych - - Unused local - Nieużywane zmienne lokalne - - - - _Show procedure line separators - _Pokaż separatory wierszy procedury - - - - Editor Help - Pomoc edytora - - - - Highlight related _keywords under cursor - Wyróżnij powiązane _słowa kluczowe pod kursorem - - - - _Highlight references to symbol under cursor - _Wyróżnij odwołania do symbolu pod kursorem - - Enter _outlining mode when files open Przejdź _do trybu konspektu przy otwieraniu plików - - Extract Method - Wyodrębnianie metody - - _Generate XML documentation comments for /// _Generuj komentarze dokumentacji XML dla /// - - Highlighting - Wyróżnianie - - _Insert * at the start of new lines when writing /* */ comments _Wstawiaj znak * na początku nowych wierszy podczas pisania komentarzy (/* */) - - Optimize for solution size - Optymalizuj pod kątem rozmiaru rozwiązania - - - - Large - Duży - - - - Regular - Standardowy - - - - Small - Mały - - Using Directives Dyrektywy using - - Performance - Wydajność - - _Place 'System' directives first when sorting usings _Umieść dyrektywy „System” jako pierwsze podczas sortowania użyć - - _Show completion list after a character is typed - _Pokaż listę uzupełniania po wpisaniu znaku - - Place _keywords in completion lists Umieść słowa _kluczowe na listach uzupełniania @@ -627,11 +532,6 @@ Wybór na liście uzupełniania - - Show preview for rename _tracking - Pokaż podgląd śledzenia _zmian nazw - - Place open brace on new line for property, indexer, and event accessors Umieść otwierający nawias klamrowy w nowym wierszu dla metod dostępu właściwości, indeksatora i zdarzenia @@ -732,36 +632,6 @@ Dziel literały ciągów po _wpisaniu - - _Highlight matching portions of completion list items - _Wyróżnij pasujące fragmenty elementów listy uzupełniania - - - - Show completion item _filters - Pokaż _filtry elementów uzupełniania - - - - Enter key behavior: - Zachowanie klawisza Enter: - - - - _Only add new line on enter after end of fully typed word - _Dodaj nowy wiersz po naciśnięciu klawisza Enter tylko po zakończeniu pełnego wpisanego wyrazu - - - - _Always add new line on enter - _Zawsze dodawaj nowy wiersz po naciśnięciu klawisza Enter - - - - _Never add new line on enter - _Nigdy nie dodawaj nowego wiersza po naciśnięciu klawisza Enter - - Always include snippets Zawsze dołączaj fragmenty kodu @@ -772,21 +642,6 @@ Dołącz fragmenty kodu po wpisaniu znaku ? po identyfikatorze i naciśnięciu klawisza Tab - - Never include snippets - Nigdy nie dołączaj fragmentów kodu - - - - Snippets behavior - Zachowanie fragmentów kodu - - - - Show completion list after a character is _deleted - Pokaż listę _uzupełniania po usunięciu znaku - - 'null' checking: 'sprawdzanie wartości „null”: @@ -822,11 +677,6 @@ Formatuj automatycznie podczas pisania - - Never - Nigdy - - When on single line W pojedynczym wierszu @@ -858,8 +708,8 @@ - Show name s_uggestions - Pokaż s_ugestie dotyczące nazwy + Show name suggestions + Pokaż s_ugestie dotyczące nazwy diff --git a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.pt-BR.xlf b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.pt-BR.xlf index c9bcd48783f8a..87455a313f37c 100644 --- a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.pt-BR.xlf +++ b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.pt-BR.xlf @@ -122,11 +122,6 @@ Namespace interno 'namespace' is a C# keyword and should not be localized - - Outside namespace - Namespace externo - 'namespace' is a C# keyword and should not be localized - Pattern matching preferences: Preferências de correspondência de padrões: @@ -147,16 +142,6 @@ Preferir a criação de objeto implícito quando o tipo for aparente - - Prefer 'is null' for reference equality checks - Preferir 'is null' para as verificações de igualdade de referência - 'is null' is a C# string and should not be localized. - - - Prefer 'null' check over type check - Preferir a verificação 'nula' à verificação de tipo - - Prefer pattern matching Preferir a correspondência de padrões @@ -177,11 +162,6 @@ Posicionamento da diretiva 'using' preferencial 'using' is a C# keyword and should not be localized - - Remove unnecessary usings - Remover Usos Desnecessários - - Run Query Executar Consulta @@ -192,19 +172,19 @@ Executar (Ctrl+Enter) - - Semantic Search - Pesquisa Semântica - - Show hints for 'new' expressions Mostrar as dicas para as expressões 'new' - - Show items from unimported namespaces - Mostrar os itens de namespaces não importados + + Show name s_uggestions + Show name s_uggestions + + + + Show new snippet experience + Show new snippet experience @@ -212,11 +192,6 @@ Mostrar nova experiência de snippet de código (experimental) - - Show remarks in Quick Info - Mostrar os comentários nas Informações Rápidas - - Suggest usings for types in .NET Framework assemblies Sugerir usings para tipos nos assemblies do .NET Framework @@ -227,11 +202,6 @@ Envolver com - - Insert Snippet - Inserir Snippet - - Automatically format _block on } Formatar automaticamente _bloco em } @@ -522,96 +492,31 @@ Novas opções de linha para palavras-chaves - - Unused local - Local não usado - - - - _Show procedure line separators - _Mostrar separadores de linha de procedimento - - - - Editor Help - Ajuda do Editor - - - - Highlight related _keywords under cursor - Realçar _palavras-chave relacionadas usando o cursor - - - - _Highlight references to symbol under cursor - _Realçar referências a símbolo sob o cursor - - Enter _outlining mode when files open Entrar no modo de _estrutura de tópicos ao abrir arquivos - - Extract Method - Extrair Método - - _Generate XML documentation comments for /// _Gerar comentário da documentação XML /// - - Highlighting - Destaque - - _Insert * at the start of new lines when writing /* */ comments _Insira um * no início das novas linhas ao escrever /* */ comentários - - Optimize for solution size - Otimizar para o tamanho de solução - - - - Large - Grande - - - - Regular - Normal - - - - Small - Pequeno - - Using Directives Usando Diretivas - - Performance - Desempenho - - _Place 'System' directives first when sorting usings _Colocar as diretivas 'System' primeiro ao classificar usos - - _Show completion list after a character is typed - _Mostrar lista de conclusão depois que um caractere é digitado - - Place _keywords in completion lists Colocar _palavras-chave em listas de conclusão @@ -627,11 +532,6 @@ Seleção na Lista de Conclusão - - Show preview for rename _tracking - Mostrar visualização para acompanhamento de _renomeação - - Place open brace on new line for property, indexer, and event accessors Colocar chave de abertura em nova linha para acessadores de eventos, propriedades e indexadores @@ -732,36 +632,6 @@ Dividir sequências literais em _enter - - _Highlight matching portions of completion list items - _Realçar partes correspondentes dos itens da lista de conclusão - - - - Show completion item _filters - Mostrar _filtros de itens de conclusão - - - - Enter key behavior: - Insira o comportamento da tecla: - - - - _Only add new line on enter after end of fully typed word - _Só adicionar nova linha ao inserir depois do final de uma palavra totalmente digitada - - - - _Always add new line on enter - _Sempre adicionar nova linha ao inserir - - - - _Never add new line on enter - _Nunca adicionar nova linha ao inserir - - Always include snippets Sempre incluir snippets @@ -772,21 +642,6 @@ Incluir snippets quando ?-Tab for digitado após um identificador - - Never include snippets - Nunca incluir snippets - - - - Snippets behavior - Comportamento de snippets - - - - Show completion list after a character is _deleted - Mostrar lista de conclusão após um caractere ser _excluído - - 'null' checking: 'verificação 'null': @@ -822,11 +677,6 @@ Formatar automaticamente ao digitar - - Never - Nunca - - When on single line Quando em linha única @@ -858,8 +708,8 @@ - Show name s_uggestions - Mostrar s_ugestões de nomes + Show name suggestions + Mostrar s_ugestões de nomes diff --git a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.ru.xlf b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.ru.xlf index 7cc9fb326b264..8337be2b11d50 100644 --- a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.ru.xlf +++ b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.ru.xlf @@ -122,11 +122,6 @@ Внутри пространства имен 'namespace' is a C# keyword and should not be localized - - Outside namespace - Вне пространства имен - 'namespace' is a C# keyword and should not be localized - Pattern matching preferences: Параметры сопоставления шаблонов: @@ -147,16 +142,6 @@ Предпочитать неявное создание объекта, когда тип очевиден. - - Prefer 'is null' for reference equality checks - Использовать "is null" вместо проверки ссылок на равенство. - 'is null' is a C# string and should not be localized. - - - Prefer 'null' check over type check - Предпочитать проверку "null" проверке типа - - Prefer pattern matching Предпочитать соответствие шаблону @@ -177,11 +162,6 @@ Предпочтительное размещение директивы using 'using' is a C# keyword and should not be localized - - Remove unnecessary usings - Удалить ненужные директивы using - - Run Query Выполнить запрос @@ -192,19 +172,19 @@ Выполнить (CTRL+ВВОД) - - Semantic Search - Семантический поиск - - Show hints for 'new' expressions Отображать подсказки для выражений "new" - - Show items from unimported namespaces - Отображать элементы из неимпортированных пространств имен + + Show name s_uggestions + Show name s_uggestions + + + + Show new snippet experience + Show new snippet experience @@ -212,11 +192,6 @@ Показывать новый интерфейс фрагмента кода (экспериментальная функция) - - Show remarks in Quick Info - Показать заметки в кратких сведениях - - Suggest usings for types in .NET Framework assemblies Предлагать using для типов в сборках .NET Framework @@ -227,11 +202,6 @@ Окружить - - Insert Snippet - Вставить фрагмент - - Automatically format _block on } Автоматически форматировать _блок при вводе "}" @@ -522,96 +492,31 @@ Параметры новых строк для ключевых слов - - Unused local - Не использовать локальный аргумент - - - - _Show procedure line separators - _Показывать разделительные линии процедур - - - - Editor Help - Справка по редактору - - - - Highlight related _keywords under cursor - Выделить связанные _ключевые слова под курсором - - - - _Highlight references to symbol under cursor - _Выделить ссылки на символ под курсором - - Enter _outlining mode when files open Включать режим редактирования структуры при _открытии файлов - - Extract Method - Извлечение метода - - _Generate XML documentation comments for /// _Создавать комментарии XML-документации для /// - - Highlighting - Выделение - - _Insert * at the start of new lines when writing /* */ comments _Вставлять "*" в начале новой строки при написании комментариев /* */ - - Optimize for solution size - Оптимизировать под размер решения - - - - Large - Большой - - - - Regular - обычный - - - - Small - Малый - - Using Directives Директивы Using - - Performance - Производительность - - _Place 'System' directives first when sorting usings _Располагать директивы "System" первыми при сортировке using - - _Show completion list after a character is typed - _Показывать список завершения после ввода знака - - Place _keywords in completion lists Помещать _ключевые слова в списки завершения @@ -627,11 +532,6 @@ Выделение в списке завершения - - Show preview for rename _tracking - Показывать предпросмотр для _отслеживания переименований - - Place open brace on new line for property, indexer, and event accessors Поместите открывающую скобку на новой строке для указания метода доступа к свойству, индексатору или событию @@ -732,36 +632,6 @@ Разделить строковые литералы на _enter - - _Highlight matching portions of completion list items - _Выделять совпадающие части элементов списка завершения - - - - Show completion item _filters - Показывать фильтр_ы элементов завершения - - - - Enter key behavior: - Поведение при нажатии клавиши ВВОД: - - - - _Only add new line on enter after end of fully typed word - До_бавлять новую строку при нажатии клавиши ВВОД только в конце полностью введенного слова - - - - _Always add new line on enter - _Всегда добавлять символ новой строки при нажатии клавиши ВВОД - - - - _Never add new line on enter - _Никогда не добавлять новую строку при нажатии клавиши ВВОД - - Always include snippets Всегда включать фрагменты кода @@ -772,21 +642,6 @@ Включать фрагменты кода, когда после идентификатора указывается "?-Tab" - - Never include snippets - Никогда не включать фрагменты кода - - - - Snippets behavior - Поведение фрагментов кода - - - - Show completion list after a character is _deleted - Показывать список завершения после удалени_я знака - - 'null' checking: 'проверка "null": @@ -822,11 +677,6 @@ Автоматически форматировать при вводе - - Never - Никогда - - When on single line В одной строке @@ -858,8 +708,8 @@ - Show name s_uggestions - Показывать в_арианты имен + Show name suggestions + Показывать в_арианты имен diff --git a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.tr.xlf b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.tr.xlf index fb5bb09635fef..9400db37331ff 100644 --- a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.tr.xlf +++ b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.tr.xlf @@ -122,11 +122,6 @@ namespace içinde 'namespace' is a C# keyword and should not be localized - - Outside namespace - namespace dışında - 'namespace' is a C# keyword and should not be localized - Pattern matching preferences: Desen eşleştirme tercihleri: @@ -147,16 +142,6 @@ Tür görünür olduğunda örtük nesne oluşturmayı tercih et - - Prefer 'is null' for reference equality checks - Başvuru eşitliği denetimleri için 'is null'ı tercih et - 'is null' is a C# string and should not be localized. - - - Prefer 'null' check over type check - Tür denetimi yerine 'null' denetimini tercih edin - - Prefer pattern matching Desen eşleştirmeyi tercih et @@ -177,11 +162,6 @@ Tercih edilen 'using' yönergesi yerleştirmesi 'using' is a C# keyword and should not be localized - - Remove unnecessary usings - Gereksiz Kullanımları Kaldır - - Run Query Sorguyu Çalıştır @@ -192,19 +172,19 @@ Çalıştır (Ctrl+Enter) - - Semantic Search - Anlamsal Arama - - Show hints for 'new' expressions 'new' ifadeleri için ipuçlarını göster - - Show items from unimported namespaces - İçeri aktarılmayan ad alanlarındaki öğeleri göster + + Show name s_uggestions + Show name s_uggestions + + + + Show new snippet experience + Show new snippet experience @@ -212,11 +192,6 @@ Yeni kod parçacığı deneyimini göster (deneysel) - - Show remarks in Quick Info - Hızlı Bilgi notlarını göster - - Suggest usings for types in .NET Framework assemblies .NET Framework bütünleştirilmiş kodlarında türler için using öner @@ -227,11 +202,6 @@ Şununla Çevrele - - Insert Snippet - Kod Parçacığı Ekle - - Automatically format _block on } } girildiğinde _bloğu otomatik biçimlendir @@ -522,96 +492,31 @@ Anahtar sözcükler için yeni satır seçenekleri - - Unused local - Kullanılmayan yerel - - - - _Show procedure line separators - Yordam satır ayıraçlarını _göster - - - - Editor Help - Düzenleyici Yardımı - - - - Highlight related _keywords under cursor - İmlecin altında ilgili ana_htar sözcükleri vurgula - - - - _Highlight references to symbol under cursor - İmlecin altındaki sembole başvuruları _vurgula - - Enter _outlining mode when files open Dosyalar açıldığında a_na hat oluşturma moduna gir - - Extract Method - Metodu Ayıkla - - _Generate XML documentation comments for /// /// için _XML belge açıklamaları üret - - Highlighting - Vurgulama - - _Insert * at the start of new lines when writing /* */ comments _/* */ açıklamaları yazarken her yeni satırın başına _ekle * - - Optimize for solution size - Çözüm boyutunu iyileştir - - - - Large - Büyük - - - - Regular - Normal - - - - Small - Küçük - - Using Directives Using Yönergeleri - - Performance - Performans - - _Place 'System' directives first when sorting usings using deyimlerini sıralarken 'System' yönergelerini ilk sıraya _yerleştir - - _Show completion list after a character is typed - Bir karakter yazıldıktan sonra tamamlanma listesini _göster - - Place _keywords in completion lists A_nahtar sözcükleri tamamlama listelerine yerleştir @@ -627,11 +532,6 @@ Tamamlama Listesinden Seçim - - Show preview for rename _tracking - Yeniden adlandırma i_zlemesi için önizleme göster - - Place open brace on new line for property, indexer, and event accessors Özellik, dizin oluşturucusu ve olay erişimcileri için yeni satıra açık ayraç yerleştir @@ -732,36 +632,6 @@ _Enter tuşuna basıldığında dize değişmez değerlerini böl - - _Highlight matching portions of completion list items - Tamamlanma listesi öğelerinin eşleşen bölümlerini _vurgula - - - - Show completion item _filters - Tamamlanma öğesi _filtrelerini göster - - - - Enter key behavior: - Enter tuşu davranışı: - - - - _Only add new line on enter after end of fully typed word - _Enter tuşuna basıldığında yalnızca tam bir kelime yazılmışsa sonuna yeni satır ekle - - - - _Always add new line on enter - _Enter tuşuna basıldığında her zaman yeni satır ekle - - - - _Never add new line on enter - Enter tuşuna basıldığında _hiçbir zaman yeni satır ekleme - - Always include snippets Kod parçacıklarını her zaman dahil et @@ -772,21 +642,6 @@ Bir tanımlayıcıdan sonra ?-Tab yazılırsa kod parçacıklarını dahil et - - Never include snippets - Kod parçacıklarını hiçbir zaman dahil etme - - - - Snippets behavior - Kod parçacığı davranışı - - - - Show completion list after a character is _deleted - Bir karakter _silindikten sonra tamamlanma listesini göster - - 'null' checking: 'null' denetleniyor: @@ -822,11 +677,6 @@ Yazarken otomatik biçimlendir - - Never - Hiçbir zaman - - When on single line Tek satırdayken @@ -858,8 +708,8 @@ - Show name s_uggestions - Ad ö_nerilerini göster + Show name suggestions + Ad ö_nerilerini göster diff --git a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.zh-Hans.xlf b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.zh-Hans.xlf index e077411ba53ae..6e6d46a78e19c 100644 --- a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.zh-Hans.xlf +++ b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.zh-Hans.xlf @@ -122,11 +122,6 @@ 在命名空间中 'namespace' is a C# keyword and should not be localized - - Outside namespace - 命名空间外 - 'namespace' is a C# keyword and should not be localized - Pattern matching preferences: 模式匹配首选项: @@ -147,16 +142,6 @@ 类型明显时首选隐式对象创建 - - Prefer 'is null' for reference equality checks - 引用相等检查偏好 “is null” - 'is null' is a C# string and should not be localized. - - - Prefer 'null' check over type check - 与类型检查相比,首选 Null 检查 - - Prefer pattern matching 首选模式匹配 @@ -177,11 +162,6 @@ 首选 "using" 指令放置 'using' is a C# keyword and should not be localized - - Remove unnecessary usings - 删除不必要的 Using - - Run Query 运行查询 @@ -192,19 +172,19 @@ 运行 (Ctrl+Enter) - - Semantic Search - 语义搜索 - - Show hints for 'new' expressions 显示 "new" 表达式的提示 - - Show items from unimported namespaces - 显示 unimported 命名空间中的项 + + Show name s_uggestions + Show name s_uggestions + + + + Show new snippet experience + Show new snippet experience @@ -212,11 +192,6 @@ 显示新的代码片段体验(试验) - - Show remarks in Quick Info - 在快速信息中显示备注 - - Suggest usings for types in .NET Framework assemblies 建议对 .NET Framework 程序集中的类型使用 using @@ -227,11 +202,6 @@ 外侧代码 - - Insert Snippet - 插入片段 - - Automatically format _block on } 在 } 后自动格式化程序块(_B) @@ -522,96 +492,31 @@ 关键字的新行选项 - - Unused local - 未使用的本地 - - - - _Show procedure line separators - 显示过程行分隔符(_S) - - - - Editor Help - 编辑器帮助 - - - - Highlight related _keywords under cursor - 突出显示光标下相关的关键字(_K) - - - - _Highlight references to symbol under cursor - 突出显示对光标下符号的引用(_H) - - Enter _outlining mode when files open 打开文件时进入大纲模式(_O) - - Extract Method - 提取方法 - - _Generate XML documentation comments for /// 为 /// 生成 XML 文档注释(_G) - - Highlighting - 突出显示 - - _Insert * at the start of new lines when writing /* */ comments 编写 /* */ 注释时,请在新行的开头插入 *(_I) - - Optimize for solution size - 优化解决方案大小 - - - - Large - - - - - Regular - 常规 - - - - Small - - - Using Directives Using 指令 - - Performance - 性能 - - _Place 'System' directives first when sorting usings 对 using 排序时将“System”指令排在第一位(_P) - - _Show completion list after a character is typed - 键入字符后显示完成列表(_S) - - Place _keywords in completion lists 将关键字放入完成列表(_K) @@ -627,11 +532,6 @@ 完成列表中的选定内容 - - Show preview for rename _tracking - 显示重命名跟踪的预览(_T) - - Place open brace on new line for property, indexer, and event accessors 将左大括号放置在新行中,以表示属性、索引器和事件访问器 @@ -732,36 +632,6 @@ 输入时拆分字符串文本(_E) - - _Highlight matching portions of completion list items - 突出显示完成列表项的匹配部分(_H) - - - - Show completion item _filters - 显示完成项筛选器(_F) - - - - Enter key behavior: - 输入关键行为: - - - - _Only add new line on enter after end of fully typed word - _只有在完整键入的单词结尾后按下回车键时才添加新行 - - - - _Always add new line on enter - 始终在按下 Enter 时添加新行(_A) - - - - _Never add new line on enter - 按下 Enter 时不添加新行(_N) - - Always include snippets 始终包含片段 @@ -772,21 +642,6 @@ 在标识符后键入 ?-Tab 时包含片段 - - Never include snippets - 从不包含片段 - - - - Snippets behavior - 片段行为 - - - - Show completion list after a character is _deleted - 删除字符后显示完成列表(_D) - - 'null' checking: '"null" 检查: @@ -822,11 +677,6 @@ 键入时自动格式化 - - Never - 从不 - - When on single line 处于单行上时 @@ -858,8 +708,8 @@ - Show name s_uggestions - 显示名称建议(_U) + Show name suggestions + 显示名称建议(_U) diff --git a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.zh-Hant.xlf b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.zh-Hant.xlf index a7710f1d3442c..97b2e8f4ade82 100644 --- a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.zh-Hant.xlf +++ b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.zh-Hant.xlf @@ -122,11 +122,6 @@ 位於 namespace 內 'namespace' is a C# keyword and should not be localized - - Outside namespace - 位於 namespace 外 - 'namespace' is a C# keyword and should not be localized - Pattern matching preferences: 模式比對喜好設定: @@ -147,16 +142,6 @@ 當類型為實際型態時,建議建立隱含物件 - - Prefer 'is null' for reference equality checks - 參考相等檢查最好使用 'is null' - 'is null' is a C# string and should not be localized. - - - Prefer 'null' check over type check - 建議使用 'null' 檢查而非鍵入檢查 - - Prefer pattern matching 建議使用模式比對 @@ -177,11 +162,6 @@ 優先使用的 'using' 指示詞位置 'using' is a C# keyword and should not be localized - - Remove unnecessary usings - 移除不必要的 Using - - Run Query 執行查詢 @@ -192,19 +172,19 @@ 執行 (Ctrl+Enter) - - Semantic Search - 語意搜尋 - - Show hints for 'new' expressions 顯示 'new' 運算式的提示 - - Show items from unimported namespaces - 顯示來自未匯入命名空間的項目 + + Show name s_uggestions + Show name s_uggestions + + + + Show new snippet experience + Show new snippet experience @@ -212,11 +192,6 @@ 顯示新的程式碼片段體驗 (實驗性) - - Show remarks in Quick Info - 在快速諮詢中顯示備註 - - Suggest usings for types in .NET Framework assemblies 為 .NET Framework 組件中的類型建議 using @@ -227,11 +202,6 @@ 範圍陳述式 - - Insert Snippet - 插入程式碼片段 - - Automatically format _block on } 於 } 處將區塊自動格式化(_B) @@ -522,96 +492,31 @@ 關鍵字的新行選項 - - Unused local - 未使用的區域函式 - - - - _Show procedure line separators - 顯示程序行分隔符號(_S) - - - - Editor Help - 編輯器說明 - - - - Highlight related _keywords under cursor - 反白資料指標下的相關關鍵字(_K) - - - - _Highlight references to symbol under cursor - 反白顯示資料指標下符號的參考項目(_H) - - Enter _outlining mode when files open 當檔案開啟時進入大綱模式(_O) - - Extract Method - 擷取方法 - - _Generate XML documentation comments for /// 產生 /// 的 XML 文件註解(_G) - - Highlighting - 反白 - - _Insert * at the start of new lines when writing /* */ comments 在寫入 /* */ 時,於新行開頭插入 *(_I) - - Optimize for solution size - 最佳化方案大小 - - - - Large - - - - - Regular - 一般 - - - - Small - - - Using Directives Using 指示詞 - - Performance - 效能 - - _Place 'System' directives first when sorting usings 排序 Using 時先放置 'System' 指示詞(_P) - - _Show completion list after a character is typed - 輸入一個字元後顯示完成清單(_S) - - Place _keywords in completion lists 將關鍵字置於完成清單中(_K) @@ -627,11 +532,6 @@ 完成清單中的選取範圍 - - Show preview for rename _tracking - 顯示預覽以追蹤重新命名(_T) - - Place open brace on new line for property, indexer, and event accessors 將屬性、索引子及事件存取子的左邊大括號放在新行 @@ -732,36 +632,6 @@ 在 Enter 字元處分隔字串文字(_E) - - _Highlight matching portions of completion list items - 反白完成清單項目的相符部分(_H) - - - - Show completion item _filters - 顯示完成項目篩選(_F) - - - - Enter key behavior: - Enter 鍵行為: - - - - _Only add new line on enter after end of fully typed word - 僅在完整輸入的字結尾處按 Enter 鍵時加入新行(_O) - - - - _Always add new line on enter - 一律在按下 Enter 鍵時加入新行(_A) - - - - _Never add new line on enter - 永不在按下 Enter 鍵時加入新行(_N) - - Always include snippets 一律包含程式碼片段 @@ -772,21 +642,6 @@ 在識別碼後輸入 ?-Tab 時包含程式碼片段 - - Never include snippets - 一律不包含程式碼片段 - - - - Snippets behavior - 程式碼片段行為 - - - - Show completion list after a character is _deleted - 刪除一個字元後顯示完成清單(_D) - - 'null' checking: 'null' 檢查: @@ -822,11 +677,6 @@ 於輸入時自動格式化 - - Never - 永不 - - When on single line 在單行上時 @@ -858,8 +708,8 @@ - Show name s_uggestions - 顯示名稱建議(_U) + Show name suggestions + 顯示名稱建議(_U) diff --git a/src/VisualStudio/CSharp/Impl/xlf/VSPackage.cs.xlf b/src/VisualStudio/CSharp/Impl/xlf/VSPackage.cs.xlf index 2b76105cd8097..491d2bb0761c9 100644 --- a/src/VisualStudio/CSharp/Impl/xlf/VSPackage.cs.xlf +++ b/src/VisualStudio/CSharp/Impl/xlf/VSPackage.cs.xlf @@ -440,11 +440,6 @@ Zobrazit položky z neimportovaných oborů názvů (experimentální); Nikdy nezahrnovat fragmenty - - Only add new line on enter after end of fully typed word - Při stisku Enter přidat nový řádek jenom po dopsání celého slova - - \ No newline at end of file diff --git a/src/VisualStudio/CSharp/Impl/xlf/VSPackage.de.xlf b/src/VisualStudio/CSharp/Impl/xlf/VSPackage.de.xlf index efc5cd572f7fe..855c18c57f7f1 100644 --- a/src/VisualStudio/CSharp/Impl/xlf/VSPackage.de.xlf +++ b/src/VisualStudio/CSharp/Impl/xlf/VSPackage.de.xlf @@ -440,11 +440,6 @@ Elemente aus nicht importierten Namespaces anzeigen (experimentell); Schnipsel nie einschließen - - Only add new line on enter after end of fully typed word - Nach Drücken der EINGABETASTE nur nach dem Ende eines vollständigen Worts neue Zeile hinzufügen - - \ No newline at end of file diff --git a/src/VisualStudio/CSharp/Impl/xlf/VSPackage.es.xlf b/src/VisualStudio/CSharp/Impl/xlf/VSPackage.es.xlf index 6d46f239f5085..7d52d75a83ee6 100644 --- a/src/VisualStudio/CSharp/Impl/xlf/VSPackage.es.xlf +++ b/src/VisualStudio/CSharp/Impl/xlf/VSPackage.es.xlf @@ -440,11 +440,6 @@ Mostrar elementos de espacios de nombres no importados (experimental); No incluir nunca fragmentos de código - - Only add new line on enter after end of fully typed word - Solo agregar una nueva línea al pulsar Intro cuando se haya terminado de escribir completamente una palabra - - \ No newline at end of file diff --git a/src/VisualStudio/CSharp/Impl/xlf/VSPackage.fr.xlf b/src/VisualStudio/CSharp/Impl/xlf/VSPackage.fr.xlf index a4e6bb816ef44..3cc99bbae9a97 100644 --- a/src/VisualStudio/CSharp/Impl/xlf/VSPackage.fr.xlf +++ b/src/VisualStudio/CSharp/Impl/xlf/VSPackage.fr.xlf @@ -440,11 +440,6 @@ Afficher les éléments des espaces de noms qui ne sont pas importés (expérime Ne jamais inclure d'extrait de code - - Only add new line on enter after end of fully typed word - Ajouter une nouvelle ligne en appuyant sur Entrée seulement après la fin d'un mot entièrement tapé - - \ No newline at end of file diff --git a/src/VisualStudio/CSharp/Impl/xlf/VSPackage.it.xlf b/src/VisualStudio/CSharp/Impl/xlf/VSPackage.it.xlf index a2043ee6d5bea..9d2070b4e618d 100644 --- a/src/VisualStudio/CSharp/Impl/xlf/VSPackage.it.xlf +++ b/src/VisualStudio/CSharp/Impl/xlf/VSPackage.it.xlf @@ -440,11 +440,6 @@ Mostra elementi da spazi dei nomi non importati (sperimentale); Non includere mai i frammenti - - Only add new line on enter after end of fully typed word - Aggiungi una nuova riga dopo INVIO solo alla fine della parola digitata - - \ No newline at end of file diff --git a/src/VisualStudio/CSharp/Impl/xlf/VSPackage.ja.xlf b/src/VisualStudio/CSharp/Impl/xlf/VSPackage.ja.xlf index 5fd4f43e9b47d..5e7e20dfe29ac 100644 --- a/src/VisualStudio/CSharp/Impl/xlf/VSPackage.ja.xlf +++ b/src/VisualStudio/CSharp/Impl/xlf/VSPackage.ja.xlf @@ -440,11 +440,6 @@ Enter キーで常に新しい行を追加する; スニペットを含めない - - Only add new line on enter after end of fully typed word - 単語を完全に入力した後 Enter キーで新しい行のみを追加する - - \ No newline at end of file diff --git a/src/VisualStudio/CSharp/Impl/xlf/VSPackage.ko.xlf b/src/VisualStudio/CSharp/Impl/xlf/VSPackage.ko.xlf index de61a5007642b..06538bb7e1f56 100644 --- a/src/VisualStudio/CSharp/Impl/xlf/VSPackage.ko.xlf +++ b/src/VisualStudio/CSharp/Impl/xlf/VSPackage.ko.xlf @@ -440,11 +440,6 @@ Show items from unimported namespaces (experimental); 코드 조각 포함 안 함 - - Only add new line on enter after end of fully typed word - 단어를 모두 입력하고 <Enter> 키를 누르면 새 줄 추가 - - \ No newline at end of file diff --git a/src/VisualStudio/CSharp/Impl/xlf/VSPackage.pl.xlf b/src/VisualStudio/CSharp/Impl/xlf/VSPackage.pl.xlf index 101df8c706b3c..d2e5a36d2d2b2 100644 --- a/src/VisualStudio/CSharp/Impl/xlf/VSPackage.pl.xlf +++ b/src/VisualStudio/CSharp/Impl/xlf/VSPackage.pl.xlf @@ -439,11 +439,6 @@ Pokaż elementy z niezaimportowanych przestrzeni nazw (funkcja eksperymentalna); Nigdy nie dołączaj fragmentów kodu - - Only add new line on enter after end of fully typed word - Dodaj nowy wiersz tylko po naciśnięciu klawisza Enter na końcu w pełni wpisanego wyrazu - - \ No newline at end of file diff --git a/src/VisualStudio/CSharp/Impl/xlf/VSPackage.pt-BR.xlf b/src/VisualStudio/CSharp/Impl/xlf/VSPackage.pt-BR.xlf index 9019773350a57..58058a14990e0 100644 --- a/src/VisualStudio/CSharp/Impl/xlf/VSPackage.pt-BR.xlf +++ b/src/VisualStudio/CSharp/Impl/xlf/VSPackage.pt-BR.xlf @@ -440,11 +440,6 @@ Mostrar itens de namespaces não importados (experimental); Nunca incluir snippets - - Only add new line on enter after end of fully typed word - Somente adiciona uma nova linha após digitar toda palavra - - \ No newline at end of file diff --git a/src/VisualStudio/CSharp/Impl/xlf/VSPackage.ru.xlf b/src/VisualStudio/CSharp/Impl/xlf/VSPackage.ru.xlf index d6320c3046efb..5e3a96779aef3 100644 --- a/src/VisualStudio/CSharp/Impl/xlf/VSPackage.ru.xlf +++ b/src/VisualStudio/CSharp/Impl/xlf/VSPackage.ru.xlf @@ -440,11 +440,6 @@ Show items from unimported namespaces (experimental); Никогда не включать фрагменты кода - - Only add new line on enter after end of fully typed word - Добавлять только новую строку при нажатии клавиши ВВОД после полностью введенного слова - - \ No newline at end of file diff --git a/src/VisualStudio/CSharp/Impl/xlf/VSPackage.tr.xlf b/src/VisualStudio/CSharp/Impl/xlf/VSPackage.tr.xlf index 15c065e8b8367..5605ea2851e78 100644 --- a/src/VisualStudio/CSharp/Impl/xlf/VSPackage.tr.xlf +++ b/src/VisualStudio/CSharp/Impl/xlf/VSPackage.tr.xlf @@ -440,11 +440,6 @@ Ad önerilerini göster; Kod parçacıklarını hiçbir zaman dahil etme - - Only add new line on enter after end of fully typed word - Yalnızca tam olarak yazılmış bir kelimeden sonra Enter'a basıldığında yeni satır ekle - - \ No newline at end of file diff --git a/src/VisualStudio/CSharp/Impl/xlf/VSPackage.zh-Hans.xlf b/src/VisualStudio/CSharp/Impl/xlf/VSPackage.zh-Hans.xlf index fd60bb9762c89..699faaf023881 100644 --- a/src/VisualStudio/CSharp/Impl/xlf/VSPackage.zh-Hans.xlf +++ b/src/VisualStudio/CSharp/Impl/xlf/VSPackage.zh-Hans.xlf @@ -440,11 +440,6 @@ Show items from unimported namespaces (experimental); 从不包含片段 - - Only add new line on enter after end of fully typed word - 只在键入完整的单词后点击回车后才添加新行 - - \ No newline at end of file diff --git a/src/VisualStudio/CSharp/Impl/xlf/VSPackage.zh-Hant.xlf b/src/VisualStudio/CSharp/Impl/xlf/VSPackage.zh-Hant.xlf index 38cdaa0163750..7bf151fe1c9dc 100644 --- a/src/VisualStudio/CSharp/Impl/xlf/VSPackage.zh-Hant.xlf +++ b/src/VisualStudio/CSharp/Impl/xlf/VSPackage.zh-Hant.xlf @@ -440,11 +440,6 @@ Enter 鍵行為; 一律不包含程式碼片段 - - Only add new line on enter after end of fully typed word - 只在完整鍵入字的結尾處按 ENTER 來新增新行 - - \ No newline at end of file diff --git a/src/VisualStudio/CSharp/Test/EditorConfigSettings/DataProvider/DataProviderTests.MockAnalyzerReference.cs b/src/VisualStudio/CSharp/Test/EditorConfigSettings/DataProvider/DataProviderTests.MockAnalyzerReference.cs index e022e47342116..59385a790e148 100644 --- a/src/VisualStudio/CSharp/Test/EditorConfigSettings/DataProvider/DataProviderTests.MockAnalyzerReference.cs +++ b/src/VisualStudio/CSharp/Test/EditorConfigSettings/DataProvider/DataProviderTests.MockAnalyzerReference.cs @@ -58,7 +58,7 @@ public class MockFixer : CodeFixProvider public bool Called; public int ContextDiagnosticsCount; - public sealed override ImmutableArray FixableDiagnosticIds => ImmutableArray.Create(Id); + public sealed override ImmutableArray FixableDiagnosticIds => [Id]; public sealed override Task RegisterCodeFixesAsync(CodeFixContext context) { diff --git a/src/VisualStudio/CSharp/Test/F1Help/F1HelpTests.cs b/src/VisualStudio/CSharp/Test/F1Help/F1HelpTests.cs index fc030c088c745..235d960b70a4d 100644 --- a/src/VisualStudio/CSharp/Test/F1Help/F1HelpTests.cs +++ b/src/VisualStudio/CSharp/Test/F1Help/F1HelpTests.cs @@ -1994,6 +1994,17 @@ public class C """, "required"); } + [Fact] + public async Task TestScoped() + { + await Test_KeywordAsync(""" + sc[||]oped var r = new R(); + ref struct R + { + } + """, "scoped"); + } + [Fact] public async Task TestDefaultConstraint() { @@ -2300,4 +2311,13 @@ await TestAsync( #pragma warning dis[||]able CS0312 """, "#disable"); } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/68009")] + public async Task TestGlobalUsing1() + { + await Test_KeywordAsync( + """ + [||]global using System; + """, "global-using"); + } } diff --git a/src/VisualStudio/CSharp/Test/Microsoft.VisualStudio.LanguageServices.CSharp.UnitTests.csproj b/src/VisualStudio/CSharp/Test/Microsoft.VisualStudio.LanguageServices.CSharp.UnitTests.csproj index 22661423096ba..cab7be9c43233 100644 --- a/src/VisualStudio/CSharp/Test/Microsoft.VisualStudio.LanguageServices.CSharp.UnitTests.csproj +++ b/src/VisualStudio/CSharp/Test/Microsoft.VisualStudio.LanguageServices.CSharp.UnitTests.csproj @@ -80,8 +80,4 @@ - - - - \ No newline at end of file diff --git a/src/VisualStudio/CSharp/Test/UnifiedSettings/CSharpUnifiedSettingsTests.cs b/src/VisualStudio/CSharp/Test/UnifiedSettings/CSharpUnifiedSettingsTests.cs deleted file mode 100644 index cd9d0faf9bdc3..0000000000000 --- a/src/VisualStudio/CSharp/Test/UnifiedSettings/CSharpUnifiedSettingsTests.cs +++ /dev/null @@ -1,119 +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.IO; -using System.Linq; -using System.Reflection; -using System.Threading.Tasks; -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.Completion; -using Microsoft.CodeAnalysis.Editor.CSharp.CompleteStatement; -using Microsoft.CodeAnalysis.Options; -using Microsoft.VisualStudio.LanguageServices; -using Microsoft.VisualStudio.LanguageServices.UnitTests.UnifiedSettings; -using Newtonsoft.Json.Linq; -using Xunit; - -namespace Roslyn.VisualStudio.CSharp.UnitTests.UnifiedSettings -{ - public class CSharpUnifiedSettingsTests : UnifiedSettingsTests - { - internal override ImmutableArray OnboardedOptions => ImmutableArray.Create( - CompletionOptionsStorage.TriggerOnTypingLetters, - CompletionOptionsStorage.TriggerOnDeletion, - CompletionOptionsStorage.TriggerInArgumentLists, - CompletionViewOptionsStorage.HighlightMatchingPortionsOfCompletionListItems, - CompletionViewOptionsStorage.ShowCompletionItemFilters, - CompleteStatementOptionsStorage.AutomaticallyCompleteStatementOnSemicolon, - CompletionOptionsStorage.SnippetsBehavior, - CompletionOptionsStorage.EnterKeyBehavior, - CompletionOptionsStorage.ShowNameSuggestions, - CompletionOptionsStorage.ShowItemsFromUnimportedNamespaces, - CompletionViewOptionsStorage.EnableArgumentCompletionSnippets, - CompletionOptionsStorage.ShowNewSnippetExperienceUserOption - ); - - internal override object[] GetEnumOptionValues(IOption2 option) - { - var allValues = Enum.GetValues(option.Type).Cast(); - if (option == CompletionOptionsStorage.SnippetsBehavior) - { - // SnippetsRule.Default is used as a stub value, overridden per language at runtime. - // It is not shown in the option page - return allValues.Where(value => !value.Equals(SnippetsRule.Default)).ToArray(); - } - else if (option == CompletionOptionsStorage.EnterKeyBehavior) - { - // EnterKeyRule.Default is used as a stub value, overridden per language at runtime. - // It is not shown in the option page - return allValues.Where(value => !value.Equals(EnterKeyRule.Default)).ToArray(); - } - - return base.GetEnumOptionValues(option); - } - - internal override object GetOptionsDefaultValue(IOption2 option) - { - // The default values of some options are set at runtime. option.defaultValue is just a dummy value in this case. - // However, in unified settings we always set the correct value in registration.json. - if (option == CompletionOptionsStorage.SnippetsBehavior) - { - // CompletionOptionsStorage.SnippetsBehavior's default value is SnippetsRule.Default. - // It's overridden differently per-language at runtime. - return SnippetsRule.AlwaysInclude; - } - else if (option == CompletionOptionsStorage.EnterKeyBehavior) - { - // CompletionOptionsStorage.EnterKeyBehavior's default value is EnterKeyBehavior.Default. - // It's overridden differently per-language at runtime. - return EnterKeyRule.Never; - } - else if (option == CompletionOptionsStorage.TriggerOnDeletion) - { - // CompletionOptionsStorage.TriggerOnDeletion's default value is null. - // It's disabled by default for C# - return false; - } - else if (option == CompletionOptionsStorage.ShowItemsFromUnimportedNamespaces) - { - // CompletionOptionsStorage.ShowItemsFromUnimportedNamespaces's default value is null - // It's enabled by default for C# - return true; - } - else if (option == CompletionViewOptionsStorage.EnableArgumentCompletionSnippets) - { - // CompletionViewOptionsStorage.EnableArgumentCompletionSnippets' default value is null - // It's disabled by default for C# - return false; - } - else if (option == CompletionOptionsStorage.ShowNewSnippetExperienceUserOption) - { - // CompletionOptionsStorage.ShowNewSnippetExperienceUserOption's default value is null. - // It's in experiment, so disabled by default. - return false; - } - - return base.GetOptionsDefaultValue(option); - } - - [Fact] - public async Task IntelliSensePageTests() - { - using var registrationFileStream = typeof(CSharpUnifiedSettingsTests).GetTypeInfo().Assembly.GetManifestResourceStream("Roslyn.VisualStudio.CSharp.UnitTests.csharpSettings.registration.json"); - using var reader = new StreamReader(registrationFileStream); - var registrationFile = await reader.ReadToEndAsync().ConfigureAwait(false); - var registrationJsonObject = JObject.Parse(registrationFile, new JsonLoadSettings() { CommentHandling = CommentHandling.Ignore }); - var categoriesTitle = registrationJsonObject.SelectToken($"$.categories['textEditor.csharp'].title")!; - Assert.Equal("C#", actual: categoriesTitle.ToString()); - var optionPageId = registrationJsonObject.SelectToken("$.categories['textEditor.csharp.intellisense'].legacyOptionPageId"); - Assert.Equal(Guids.CSharpOptionPageIntelliSenseIdString, optionPageId!.ToString()); - using var pkgdefFileStream = typeof(CSharpUnifiedSettingsTests).GetTypeInfo().Assembly.GetManifestResourceStream("Roslyn.VisualStudio.CSharp.UnitTests.PackageRegistration.pkgdef"); - using var pkgdefReader = new StreamReader(pkgdefFileStream); - var pkgdefFile = await pkgdefReader.ReadToEndAsync().ConfigureAwait(false); - TestUnifiedSettingsCategory(registrationJsonObject, categoryBasePath: "textEditor.csharp.intellisense", languageName: LanguageNames.CSharp, pkgdefFile); - } - } -} diff --git a/src/VisualStudio/CodeLens/ReferenceCodeLensProvider.cs b/src/VisualStudio/CodeLens/ReferenceCodeLensProvider.cs index 22e4fa8171da8..433816613164d 100644 --- a/src/VisualStudio/CodeLens/ReferenceCodeLensProvider.cs +++ b/src/VisualStudio/CodeLens/ReferenceCodeLensProvider.cs @@ -99,7 +99,7 @@ private async Task PollForUpdatesAsync() ImmutableArray keys; lock (_dataPoints) { - keys = _dataPoints.Keys.ToImmutableArray(); + keys = [.. _dataPoints.Keys]; } var projectVersions = await _lazyCodeLensCallbackService.Value.InvokeAsync>( diff --git a/src/VisualStudio/Core/Def/CallHierarchy/CallHierarchyCommandHandler.cs b/src/VisualStudio/Core/Def/CallHierarchy/CallHierarchyCommandHandler.cs index 3a1998657694c..826fbb6f7b468 100644 --- a/src/VisualStudio/Core/Def/CallHierarchy/CallHierarchyCommandHandler.cs +++ b/src/VisualStudio/Core/Def/CallHierarchy/CallHierarchyCommandHandler.cs @@ -73,7 +73,7 @@ private async Task ExecuteCommandAsync(ViewCallHierarchyCommandArgs args, Comman Document document; using (var context = _threadOperationExecutor.BeginExecute( - ServicesVSResources.Call_Hierarchy, ServicesVSResources.Navigating, allowCancellation: true, showProgress: false)) + EditorFeaturesResources.Call_Hierarchy, ServicesVSResources.Navigating, allowCancellation: true, showProgress: false)) { document = await args.SubjectBuffer.CurrentSnapshot.GetFullyLoadedOpenDocumentInCurrentContextWithChangesAsync( commandExecutionContext.OperationContext).ConfigureAwait(true); @@ -97,7 +97,7 @@ private async Task ExecuteCommandAsync(ViewCallHierarchyCommandArgs args, Comman if (mapping.Symbol != null) { - var node = await _provider.CreateItemAsync(mapping.Symbol, mapping.Project, ImmutableArray.Empty, cancellationToken).ConfigureAwait(false); + var node = await _provider.CreateItemAsync(mapping.Symbol, mapping.Project, [], cancellationToken).ConfigureAwait(false); if (node != null) { diff --git a/src/VisualStudio/Core/Def/CallHierarchy/CallHierarchyDetail.cs b/src/VisualStudio/Core/Def/CallHierarchy/CallHierarchyDetail.cs index 025e7da51bf41..66bd098b17f54 100644 --- a/src/VisualStudio/Core/Def/CallHierarchy/CallHierarchyDetail.cs +++ b/src/VisualStudio/Core/Def/CallHierarchy/CallHierarchyDetail.cs @@ -64,7 +64,7 @@ public void NavigateTo() private async Task NavigateToAsync() { using var context = _provider.ThreadOperationExecutor.BeginExecute( - ServicesVSResources.Call_Hierarchy, ServicesVSResources.Navigating, allowCancellation: true, showProgress: false); + EditorFeaturesResources.Call_Hierarchy, ServicesVSResources.Navigating, allowCancellation: true, showProgress: false); var solution = _workspace.CurrentSolution; var document = solution.GetDocument(_documentId); diff --git a/src/VisualStudio/Core/Def/CallHierarchy/CallHierarchyItem.cs b/src/VisualStudio/Core/Def/CallHierarchy/CallHierarchyItem.cs index dd9c5604304b8..24be31df5a6a3 100644 --- a/src/VisualStudio/Core/Def/CallHierarchy/CallHierarchyItem.cs +++ b/src/VisualStudio/Core/Def/CallHierarchy/CallHierarchyItem.cs @@ -138,7 +138,7 @@ public void NavigateTo() private async Task NavigateToAsync() { using var context = _provider.ThreadOperationExecutor.BeginExecute( - ServicesVSResources.Call_Hierarchy, ServicesVSResources.Navigating, allowCancellation: true, showProgress: false); + EditorFeaturesResources.Call_Hierarchy, ServicesVSResources.Navigating, allowCancellation: true, showProgress: false); await _navigableLocation.NavigateToAsync( NavigationOptions.Default with { PreferProvisionalTab = true }, context.UserCancellationToken).ConfigureAwait(false); } diff --git a/src/VisualStudio/Core/Def/CallHierarchy/Finders/AbstractCallFinder.cs b/src/VisualStudio/Core/Def/CallHierarchy/Finders/AbstractCallFinder.cs index e3290806f99f4..eb1295fa59ab1 100644 --- a/src/VisualStudio/Core/Def/CallHierarchy/Finders/AbstractCallFinder.cs +++ b/src/VisualStudio/Core/Def/CallHierarchy/Finders/AbstractCallFinder.cs @@ -163,7 +163,7 @@ protected virtual async Task SearchWorkerAsync(ISymbol symbol, Project project, else { var callingProject = project.Solution.GetProject(caller.CallingSymbol.ContainingAssembly, cancellationToken); - var item = await Provider.CreateItemAsync(caller.CallingSymbol, callingProject, caller.Locations.ToImmutableArray(), cancellationToken).ConfigureAwait(false); + var item = await Provider.CreateItemAsync(caller.CallingSymbol, callingProject, [.. caller.Locations], cancellationToken).ConfigureAwait(false); callback.AddResult(item); cancellationToken.ThrowIfCancellationRequested(); } diff --git a/src/VisualStudio/Core/Def/CallHierarchy/Finders/ImplementerFinder.cs b/src/VisualStudio/Core/Def/CallHierarchy/Finders/ImplementerFinder.cs index d380b8eac8771..7713dbaa000d3 100644 --- a/src/VisualStudio/Core/Def/CallHierarchy/Finders/ImplementerFinder.cs +++ b/src/VisualStudio/Core/Def/CallHierarchy/Finders/ImplementerFinder.cs @@ -45,7 +45,7 @@ protected override async Task SearchWorkerAsync(ISymbol symbol, Project project, var bestLocation = sourceLocations.FirstOrDefault(d => documents == null || documents.Contains(d)); if (bestLocation != null) { - var item = await Provider.CreateItemAsync(implementation, bestLocation.Project, ImmutableArray.Empty, cancellationToken).ConfigureAwait(false); + var item = await Provider.CreateItemAsync(implementation, bestLocation.Project, [], cancellationToken).ConfigureAwait(false); callback.AddResult(item); cancellationToken.ThrowIfCancellationRequested(); } diff --git a/src/VisualStudio/Core/Def/CallHierarchy/Finders/OverridingMemberFinder.cs b/src/VisualStudio/Core/Def/CallHierarchy/Finders/OverridingMemberFinder.cs index e6e64641a4316..5744cdbf8fc6a 100644 --- a/src/VisualStudio/Core/Def/CallHierarchy/Finders/OverridingMemberFinder.cs +++ b/src/VisualStudio/Core/Def/CallHierarchy/Finders/OverridingMemberFinder.cs @@ -41,7 +41,7 @@ protected override async Task SearchWorkerAsync(ISymbol symbol, Project project, var bestLocation = sourceLocations.FirstOrDefault(d => documents == null || documents.Contains(d)); if (bestLocation != null) { - var item = await Provider.CreateItemAsync(@override, bestLocation.Project, ImmutableArray.Empty, cancellationToken).ConfigureAwait(false); + var item = await Provider.CreateItemAsync(@override, bestLocation.Project, [], cancellationToken).ConfigureAwait(false); callback.AddResult(item); cancellationToken.ThrowIfCancellationRequested(); } diff --git a/src/VisualStudio/Core/Def/ChangeSignature/AddParameterDialog.xaml.cs b/src/VisualStudio/Core/Def/ChangeSignature/AddParameterDialog.xaml.cs index bd0b194368feb..b52ec8f735787 100644 --- a/src/VisualStudio/Core/Def/ChangeSignature/AddParameterDialog.xaml.cs +++ b/src/VisualStudio/Core/Def/ChangeSignature/AddParameterDialog.xaml.cs @@ -4,6 +4,7 @@ using System; using System.Windows; +using Microsoft.CodeAnalysis; using Microsoft.VisualStudio.PlatformUI; namespace Microsoft.VisualStudio.LanguageServices.Implementation.ChangeSignature; @@ -16,7 +17,7 @@ internal partial class AddParameterDialog : DialogWindow private readonly AddParameterDialogViewModel _viewModel; public string OK { get { return ServicesVSResources.OK; } } - public string Cancel { get { return ServicesVSResources.Cancel; } } + public string Cancel { get { return EditorFeaturesResources.Cancel; } } public string ParameterInformation { get { return ServicesVSResources.Parameter_information; } } public string TypeNameLabel { get { return ServicesVSResources.Type_Name; } } public string ParameterNameLabel { get { return ServicesVSResources.Parameter_Name; } } @@ -26,7 +27,7 @@ internal partial class AddParameterDialog : DialogWindow public string Required { get { return ServicesVSResources.Required; } } public string OptionalWithDefaultValue { get { return ServicesVSResources.Optional_with_default_value_colon; } } public string ValueToInjectAtCallsites { get { return ServicesVSResources.Value_to_inject_at_call_sites; } } - public string Value { get { return ServicesVSResources.Value_colon; } } + public string Value { get { return FeaturesResources.Value_colon; } } public string UseNamedArgument { get { return ServicesVSResources.Use_named_argument; } } public string IntroduceUndefinedTodoVariables { get { return ServicesVSResources.IntroduceUndefinedTodoVariables; } } public string OmitOnlyForOptionalParameters { get { return ServicesVSResources.Omit_only_for_optional_parameters; } } diff --git a/src/VisualStudio/Core/Def/ChangeSignature/AddParameterDialogViewModel.cs b/src/VisualStudio/Core/Def/ChangeSignature/AddParameterDialogViewModel.cs index b4f7be36bf7fe..a601e4e7b5142 100644 --- a/src/VisualStudio/Core/Def/ChangeSignature/AddParameterDialogViewModel.cs +++ b/src/VisualStudio/Core/Def/ChangeSignature/AddParameterDialogViewModel.cs @@ -3,30 +3,26 @@ // See the LICENSE file in the project root for more information. using System.Diagnostics.CodeAnalysis; -using System.Threading; using System.Windows; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Notification; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.VisualStudio.LanguageServices.Implementation.Utilities; -using Roslyn.Utilities; namespace Microsoft.VisualStudio.LanguageServices.Implementation.ChangeSignature; -internal class AddParameterDialogViewModel : AbstractNotifyPropertyChanged +internal sealed class AddParameterDialogViewModel : AbstractNotifyPropertyChanged { private readonly INotificationService? _notificationService; - public readonly Document Document; + public readonly SemanticDocument Document; public readonly int PositionForTypeBinding; - private readonly SemanticModel _semanticModel; - - public AddParameterDialogViewModel(Document document, int positionForTypeBinding) + public AddParameterDialogViewModel( + SemanticDocument document, int positionForTypeBinding) { _notificationService = document.Project.Solution.Services.GetService(); - _semanticModel = document.GetRequiredSemanticModelAsync(CancellationToken.None).AsTask().WaitAndGetResult_CanCallOnBackground(CancellationToken.None); TypeIsEmptyImage = Visibility.Visible; TypeBindsImage = Visibility.Collapsed; @@ -200,7 +196,7 @@ private void SetCurrentTypeTextAndUpdateBindingStatus(string typeName) TypeIsEmptyImage = Visibility.Collapsed; var languageService = Document.GetRequiredLanguageService(); - TypeSymbol = _semanticModel.GetSpeculativeTypeInfo(PositionForTypeBinding, languageService.GetTypeNode(typeName), SpeculativeBindingOption.BindAsTypeOrNamespace).Type; + TypeSymbol = Document.SemanticModel.GetSpeculativeTypeInfo(PositionForTypeBinding, languageService.GetTypeNode(typeName), SpeculativeBindingOption.BindAsTypeOrNamespace).Type; if (TypeSymbol is { SpecialType: SpecialType.System_Void }) { diff --git a/src/VisualStudio/Core/Def/ChangeSignature/ChangeSignatureDialog.xaml.cs b/src/VisualStudio/Core/Def/ChangeSignature/ChangeSignatureDialog.xaml.cs index f0ed4a29f790b..aad4454f824cf 100644 --- a/src/VisualStudio/Core/Def/ChangeSignature/ChangeSignatureDialog.xaml.cs +++ b/src/VisualStudio/Core/Def/ChangeSignature/ChangeSignatureDialog.xaml.cs @@ -10,6 +10,7 @@ using System.Windows.Controls; using System.Windows.Input; using System.Windows.Media; +using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.ChangeSignature; using Microsoft.VisualStudio.PlatformUI; @@ -23,7 +24,7 @@ internal partial class ChangeSignatureDialog : DialogWindow private readonly ChangeSignatureDialogViewModel _viewModel; // Expose localized strings for binding - public static string ChangeSignatureDialogTitle { get { return ServicesVSResources.Change_Signature; } } + public static string ChangeSignatureDialogTitle { get { return EditorFeaturesResources.Change_Signature; } } public static string CurrentParameter { get { return ServicesVSResources.Current_parameter; } } public static string Parameters { get { return ServicesVSResources.Parameters_colon2; } } public static string PreviewMethodSignature { get { return ServicesVSResources.Preview_method_signature_colon; } } @@ -32,7 +33,7 @@ internal partial class ChangeSignatureDialog : DialogWindow public static string Restore { get { return ServicesVSResources.Restore; } } public static string Add { get { return ServicesVSResources.Add; } } public static string OK { get { return ServicesVSResources.OK; } } - public static string Cancel { get { return ServicesVSResources.Cancel; } } + public static string Cancel { get { return EditorFeaturesResources.Cancel; } } public static string WarningTypeDoesNotBind { get { return ServicesVSResources.Warning_colon_type_does_not_bind; } } public static string WarningDuplicateParameterName { get { return ServicesVSResources.Warning_colon_duplicate_parameter_name; } } diff --git a/src/VisualStudio/Core/Def/ChangeSignature/ChangeSignatureDialogViewModel.ParameterViewModels.cs b/src/VisualStudio/Core/Def/ChangeSignature/ChangeSignatureDialogViewModel.ParameterViewModels.cs index d8a0dc3ba8902..5312476562a13 100644 --- a/src/VisualStudio/Core/Def/ChangeSignature/ChangeSignatureDialogViewModel.ParameterViewModels.cs +++ b/src/VisualStudio/Core/Def/ChangeSignature/ChangeSignatureDialogViewModel.ParameterViewModels.cs @@ -44,7 +44,7 @@ private static string ValueOrNone(string value) { return !string.IsNullOrEmpty(value) ? value - : ServicesVSResources.None; + : WorkspacesResources.None; } public Visibility HasParameterNameConflict { get; set; } diff --git a/src/VisualStudio/Core/Def/ChangeSignature/ChangeSignatureDialogViewModel.cs b/src/VisualStudio/Core/Def/ChangeSignature/ChangeSignatureDialogViewModel.cs index 34c60b0c81683..073e8e25ae3a8 100644 --- a/src/VisualStudio/Core/Def/ChangeSignature/ChangeSignatureDialogViewModel.cs +++ b/src/VisualStudio/Core/Def/ChangeSignature/ChangeSignatureDialogViewModel.cs @@ -43,19 +43,19 @@ internal partial class ChangeSignatureDialogViewModel : AbstractNotifyPropertyCh /// /// The document where the symbol we are changing signature is defined. /// - private readonly Document _document; + private readonly SemanticDocument _document; private readonly int _positionForTypeBinding; internal ChangeSignatureDialogViewModel( + SemanticDocument document, ParameterConfiguration parameters, ISymbol symbol, - Document document, int positionForTypeBinding, IClassificationFormatMap classificationFormatMap, ClassificationTypeMap classificationTypeMap) { - _originalParameterConfiguration = parameters; _document = document; + _originalParameterConfiguration = parameters; _positionForTypeBinding = positionForTypeBinding; _classificationFormatMap = classificationFormatMap; _classificationTypeMap = classificationTypeMap; @@ -280,8 +280,8 @@ internal ParameterConfiguration GetParameterConfiguration() { return new ParameterConfiguration( _originalParameterConfiguration.ThisParameter, - _parametersWithoutDefaultValues.Where(p => !p.IsRemoved).Select(p => p.Parameter).ToImmutableArray(), - _parametersWithDefaultValues.Where(p => !p.IsRemoved).Select(p => p.Parameter).ToImmutableArray(), + [.. _parametersWithoutDefaultValues.Where(p => !p.IsRemoved).Select(p => p.Parameter)], + [.. _parametersWithDefaultValues.Where(p => !p.IsRemoved).Select(p => p.Parameter)], (_paramsParameter == null || _paramsParameter.IsRemoved) ? null : (ExistingParameter)_paramsParameter.Parameter, selectedIndex: -1); } diff --git a/src/VisualStudio/Core/Def/ChangeSignature/VisualStudioChangeSignatureOptionsService.cs b/src/VisualStudio/Core/Def/ChangeSignature/VisualStudioChangeSignatureOptionsService.cs index 337366293ca3e..dab39b218ef57 100644 --- a/src/VisualStudio/Core/Def/ChangeSignature/VisualStudioChangeSignatureOptionsService.cs +++ b/src/VisualStudio/Core/Def/ChangeSignature/VisualStudioChangeSignatureOptionsService.cs @@ -26,7 +26,7 @@ internal sealed class VisualStudioChangeSignatureOptionsService( private readonly IThreadingContext _threadingContext = threadingContext; public ChangeSignatureOptionsResult? GetChangeSignatureOptions( - Document document, + SemanticDocument document, int positionForTypeBinding, ISymbol symbol, ParameterConfiguration parameters) @@ -34,9 +34,9 @@ internal sealed class VisualStudioChangeSignatureOptionsService( _threadingContext.ThrowIfNotOnUIThread(); var viewModel = new ChangeSignatureDialogViewModel( + document, parameters, symbol, - document, positionForTypeBinding, _classificationFormatMap, _classificationTypeMap); diff --git a/src/VisualStudio/Core/Def/CodeCleanup/AbstractCodeCleanUpFixer.cs b/src/VisualStudio/Core/Def/CodeCleanup/AbstractCodeCleanUpFixer.cs index 099c274c0f812..e3cac6db10047 100644 --- a/src/VisualStudio/Core/Def/CodeCleanup/AbstractCodeCleanUpFixer.cs +++ b/src/VisualStudio/Core/Def/CodeCleanup/AbstractCodeCleanUpFixer.cs @@ -59,7 +59,7 @@ private async Task FixHierarchyContentAsync(IVsHierarchyCodeCleanupScope h _workspace, // Just defer to FixProjectsAsync, passing in all fixable projects in the solution. (progress, cancellationToken) => FixProjectsAsync( - solution, solution.Projects.Where(p => p.SupportsCompilation).ToImmutableArray(), context.EnabledFixIds, progress, cancellationToken), + solution, [.. solution.Projects.Where(p => p.SupportsCompilation)], context.EnabledFixIds, progress, cancellationToken), context).ConfigureAwait(false); } diff --git a/src/VisualStudio/Core/Def/CodeCleanup/AbstractCodeCleanupFixerProvider.cs b/src/VisualStudio/Core/Def/CodeCleanup/AbstractCodeCleanupFixerProvider.cs index 1a6eff309d37d..0497e5f5468d8 100644 --- a/src/VisualStudio/Core/Def/CodeCleanup/AbstractCodeCleanupFixerProvider.cs +++ b/src/VisualStudio/Core/Def/CodeCleanup/AbstractCodeCleanupFixerProvider.cs @@ -21,7 +21,7 @@ internal abstract class AbstractCodeCleanUpFixerProvider : ICodeCleanUpFixerProv protected AbstractCodeCleanUpFixerProvider( IEnumerable> codeCleanUpFixers) { - _codeCleanUpFixers = codeCleanUpFixers.ToImmutableArray(); + _codeCleanUpFixers = [.. codeCleanUpFixers]; } public IReadOnlyCollection GetFixers() diff --git a/src/VisualStudio/Core/Def/ColorSchemes/ColorSchemeApplier.ClassificationVerifier.cs b/src/VisualStudio/Core/Def/ColorSchemes/ColorSchemeApplier.ClassificationVerifier.cs deleted file mode 100644 index ffc476aee1b98..0000000000000 --- a/src/VisualStudio/Core/Def/ColorSchemes/ColorSchemeApplier.ClassificationVerifier.cs +++ /dev/null @@ -1,203 +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.Generic; -using System.Collections.Immutable; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; -using System.Windows; -using Microsoft.CodeAnalysis.Classification; -using Microsoft.CodeAnalysis.Editor.Shared.Extensions; -using Microsoft.CodeAnalysis.Editor.Shared.Utilities; -using Microsoft.VisualStudio; -using Microsoft.VisualStudio.Shell; -using Microsoft.VisualStudio.Shell.Interop; -using Microsoft.VisualStudio.Threading; -using Roslyn.Utilities; - -namespace Microsoft.CodeAnalysis.ColorSchemes; - -internal partial class ColorSchemeApplier -{ - private sealed class ClassificationVerifier - { - private static readonly Guid TextEditorMEFItemsColorCategory = new("75a05685-00a8-4ded-bae5-e7a50bfa929a"); - - // These classification colors (0x00BBGGRR) should match the VS\EditorColors.xml file. - // They are not in the scheme files because they are core classifications. - private const uint DarkThemePlainText = 0x00DCDCDCu; - private const uint DarkThemeIdentifier = DarkThemePlainText; - private const uint DarkThemeOperator = 0x00B4B4B4u; - private const uint DarkThemeKeyword = 0x00D69C56u; - - private const uint LightThemePlainText = 0x00000000u; - private const uint LightThemeIdentifier = LightThemePlainText; - private const uint LightThemeOperator = LightThemePlainText; - private const uint LightThemeKeyword = 0x00FF0000u; - - private const string PlainTextClassificationTypeName = "plain text"; - - // Dark Theme Core Classifications - private static ImmutableDictionary DarkThemeForeground - => new Dictionary() - { - [PlainTextClassificationTypeName] = DarkThemePlainText, - [ClassificationTypeNames.Identifier] = DarkThemeIdentifier, - [ClassificationTypeNames.Keyword] = DarkThemeKeyword, - [ClassificationTypeNames.Operator] = DarkThemeOperator, - }.ToImmutableDictionary(); - - // Light, Blue, or AdditionalContrast Theme Core Classifications - private static ImmutableDictionary BlueLightThemeForeground - => new Dictionary() - { - [PlainTextClassificationTypeName] = LightThemePlainText, - [ClassificationTypeNames.Identifier] = LightThemeIdentifier, - [ClassificationTypeNames.Keyword] = LightThemeKeyword, - [ClassificationTypeNames.Operator] = LightThemeOperator, - }.ToImmutableDictionary(); - - private readonly IThreadingContext _threadingContext; - private readonly IVsService _fontAndColorStorage; - private readonly ImmutableArray _classifications; - private readonly ImmutableDictionary>> _colorSchemes; - - // The High Contrast theme is not included because we do not want to make changes when the user is in High Contrast mode. - - public ClassificationVerifier( - IThreadingContext threadingContext, - IVsService fontAndColorStorage, - ImmutableDictionary colorSchemes) - { - _threadingContext = threadingContext; - _fontAndColorStorage = fontAndColorStorage; - _colorSchemes = colorSchemes.ToImmutableDictionary( - nameAndScheme => nameAndScheme.Key, - nameAndScheme => nameAndScheme.Value.Themes.ToImmutableDictionary( - theme => theme.Guid, - theme => theme.Category.Colors - .Where(color => color.Foreground.HasValue) - .ToImmutableDictionary(color => color.Name, color => color.Foreground!.Value))); - - // Gather all the classifications from the core and scheme dictionaries. - var coreClassifications = DarkThemeForeground.Keys.Concat(BlueLightThemeForeground.Keys).Distinct(); - var colorSchemeClassifications = _colorSchemes.Values.SelectMany(scheme => scheme.Values.SelectMany(theme => theme.Keys)).Distinct(); - _classifications = coreClassifications.Concat(colorSchemeClassifications).ToImmutableArray(); - } - - /// - /// Determines if any Classification foreground colors have been customized in Fonts and Colors. - /// - public async Task AreForegroundColorsCustomizedAsync( - ColorSchemeName schemeName, Guid themeId, CancellationToken cancellationToken) - { - // Make no changes when in high contast mode or in unknown theme. - if (SystemParameters.HighContrast || - !_colorSchemes.TryGetValue(schemeName, out var colorScheme) || - !colorScheme.TryGetValue(themeId, out var colorSchemeTheme)) - { - return false; - } - - // Ensure we are initialized - var fontAndColorStorage = await _fontAndColorStorage.GetValueAsync(cancellationToken).ConfigureAwait(true); - - await _threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); - var fontAndColorUtilities = (IVsFontAndColorUtilities)fontAndColorStorage; - - var coreThemeColors = themeId == KnownColorThemes.Dark - ? DarkThemeForeground - : BlueLightThemeForeground; - - // Open Text Editor category for readonly access and do not load items if they are defaulted. - if (fontAndColorStorage.OpenCategory(TextEditorMEFItemsColorCategory, (uint)__FCSTORAGEFLAGS.FCSF_READONLY) == VSConstants.S_OK) - { - try - { - foreach (var classification in _classifications) - { - var colorItems = new ColorableItemInfo[1]; - if (fontAndColorStorage.GetItem(classification, colorItems) != VSConstants.S_OK) - { - // Classifications that are still defaulted will not have entries. - continue; - } - - var colorItem = colorItems[0]; - - if (IsClassificationCustomized(coreThemeColors, colorSchemeTheme, fontAndColorUtilities, colorItem, classification)) - { - return true; - } - } - } - finally - { - fontAndColorStorage.CloseCategory(); - } - } - - return false; - } - - /// - /// Determines if the ColorableItemInfo's Foreground has been customized to a color that doesn't match the - /// selected scheme. - /// - private bool IsClassificationCustomized( - ImmutableDictionary coreThemeColors, - ImmutableDictionary schemeThemeColors, - IVsFontAndColorUtilities fontAndColorUtilities, - ColorableItemInfo colorItem, - string classification) - { - _threadingContext.ThrowIfNotOnUIThread(); - - var foregroundColorRef = colorItem.crForeground; - - if (fontAndColorUtilities.GetColorType(foregroundColorRef, out var foregroundColorType) != VSConstants.S_OK) - { - // Without being able to check color type, we cannot make a determination. - return false; - } - - // If the color is defaulted then it isn't customized. - if (foregroundColorType == (int)__VSCOLORTYPE.CT_AUTOMATIC) - { - return false; - } - - // Since the color type isn't default then it has been customized, we will - // perform an additional check for RGB colors to see if the customized color - // matches the color scheme color. - if (foregroundColorType != (int)__VSCOLORTYPE.CT_RAW) - { - return true; - } - - if (coreThemeColors.TryGetValue(classification, out var coreColor)) - { - return foregroundColorRef != coreColor; - } - - if (schemeThemeColors.TryGetValue(classification, out var schemeColor)) - { - return foregroundColorRef != schemeColor; - } - - // Since Classification inheritance isn't represented in the scheme files, - // this switch case will handle the 3 cases we expect. - var fallbackColor = classification switch - { - ClassificationTypeNames.OperatorOverloaded => coreThemeColors[ClassificationTypeNames.Operator], - ClassificationTypeNames.ControlKeyword => coreThemeColors[ClassificationTypeNames.Keyword], - _ => coreThemeColors[ClassificationTypeNames.Identifier] - }; - - return foregroundColorRef != fallbackColor; - } - } -} diff --git a/src/VisualStudio/Core/Def/ColorSchemes/ColorSchemeApplier.ColorSchemeReader.cs b/src/VisualStudio/Core/Def/ColorSchemes/ColorSchemeApplier.ColorSchemeReader.cs index d0b4104977b2c..45b025871bcf4 100644 --- a/src/VisualStudio/Core/Def/ColorSchemes/ColorSchemeApplier.ColorSchemeReader.cs +++ b/src/VisualStudio/Core/Def/ColorSchemes/ColorSchemeApplier.ColorSchemeReader.cs @@ -31,7 +31,7 @@ public static ColorScheme ReadColorScheme(Stream schemeStream) .Descendants("Theme") .Select(ReadColorTheme); - return new ColorScheme(themes.ToImmutableArray()); + return new ColorScheme([.. themes]); } private static ColorTheme ReadColorTheme(XElement themeElement) @@ -55,7 +55,7 @@ private static ColorCategory ReadColorCategory(XElement categoryElement) .Select(ReadColorItem) .WhereNotNull(); - return new ColorCategory(categoryName, categoryGuid, colorItems.ToImmutableArray()); + return new ColorCategory(categoryName, categoryGuid, [.. colorItems]); } private static ColorItem? ReadColorItem(XElement colorElement) diff --git a/src/VisualStudio/Core/Def/ColorSchemes/ColorSchemeApplier.RegistryItemConverter.cs b/src/VisualStudio/Core/Def/ColorSchemes/ColorSchemeApplier.RegistryItemConverter.cs index 90a87c9d6bfb6..ed58ae66355a0 100644 --- a/src/VisualStudio/Core/Def/ColorSchemes/ColorSchemeApplier.RegistryItemConverter.cs +++ b/src/VisualStudio/Core/Def/ColorSchemes/ColorSchemeApplier.RegistryItemConverter.cs @@ -20,9 +20,7 @@ private static class RegistryItemConverter public static ImmutableArray Convert(ColorScheme scheme) { - return scheme.Themes - .Select(ToRegistryItem) - .ToImmutableArray(); + return [.. scheme.Themes.Select(ToRegistryItem)]; } private static RegistryItem ToRegistryItem(ColorTheme theme) diff --git a/src/VisualStudio/Core/Def/ColorSchemes/ColorSchemeApplier.cs b/src/VisualStudio/Core/Def/ColorSchemes/ColorSchemeApplier.cs index c77d5f9293384..b9ac22121c1fd 100644 --- a/src/VisualStudio/Core/Def/ColorSchemes/ColorSchemeApplier.cs +++ b/src/VisualStudio/Core/Def/ColorSchemes/ColorSchemeApplier.cs @@ -6,7 +6,6 @@ using System.Collections.Immutable; using System.ComponentModel; using System.ComponentModel.Composition; -using System.Linq; using System.Runtime.InteropServices; using System.Threading; using System.Threading.Tasks; @@ -15,12 +14,10 @@ using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Shared.TestHooks; using Microsoft.VisualStudio; -using Microsoft.VisualStudio.PlatformUI; using Microsoft.VisualStudio.Settings; using Microsoft.VisualStudio.Shell; using Microsoft.VisualStudio.Shell.Interop; using Microsoft.VisualStudio.Threading; -using Microsoft.Win32; using Roslyn.Utilities; using Task = System.Threading.Tasks.Task; @@ -29,14 +26,10 @@ namespace Microsoft.CodeAnalysis.ColorSchemes; [Export(typeof(ColorSchemeApplier))] internal sealed partial class ColorSchemeApplier { - private const string ColorThemeValueName = "Microsoft.VisualStudio.ColorTheme"; - private const string ColorThemeNewValueName = "Microsoft.VisualStudio.ColorThemeNew"; - private readonly IThreadingContext _threadingContext; private readonly IServiceProvider _serviceProvider; private readonly IAsyncServiceProvider _asyncServiceProvider; private readonly ColorSchemeSettings _settings; - private readonly ClassificationVerifier _classificationVerifier; private readonly ImmutableDictionary _colorSchemes; private readonly AsyncBatchingWorkQueue _workQueue; @@ -60,7 +53,6 @@ public ColorSchemeApplier( _settings = new ColorSchemeSettings(threadingContext, _serviceProvider, globalOptions); _colorSchemes = ColorSchemeSettings.GetColorSchemes(); - _classificationVerifier = new ClassificationVerifier(threadingContext, fontAndColorStorage, _colorSchemes); _workQueue = new( DelayTimeSpan.Idle, QueueColorSchemeUpdateAsync, @@ -78,13 +70,12 @@ public async Task InitializeAsync(CancellationToken cancellationToken) _isInitialized = true; } - // We need to update the theme whenever the Editor Color Scheme setting changes or the VS Theme changes. + // We need to update the theme whenever the Editor Color Scheme setting changes. await TaskScheduler.Default; var settingsManager = await _asyncServiceProvider.GetServiceAsync(_threadingContext.JoinableTaskFactory).ConfigureAwait(false); await _threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); settingsManager.GetSubset(ColorSchemeOptionsStorage.ColorSchemeSettingKey).SettingChangedAsync += ColorSchemeChangedAsync; - VSColorTheme.ThemeChanged += VSColorTheme_ThemeChanged; await TaskScheduler.Default; @@ -115,9 +106,6 @@ await _settings.ApplyColorSchemeAsync( colorScheme.Value, _colorSchemeRegistryItems[colorScheme.Value], cancellationToken).ConfigureAwait(false); } - private void VSColorTheme_ThemeChanged(ThemeChangedEventArgs e) - => _workQueue.AddWork(); - private Task ColorSchemeChangedAsync(object sender, PropertyChangedEventArgs args) { _workQueue.AddWork(); @@ -131,18 +119,15 @@ private async ValueTask QueueColorSchemeUpdateAsync(CancellationToken cancellati } /// - /// Returns true if the color scheme needs updating. + /// Returns a non-null value, if the color scheme needs updating. /// private async Task TryGetUpdatedColorSchemeAsync(CancellationToken cancellationToken) { // The color scheme that is currently applied to the registry var appliedColorScheme = await _settings.GetAppliedColorSchemeAsync(cancellationToken).ConfigureAwait(false); - // If this is a supported theme then, use the users configured scheme, otherwise fallback to the VS 2017. - // Custom themes would be based on the MEF exported color information for classifications which matches the VS 2017 theme. - var configuredColorScheme = await IsSupportedThemeAsync(cancellationToken).ConfigureAwait(false) - ? _settings.GetConfiguredColorScheme() - : ColorSchemeName.VisualStudio2017; + // The color scheme configured in VS settings. + var configuredColorScheme = _settings.GetConfiguredColorScheme(); if (appliedColorScheme == configuredColorScheme) return null; @@ -150,63 +135,6 @@ private async ValueTask QueueColorSchemeUpdateAsync(CancellationToken cancellati return configuredColorScheme; } - public async Task IsSupportedThemeAsync(CancellationToken cancellationToken) - => IsSupportedTheme(await GetThemeIdAsync(cancellationToken).ConfigureAwait(false)); - - private bool IsSupportedTheme(Guid themeId) - { - return _colorSchemes.Values.Any( - scheme => scheme.Themes.Any( - static (theme, themeId) => theme.Guid == themeId, themeId)); - } - - public async Task IsThemeCustomizedAsync(CancellationToken cancellationToken) - => await _classificationVerifier.AreForegroundColorsCustomizedAsync( - _settings.GetConfiguredColorScheme(), - await GetThemeIdAsync(cancellationToken).ConfigureAwait(false), - cancellationToken).ConfigureAwait(false); - - private async Task GetThemeIdAsync(CancellationToken cancellationToken) - { - await TaskScheduler.Default; - var settingsManager = await _asyncServiceProvider.GetServiceAsync(_threadingContext.JoinableTaskFactory).ConfigureAwait(false); - await _threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); - - // Look up the value from the new roamed theme property first - // Fallback to the original roamed theme property if that fails - var currentThemeString = settingsManager.GetValueOrDefault(ColorThemeNewValueName, defaultValue: null) ?? - settingsManager.GetValueOrDefault(ColorThemeValueName, defaultValue: null); - - if (currentThemeString is null) - { - // The ColorTheme setting is unpopulated when it has never been changed from its default. - // The default VS ColorTheme is Blue - return KnownColorThemes.Blue; - } - - var themeId = Guid.Parse(currentThemeString); - - if (themeId == KnownColorThemes.System) - { - themeId = ShouldAppsUseLightTheme() - ? KnownColorThemes.Light - : KnownColorThemes.Dark; - } - - return themeId; - } - - private static bool ShouldAppsUseLightTheme() - { - const string PersonalizeKey = @"Software\Microsoft\Windows\CurrentVersion\Themes\Personalize"; - const string AppsUseLightThemeValue = "AppsUseLightTheme"; - const string appsUseDarkTheme = "0"; - - using var personalizeKey = Registry.CurrentUser.OpenSubKey(PersonalizeKey, writable: false); - var appsThemeValue = personalizeKey?.GetValue(AppsUseLightThemeValue)?.ToString(); - return appsThemeValue != appsUseDarkTheme; - } - // NOTE: This service is not public or intended for use by teams/individuals outside of Microsoft. Any data stored is subject to deletion without warning. [Guid("9B164E40-C3A2-4363-9BC5-EB4039DEF653")] private class SVsSettingsPersistenceManager { } diff --git a/src/VisualStudio/Core/Def/CommonControls/MemberSelectionViewModel.cs b/src/VisualStudio/Core/Def/CommonControls/MemberSelectionViewModel.cs index 5fad7fdb9b74c..2b4039844ae43 100644 --- a/src/VisualStudio/Core/Def/CommonControls/MemberSelectionViewModel.cs +++ b/src/VisualStudio/Core/Def/CommonControls/MemberSelectionViewModel.cs @@ -34,7 +34,7 @@ public MemberSelectionViewModel( { _uiThreadOperationExecutor = uiThreadOperationExecutor; // Use public property to hook property change events up - Members = members.OrderBy(s => s.SymbolName).ToImmutableArray(); + Members = [.. members.OrderBy(s => s.SymbolName)]; _symbolToDependentsMap = dependentsMap; _symbolToMemberViewMap = members.ToImmutableDictionary(memberViewModel => memberViewModel.Symbol); @@ -189,6 +189,6 @@ private ImmutableHashSet FindDependentsRecursively(ISymbol member) } } - return result.ToImmutableHashSet(); + return [.. result]; } } diff --git a/src/VisualStudio/Core/Def/CommonControls/NewTypeDestinationSelectionViewModel.cs b/src/VisualStudio/Core/Def/CommonControls/NewTypeDestinationSelectionViewModel.cs index 78abf04e0a2b0..800a30c34321a 100644 --- a/src/VisualStudio/Core/Def/CommonControls/NewTypeDestinationSelectionViewModel.cs +++ b/src/VisualStudio/Core/Def/CommonControls/NewTypeDestinationSelectionViewModel.cs @@ -19,7 +19,7 @@ internal class NewTypeDestinationSelectionViewModel : AbstractNotifyPropertyChan LanguageNames.CSharp, string.Empty, string.Empty, - ImmutableArray.Empty, + [], null ); diff --git a/src/VisualStudio/Core/Def/Diagnostics/VisualStudioDiagnosticAnalyzerProvider.cs b/src/VisualStudio/Core/Def/Diagnostics/VisualStudioDiagnosticAnalyzerProvider.cs index c44d0d2a07eca..77ecdf89f0890 100644 --- a/src/VisualStudio/Core/Def/Diagnostics/VisualStudioDiagnosticAnalyzerProvider.cs +++ b/src/VisualStudio/Core/Def/Diagnostics/VisualStudioDiagnosticAnalyzerProvider.cs @@ -104,7 +104,7 @@ internal VisualStudioDiagnosticAnalyzerProvider(object extensionManager, Type ty // // fortunately, this only happens on disposing at shutdown, so we just catch the exception and silently swallow it. // we are about to shutdown anyway. - return ImmutableArray<(AnalyzerFileReference, string)>.Empty; + return []; } } diff --git a/src/VisualStudio/Core/Def/Diagnostics/VisualStudioDiagnosticAnalyzerService.cs b/src/VisualStudio/Core/Def/Diagnostics/VisualStudioDiagnosticAnalyzerService.cs index 6d8001345a238..f7f1524303b7d 100644 --- a/src/VisualStudio/Core/Def/Diagnostics/VisualStudioDiagnosticAnalyzerService.cs +++ b/src/VisualStudio/Core/Def/Diagnostics/VisualStudioDiagnosticAnalyzerService.cs @@ -313,14 +313,14 @@ public void RunAnalyzers(IVsHierarchy? hierarchy) ImmutableArray otherProjectsForMultiTfmProject; if (project != null) { - otherProjectsForMultiTfmProject = solution.Projects.Where( - p => p != project && p.FilePath == project.FilePath && p.State.NameAndFlavor.name == project.State.NameAndFlavor.name).ToImmutableArray(); + otherProjectsForMultiTfmProject = [.. solution.Projects.Where( + p => p != project && p.FilePath == project.FilePath && p.State.NameAndFlavor.name == project.State.NameAndFlavor.name)]; if (!otherProjectsForMultiTfmProject.IsEmpty) projectOrSolutionName = project.State.NameAndFlavor.name; } else { - otherProjectsForMultiTfmProject = ImmutableArray.Empty; + otherProjectsForMultiTfmProject = []; } // Force complete analyzer execution in background. diff --git a/src/VisualStudio/Core/Def/DocumentOutline/DocumentOutlineView.xaml.cs b/src/VisualStudio/Core/Def/DocumentOutline/DocumentOutlineView.xaml.cs index 3f819c374419a..52e04a12a72d0 100644 --- a/src/VisualStudio/Core/Def/DocumentOutline/DocumentOutlineView.xaml.cs +++ b/src/VisualStudio/Core/Def/DocumentOutline/DocumentOutlineView.xaml.cs @@ -18,6 +18,7 @@ using Microsoft.VisualStudio.Shell; using Microsoft.VisualStudio.Shell.Interop; using Microsoft.VisualStudio.Text; +using Microsoft.VisualStudio.Text.Editor; using Microsoft.VisualStudio.Text.Outlining; using InternalUtilities = Microsoft.Internal.VisualStudio.PlatformUI.Utilities; using IOleCommandTarget = Microsoft.VisualStudio.OLE.Interop.IOleCommandTarget; @@ -294,9 +295,13 @@ private void SymbolTree_SourceUpdated(object sender, DataTransferEventArgs e) try { var textView = _viewTracker.GetActiveView(); + + // Attempt to move the item to the center of the view. The user selected the item explicitly, and this + // gives them a consistent location they can expect to see the result at. textView.TryMoveCaretToAndEnsureVisible( symbolModel.Data.SelectionRangeSpan.TranslateTo(textView.TextSnapshot, SpanTrackingMode.EdgeInclusive).Start, - _outliningManagerService); + _outliningManagerService, + EnsureSpanVisibleOptions.AlwaysCenter); } finally { diff --git a/src/VisualStudio/Core/Def/DocumentOutline/DocumentOutlineViewModel.cs b/src/VisualStudio/Core/Def/DocumentOutline/DocumentOutlineViewModel.cs index 394931e2d375d..439e12fccf8fa 100644 --- a/src/VisualStudio/Core/Def/DocumentOutline/DocumentOutlineViewModel.cs +++ b/src/VisualStudio/Core/Def/DocumentOutline/DocumentOutlineViewModel.cs @@ -59,7 +59,7 @@ internal sealed partial class DocumentOutlineViewModel : INotifyPropertyChanged, private Visibility _visibility_doNotAccessDirectly = Visibility.Visible; private SortOption _sortOption_doNotAccessDirectly = SortOption.Location; private string _searchText_doNotAccessDirectly = ""; - private ImmutableArray _documentSymbolViewModelItems_doNotAccessDirectly = ImmutableArray.Empty; + private ImmutableArray _documentSymbolViewModelItems_doNotAccessDirectly = []; private DocumentOutlineViewState _lastPresentedViewState_doNotAccessDirectly; /// @@ -119,7 +119,7 @@ private static DocumentOutlineViewState CreateEmptyViewState(ITextSnapshot curre => new( currentSnapshot, searchText: "", - ImmutableArray.Empty, + [], []); private void OnEventSourceChanged(object sender, TaggerEventArgs e) diff --git a/src/VisualStudio/Core/Def/EditorConfigSettings/Analyzers/View/ColumnDefinitions/AnalyzerSeverityColumnDefinition.cs b/src/VisualStudio/Core/Def/EditorConfigSettings/Analyzers/View/ColumnDefinitions/AnalyzerSeverityColumnDefinition.cs index a2940c7549007..669b5e540c504 100644 --- a/src/VisualStudio/Core/Def/EditorConfigSettings/Analyzers/View/ColumnDefinitions/AnalyzerSeverityColumnDefinition.cs +++ b/src/VisualStudio/Core/Def/EditorConfigSettings/Analyzers/View/ColumnDefinitions/AnalyzerSeverityColumnDefinition.cs @@ -5,6 +5,7 @@ using System; using System.ComponentModel.Composition; using System.Windows; +using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Data; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.VisualStudio.LanguageServices.EditorConfigSettings.Analyzers.ViewModel; @@ -41,11 +42,11 @@ public override bool TryCreateStringContent(ITableEntryHandle entry, bool trunca content = setting.Severity switch { - CodeAnalysis.ReportDiagnostic.Suppress => ServicesVSResources.Disabled, - CodeAnalysis.ReportDiagnostic.Hidden => ServicesVSResources.Refactoring_Only, - CodeAnalysis.ReportDiagnostic.Info => ServicesVSResources.Suggestion, - CodeAnalysis.ReportDiagnostic.Warn => ServicesVSResources.Warning, - CodeAnalysis.ReportDiagnostic.Error => ServicesVSResources.Error, + ReportDiagnostic.Suppress => ServicesVSResources.Disabled, + ReportDiagnostic.Hidden => WorkspacesResources.Refactoring_Only, + ReportDiagnostic.Info => WorkspacesResources.Suggestion, + ReportDiagnostic.Warn => WorkspacesResources.Warning, + ReportDiagnostic.Error => WorkspacesResources.Error, _ => string.Empty, }; return true; diff --git a/src/VisualStudio/Core/Def/EditorConfigSettings/Analyzers/ViewModel/SeverityViewModel.cs b/src/VisualStudio/Core/Def/EditorConfigSettings/Analyzers/ViewModel/SeverityViewModel.cs index b6710ec3f818c..b94664b56cd0c 100644 --- a/src/VisualStudio/Core/Def/EditorConfigSettings/Analyzers/ViewModel/SeverityViewModel.cs +++ b/src/VisualStudio/Core/Def/EditorConfigSettings/Analyzers/ViewModel/SeverityViewModel.cs @@ -13,10 +13,10 @@ internal class SeverityViewModel private static readonly string[] s_severities = [ ServicesVSResources.Disabled, - ServicesVSResources.Refactoring_Only, - ServicesVSResources.Suggestion, - ServicesVSResources.Warning, - ServicesVSResources.Error + WorkspacesResources.Refactoring_Only, + WorkspacesResources.Suggestion, + WorkspacesResources.Warning, + WorkspacesResources.Error ]; private readonly int _selectedSeverityIndex; diff --git a/src/VisualStudio/Core/Def/EditorConfigSettings/CodeStyle/ViewModel/CodeStyleSeverityViewModel.cs b/src/VisualStudio/Core/Def/EditorConfigSettings/CodeStyle/ViewModel/CodeStyleSeverityViewModel.cs index ca32f7528b654..4b780bbd8514f 100644 --- a/src/VisualStudio/Core/Def/EditorConfigSettings/CodeStyle/ViewModel/CodeStyleSeverityViewModel.cs +++ b/src/VisualStudio/Core/Def/EditorConfigSettings/CodeStyle/ViewModel/CodeStyleSeverityViewModel.cs @@ -17,10 +17,10 @@ internal class CodeStyleSeverityViewModel // analyzers to turn themselves off when 'option.Notification.Severity is ReportDiagnostic.Suppress' private static readonly string[] s_severities = [ - ServicesVSResources.Refactoring_Only, - ServicesVSResources.Suggestion, - ServicesVSResources.Warning, - ServicesVSResources.Error + WorkspacesResources.Refactoring_Only, + WorkspacesResources.Suggestion, + WorkspacesResources.Warning, + WorkspacesResources.Error ]; private readonly int _selectedSeverityIndex; diff --git a/src/VisualStudio/Core/Def/EditorConfigSettings/Common/EditorTextUpdater.cs b/src/VisualStudio/Core/Def/EditorConfigSettings/Common/EditorTextUpdater.cs index 184802ff869d2..f6472a0b34bed 100644 --- a/src/VisualStudio/Core/Def/EditorConfigSettings/Common/EditorTextUpdater.cs +++ b/src/VisualStudio/Core/Def/EditorConfigSettings/Common/EditorTextUpdater.cs @@ -32,6 +32,6 @@ public void UpdateText(IReadOnlyList changes) return; } - TextEditApplication.UpdateText(changes.ToImmutableArray(), buffer, EditOptions.DefaultMinimalChange); + TextEditApplication.UpdateText([.. changes], buffer, EditOptions.DefaultMinimalChange); } } diff --git a/src/VisualStudio/Core/Def/EditorConfigSettings/Common/EnumSettingViewModel.cs b/src/VisualStudio/Core/Def/EditorConfigSettings/Common/EnumSettingViewModel.cs index 8b9609eafcda4..e7ff2103acef6 100644 --- a/src/VisualStudio/Core/Def/EditorConfigSettings/Common/EnumSettingViewModel.cs +++ b/src/VisualStudio/Core/Def/EditorConfigSettings/Common/EnumSettingViewModel.cs @@ -50,7 +50,7 @@ public void ChangeProperty(string propertyDescription) } public string[] GetValueDescriptions() - => _mapping.Keys.ToArray(); + => [.. _mapping.Keys]; public int GetValueIndex() { diff --git a/src/VisualStudio/Core/Def/EditorConfigSettings/NamingStyle/View/ColumnDefinitions/NamingStylesSeverityColumnDefinition.cs b/src/VisualStudio/Core/Def/EditorConfigSettings/NamingStyle/View/ColumnDefinitions/NamingStylesSeverityColumnDefinition.cs index ff6770cbf6a2c..5559437c27c7d 100644 --- a/src/VisualStudio/Core/Def/EditorConfigSettings/NamingStyle/View/ColumnDefinitions/NamingStylesSeverityColumnDefinition.cs +++ b/src/VisualStudio/Core/Def/EditorConfigSettings/NamingStyle/View/ColumnDefinitions/NamingStylesSeverityColumnDefinition.cs @@ -48,10 +48,10 @@ static string GetSeverityString(ReportDiagnostic severity) => severity switch { ReportDiagnostic.Suppress => ServicesVSResources.Disabled, - ReportDiagnostic.Hidden => ServicesVSResources.Refactoring_Only, - ReportDiagnostic.Info => ServicesVSResources.Suggestion, - ReportDiagnostic.Warn => ServicesVSResources.Warning, - ReportDiagnostic.Error => ServicesVSResources.Error, + ReportDiagnostic.Hidden => WorkspacesResources.Refactoring_Only, + ReportDiagnostic.Info => WorkspacesResources.Suggestion, + ReportDiagnostic.Warn => WorkspacesResources.Warning, + ReportDiagnostic.Error => WorkspacesResources.Error, _ => throw new InvalidOperationException(), }; } diff --git a/src/VisualStudio/Core/Def/EditorConfigSettings/NamingStyle/ViewModel/ColumnViewModels/NamingStylesSeverityViewModel.cs b/src/VisualStudio/Core/Def/EditorConfigSettings/NamingStyle/ViewModel/ColumnViewModels/NamingStylesSeverityViewModel.cs index d1161fb5d669b..f544954232ff6 100644 --- a/src/VisualStudio/Core/Def/EditorConfigSettings/NamingStyle/ViewModel/ColumnViewModels/NamingStylesSeverityViewModel.cs +++ b/src/VisualStudio/Core/Def/EditorConfigSettings/NamingStyle/ViewModel/ColumnViewModels/NamingStylesSeverityViewModel.cs @@ -52,10 +52,9 @@ internal void SelectionChanged(int selectedIndex) public static ImmutableArray Severities { get; } = [ ServicesVSResources.Disabled, - ServicesVSResources.Refactoring_Only, - ServicesVSResources.Suggestion, - ServicesVSResources.Warning, - ServicesVSResources.Error -, + WorkspacesResources.Refactoring_Only, + WorkspacesResources.Suggestion, + WorkspacesResources.Warning, + WorkspacesResources.Error, ]; } diff --git a/src/VisualStudio/Core/Def/ExtractClass/ExtractClassDialog.xaml.cs b/src/VisualStudio/Core/Def/ExtractClass/ExtractClassDialog.xaml.cs index ecf9d52e4c8be..e623674e74e18 100644 --- a/src/VisualStudio/Core/Def/ExtractClass/ExtractClassDialog.xaml.cs +++ b/src/VisualStudio/Core/Def/ExtractClass/ExtractClassDialog.xaml.cs @@ -6,6 +6,7 @@ using System.Windows; using System.Windows.Input; +using Microsoft.CodeAnalysis; using Microsoft.VisualStudio.LanguageServices.Implementation.CommonControls; using Microsoft.VisualStudio.PlatformUI; @@ -17,7 +18,7 @@ namespace Microsoft.VisualStudio.LanguageServices.Implementation.ExtractClass; internal partial class ExtractClassDialog : DialogWindow { public string OK => ServicesVSResources.OK; - public string Cancel => ServicesVSResources.Cancel; + public string Cancel => EditorFeaturesResources.Cancel; public string SelectMembers => ServicesVSResources.Select_members_colon; public string ExtractClassTitle => ViewModel.Title; public ExtractClassViewModel ViewModel { get; } diff --git a/src/VisualStudio/Core/Def/ExtractClass/VisualStudioExtractClassOptionsService.cs b/src/VisualStudio/Core/Def/ExtractClass/VisualStudioExtractClassOptionsService.cs index 74e48a82e22d4..e85ebfe6af304 100644 --- a/src/VisualStudio/Core/Def/ExtractClass/VisualStudioExtractClassOptionsService.cs +++ b/src/VisualStudio/Core/Def/ExtractClass/VisualStudioExtractClassOptionsService.cs @@ -7,15 +7,14 @@ using System.Composition; using System.Linq; using System.Threading; -using System.Threading.Tasks; using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Editor.Shared.Extensions; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.ExtractClass; using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Notification; -using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.PullMemberUp; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.Utilities; @@ -28,26 +27,25 @@ namespace Microsoft.VisualStudio.LanguageServices.Implementation.ExtractClass; [ExportWorkspaceService(typeof(IExtractClassOptionsService), ServiceLayer.Host), Shared] -internal class VisualStudioExtractClassOptionsService : IExtractClassOptionsService +[method: ImportingConstructor] +[method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] +internal sealed class VisualStudioExtractClassOptionsService( + IThreadingContext threadingContext, + IGlyphService glyphService, + IUIThreadOperationExecutor uiThreadOperationExecutor) : IExtractClassOptionsService { - private readonly IThreadingContext _threadingContext; - private readonly IGlyphService _glyphService; - private readonly IUIThreadOperationExecutor _uiThreadOperationExecutor; - - [ImportingConstructor] - [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - public VisualStudioExtractClassOptionsService( - IThreadingContext threadingContext, - IGlyphService glyphService, - IUIThreadOperationExecutor uiThreadOperationExecutor) - { - _threadingContext = threadingContext; - _glyphService = glyphService; - _uiThreadOperationExecutor = uiThreadOperationExecutor; - } - - public async Task GetExtractClassOptionsAsync(Document document, INamedTypeSymbol selectedType, ImmutableArray selectedMembers, CancellationToken cancellationToken) + private readonly IThreadingContext _threadingContext = threadingContext; + private readonly IGlyphService _glyphService = glyphService; + private readonly IUIThreadOperationExecutor _uiThreadOperationExecutor = uiThreadOperationExecutor; + + public ExtractClassOptions? GetExtractClassOptions( + Document document, + INamedTypeSymbol selectedType, + ImmutableArray selectedMembers, + SyntaxFormattingOptions formattingOptions, + CancellationToken cancellationToken) { + _threadingContext.ThrowIfNotOnUIThread(); var notificationService = document.Project.Solution.Services.GetRequiredService(); var membersInType = selectedType.GetMembers(). @@ -74,7 +72,6 @@ public VisualStudioExtractClassOptionsService( ? string.Empty : selectedType.ContainingNamespace.ToDisplayString(); - var formattingOptions = await document.GetSyntaxFormattingOptionsAsync(cancellationToken).ConfigureAwait(false); var generatedNameTypeParameterSuffix = ExtractTypeHelpers.GetTypeParameterSuffix(document, formattingOptions, selectedType, membersInType, cancellationToken); var viewModel = new ExtractClassViewModel( @@ -87,10 +84,9 @@ public VisualStudioExtractClassOptionsService( containingNamespaceDisplay, document.Project.Language, generatedNameTypeParameterSuffix, - conflictingTypeNames.ToImmutableArray(), + [.. conflictingTypeNames], document.GetRequiredLanguageService()); - await _threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); var dialog = new ExtractClassDialog(viewModel); var result = dialog.ShowModal(); diff --git a/src/VisualStudio/Core/Def/ExtractInterface/ExtractInterfaceDialog.xaml.cs b/src/VisualStudio/Core/Def/ExtractInterface/ExtractInterfaceDialog.xaml.cs index ea57fb7231952..294f36a2880c6 100644 --- a/src/VisualStudio/Core/Def/ExtractInterface/ExtractInterfaceDialog.xaml.cs +++ b/src/VisualStudio/Core/Def/ExtractInterface/ExtractInterfaceDialog.xaml.cs @@ -7,6 +7,7 @@ using System.Windows; using System.Windows.Controls; using System.Windows.Input; +using Microsoft.CodeAnalysis; using Microsoft.VisualStudio.LanguageServices.Implementation.CommonControls; using Microsoft.VisualStudio.PlatformUI; @@ -20,13 +21,13 @@ internal partial class ExtractInterfaceDialog : DialogWindow public ExtractInterfaceDialogViewModel ViewModel { get; } // Expose localized strings for binding - public string ExtractInterfaceDialogTitle { get { return ServicesVSResources.Extract_Interface; } } + public string ExtractInterfaceDialogTitle { get { return EditorFeaturesResources.Extract_Interface; } } public string NewInterfaceName { get { return ServicesVSResources.New_interface_name_colon; } } public string SelectPublicMembersToFormInterface { get { return ServicesVSResources.Select_public_members_to_form_interface; } } public string SelectAll { get { return ServicesVSResources.Select_All; } } public string DeselectAll { get { return ServicesVSResources.Deselect_All; } } public string OK { get { return ServicesVSResources.OK; } } - public string Cancel { get { return ServicesVSResources.Cancel; } } + public string Cancel { get { return EditorFeaturesResources.Cancel; } } public MemberSelection MemberSelectionControl { get; } diff --git a/src/VisualStudio/Core/Def/ExtractInterface/ExtractInterfaceDialogViewModel.cs b/src/VisualStudio/Core/Def/ExtractInterface/ExtractInterfaceDialogViewModel.cs index 782361e3f49f0..91381cfbbead3 100644 --- a/src/VisualStudio/Core/Def/ExtractInterface/ExtractInterfaceDialogViewModel.cs +++ b/src/VisualStudio/Core/Def/ExtractInterface/ExtractInterfaceDialogViewModel.cs @@ -48,7 +48,7 @@ internal ExtractInterfaceDialogViewModel( languageName, defaultNamespace, generatedNameTypeParameterSuffix, - conflictingTypeNames.ToImmutableArray(), + [.. conflictingTypeNames], syntaxFactsService); } diff --git a/src/VisualStudio/Core/Def/ExtractInterface/VisualStudioExtractInterfaceOptionsService.cs b/src/VisualStudio/Core/Def/ExtractInterface/VisualStudioExtractInterfaceOptionsService.cs index fd7fb9dcead35..5af92736f82e8 100644 --- a/src/VisualStudio/Core/Def/ExtractInterface/VisualStudioExtractInterfaceOptionsService.cs +++ b/src/VisualStudio/Core/Def/ExtractInterface/VisualStudioExtractInterfaceOptionsService.cs @@ -12,6 +12,7 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CodeGeneration; +using Microsoft.CodeAnalysis.Editor.Shared.Extensions; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.ExtractInterface; using Microsoft.CodeAnalysis.Host.Mef; @@ -26,22 +27,15 @@ namespace Microsoft.VisualStudio.LanguageServices.Implementation.ExtractInterface; [ExportWorkspaceService(typeof(IExtractInterfaceOptionsService), ServiceLayer.Host), Shared] -internal class VisualStudioExtractInterfaceOptionsService : IExtractInterfaceOptionsService +[method: ImportingConstructor] +[method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] +internal sealed class VisualStudioExtractInterfaceOptionsService(IGlyphService glyphService, IThreadingContext threadingContext, IUIThreadOperationExecutor uiThreadOperationExecutor) : IExtractInterfaceOptionsService { - private readonly IGlyphService _glyphService; - private readonly IThreadingContext _threadingContext; - private readonly IUIThreadOperationExecutor _uiThreadOperationExecutor; + private readonly IGlyphService _glyphService = glyphService; + private readonly IThreadingContext _threadingContext = threadingContext; + private readonly IUIThreadOperationExecutor _uiThreadOperationExecutor = uiThreadOperationExecutor; - [ImportingConstructor] - [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - public VisualStudioExtractInterfaceOptionsService(IGlyphService glyphService, IThreadingContext threadingContext, IUIThreadOperationExecutor uiThreadOperationExecutor) - { - _glyphService = glyphService; - _threadingContext = threadingContext; - _uiThreadOperationExecutor = uiThreadOperationExecutor; - } - - public async Task GetExtractInterfaceOptionsAsync( + public ExtractInterfaceOptionsResult GetExtractInterfaceOptions( ISyntaxFactsService syntaxFactsService, INotificationService notificationService, List extractableMembers, @@ -52,6 +46,8 @@ public async Task GetExtractInterfaceOptionsAsync string languageName, CancellationToken cancellationToken) { + _threadingContext.ThrowIfNotOnUIThread(); + using var cancellationTokenSource = new CancellationTokenSource(); var memberViewModels = extractableMembers @@ -64,8 +60,6 @@ public async Task GetExtractInterfaceOptionsAsync IsCheckable = true }); - await _threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); - var viewModel = new ExtractInterfaceDialogViewModel( syntaxFactsService, _uiThreadOperationExecutor, diff --git a/src/VisualStudio/Core/Def/FindReferences/FindReferencesTableControlEventProcessorProvider.cs b/src/VisualStudio/Core/Def/FindReferences/FindReferencesTableControlEventProcessorProvider.cs index 2cefa56ca343a..c3481b75b1ad3 100644 --- a/src/VisualStudio/Core/Def/FindReferences/FindReferencesTableControlEventProcessorProvider.cs +++ b/src/VisualStudio/Core/Def/FindReferences/FindReferencesTableControlEventProcessorProvider.cs @@ -77,7 +77,7 @@ async static Task ProcessNavigateAsync( { using var token = listener.BeginAsyncOperation(nameof(ProcessNavigateAsync)); using var context = operationExecutor.BeginExecute( - ServicesVSResources.IntelliSense, + EditorFeaturesResources.IntelliSense, EditorFeaturesResources.Navigating, allowCancellation: true, showProgress: false); diff --git a/src/VisualStudio/Core/Def/FindReferences/StreamingFindUsagesPresenter.cs b/src/VisualStudio/Core/Def/FindReferences/StreamingFindUsagesPresenter.cs index b3873f7f49ab3..69a9189727488 100644 --- a/src/VisualStudio/Core/Def/FindReferences/StreamingFindUsagesPresenter.cs +++ b/src/VisualStudio/Core/Def/FindReferences/StreamingFindUsagesPresenter.cs @@ -128,7 +128,7 @@ private StreamingFindUsagesPresenter( return classificationFormatMapService.GetClassificationFormatMap("tooltip"); }); - _customColumns = columns.ToImmutableArray(); + _customColumns = [.. columns]; } public IClassificationFormatMap ClassificationFormatMap diff --git a/src/VisualStudio/Core/Def/FindReferences/VisualStudioDefinitionsAndReferencesFactory.cs b/src/VisualStudio/Core/Def/FindReferences/VisualStudioDefinitionsAndReferencesFactory.cs index 5612e9ad117b1..ae220ec7ea130 100644 --- a/src/VisualStudio/Core/Def/FindReferences/VisualStudioDefinitionsAndReferencesFactory.cs +++ b/src/VisualStudio/Core/Def/FindReferences/VisualStudioDefinitionsAndReferencesFactory.cs @@ -79,7 +79,7 @@ private sealed class ExternalDefinitionItem( : DefinitionItem( tags, displayParts, - nameDisplayParts: ImmutableArray.Empty, + nameDisplayParts: [], sourceSpans: default, metadataLocations: default, classifiedSpans: default, diff --git a/src/VisualStudio/Core/Def/GenerateType/GenerateTypeDialog.xaml.cs b/src/VisualStudio/Core/Def/GenerateType/GenerateTypeDialog.xaml.cs index e2e3dd917a8e6..6faa8ef9f0fcd 100644 --- a/src/VisualStudio/Core/Def/GenerateType/GenerateTypeDialog.xaml.cs +++ b/src/VisualStudio/Core/Def/GenerateType/GenerateTypeDialog.xaml.cs @@ -8,6 +8,7 @@ using System.Windows; using System.Windows.Controls; using System.Windows.Input; +using Microsoft.CodeAnalysis; using Microsoft.VisualStudio.PlatformUI; namespace Microsoft.VisualStudio.LanguageServices.Implementation.GenerateType; @@ -31,7 +32,7 @@ internal partial class GenerateTypeDialog : DialogWindow public string CreateNewFile { get { return ServicesVSResources.Create_new_file; } } public string AddToExistingFile { get { return ServicesVSResources.Add_to_existing_file; } } public string OK { get { return ServicesVSResources.OK; } } - public string Cancel { get { return ServicesVSResources.Cancel; } } + public string Cancel { get { return EditorFeaturesResources.Cancel; } } public GenerateTypeDialog(GenerateTypeDialogViewModel viewModel) : base("vsl.GenerateFromUsage") diff --git a/src/VisualStudio/Core/Def/GenerateType/GenerateTypeDialogViewModel.cs b/src/VisualStudio/Core/Def/GenerateType/GenerateTypeDialogViewModel.cs index b7fd599a1c4e6..b09e2a56571da 100644 --- a/src/VisualStudio/Core/Def/GenerateType/GenerateTypeDialogViewModel.cs +++ b/src/VisualStudio/Core/Def/GenerateType/GenerateTypeDialogViewModel.cs @@ -301,7 +301,7 @@ internal bool TrySubmit() var lastIndexOfSeparatorInFullPath = this.FullFilePath.LastIndexOf('\\'); if (lastIndexOfSeparatorInFullPath != -1) { - var fileNameInFullPathInContainers = this.FullFilePath.Split(new[] { '\\' }, StringSplitOptions.RemoveEmptyEntries); + var fileNameInFullPathInContainers = this.FullFilePath.Split(['\\'], StringSplitOptions.RemoveEmptyEntries); // Trim spaces of each component of the file name. // Note that path normalization changed between 4.6.1 and 4.6.2 and GetFullPath no longer trims trailing spaces. @@ -323,13 +323,13 @@ internal bool TrySubmit() { // The new file will be within the root of the project var folderPath = this.FullFilePath[projectRootPath.Length..]; - var containers = folderPath.Split(new[] { '\\' }, StringSplitOptions.RemoveEmptyEntries); + var containers = folderPath.Split(['\\'], StringSplitOptions.RemoveEmptyEntries); // Folder name was mentioned if (containers.Length > 1) { _fileName = containers.Last(); - Folders = new List(containers); + Folders = [.. containers]; Folders.RemoveAt(Folders.Count - 1); if (Folders.Any(folder => !(_syntaxFactsService.IsValidIdentifier(folder) || _syntaxFactsService.IsVerbatimIdentifier(folder)))) @@ -365,7 +365,7 @@ internal bool TrySubmit() } // Check for reserved words in the folder or filename - if (this.FullFilePath.Split(new[] { '\\' }, StringSplitOptions.RemoveEmptyEntries).Any(s => _reservedKeywords.Contains(s, StringComparer.OrdinalIgnoreCase))) + if (this.FullFilePath.Split(['\\'], StringSplitOptions.RemoveEmptyEntries).Any(s => _reservedKeywords.Contains(s, StringComparer.OrdinalIgnoreCase))) { SendFailureNotification(ServicesVSResources.File_path_cannot_use_reserved_keywords); return false; diff --git a/src/VisualStudio/Core/Def/Implementation/AbstractOleCommandTarget.cs b/src/VisualStudio/Core/Def/Implementation/AbstractOleCommandTarget.cs index a961de850f148..937c7342b8289 100644 --- a/src/VisualStudio/Core/Def/Implementation/AbstractOleCommandTarget.cs +++ b/src/VisualStudio/Core/Def/Implementation/AbstractOleCommandTarget.cs @@ -5,6 +5,7 @@ using System.Diagnostics.CodeAnalysis; using System.Runtime.InteropServices; using Microsoft.CodeAnalysis.Editor.Shared.Extensions; +using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.VisualStudio.ComponentModelHost; using Microsoft.VisualStudio.Editor; using Microsoft.VisualStudio.OLE.Interop; @@ -35,6 +36,7 @@ public AbstractOleCommandTarget( } public IComponentModel ComponentModel { get; } + protected IThreadingContext ThreadingContext => ComponentModel.GetService(); public IVsEditorAdaptersFactoryService EditorAdaptersFactory { diff --git a/src/VisualStudio/Core/Def/Implementation/AbstractVsTextViewFilter.cs b/src/VisualStudio/Core/Def/Implementation/AbstractVsTextViewFilter.cs index 743ec6bcd082b..c76b3b9699c59 100644 --- a/src/VisualStudio/Core/Def/Implementation/AbstractVsTextViewFilter.cs +++ b/src/VisualStudio/Core/Def/Implementation/AbstractVsTextViewFilter.cs @@ -7,6 +7,7 @@ using System; using System.Linq; using System.Threading; +using System.Threading.Tasks; using Microsoft.CodeAnalysis.BraceMatching; using Microsoft.CodeAnalysis.Debugging; using Microsoft.CodeAnalysis.Editor; @@ -29,26 +30,24 @@ namespace Microsoft.VisualStudio.LanguageServices.Implementation; -internal abstract class AbstractVsTextViewFilter : AbstractOleCommandTarget, IVsTextViewFilter +internal abstract class AbstractVsTextViewFilter( + IWpfTextView wpfTextView, + IComponentModel componentModel) : AbstractOleCommandTarget(wpfTextView, componentModel), IVsTextViewFilter { - public AbstractVsTextViewFilter( - IWpfTextView wpfTextView, - IComponentModel componentModel) - : base(wpfTextView, componentModel) + int IVsTextViewFilter.GetDataTipText(TextSpan[] pSpan, out string pbstrText) { + (pbstrText, var result) = this.ThreadingContext.JoinableTaskFactory.Run(() => GetDataTipTextAsync(pSpan)); + return result; } - int IVsTextViewFilter.GetDataTipText(TextSpan[] pSpan, out string pbstrText) + private async Task<(string pbstrText, int result)> GetDataTipTextAsync(TextSpan[] pSpan) { try { if (pSpan == null || pSpan.Length != 1) - { - pbstrText = null; - return VSConstants.E_INVALIDARG; - } + return (null, VSConstants.E_INVALIDARG); - return GetDataTipTextImpl(pSpan, out pbstrText); + return await GetDataTipTextImplAsync(pSpan).ConfigureAwait(true); } catch (Exception e) when (FatalError.ReportAndCatch(e) && false) { @@ -56,114 +55,96 @@ int IVsTextViewFilter.GetDataTipText(TextSpan[] pSpan, out string pbstrText) } } - protected virtual int GetDataTipTextImpl(TextSpan[] pSpan, out string pbstrText) + protected virtual async Task<(string pbstrText, int result)> GetDataTipTextImplAsync(TextSpan[] pSpan) { var subjectBuffer = WpfTextView.GetBufferContainingCaret(); if (subjectBuffer == null) - { - pbstrText = null; - return VSConstants.E_FAIL; - } + return (null, VSConstants.E_FAIL); - return GetDataTipTextImpl(subjectBuffer, pSpan, out pbstrText); + return await GetDataTipTextImplAsync(subjectBuffer, pSpan).ConfigureAwait(true); } - protected int GetDataTipTextImpl(ITextBuffer subjectBuffer, TextSpan[] pSpan, out string pbstrText) + protected async Task<(string pbstrText, int result)> GetDataTipTextImplAsync(ITextBuffer subjectBuffer, TextSpan[] pSpan) { - pbstrText = null; - var vsBuffer = EditorAdaptersFactory.GetBufferAdapter(subjectBuffer); // TODO: broken in REPL if (vsBuffer == null) - { - return VSConstants.E_FAIL; - } + return (null, VSConstants.E_FAIL); using (Logger.LogBlock(FunctionId.Debugging_VsLanguageDebugInfo_GetDataTipText, CancellationToken.None)) { - pbstrText = null; if (pSpan == null || pSpan.Length != 1) - { - return VSConstants.E_INVALIDARG; - } + return (null, VSConstants.E_INVALIDARG); var result = VSConstants.E_FAIL; - string pbstrTextInternal = null; + string pbstrText = null; var uiThreadOperationExecutor = ComponentModel.GetService(); - uiThreadOperationExecutor.Execute( + using var context = uiThreadOperationExecutor.BeginExecute( title: ServicesVSResources.Debugger, defaultDescription: ServicesVSResources.Getting_DataTip_text, allowCancellation: true, - showProgress: false, - action: context => - { - IServiceProvider serviceProvider = ComponentModel.GetService(); - var debugger = (IVsDebugger)serviceProvider.GetService(typeof(SVsShellDebugger)); - var debugMode = new DBGMODE[1]; + showProgress: false); - var cancellationToken = context.UserCancellationToken; - if (ErrorHandler.Succeeded(debugger.GetMode(debugMode)) && debugMode[0] != DBGMODE.DBGMODE_Design) - { - var textSpan = pSpan[0]; + IServiceProvider serviceProvider = ComponentModel.GetService(); + var debugger = (IVsDebugger)serviceProvider.GetService(typeof(SVsShellDebugger)); + var debugMode = new DBGMODE[1]; + + var cancellationToken = context.UserCancellationToken; + if (ErrorHandler.Succeeded(debugger.GetMode(debugMode)) && debugMode[0] != DBGMODE.DBGMODE_Design) + { + var textSpan = pSpan[0]; - var textSnapshot = subjectBuffer.CurrentSnapshot; - var document = textSnapshot.GetOpenDocumentInCurrentContextWithChanges(); + var textSnapshot = subjectBuffer.CurrentSnapshot; + var document = textSnapshot.GetOpenDocumentInCurrentContextWithChanges(); - if (document != null) + if (document != null) + { + var languageDebugInfo = document.Project.Services.GetService(); + if (languageDebugInfo != null) { - var languageDebugInfo = document.Project.Services.GetService(); - if (languageDebugInfo != null) + var spanOpt = textSnapshot.TryGetSpan(textSpan); + if (spanOpt.HasValue) { - var spanOpt = textSnapshot.TryGetSpan(textSpan); - if (spanOpt.HasValue) + // 'kind' is an lsp-only concept, so we don't want/need to include it here (especially + // as it can be expensive to compute, and we don't want to block the UI thread). + var dataTipInfo = await languageDebugInfo.GetDataTipInfoAsync( + document, spanOpt.Value.Start, includeKind: false, cancellationToken).ConfigureAwait(true); + if (!dataTipInfo.IsDefault) { - var dataTipInfo = languageDebugInfo.GetDataTipInfoAsync(document, spanOpt.Value.Start, cancellationToken).WaitAndGetResult(cancellationToken); - if (!dataTipInfo.IsDefault) - { - var resultSpan = dataTipInfo.Span.ToSnapshotSpan(textSnapshot); - var textOpt = dataTipInfo.Text; + var resultSpan = dataTipInfo.Span.ToSnapshotSpan(textSnapshot); + var textOpt = dataTipInfo.Text; - pSpan[0] = resultSpan.ToVsTextSpan(); - result = debugger.GetDataTipValue((IVsTextLines)vsBuffer, pSpan, textOpt, out pbstrTextInternal); - } + pSpan[0] = resultSpan.ToVsTextSpan(); + result = debugger.GetDataTipValue((IVsTextLines)vsBuffer, pSpan, textOpt, out pbstrText); } } } } - }); + } - pbstrText = pbstrTextInternal; - return result; + return (pbstrText, result); } } int IVsTextViewFilter.GetPairExtents(int iLine, int iIndex, TextSpan[] pSpan) { - try - { - var result = VSConstants.S_OK; - ComponentModel.GetService().Execute( - "Intellisense", - defaultDescription: "", - allowCancellation: true, - showProgress: false, - action: c => result = GetPairExtentsWorker(iLine, iIndex, pSpan, c.UserCancellationToken)); - - return result; - } - catch (Exception e) when (FatalError.ReportAndCatch(e) && false) - { - throw ExceptionUtilities.Unreachable(); - } + return this.ThreadingContext.JoinableTaskFactory.Run(() => GetPairExtentsAsync(iLine, iIndex, pSpan)); } - private int GetPairExtentsWorker(int iLine, int iIndex, TextSpan[] pSpan, CancellationToken cancellationToken) + private async Task GetPairExtentsAsync(int iLine, int iIndex, TextSpan[] pSpan) { + using var waitContext = ComponentModel.GetService().BeginExecute( + "Intellisense", + defaultDescription: "", + allowCancellation: true, + showProgress: false); + var braceMatcher = ComponentModel.GetService(); var globalOptions = ComponentModel.GetService(); - return GetPairExtentsWorker( + + return await GetPairExtentsAsync( WpfTextView, braceMatcher, globalOptions, @@ -171,11 +152,19 @@ private int GetPairExtentsWorker(int iLine, int iIndex, TextSpan[] pSpan, Cancel iIndex, pSpan, (VSConstants.VSStd2KCmdID)this.CurrentlyExecutingCommand == VSConstants.VSStd2KCmdID.GOTOBRACE_EXT, - cancellationToken); + waitContext.UserCancellationToken).ConfigureAwait(true); } // Internal for testing purposes - internal static int GetPairExtentsWorker(ITextView textView, IBraceMatchingService braceMatcher, IGlobalOptionService globalOptions, int iLine, int iIndex, TextSpan[] pSpan, bool extendSelection, CancellationToken cancellationToken) + internal static async Task GetPairExtentsAsync( + ITextView textView, + IBraceMatchingService braceMatcher, + IGlobalOptionService globalOptions, + int iLine, + int iIndex, + TextSpan[] pSpan, + bool extendSelection, + CancellationToken cancellationToken) { pSpan[0].iStartLine = pSpan[0].iEndLine = iLine; pSpan[0].iStartIndex = pSpan[0].iEndIndex = iIndex; @@ -199,7 +188,8 @@ internal static int GetPairExtentsWorker(ITextView textView, IBraceMatchingServi if (document != null) { var options = globalOptions.GetBraceMatchingOptions(document.Project.Language); - var matchingSpan = braceMatcher.FindMatchingSpanAsync(document, position, options, cancellationToken).WaitAndGetResult(cancellationToken); + var matchingSpan = await braceMatcher.FindMatchingSpanAsync( + document, position, options, cancellationToken).ConfigureAwait(true); if (matchingSpan.HasValue) { @@ -233,7 +223,8 @@ internal static int GetPairExtentsWorker(ITextView textView, IBraceMatchingServi if (extendSelection) { // case a. - var closingSpans = braceMatcher.FindMatchingSpanAsync(document, matchingSpan.Value.Start, options, cancellationToken).WaitAndGetResult(cancellationToken); + var closingSpans = await braceMatcher.FindMatchingSpanAsync( + document, matchingSpan.Value.Start, options, cancellationToken).ConfigureAwait(true); var vsClosingSpans = textView.GetSpanInView(closingSpans.Value.ToSnapshotSpan(subjectBuffer.CurrentSnapshot)).First().ToVsTextSpan(); pSpan[0].iEndIndex = vsClosingSpans.iStartIndex; } @@ -252,7 +243,8 @@ internal static int GetPairExtentsWorker(ITextView textView, IBraceMatchingServi pSpan[0].iEndIndex = vsTextSpan.iStartIndex; // case b. - var openingSpans = braceMatcher.FindMatchingSpanAsync(document, matchingSpan.Value.End, options, cancellationToken).WaitAndGetResult(cancellationToken); + var openingSpans = await braceMatcher.FindMatchingSpanAsync( + document, matchingSpan.Value.End, options, cancellationToken).ConfigureAwait(true); var vsOpeningSpans = textView.GetSpanInView(openingSpans.Value.ToSnapshotSpan(subjectBuffer.CurrentSnapshot)).First().ToVsTextSpan(); pSpan[0].iStartIndex = vsOpeningSpans.iStartIndex; } diff --git a/src/VisualStudio/Core/Def/Implementation/GCManager.cs b/src/VisualStudio/Core/Def/Implementation/GCManager.cs index c80c0b07d6ea1..efa797441fc1e 100644 --- a/src/VisualStudio/Core/Def/Implementation/GCManager.cs +++ b/src/VisualStudio/Core/Def/Implementation/GCManager.cs @@ -85,14 +85,26 @@ internal static void UseLowLatencyModeForProcessingUserInput() { GCSettings.LatencyMode = GCLatencyMode.SustainedLowLatency; - // Restore the LatencyMode a short duration after the - // last request to UseLowLatencyModeForProcessingUserInput. + // Restore the LatencyMode a short duration after the last UseLowLatencyModeForProcessingUserInput. currentDelay = new ResettableDelay(s_delayMilliseconds, AsynchronousOperationListenerProvider.NullListener); - currentDelay.Task.SafeContinueWith(_ => RestoreGCLatencyMode(currentMode), TaskScheduler.Default); + RestoreGCLatencyModeWhenCompleteAsync(currentDelay.Task, currentMode).ReportNonFatalErrorAsync(); s_delay = currentDelay; } currentDelay?.Reset(); + return; + + async Task RestoreGCLatencyModeWhenCompleteAsync(Task task, GCLatencyMode latencyMode) + { + try + { + await task.ConfigureAwait(false); + } + finally + { + RestoreGCLatencyMode(latencyMode); + } + } } private static void RestoreGCLatencyMode(GCLatencyMode originalMode) diff --git a/src/VisualStudio/Core/Def/Implementation/StandaloneCommandFilter.cs b/src/VisualStudio/Core/Def/Implementation/StandaloneCommandFilter.cs index 9207321afefe6..b55df9237b541 100644 --- a/src/VisualStudio/Core/Def/Implementation/StandaloneCommandFilter.cs +++ b/src/VisualStudio/Core/Def/Implementation/StandaloneCommandFilter.cs @@ -10,16 +10,5 @@ namespace Microsoft.VisualStudio.LanguageServices.Implementation; /// /// A CommandFilter used for "normal" files, as opposed to Venus files which are special. /// -internal sealed class StandaloneCommandFilter : AbstractVsTextViewFilter -{ - /// - /// Creates a new command handler that is attached to an IVsTextView. - /// - /// The IWpfTextView of the view. - internal StandaloneCommandFilter( - IWpfTextView wpfTextView, - IComponentModel componentModel) - : base(wpfTextView, componentModel) - { - } -} +internal sealed class StandaloneCommandFilter( + IWpfTextView wpfTextView, IComponentModel componentModel) : AbstractVsTextViewFilter(wpfTextView, componentModel); diff --git a/src/VisualStudio/Core/Def/InheritanceMargin/InheritanceMarginHelpers.cs b/src/VisualStudio/Core/Def/InheritanceMargin/InheritanceMarginHelpers.cs index b9764f5656baa..e132c496fe1d5 100644 --- a/src/VisualStudio/Core/Def/InheritanceMargin/InheritanceMarginHelpers.cs +++ b/src/VisualStudio/Core/Def/InheritanceMargin/InheritanceMarginHelpers.cs @@ -107,10 +107,9 @@ public static ImmutableArray CreateModelsForMarginItem(Inheri foreach (var target in targets) nameToTargets.Add(target.DisplayName, target); - return item.TargetItems + return [.. item.TargetItems .GroupBy(t => t.RelationToMember) - .SelectMany(g => CreateMenuItemsWithHeader(item, g.Key, g, nameToTargets)) - .ToImmutableArray(); + .SelectMany(g => CreateMenuItemsWithHeader(item, g.Key, g, nameToTargets))]; } finally { diff --git a/src/VisualStudio/Core/Def/Interactive/VsInteractiveWindowProvider.cs b/src/VisualStudio/Core/Def/Interactive/VsInteractiveWindowProvider.cs index 44603eea333e1..bd38aac5f3580 100644 --- a/src/VisualStudio/Core/Def/Interactive/VsInteractiveWindowProvider.cs +++ b/src/VisualStudio/Core/Def/Interactive/VsInteractiveWindowProvider.cs @@ -182,6 +182,6 @@ private static ImmutableArray GetApplicableCommands(I } } - return interactiveCommands.ToImmutableArray(); + return [.. interactiveCommands]; } } diff --git a/src/VisualStudio/Core/Def/Interactive/VsResetInteractive.cs b/src/VisualStudio/Core/Def/Interactive/VsResetInteractive.cs index cabb6c4c76942..cc791e64cfe58 100644 --- a/src/VisualStudio/Core/Def/Interactive/VsResetInteractive.cs +++ b/src/VisualStudio/Core/Def/Interactive/VsResetInteractive.cs @@ -67,10 +67,10 @@ protected override bool GetProjectProperties( { var hierarchyPointer = default(IntPtr); var selectionContainerPointer = default(IntPtr); - references = ImmutableArray.Empty; - referenceSearchPaths = ImmutableArray.Empty; - sourceSearchPaths = ImmutableArray.Empty; - projectNamespaces = ImmutableArray.Empty; + references = []; + referenceSearchPaths = []; + sourceSearchPaths = []; + projectNamespaces = []; projectDirectory = null; platform = null; diff --git a/src/VisualStudio/Core/Def/KeybindingReset/KeybindingResetDetector.cs b/src/VisualStudio/Core/Def/KeybindingReset/KeybindingResetDetector.cs index 0711327e2ebf1..e94d9c9579b6b 100644 --- a/src/VisualStudio/Core/Def/KeybindingReset/KeybindingResetDetector.cs +++ b/src/VisualStudio/Core/Def/KeybindingReset/KeybindingResetDetector.cs @@ -163,10 +163,15 @@ private void StartUpdateStateMachine() // make sure all state machine change work is serialized so that cancellation // doesn't mess the state up. - _lastTask = _lastTask.SafeContinueWithFromAsync(_ => + _lastTask = ContinueAsync(_lastTask); + + async Task ContinueAsync(Task task) { - return UpdateStateMachineWorkerAsync(cancellationToken); - }, cancellationToken, TaskScheduler.Default); + // We always want to run UpdateStateMachineWorkerAsync no matter what happens with the prior task. So we use + // NoThrowAwaitableInternal to ensure that we always continue. + await task.NoThrowAwaitableInternal(captureContext: false); + await UpdateStateMachineWorkerAsync(cancellationToken).ConfigureAwait(false); + } } private async Task UpdateStateMachineWorkerAsync(CancellationToken cancellationToken) diff --git a/src/VisualStudio/Core/Def/LanguageService/AbstractLanguageService`2.IVsLanguageContextProvider.cs b/src/VisualStudio/Core/Def/LanguageService/AbstractLanguageService`2.IVsLanguageContextProvider.cs index 6528a1415ed3e..e2da72836fe0e 100644 --- a/src/VisualStudio/Core/Def/LanguageService/AbstractLanguageService`2.IVsLanguageContextProvider.cs +++ b/src/VisualStudio/Core/Def/LanguageService/AbstractLanguageService`2.IVsLanguageContextProvider.cs @@ -2,15 +2,12 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System.Threading; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.LanguageServices.Implementation.F1Help; using Microsoft.VisualStudio.Shell.Interop; using Microsoft.VisualStudio.TextManager.Interop; -using Roslyn.Utilities; namespace Microsoft.VisualStudio.LanguageServices.Implementation.LanguageService; @@ -18,45 +15,41 @@ internal abstract partial class AbstractLanguageService { - return VSConstants.E_UNEXPECTED; - } + var textBuffer = EditorAdaptersFactoryService.GetDataBuffer(pBuffer); + var context = (IVsUserContext)pUC; - var document = textBuffer.CurrentSnapshot.GetOpenDocumentInCurrentContextWithChanges(); - if (document == null) - { - return VSConstants.E_FAIL; - } + if (textBuffer == null || context == null) + return VSConstants.E_UNEXPECTED; - var start = textBuffer.CurrentSnapshot.GetLineFromLineNumber(ptsSelection[0].iStartLine).Start + ptsSelection[0].iStartIndex; - var end = textBuffer.CurrentSnapshot.GetLineFromLineNumber(ptsSelection[0].iEndLine).Start + ptsSelection[0].iEndIndex; - var span = Microsoft.CodeAnalysis.Text.TextSpan.FromBounds(start, end); + var document = textBuffer.CurrentSnapshot.GetOpenDocumentInCurrentContextWithChanges(); + if (document == null) + return VSConstants.E_FAIL; - var helpService = document.GetLanguageService(); - if (helpService == null) - { - return VSConstants.E_NOTIMPL; - } + var start = textBuffer.CurrentSnapshot.GetLineFromLineNumber(ptsSelection[0].iStartLine).Start + ptsSelection[0].iStartIndex; + var end = textBuffer.CurrentSnapshot.GetLineFromLineNumber(ptsSelection[0].iEndLine).Start + ptsSelection[0].iEndIndex; + var span = Microsoft.CodeAnalysis.Text.TextSpan.FromBounds(start, end); - // VS help is not cancellable. - var cancellationToken = CancellationToken.None; - var helpTerm = helpService.GetHelpTermAsync(document, span, cancellationToken).WaitAndGetResult(cancellationToken); + var helpService = document.GetLanguageService(); + if (helpService == null) + return VSConstants.E_NOTIMPL; - if (string.IsNullOrWhiteSpace(helpTerm)) - { - return VSConstants.S_FALSE; - } + // VS help is not cancellable. + var cancellationToken = CancellationToken.None; + var helpTerm = await helpService.GetHelpTermAsync( + document, span, cancellationToken).ConfigureAwait(true); + + if (string.IsNullOrWhiteSpace(helpTerm)) + return VSConstants.S_FALSE; - context.RemoveAttribute("keyword", null); - context.AddAttribute(VSUSERCONTEXTATTRIBUTEUSAGE.VSUC_Usage_Filter, "devlang", helpService.Language); - context.AddAttribute(VSUSERCONTEXTATTRIBUTEUSAGE.VSUC_Usage_Filter, "product", helpService.Product); - context.AddAttribute(VSUSERCONTEXTATTRIBUTEUSAGE.VSUC_Usage_Filter, "product", "VS"); - context.AddAttribute(VSUSERCONTEXTATTRIBUTEUSAGE.VSUC_Usage_LookupF1_CaseSensitive, "keyword", helpTerm); + context.RemoveAttribute("keyword", null); + context.AddAttribute(VSUSERCONTEXTATTRIBUTEUSAGE.VSUC_Usage_Filter, "devlang", helpService.Language); + context.AddAttribute(VSUSERCONTEXTATTRIBUTEUSAGE.VSUC_Usage_Filter, "product", helpService.Product); + context.AddAttribute(VSUSERCONTEXTATTRIBUTEUSAGE.VSUC_Usage_Filter, "product", "VS"); + context.AddAttribute(VSUSERCONTEXTATTRIBUTEUSAGE.VSUC_Usage_LookupF1_CaseSensitive, "keyword", helpTerm); - return VSConstants.S_OK; + return VSConstants.S_OK; + }); } } diff --git a/src/VisualStudio/Core/Def/LanguageService/AbstractLanguageService`2.VsLanguageDebugInfo.cs b/src/VisualStudio/Core/Def/LanguageService/AbstractLanguageService`2.VsLanguageDebugInfo.cs index e068d095d46e2..abdf5313d6093 100644 --- a/src/VisualStudio/Core/Def/LanguageService/AbstractLanguageService`2.VsLanguageDebugInfo.cs +++ b/src/VisualStudio/Core/Def/LanguageService/AbstractLanguageService`2.VsLanguageDebugInfo.cs @@ -13,6 +13,7 @@ using Microsoft.CodeAnalysis.Internal.Log; using Microsoft.CodeAnalysis.Text; using Microsoft.CodeAnalysis.Text.Shared.Extensions; +using Microsoft.Internal.VisualStudio.Shell.Interop; using Microsoft.VisualStudio.LanguageServices.Implementation.Extensions; using Microsoft.VisualStudio.LanguageServices.Implementation.Utilities; using Microsoft.VisualStudio.Utilities; @@ -31,7 +32,6 @@ internal sealed class VsLanguageDebugInfo : IVsLanguageDebugInfo { private readonly Guid _languageId; private readonly TLanguageService _languageService; - private readonly IThreadingContext _threadingContext; private readonly ILanguageDebugInfoService? _languageDebugInfo; private readonly IBreakpointResolutionService? _breakpointService; private readonly IProximityExpressionsService? _proximityExpressionsService; @@ -41,7 +41,6 @@ public VsLanguageDebugInfo( Guid languageId, TLanguageService languageService, HostLanguageServices languageServiceProvider, - IThreadingContext threadingContext, IUIThreadOperationExecutor uiThreadOperationExecutor) { Contract.ThrowIfNull(languageService); @@ -49,13 +48,14 @@ public VsLanguageDebugInfo( _languageId = languageId; _languageService = languageService; - _threadingContext = threadingContext; _languageDebugInfo = languageServiceProvider.GetService(); _breakpointService = languageServiceProvider.GetService(); _proximityExpressionsService = languageServiceProvider.GetService(); _uiThreadOperationExecutor = uiThreadOperationExecutor; } + private IThreadingContext ThreadingContext => _languageService.ThreadingContext; + public int GetLanguageID(IVsTextBuffer pBuffer, int iLine, int iCol, out Guid pguidLanguageID) { pguidLanguageID = _languageId; @@ -71,109 +71,96 @@ public int GetLocationOfName(string pszName, out string? pbstrMkDoc, out VsTextS public int GetNameOfLocation(IVsTextBuffer pBuffer, int iLine, int iCol, out string? pbstrName, out int piLineOffset) { - using (Logger.LogBlock(FunctionId.Debugging_VsLanguageDebugInfo_GetNameOfLocation, CancellationToken.None)) - { - string? name = null; - var lineOffset = 0; + (pbstrName, piLineOffset) = GetNameOfLocationWorker(); - if (_languageDebugInfo != null) - { - _uiThreadOperationExecutor.Execute( - title: ServicesVSResources.Debugger, - defaultDescription: ServicesVSResources.Determining_breakpoint_location, - allowCancellation: true, - showProgress: false, - action: waitContext => - { - var cancellationToken = waitContext.UserCancellationToken; - var textBuffer = _languageService.EditorAdaptersFactoryService.GetDataBuffer(pBuffer); - if (textBuffer != null) - { - var nullablePoint = textBuffer.CurrentSnapshot.TryGetPoint(iLine, iCol); - if (nullablePoint.HasValue) - { - var point = nullablePoint.Value; - var document = point.Snapshot.GetOpenDocumentInCurrentContextWithChanges(); - - if (document != null) - { - // NOTE(cyrusn): We have to wait here because the debuggers' - // GetNameOfLocation is a blocking call. In the future, it - // would be nice if they could make it async. - _threadingContext.JoinableTaskFactory.Run(async () => - { - var debugLocationInfo = await _languageDebugInfo.GetLocationInfoAsync(document, point, cancellationToken).ConfigureAwait(false); - - if (!debugLocationInfo.IsDefault) - { - name = debugLocationInfo.Name; - lineOffset = debugLocationInfo.LineOffset; - } - }); - } - } - } - }); + // Note(DustinCa): Docs say that GetNameOfLocation should return S_FALSE if a name could not be found. + // Also, that's what the old native code does, so we should do it here. + return pbstrName != null ? VSConstants.S_OK : VSConstants.S_FALSE; - if (name != null) + (string name, int lineOffset) GetNameOfLocationWorker() + { + return this.ThreadingContext.JoinableTaskFactory.Run(async () => + { + using (Logger.LogBlock(FunctionId.Debugging_VsLanguageDebugInfo_GetNameOfLocation, CancellationToken.None)) { - pbstrName = name; - piLineOffset = lineOffset; - return VSConstants.S_OK; - } - } + if (_languageDebugInfo == null) + return default; - // Note(DustinCa): Docs say that GetNameOfLocation should return S_FALSE if a name could not be found. - // Also, that's what the old native code does, so we should do it here. - pbstrName = null; - piLineOffset = 0; - return VSConstants.S_FALSE; + using var waitContext = _uiThreadOperationExecutor.BeginExecute( + title: ServicesVSResources.Debugger, + defaultDescription: ServicesVSResources.Determining_breakpoint_location, + allowCancellation: true, + showProgress: false); + + var cancellationToken = waitContext.UserCancellationToken; + var textBuffer = _languageService.EditorAdaptersFactoryService.GetDataBuffer(pBuffer); + if (textBuffer == null) + return default; + + var nullablePoint = textBuffer.CurrentSnapshot.TryGetPoint(iLine, iCol); + if (!nullablePoint.HasValue) + return default; + + var point = nullablePoint.Value; + var document = point.Snapshot.GetOpenDocumentInCurrentContextWithChanges(); + if (document == null) + return default; + + // NOTE(cyrusn): We have to wait here because the debuggers' + // GetNameOfLocation is a blocking call. In the future, it + // would be nice if they could make it async. + var debugLocationInfo = await _languageDebugInfo.GetLocationInfoAsync(document, point, cancellationToken).ConfigureAwait(true); + + if (debugLocationInfo.IsDefault) + return default; + + return (debugLocationInfo.Name, debugLocationInfo.LineOffset); + } + }); } } public int GetProximityExpressions(IVsTextBuffer pBuffer, int iLine, int iCol, int cLines, out IVsEnumBSTR? ppEnum) { - // NOTE(cyrusn): cLines is ignored. This is to match existing dev10 behavior. - using (Logger.LogBlock(FunctionId.Debugging_VsLanguageDebugInfo_GetProximityExpressions, CancellationToken.None)) + ppEnum = this.ThreadingContext.JoinableTaskFactory.Run(async () => { - VsEnumBSTR? enumBSTR = null; - - if (_proximityExpressionsService != null) + // NOTE(cyrusn): cLines is ignored. This is to match existing dev10 behavior. + using (Logger.LogBlock(FunctionId.Debugging_VsLanguageDebugInfo_GetProximityExpressions, CancellationToken.None)) { - _uiThreadOperationExecutor.Execute( + using var context = _uiThreadOperationExecutor.BeginExecute( title: ServicesVSResources.Debugger, defaultDescription: ServicesVSResources.Determining_autos, allowCancellation: true, - showProgress: false, - action: context => - { - var textBuffer = _languageService.EditorAdaptersFactoryService.GetDataBuffer(pBuffer); + showProgress: false); - if (textBuffer != null) - { - var snapshot = textBuffer.CurrentSnapshot; - var nullablePoint = snapshot.TryGetPoint(iLine, iCol); - if (nullablePoint.HasValue) - { - var document = snapshot.GetOpenDocumentInCurrentContextWithChanges(); - if (document != null) - { - var point = nullablePoint.Value; - var proximityExpressions = _proximityExpressionsService.GetProximityExpressionsAsync(document, point.Position, context.UserCancellationToken).WaitAndGetResult(context.UserCancellationToken); - - if (proximityExpressions != null) - { - enumBSTR = new VsEnumBSTR(proximityExpressions); - } - } - } - } - }); + if (_proximityExpressionsService == null) + return null; + + var textBuffer = _languageService.EditorAdaptersFactoryService.GetDataBuffer(pBuffer); + if (textBuffer == null) + return null; + + var snapshot = textBuffer.CurrentSnapshot; + var nullablePoint = snapshot.TryGetPoint(iLine, iCol); + if (!nullablePoint.HasValue) + return null; + + var document = snapshot.GetOpenDocumentInCurrentContextWithChanges(); + if (document == null) + return null; + + var point = nullablePoint.Value; + var proximityExpressions = await _proximityExpressionsService.GetProximityExpressionsAsync( + document, point.Position, context.UserCancellationToken).ConfigureAwait(true); + + if (proximityExpressions == null) + return null; + + return new VsEnumBSTR(proximityExpressions); } + }); - ppEnum = enumBSTR; - return ppEnum != null ? VSConstants.S_OK : VSConstants.E_FAIL; - } + return ppEnum != null ? VSConstants.S_OK : VSConstants.E_FAIL; } public int IsMappedLocation(IVsTextBuffer pBuffer, int iLine, int iCol) @@ -181,51 +168,49 @@ public int IsMappedLocation(IVsTextBuffer pBuffer, int iLine, int iCol) public int ResolveName(string pszName, uint dwFlags, out IVsEnumDebugName? ppNames) { - using (Logger.LogBlock(FunctionId.Debugging_VsLanguageDebugInfo_ResolveName, CancellationToken.None)) + // In VS, this method frequently get's called with an empty string to test if the language service + // supports this method (some language services, like F#, implement IVsLanguageDebugInfo but don't + // implement this method). In that scenario, there's no sense doing work, so we'll just return + // S_FALSE (as the old VB language service did). + if (string.IsNullOrEmpty(pszName)) { - // In VS, this method frequently get's called with an empty string to test if the language service - // supports this method (some language services, like F#, implement IVsLanguageDebugInfo but don't - // implement this method). In that scenario, there's no sense doing work, so we'll just return - // S_FALSE (as the old VB language service did). - if (string.IsNullOrEmpty(pszName)) - { - ppNames = null; - return VSConstants.S_FALSE; - } + ppNames = null; + return VSConstants.S_FALSE; + } - VsEnumDebugName? enumName = null; - _uiThreadOperationExecutor.Execute( - title: ServicesVSResources.Debugger, - defaultDescription: ServicesVSResources.Resolving_breakpoint_location, - allowCancellation: true, - showProgress: false, - action: waitContext => + ppNames = this.ThreadingContext.JoinableTaskFactory.Run(async () => + { + using (Logger.LogBlock(FunctionId.Debugging_VsLanguageDebugInfo_ResolveName, CancellationToken.None)) { - _threadingContext.JoinableTaskFactory.Run(async () => + using var waitContext = _uiThreadOperationExecutor.BeginExecute( + title: ServicesVSResources.Debugger, + defaultDescription: ServicesVSResources.Resolving_breakpoint_location, + allowCancellation: true, + showProgress: false); + + var cancellationToken = waitContext.UserCancellationToken; + if (dwFlags == (uint)RESOLVENAMEFLAGS.RNF_BREAKPOINT) { - var cancellationToken = waitContext.UserCancellationToken; - if (dwFlags == (uint)RESOLVENAMEFLAGS.RNF_BREAKPOINT) - { - var solution = _languageService.Workspace.CurrentSolution; + var solution = _languageService.Workspace.CurrentSolution; - // NOTE(cyrusn): We have to wait here because the debuggers' ResolveName - // call is synchronous. In the future it would be nice to make it async. - if (_breakpointService != null) - { - var breakpoints = await _breakpointService.ResolveBreakpointsAsync( - solution, pszName, cancellationToken).ConfigureAwait(false); - var debugNames = await breakpoints.SelectAsArrayAsync( - bp => CreateDebugNameAsync(bp, cancellationToken)).ConfigureAwait(false); + // NOTE(cyrusn): We have to wait here because the debuggers' ResolveName + // call is synchronous. In the future it would be nice to make it async. + if (_breakpointService != null) + { + var breakpoints = await _breakpointService.ResolveBreakpointsAsync( + solution, pszName, cancellationToken).ConfigureAwait(false); + var debugNames = await breakpoints.SelectAsArrayAsync( + bp => CreateDebugNameAsync(bp, cancellationToken)).ConfigureAwait(true); - enumName = new VsEnumDebugName(debugNames); - } + return new VsEnumDebugName(debugNames); } - }); - }); + } + } - ppNames = enumName; - return ppNames != null ? VSConstants.S_OK : VSConstants.E_NOTIMPL; - } + return null; + }); + + return ppNames != null ? VSConstants.S_OK : VSConstants.E_NOTIMPL; } private async ValueTask CreateDebugNameAsync( @@ -238,7 +223,7 @@ private async ValueTask CreateDebugNameAsync( // If we're inside an Venus code nugget, we need to map the span to the surface buffer. // Otherwise, we'll just use the original span. var mappedSpan = await span.MapSpanFromSecondaryBufferToPrimaryBufferAsync( - _threadingContext, document.Id, cancellationToken).ConfigureAwait(false); + this.ThreadingContext, document.Id, cancellationToken).ConfigureAwait(true); if (mappedSpan != null) span = mappedSpan.Value; @@ -247,24 +232,23 @@ private async ValueTask CreateDebugNameAsync( public int ValidateBreakpointLocation(IVsTextBuffer pBuffer, int iLine, int iCol, VsTextSpan[] pCodeSpan) { - using (Logger.LogBlock(FunctionId.Debugging_VsLanguageDebugInfo_ValidateBreakpointLocation, CancellationToken.None)) + return this.ThreadingContext.JoinableTaskFactory.Run(async () => { - var result = VSConstants.E_NOTIMPL; - _uiThreadOperationExecutor.Execute( - title: ServicesVSResources.Debugger, - defaultDescription: ServicesVSResources.Validating_breakpoint_location, - allowCancellation: true, - showProgress: false, - action: waitContext => + using (Logger.LogBlock(FunctionId.Debugging_VsLanguageDebugInfo_ValidateBreakpointLocation, CancellationToken.None)) { - result = ValidateBreakpointLocationWorker(pBuffer, iLine, iCol, pCodeSpan, waitContext.UserCancellationToken); - }); + using var waitContext = _uiThreadOperationExecutor.BeginExecute( + title: ServicesVSResources.Debugger, + defaultDescription: ServicesVSResources.Validating_breakpoint_location, + allowCancellation: true, + showProgress: false); - return result; - } + return await ValidateBreakpointLocationAsync( + pBuffer, iLine, iCol, pCodeSpan, waitContext.UserCancellationToken).ConfigureAwait(true); + } + }); } - private int ValidateBreakpointLocationWorker( + private async Task ValidateBreakpointLocationAsync( IVsTextBuffer pBuffer, int iLine, int iCol, @@ -272,9 +256,7 @@ private int ValidateBreakpointLocationWorker( CancellationToken cancellationToken) { if (_breakpointService == null) - { return VSConstants.E_FAIL; - } var textBuffer = _languageService.EditorAdaptersFactoryService.GetDataBuffer(pBuffer); if (textBuffer != null) @@ -336,7 +318,8 @@ private int ValidateBreakpointLocationWorker( // NOTE(cyrusn): we need to wait here because ValidateBreakpointLocation is // synchronous. In the future, it would be nice for the debugger to provide // an async entry point for this. - var breakpoint = _breakpointService.ResolveBreakpointAsync(document, new TextSpan(point.Position, length), cancellationToken).WaitAndGetResult(cancellationToken); + var breakpoint = await _breakpointService.ResolveBreakpointAsync( + document, new TextSpan(point.Position, length), cancellationToken).ConfigureAwait(true); if (breakpoint == null) { // There should *not* be a breakpoint here. E_FAIL to let the debugger know @@ -357,9 +340,7 @@ private int ValidateBreakpointLocationWorker( // There should be a breakpoint at the location passed back. if (pCodeSpan != null && pCodeSpan.Length > 0) - { pCodeSpan[0] = breakpoint.TextSpan.ToSnapshotSpan(snapshot).ToVsTextSpan(); - } return VSConstants.S_OK; } diff --git a/src/VisualStudio/Core/Def/LanguageService/AbstractLanguageService`2.cs b/src/VisualStudio/Core/Def/LanguageService/AbstractLanguageService`2.cs index bac0507b76bf7..6044e5dc3227e 100644 --- a/src/VisualStudio/Core/Def/LanguageService/AbstractLanguageService`2.cs +++ b/src/VisualStudio/Core/Def/LanguageService/AbstractLanguageService`2.cs @@ -87,6 +87,8 @@ protected AbstractLanguageService(TPackage package) this._languageDebugInfo = CreateLanguageDebugInfo(); } + private IThreadingContext ThreadingContext => this.Package.ComponentModel.GetService(); + public override IServiceProvider SystemServiceProvider => Package; @@ -223,7 +225,6 @@ private VsLanguageDebugInfo CreateLanguageDebugInfo() this.DebuggerLanguageId, (TLanguageService)this, languageServices, - this.Package.ComponentModel.GetService(), this.Package.ComponentModel.GetService()); } diff --git a/src/VisualStudio/Core/Def/Library/AbstractLibraryManager.cs b/src/VisualStudio/Core/Def/Library/AbstractLibraryManager.cs index 30192aa47dcd6..1544d9983e218 100644 --- a/src/VisualStudio/Core/Def/Library/AbstractLibraryManager.cs +++ b/src/VisualStudio/Core/Def/Library/AbstractLibraryManager.cs @@ -5,6 +5,7 @@ #nullable disable using System; +using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.VisualStudio.ComponentModelHost; using Microsoft.VisualStudio.LanguageServices.Implementation.Utilities; using Microsoft.VisualStudio.Shell.Interop; @@ -16,19 +17,21 @@ internal abstract partial class AbstractLibraryManager : IVsCoTaskMemFreeMyStrin internal readonly Guid LibraryGuid; private readonly IntPtr _imageListPtr; + public readonly IThreadingContext ThreadingContext; + public readonly IComponentModel ComponentModel; + public readonly IServiceProvider ServiceProvider; + protected AbstractLibraryManager(Guid libraryGuid, IComponentModel componentModel, IServiceProvider serviceProvider) { LibraryGuid = libraryGuid; ComponentModel = componentModel; ServiceProvider = serviceProvider; + ThreadingContext = componentModel.GetService(); var vsShell = serviceProvider.GetService(typeof(SVsShell)) as IVsShell; vsShell?.TryGetPropertyValue(__VSSPROPID.VSSPROPID_ObjectMgrTypesImgList, out _imageListPtr); } - public IComponentModel ComponentModel { get; } - public IServiceProvider ServiceProvider { get; } - public IntPtr ImageListPtr { get { return _imageListPtr; } diff --git a/src/VisualStudio/Core/Def/Library/AbstractLibraryManager_IVsSimpleLibrary2.cs b/src/VisualStudio/Core/Def/Library/AbstractLibraryManager_IVsSimpleLibrary2.cs index e51594f7c63a2..273af5f942103 100644 --- a/src/VisualStudio/Core/Def/Library/AbstractLibraryManager_IVsSimpleLibrary2.cs +++ b/src/VisualStudio/Core/Def/Library/AbstractLibraryManager_IVsSimpleLibrary2.cs @@ -5,6 +5,8 @@ #nullable disable using System; +using System.Threading; +using System.Threading.Tasks; using Microsoft.VisualStudio.OLE.Interop; using Microsoft.VisualStudio.Shell.Interop; @@ -14,7 +16,7 @@ internal partial class AbstractLibraryManager : IVsSimpleLibrary2 { public abstract uint GetLibraryFlags(); protected abstract uint GetSupportedCategoryFields(uint category); - protected abstract IVsSimpleObjectList2 GetList(uint listType, uint flags, VSOBSEARCHCRITERIA2[] pobSrch); + protected abstract Task GetListAsync(uint listType, uint flags, VSOBSEARCHCRITERIA2[] pobSrch, CancellationToken cancellationToken); protected abstract uint GetUpdateCounter(); protected virtual int CreateNavInfo(SYMBOL_DESCRIPTION_NODE[] rgSymbolNodes, uint ulcNodes, out IVsNavInfo ppNavInfo) @@ -50,7 +52,8 @@ int IVsSimpleLibrary2.GetLibFlags2(out uint pgrfFlags) int IVsSimpleLibrary2.GetList2(uint listType, uint flags, VSOBSEARCHCRITERIA2[] pobSrch, out IVsSimpleObjectList2 ppIVsSimpleObjectList2) { - ppIVsSimpleObjectList2 = GetList(listType, flags, pobSrch); + ppIVsSimpleObjectList2 = this.ThreadingContext.JoinableTaskFactory.Run( + () => GetListAsync(listType, flags, pobSrch, CancellationToken.None)); return ppIVsSimpleObjectList2 != null ? VSConstants.S_OK diff --git a/src/VisualStudio/Core/Def/Library/AbstractObjectList.cs b/src/VisualStudio/Core/Def/Library/AbstractObjectList.cs index 6df287f89d896..b7cef249a7e36 100644 --- a/src/VisualStudio/Core/Def/Library/AbstractObjectList.cs +++ b/src/VisualStudio/Core/Def/Library/AbstractObjectList.cs @@ -6,10 +6,12 @@ using System; using System.Runtime.InteropServices; +using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Shared.TestHooks; using Microsoft.VisualStudio.OLE.Interop; using Microsoft.VisualStudio.Shell.Interop; +using Roslyn.Utilities; namespace Microsoft.VisualStudio.LanguageServices.Implementation.Library; @@ -24,9 +26,10 @@ protected AbstractObjectList(TLibraryManager libraryManager) protected abstract bool CanGoToSource(uint index, VSOBJGOTOSRCTYPE srcType); protected abstract bool TryGetCategoryField(uint index, int category, out uint categoryField); protected abstract void GetDisplayData(uint index, ref VSTREEDISPLAYDATA data); - protected abstract bool GetExpandable(uint index, uint listTypeExcluded); + protected abstract Task GetExpandableAsync(uint index, uint listTypeExcluded, CancellationToken cancellationToken); protected abstract uint GetItemCount(); - protected abstract IVsSimpleObjectList2 GetList(uint index, uint listType, uint flags, VSOBSEARCHCRITERIA2[] pobSrch); + protected abstract Task GetListAsync( + uint index, uint listType, uint flags, VSOBSEARCHCRITERIA2[] pobSrch, CancellationToken cancellationToken); protected abstract string GetText(uint index, VSTREETEXTOPTIONS tto); protected abstract string GetTipText(uint index, VSTREETOOLTIPTYPE eTipType); protected abstract Task GoToSourceAsync(uint index, VSOBJGOTOSRCTYPE srcType); @@ -59,11 +62,8 @@ protected virtual bool TryGetContextMenu(uint index, out Guid menuGuid, out int return false; } - protected virtual bool TryGetProperty(uint index, _VSOBJLISTELEMPROPID propertyId, out object pvar) - { - pvar = null; - return false; - } + protected virtual Task<(bool success, object pvar)> TryGetPropertyAsync(uint index, _VSOBJLISTELEMPROPID propertyId, CancellationToken cancellationToken) + => SpecializedTasks.Default<(bool success, object pvar)>(); protected virtual bool TryCountSourceItems(uint index, out IVsHierarchy hierarchy, out uint itemid, out uint items) { @@ -73,16 +73,16 @@ protected virtual bool TryCountSourceItems(uint index, out IVsHierarchy hierarch return false; } - protected virtual object GetBrowseObject(uint index) - => null; + protected virtual Task GetBrowseObjectAsync(uint index, CancellationToken cancellationToken) + => SpecializedTasks.Null(); protected virtual bool SupportsNavInfo { get { return false; } } - protected virtual IVsNavInfo GetNavInfo(uint index) - => null; + protected virtual Task GetNavInfoAsync(uint index, CancellationToken cancellationToken) + => SpecializedTasks.Null(); protected virtual IVsNavInfoNode GetNavInfoNode(uint index) => null; @@ -98,8 +98,8 @@ protected virtual bool SupportsDescription get { return false; } } - protected virtual bool TryFillDescription(uint index, _VSOBJDESCOPTIONS options, IVsObjectBrowserDescription3 description) - => false; + protected virtual Task TryFillDescriptionAsync(uint index, _VSOBJDESCOPTIONS options, IVsObjectBrowserDescription3 description, CancellationToken cancellationToken) + => SpecializedTasks.False; int IVsSimpleObjectList2.CanDelete(uint index, out int pfOK) { @@ -144,18 +144,19 @@ int IVsSimpleObjectList2.EnumClipboardFormats(uint index, uint grfFlags, uint ce int IVsSimpleObjectList2.FillDescription2(uint index, uint grfOptions, IVsObjectBrowserDescription3 pobDesc) { if (!SupportsDescription) - { return VSConstants.E_NOTIMPL; - } - return TryFillDescription(index, (_VSOBJDESCOPTIONS)grfOptions, pobDesc) + var result = this.LibraryManager.ThreadingContext.JoinableTaskFactory.Run( + () => TryFillDescriptionAsync(index, (_VSOBJDESCOPTIONS)grfOptions, pobDesc, CancellationToken.None)); + return result ? VSConstants.S_OK : VSConstants.E_FAIL; } int IVsSimpleObjectList2.GetBrowseObject(uint index, out object ppdispBrowseObj) { - ppdispBrowseObj = GetBrowseObject(index); + ppdispBrowseObj = this.LibraryManager.ThreadingContext.JoinableTaskFactory.Run(() => + GetBrowseObjectAsync(index, CancellationToken.None)); return ppdispBrowseObj != null ? VSConstants.S_OK @@ -206,7 +207,8 @@ int IVsSimpleObjectList2.GetDisplayData(uint index, VSTREEDISPLAYDATA[] pData) int IVsSimpleObjectList2.GetExpandable3(uint index, uint listTypeExcluded, out int pfExpandable) { - pfExpandable = GetExpandable(index, listTypeExcluded) ? 1 : 0; + pfExpandable = this.LibraryManager.ThreadingContext.JoinableTaskFactory.Run( + () => GetExpandableAsync(index, listTypeExcluded, CancellationToken.None)) ? 1 : 0; return VSConstants.S_OK; } @@ -230,7 +232,8 @@ int IVsSimpleObjectList2.GetItemCount(out uint pCount) int IVsSimpleObjectList2.GetList2(uint index, uint listType, uint flags, VSOBSEARCHCRITERIA2[] pobSrch, out IVsSimpleObjectList2 ppIVsSimpleObjectList2) { - ppIVsSimpleObjectList2 = GetList(index, listType, flags, pobSrch); + ppIVsSimpleObjectList2 = this.LibraryManager.ThreadingContext.JoinableTaskFactory.Run( + () => GetListAsync(index, listType, flags, pobSrch, CancellationToken.None)); return VSConstants.S_OK; } @@ -239,16 +242,18 @@ int IVsSimpleObjectList2.GetMultipleSourceItems(uint index, uint grfGSI, uint cI int IVsSimpleObjectList2.GetNavInfo(uint index, out IVsNavInfo ppNavInfo) { - if (!SupportsNavInfo) + (ppNavInfo, var result) = this.LibraryManager.ThreadingContext.JoinableTaskFactory.Run(async () => { - ppNavInfo = null; - return VSConstants.E_NOTIMPL; - } + if (!SupportsNavInfo) + return (null, VSConstants.E_NOTIMPL); - ppNavInfo = GetNavInfo(index); - return ppNavInfo != null - ? VSConstants.S_OK - : VSConstants.E_FAIL; + var ppNavInfo = await GetNavInfoAsync(index, CancellationToken.None).ConfigureAwait(true); + return (ppNavInfo, ppNavInfo != null + ? VSConstants.S_OK + : VSConstants.E_FAIL); + }); + + return result; } int IVsSimpleObjectList2.GetNavInfoNode(uint index, out IVsNavInfoNode ppNavInfoNode) @@ -262,11 +267,15 @@ int IVsSimpleObjectList2.GetNavInfoNode(uint index, out IVsNavInfoNode ppNavInfo int IVsSimpleObjectList2.GetProperty(uint index, int propid, out object pvar) { - if (TryGetProperty(index, (_VSOBJLISTELEMPROPID)propid, out pvar)) + var (success, obj) = this.LibraryManager.ThreadingContext.JoinableTaskFactory.Run(() => + TryGetPropertyAsync(index, (_VSOBJLISTELEMPROPID)propid, CancellationToken.None)); + if (success) { + pvar = obj; return VSConstants.S_OK; } + pvar = null; return VSConstants.E_FAIL; } diff --git a/src/VisualStudio/Core/Def/Library/ClassView/AbstractSyncClassViewCommandHandler.cs b/src/VisualStudio/Core/Def/Library/ClassView/AbstractSyncClassViewCommandHandler.cs index 32d8aebbf658c..e3a563581092d 100644 --- a/src/VisualStudio/Core/Def/Library/ClassView/AbstractSyncClassViewCommandHandler.cs +++ b/src/VisualStudio/Core/Def/Library/ClassView/AbstractSyncClassViewCommandHandler.cs @@ -5,6 +5,7 @@ #nullable disable using System; +using System.Threading.Tasks; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Editor.Shared.Extensions; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; @@ -14,67 +15,53 @@ using Microsoft.VisualStudio.Shell; using Microsoft.VisualStudio.Shell.Interop; using Microsoft.VisualStudio.Text.Editor.Commanding.Commands; -using Roslyn.Utilities; namespace Microsoft.VisualStudio.LanguageServices.Implementation.Library.ClassView; -internal abstract class AbstractSyncClassViewCommandHandler : ICommandHandler +internal abstract class AbstractSyncClassViewCommandHandler( + IThreadingContext threadingContext, + SVsServiceProvider serviceProvider) : ICommandHandler { private const string ClassView = "Class View"; - private readonly IThreadingContext _threadingContext; - private readonly IServiceProvider _serviceProvider; + private readonly IThreadingContext _threadingContext = threadingContext; + private readonly IServiceProvider _serviceProvider = serviceProvider; public string DisplayName => ServicesVSResources.Sync_Class_View; - protected AbstractSyncClassViewCommandHandler( - IThreadingContext threadingContext, - SVsServiceProvider serviceProvider) - { - Contract.ThrowIfNull(serviceProvider); - _threadingContext = threadingContext; - _serviceProvider = serviceProvider; - } - public bool ExecuteCommand(SyncClassViewCommandArgs args, CommandExecutionContext context) { _threadingContext.ThrowIfNotOnUIThread(); var caretPosition = args.TextView.GetCaretPoint(args.SubjectBuffer) ?? -1; if (caretPosition < 0) - { return false; - } + using var waitScope = context.OperationContext.AddScope(allowCancellation: true, string.Format(ServicesVSResources.Synchronizing_with_0, ClassView)); + return _threadingContext.JoinableTaskFactory.Run(() => ExecuteCommandAsync(args, context, caretPosition)); + } + + private async Task ExecuteCommandAsync( + SyncClassViewCommandArgs args, CommandExecutionContext context, int caretPosition) + { var snapshot = args.SubjectBuffer.CurrentSnapshot; - using var waitScope = context.OperationContext.AddScope(allowCancellation: true, string.Format(ServicesVSResources.Synchronizing_with_0, ClassView)); - var document = snapshot.GetFullyLoadedOpenDocumentInCurrentContextWithChangesAsync( - context.OperationContext).WaitAndGetResult(context.OperationContext.UserCancellationToken); + var document = await snapshot.GetFullyLoadedOpenDocumentInCurrentContextWithChangesAsync( + context.OperationContext).ConfigureAwait(true); if (document == null) - { return true; - } var syntaxFactsService = document.GetLanguageService(); if (syntaxFactsService == null) - { return true; - } var libraryService = document.GetLanguageService(); if (libraryService == null) - { return true; - } var userCancellationToken = context.OperationContext.UserCancellationToken; - var semanticModel = document - .GetSemanticModelAsync(userCancellationToken) - .WaitAndGetResult(userCancellationToken); + var semanticModel = await document.GetSemanticModelAsync(userCancellationToken).ConfigureAwait(true); - var root = semanticModel.SyntaxTree - .GetRootAsync(userCancellationToken) - .WaitAndGetResult(userCancellationToken); + var root = await semanticModel.SyntaxTree.GetRootAsync(userCancellationToken).ConfigureAwait(true); var memberDeclaration = syntaxFactsService.GetContainingMemberDeclaration(root, caretPosition); @@ -83,22 +70,15 @@ public bool ExecuteCommand(SyncClassViewCommandArgs args, CommandExecutionContex : null; while (symbol != null && !IsValidSymbolToSynchronize(symbol)) - { symbol = symbol.ContainingSymbol; - } IVsNavInfo navInfo = null; if (symbol != null) - { navInfo = libraryService.NavInfoFactory.CreateForSymbol(symbol, document.Project, semanticModel.Compilation, useExpandedHierarchy: true); - } navInfo ??= libraryService.NavInfoFactory.CreateForProject(document.Project); - if (navInfo == null) - { return true; - } var navigationTool = _serviceProvider.GetServiceOnMainThread(); navigationTool.NavigateToNavInfo(navInfo); diff --git a/src/VisualStudio/Core/Def/Library/ObjectBrowser/AbstractDescriptionBuilder.cs b/src/VisualStudio/Core/Def/Library/ObjectBrowser/AbstractDescriptionBuilder.cs index 0e595d12a9925..cb11885370585 100644 --- a/src/VisualStudio/Core/Def/Library/ObjectBrowser/AbstractDescriptionBuilder.cs +++ b/src/VisualStudio/Core/Def/Library/ObjectBrowser/AbstractDescriptionBuilder.cs @@ -7,6 +7,7 @@ using System; using System.Diagnostics; using System.Threading; +using System.Threading.Tasks; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.DocumentationComments; using Microsoft.CodeAnalysis.Shared.Extensions; @@ -37,12 +38,8 @@ protected AbstractDescriptionBuilder( _project = project; } - private Compilation GetCompilation() - { - return _project - .GetCompilationAsync(CancellationToken.None) - .WaitAndGetResult_ObjectBrowser(CancellationToken.None); - } + private Task GetCompilationAsync(CancellationToken cancellationToken) + => _project.GetCompilationAsync(cancellationToken); protected void AddAssemblyLink(IAssemblySymbol assemblySymbol) { @@ -67,7 +64,7 @@ protected void AddLineBreak() protected void AddName(string text) => _description.AddDescriptionText3(text, VSOBDESCRIPTIONSECTION.OBDS_NAME, null); - protected void AddNamespaceLink(INamespaceSymbol namespaceSymbol) + protected async Task AddNamespaceLinkAsync(INamespaceSymbol namespaceSymbol, CancellationToken cancellationToken) { if (namespaceSymbol.IsGlobalNamespace) { @@ -75,7 +72,8 @@ protected void AddNamespaceLink(INamespaceSymbol namespaceSymbol) } var text = namespaceSymbol.ToDisplayString(); - var navInfo = _libraryManager.LibraryService.NavInfoFactory.CreateForNamespace(namespaceSymbol, _project, GetCompilation(), useExpandedHierarchy: false); + var navInfo = _libraryManager.LibraryService.NavInfoFactory.CreateForNamespace( + namespaceSymbol, _project, await GetCompilationAsync(cancellationToken).ConfigureAwait(true), useExpandedHierarchy: false); _description.AddDescriptionText3(text, VSOBDESCRIPTIONSECTION.OBDS_TYPE, navInfo); } @@ -86,7 +84,8 @@ protected void AddParam(string text) protected void AddText(string text) => _description.AddDescriptionText3(text, VSOBDESCRIPTIONSECTION.OBDS_MISC, null); - protected void AddTypeLink(ITypeSymbol typeSymbol, LinkFlags flags) + protected async Task AddTypeLinkAsync( + ITypeSymbol typeSymbol, LinkFlags flags, CancellationToken cancellationToken) { if (typeSymbol.TypeKind is TypeKind.Unknown or TypeKind.Error or TypeKind.TypeParameter || typeSymbol.SpecialType == SpecialType.System_Void) @@ -100,7 +99,7 @@ protected void AddTypeLink(ITypeSymbol typeSymbol, LinkFlags flags) if (splitLink && !typeSymbol.ContainingNamespace.IsGlobalNamespace) { - AddNamespaceLink(typeSymbol.ContainingNamespace); + await AddNamespaceLinkAsync(typeSymbol.ContainingNamespace, cancellationToken).ConfigureAwait(true); AddText("."); } @@ -118,7 +117,8 @@ protected void AddTypeLink(ITypeSymbol typeSymbol, LinkFlags flags) miscellaneousOptions: miscellaneousOptions); var text = typeSymbol.ToDisplayString(typeDisplayFormat); - var navInfo = _libraryManager.LibraryService.NavInfoFactory.CreateForType(typeSymbol, _project, GetCompilation(), useExpandedHierarchy: false); + var navInfo = _libraryManager.LibraryService.NavInfoFactory.CreateForType( + typeSymbol, _project, await GetCompilationAsync(cancellationToken).ConfigureAwait(true), useExpandedHierarchy: false); _description.AddDescriptionText3(text, VSOBDESCRIPTIONSECTION.OBDS_TYPE, navInfo); } @@ -142,9 +142,10 @@ private void BuildReference(ReferenceListItem referenceListItem) } } - private void BuildNamespace(NamespaceListItem namespaceListItem, _VSOBJDESCOPTIONS options) + private async Task BuildNamespaceAsync( + NamespaceListItem namespaceListItem, _VSOBJDESCOPTIONS options, CancellationToken cancellationToken) { - var compilation = GetCompilation(); + var compilation = await GetCompilationAsync(cancellationToken).ConfigureAwait(true); if (compilation == null) { return; @@ -159,12 +160,12 @@ private void BuildNamespace(NamespaceListItem namespaceListItem, _VSOBJDESCOPTIO BuildNamespaceDeclaration(namespaceSymbol, options); AddEndDeclaration(); - BuildMemberOf(namespaceSymbol.ContainingAssembly); + await BuildMemberOfAsync(namespaceSymbol.ContainingAssembly, cancellationToken).ConfigureAwait(true); } - private void BuildType(TypeListItem typeListItem, _VSOBJDESCOPTIONS options) + private async Task BuildTypeAsync(TypeListItem typeListItem, _VSOBJDESCOPTIONS options, CancellationToken cancellationToken) { - var compilation = GetCompilation(); + var compilation = await GetCompilationAsync(cancellationToken).ConfigureAwait(true); if (compilation == null) { return; @@ -178,49 +179,44 @@ private void BuildType(TypeListItem typeListItem, _VSOBJDESCOPTIONS options) if (symbol.TypeKind == TypeKind.Delegate) { - BuildDelegateDeclaration(symbol, options); + await BuildDelegateDeclarationAsync(symbol, options, cancellationToken).ConfigureAwait(true); } else { - BuildTypeDeclaration(symbol, options); + await BuildTypeDeclarationAsync(symbol, options, cancellationToken).ConfigureAwait(true); } AddEndDeclaration(); - BuildMemberOf(symbol.ContainingNamespace); - - BuildXmlDocumentation(symbol, compilation); + await BuildMemberOfAsync(symbol.ContainingNamespace, cancellationToken).ConfigureAwait(true); + await BuildXmlDocumentationAsync(symbol, compilation, cancellationToken).ConfigureAwait(true); } - private void BuildMember(MemberListItem memberListItem, _VSOBJDESCOPTIONS options) + private async Task BuildMemberAsync(MemberListItem memberListItem, _VSOBJDESCOPTIONS options, CancellationToken cancellationToken) { - var compilation = GetCompilation(); + var compilation = await GetCompilationAsync(cancellationToken).ConfigureAwait(true); if (compilation == null) - { return; - } var symbol = memberListItem.ResolveTypedSymbol(compilation); if (symbol == null) - { return; - } switch (symbol.Kind) { case SymbolKind.Method: - BuildMethodDeclaration((IMethodSymbol)symbol, options); + await BuildMethodDeclarationAsync((IMethodSymbol)symbol, options, cancellationToken).ConfigureAwait(true); break; case SymbolKind.Field: - BuildFieldDeclaration((IFieldSymbol)symbol, options); + await BuildFieldDeclarationAsync((IFieldSymbol)symbol, options, cancellationToken).ConfigureAwait(true); break; case SymbolKind.Property: - BuildPropertyDeclaration((IPropertySymbol)symbol, options); + await BuildPropertyDeclarationAsync((IPropertySymbol)symbol, options, cancellationToken).ConfigureAwait(true); break; case SymbolKind.Event: - BuildEventDeclaration((IEventSymbol)symbol, options); + await BuildEventDeclarationAsync((IEventSymbol)symbol, options, cancellationToken).ConfigureAwait(true); break; default: @@ -229,20 +225,19 @@ private void BuildMember(MemberListItem memberListItem, _VSOBJDESCOPTIONS option } AddEndDeclaration(); - BuildMemberOf(symbol.ContainingType); - - BuildXmlDocumentation(symbol, compilation); + await BuildMemberOfAsync(symbol.ContainingType, cancellationToken).ConfigureAwait(true); + await BuildXmlDocumentationAsync(symbol, compilation, cancellationToken).ConfigureAwait(true); } protected abstract void BuildNamespaceDeclaration(INamespaceSymbol namespaceSymbol, _VSOBJDESCOPTIONS options); - protected abstract void BuildDelegateDeclaration(INamedTypeSymbol typeSymbol, _VSOBJDESCOPTIONS options); - protected abstract void BuildTypeDeclaration(INamedTypeSymbol typeSymbol, _VSOBJDESCOPTIONS options); - protected abstract void BuildMethodDeclaration(IMethodSymbol methodSymbol, _VSOBJDESCOPTIONS options); - protected abstract void BuildFieldDeclaration(IFieldSymbol fieldSymbol, _VSOBJDESCOPTIONS options); - protected abstract void BuildPropertyDeclaration(IPropertySymbol propertySymbol, _VSOBJDESCOPTIONS options); - protected abstract void BuildEventDeclaration(IEventSymbol eventSymbol, _VSOBJDESCOPTIONS options); - - private void BuildMemberOf(ISymbol containingSymbol) + protected abstract Task BuildDelegateDeclarationAsync(INamedTypeSymbol typeSymbol, _VSOBJDESCOPTIONS options, CancellationToken cancellationToken); + protected abstract Task BuildTypeDeclarationAsync(INamedTypeSymbol typeSymbol, _VSOBJDESCOPTIONS options, CancellationToken cancellationToken); + protected abstract Task BuildMethodDeclarationAsync(IMethodSymbol methodSymbol, _VSOBJDESCOPTIONS options, CancellationToken cancellationToken); + protected abstract Task BuildFieldDeclarationAsync(IFieldSymbol fieldSymbol, _VSOBJDESCOPTIONS options, CancellationToken cancellationToken); + protected abstract Task BuildPropertyDeclarationAsync(IPropertySymbol propertySymbol, _VSOBJDESCOPTIONS options, CancellationToken cancellationToken); + protected abstract Task BuildEventDeclarationAsync(IEventSymbol eventSymbol, _VSOBJDESCOPTIONS options, CancellationToken cancellationToken); + + private async Task BuildMemberOfAsync(ISymbol containingSymbol, CancellationToken cancellationToken) { if (containingSymbol is INamespaceSymbol && ((INamespaceSymbol)containingSymbol).IsGlobalNamespace) @@ -272,18 +267,20 @@ private void BuildMemberOf(ISymbol containingSymbol) } else if (containingSymbol is ITypeSymbol typeSymbol) { - AddTypeLink(typeSymbol, LinkFlags.SplitNamespaceAndType | LinkFlags.ExpandPredefinedTypes); + await AddTypeLinkAsync( + typeSymbol, LinkFlags.SplitNamespaceAndType | LinkFlags.ExpandPredefinedTypes, cancellationToken).ConfigureAwait(true); } else if (containingSymbol is INamespaceSymbol namespaceSymbol) { - AddNamespaceLink(namespaceSymbol); + await AddNamespaceLinkAsync(namespaceSymbol, cancellationToken).ConfigureAwait(true); } AddText(right); AddEndDeclaration(); } - private void BuildXmlDocumentation(ISymbol symbol, Compilation compilation) + private async Task BuildXmlDocumentationAsync( + ISymbol symbol, Compilation compilation, CancellationToken cancellationToken) { var documentationComment = symbol.GetDocumentationComment(compilation, expandIncludes: true, expandInheritdoc: true, cancellationToken: CancellationToken.None); if (documentationComment == null) @@ -302,7 +299,7 @@ private void BuildXmlDocumentation(ISymbol symbol, Compilation compilation) if (documentationComment.SummaryText != null) { AddLineBreak(); - AddName(ServicesVSResources.Summary_colon); + AddName(FeaturesResources.Summary_colon); AddLineBreak(); AddText(formattingService.Format(documentationComment.SummaryText, compilation)); @@ -343,7 +340,7 @@ private void BuildXmlDocumentation(ISymbol symbol, Compilation compilation) } AddLineBreak(); - AddName(ServicesVSResources.Parameters_colon1); + AddName(FeaturesResources.Parameters_colon); foreach (var parameterName in documentationComment.ParameterNames) { @@ -369,7 +366,7 @@ private void BuildXmlDocumentation(ISymbol symbol, Compilation compilation) } AddLineBreak(); - AddName(ServicesVSResources.Returns_colon); + AddName(FeaturesResources.Returns_colon); AddLineBreak(); AddText(formattingService.Format(documentationComment.ReturnsText, compilation)); @@ -384,7 +381,7 @@ private void BuildXmlDocumentation(ISymbol symbol, Compilation compilation) } AddLineBreak(); - AddName(ServicesVSResources.Value_colon); + AddName(FeaturesResources.Value_colon); AddLineBreak(); AddText(formattingService.Format(documentationComment.ValueText, compilation)); @@ -399,7 +396,7 @@ private void BuildXmlDocumentation(ISymbol symbol, Compilation compilation) } AddLineBreak(); - AddName(ServicesVSResources.Remarks_colon); + AddName(FeaturesResources.Remarks_colon); AddLineBreak(); AddText(formattingService.Format(documentationComment.RemarksText, compilation)); @@ -414,7 +411,7 @@ private void BuildXmlDocumentation(ISymbol symbol, Compilation compilation) } AddLineBreak(); - AddName(ServicesVSResources.Exceptions_colon); + AddName(WorkspacesResources.Exceptions_colon); foreach (var exceptionType in documentationComment.ExceptionTypes) { @@ -425,13 +422,13 @@ private void BuildXmlDocumentation(ISymbol symbol, Compilation compilation) var exceptionTexts = documentationComment.GetExceptionTexts(exceptionType); if (exceptionTexts.Length == 0) { - AddTypeLink(exceptionTypeSymbol, LinkFlags.None); + await AddTypeLinkAsync(exceptionTypeSymbol, LinkFlags.None, cancellationToken).ConfigureAwait(true); } else { foreach (var exceptionText in exceptionTexts) { - AddTypeLink(exceptionTypeSymbol, LinkFlags.None); + await AddTypeLinkAsync(exceptionTypeSymbol, LinkFlags.None, cancellationToken).ConfigureAwait(true); AddText(": "); AddText(formattingService.Format(exceptionText, compilation)); } @@ -455,7 +452,7 @@ private static bool ShowValueDocumentation(ISymbol symbol) return ShowReturnsDocumentation(symbol); } - internal bool TryBuild(_VSOBJDESCOPTIONS options) + internal async Task TryBuildAsync(_VSOBJDESCOPTIONS options, CancellationToken cancellationToken) { switch (_listItem) { @@ -466,13 +463,13 @@ internal bool TryBuild(_VSOBJDESCOPTIONS options) BuildReference(referenceListItem); return true; case NamespaceListItem namespaceListItem: - BuildNamespace(namespaceListItem, options); + await BuildNamespaceAsync(namespaceListItem, options, cancellationToken).ConfigureAwait(true); return true; case TypeListItem typeListItem: - BuildType(typeListItem, options); + await BuildTypeAsync(typeListItem, options, cancellationToken).ConfigureAwait(true); return true; case MemberListItem memberListItem: - BuildMember(memberListItem, options); + await BuildMemberAsync(memberListItem, options, cancellationToken).ConfigureAwait(true); return true; } diff --git a/src/VisualStudio/Core/Def/Library/ObjectBrowser/AbstractListItemFactory.cs b/src/VisualStudio/Core/Def/Library/ObjectBrowser/AbstractListItemFactory.cs index 5f8bbbc47aac1..fa7e1a7eabddd 100644 --- a/src/VisualStudio/Core/Def/Library/ObjectBrowser/AbstractListItemFactory.cs +++ b/src/VisualStudio/Core/Def/Library/ObjectBrowser/AbstractListItemFactory.cs @@ -17,6 +17,7 @@ using Microsoft.CodeAnalysis.Shared.Utilities; using Microsoft.VisualStudio.LanguageServices.Implementation.Library.ObjectBrowser.Lists; using Roslyn.Utilities; +using System.Threading.Tasks; namespace Microsoft.VisualStudio.LanguageServices.Implementation.Library.ObjectBrowser; @@ -206,7 +207,7 @@ private ImmutableArray GetBaseTypeListItems(INamedTypeSymbol nam // Special case: System.Object doesn't have a base type if (namedTypeSymbol.SpecialType == SpecialType.System_Object) { - return ImmutableArray.Empty; + return []; } var symbolBuilder = ImmutableArray.CreateBuilder(); @@ -233,7 +234,7 @@ public ImmutableArray GetBaseTypeListItems(ObjectListItem parent if (parentListItem is not TypeListItem parentTypeItem) { - return ImmutableArray.Empty; + return []; } var typeSymbol = parentTypeItem.ResolveTypedSymbol(compilation); @@ -393,7 +394,7 @@ public ImmutableArray GetMemberListItems(ObjectListItem parentLi if (parentListItem is not TypeListItem parentTypeItem) { - return ImmutableArray.Empty; + return []; } var typeSymbol = parentTypeItem.ResolveTypedSymbol(compilation); @@ -452,16 +453,17 @@ public ImmutableArray GetNamespaceListItems(ObjectListItem paren return builder.ToImmutableAndClear(); } - private class AssemblySymbolComparer : IEqualityComparer> + private class AssemblySymbolComparer : IEqualityComparer<(ProjectId, IAssemblySymbol)> { - public bool Equals(Tuple x, Tuple y) + public bool Equals((ProjectId, IAssemblySymbol) x, (ProjectId, IAssemblySymbol) y) => x.Item2.Identity.Equals(y.Item2.Identity); - public int GetHashCode(Tuple obj) + public int GetHashCode((ProjectId, IAssemblySymbol) obj) => obj.Item2.Identity.GetHashCode(); } - public ImmutableHashSet> GetAssemblySet(Solution solution, string languageName, CancellationToken cancellationToken) + public async Task> GetAssemblySetAsync( + Solution solution, string languageName, CancellationToken cancellationToken) { var set = ImmutableHashSet.CreateBuilder(new AssemblySymbolComparer()); @@ -480,14 +482,12 @@ public ImmutableHashSet> GetAssemblySet(Soluti continue; } - var compilation = project - .GetCompilationAsync(cancellationToken) - .WaitAndGetResult(cancellationToken); + var compilation = await project.GetCompilationAsync(cancellationToken).ConfigureAwait(true); if (compilation != null && compilation.Assembly != null) { - set.Add(Tuple.Create(projectId, compilation.Assembly)); + set.Add((projectId, compilation.Assembly)); foreach (var reference in project.MetadataReferences) { @@ -495,7 +495,7 @@ public ImmutableHashSet> GetAssemblySet(Soluti if (compilation.GetAssemblyOrModuleSymbol(reference) is IAssemblySymbol referenceAssembly) { - set.Add(Tuple.Create(projectId, referenceAssembly)); + set.Add((projectId, referenceAssembly)); } } } @@ -504,18 +504,16 @@ public ImmutableHashSet> GetAssemblySet(Soluti return set.ToImmutable(); } - public ImmutableHashSet> GetAssemblySet(Project project, bool lookInReferences, CancellationToken cancellationToken) + public async Task> GetAssemblySetAsync(Project project, bool lookInReferences, CancellationToken cancellationToken) { var set = ImmutableHashSet.CreateBuilder(new AssemblySymbolComparer()); - var compilation = project - .GetCompilationAsync(cancellationToken) - .WaitAndGetResult(cancellationToken); + var compilation = await project.GetCompilationAsync(cancellationToken).ConfigureAwait(true); if (compilation != null && compilation.Assembly != null) { - set.Add(Tuple.Create(project.Id, compilation.Assembly)); + set.Add((project.Id, compilation.Assembly)); if (lookInReferences) { @@ -525,7 +523,7 @@ public ImmutableHashSet> GetAssemblySet(Projec if (compilation.GetAssemblyOrModuleSymbol(reference) is IAssemblySymbol referenceAssembly) { - set.Add(Tuple.Create(project.Id, referenceAssembly)); + set.Add((project.Id, referenceAssembly)); } } } @@ -588,7 +586,7 @@ public ImmutableArray GetProjectListItems(Solution solution, str var projectIds = solution.ProjectIds; if (!projectIds.Any()) { - return ImmutableArray.Empty; + return []; } var projectListItemBuilder = ImmutableArray.CreateBuilder(); @@ -645,7 +643,7 @@ public ImmutableArray GetReferenceListItems(ObjectListItem paren if (!compilation.References.Any()) { - return ImmutableArray.Empty; + return []; } var builder = ArrayBuilder.GetInstance(); diff --git a/src/VisualStudio/Core/Def/Library/ObjectBrowser/AbstractObjectBrowserLibraryManager.cs b/src/VisualStudio/Core/Def/Library/ObjectBrowser/AbstractObjectBrowserLibraryManager.cs index 8d05193d1b33e..aba4e28fe4c90 100644 --- a/src/VisualStudio/Core/Def/Library/ObjectBrowser/AbstractObjectBrowserLibraryManager.cs +++ b/src/VisualStudio/Core/Def/Library/ObjectBrowser/AbstractObjectBrowserLibraryManager.cs @@ -195,17 +195,14 @@ internal Project GetProject(ObjectListItem listItem) return this.GetProject(projectId); } - internal Compilation GetCompilation(ProjectId projectId) + internal async Task GetCompilationAsync( + ProjectId projectId, CancellationToken cancellationToken) { var project = GetProject(projectId); if (project == null) - { return null; - } - return project - .GetCompilationAsync(CancellationToken.None) - .WaitAndGetResult_ObjectBrowser(CancellationToken.None); + return await project.GetCompilationAsync(cancellationToken).ConfigureAwait(true); } public override uint GetLibraryFlags() @@ -301,14 +298,16 @@ protected override uint GetSupportedCategoryFields(uint category) return 0; } - protected override IVsSimpleObjectList2 GetList(uint listType, uint flags, VSOBSEARCHCRITERIA2[] pobSrch) + protected override async Task GetListAsync( + uint listType, uint flags, VSOBSEARCHCRITERIA2[] pobSrch, CancellationToken cancellationToken) { var listKind = Helpers.ListTypeToObjectListKind(listType); if (Helpers.IsFindSymbol(flags)) { - var projectAndAssemblySet = this.GetAssemblySet(this.Workspace.CurrentSolution, _languageName, CancellationToken.None); - return GetSearchList(listKind, flags, pobSrch, projectAndAssemblySet); + var projectAndAssemblySet = await this.GetAssemblySetAsync( + this.Workspace.CurrentSolution, _languageName, CancellationToken.None).ConfigureAwait(true); + return await GetSearchListAsync(listKind, flags, pobSrch, projectAndAssemblySet, cancellationToken).ConfigureAwait(true); } if (listKind == ObjectListKind.Hierarchy) @@ -408,7 +407,8 @@ protected override int CreateNavInfo(SYMBOL_DESCRIPTION_NODE[] rgSymbolNodes, ui return VSConstants.S_OK; } - internal IVsNavInfo GetNavInfo(SymbolListItem symbolListItem, bool useExpandedHierarchy) + internal async Task GetNavInfoAsync( + SymbolListItem symbolListItem, bool useExpandedHierarchy, CancellationToken cancellationToken) { var project = GetProject(symbolListItem); if (project == null) @@ -416,7 +416,8 @@ internal IVsNavInfo GetNavInfo(SymbolListItem symbolListItem, bool useExpandedHi return null; } - var compilation = symbolListItem.GetCompilation(this.Workspace); + var compilation = await symbolListItem.GetCompilationAsync( + this.Workspace, cancellationToken).ConfigureAwait(true); if (compilation == null) { return null; diff --git a/src/VisualStudio/Core/Def/Library/ObjectBrowser/AbstractObjectBrowserLibraryManager_Description.cs b/src/VisualStudio/Core/Def/Library/ObjectBrowser/AbstractObjectBrowserLibraryManager_Description.cs index 98ffc9fef6ccc..dfce8ffdb2c53 100644 --- a/src/VisualStudio/Core/Def/Library/ObjectBrowser/AbstractObjectBrowserLibraryManager_Description.cs +++ b/src/VisualStudio/Core/Def/Library/ObjectBrowser/AbstractObjectBrowserLibraryManager_Description.cs @@ -4,20 +4,26 @@ #nullable disable +using System.Threading; +using System.Threading.Tasks; using Microsoft.VisualStudio.Shell.Interop; namespace Microsoft.VisualStudio.LanguageServices.Implementation.Library.ObjectBrowser; internal abstract partial class AbstractObjectBrowserLibraryManager { - internal bool TryFillDescription(ObjectListItem listItem, IVsObjectBrowserDescription3 description, _VSOBJDESCOPTIONS options) + internal async Task TryFillDescriptionAsync( + ObjectListItem listItem, + IVsObjectBrowserDescription3 description, + _VSOBJDESCOPTIONS options, + CancellationToken cancellationToken) { var project = GetProject(listItem); if (project == null) - { return false; - } - return CreateDescriptionBuilder(description, listItem, project).TryBuild(options); + return await CreateDescriptionBuilder(description, listItem, project) + .TryBuildAsync(options, cancellationToken) + .ConfigureAwait(true); } } diff --git a/src/VisualStudio/Core/Def/Library/ObjectBrowser/AbstractObjectBrowserLibraryManager_ListItems.cs b/src/VisualStudio/Core/Def/Library/ObjectBrowser/AbstractObjectBrowserLibraryManager_ListItems.cs index 540623fe2be39..171dcc085cbd9 100644 --- a/src/VisualStudio/Core/Def/Library/ObjectBrowser/AbstractObjectBrowserLibraryManager_ListItems.cs +++ b/src/VisualStudio/Core/Def/Library/ObjectBrowser/AbstractObjectBrowserLibraryManager_ListItems.cs @@ -7,6 +7,7 @@ using System; using System.Collections.Immutable; using System.Threading; +using System.Threading.Tasks; using Microsoft.CodeAnalysis; namespace Microsoft.VisualStudio.LanguageServices.Implementation.Library.ObjectBrowser; @@ -22,11 +23,11 @@ internal void CollectNamespaceListItems(IAssemblySymbol assemblySymbol, ProjectI internal void CollectTypeListItems(IAssemblySymbol assemblySymbol, Compilation compilation, ProjectId projectId, ImmutableArray.Builder builder, string searchString) => GetListItemFactory().CollectTypeListItems(assemblySymbol, compilation, projectId, builder, searchString); - internal ImmutableHashSet> GetAssemblySet(Solution solution, string languageName, CancellationToken cancellationToken) - => GetListItemFactory().GetAssemblySet(solution, languageName, cancellationToken); + internal Task> GetAssemblySetAsync(Solution solution, string languageName, CancellationToken cancellationToken) + => GetListItemFactory().GetAssemblySetAsync(solution, languageName, cancellationToken); - internal ImmutableHashSet> GetAssemblySet(Project project, bool lookInReferences, CancellationToken cancellationToken) - => GetListItemFactory().GetAssemblySet(project, lookInReferences, cancellationToken); + internal Task> GetAssemblySetAsync(Project project, bool lookInReferences, CancellationToken cancellationToken) + => GetListItemFactory().GetAssemblySetAsync(project, lookInReferences, cancellationToken); internal ImmutableArray GetBaseTypeListItems(ObjectListItem parentListItem, Compilation compilation) => GetListItemFactory().GetBaseTypeListItems(parentListItem, compilation); diff --git a/src/VisualStudio/Core/Def/Library/ObjectBrowser/AbstractObjectBrowserLibraryManager_Search.cs b/src/VisualStudio/Core/Def/Library/ObjectBrowser/AbstractObjectBrowserLibraryManager_Search.cs index a1bba60986124..1e1398be7e774 100644 --- a/src/VisualStudio/Core/Def/Library/ObjectBrowser/AbstractObjectBrowserLibraryManager_Search.cs +++ b/src/VisualStudio/Core/Def/Library/ObjectBrowser/AbstractObjectBrowserLibraryManager_Search.cs @@ -6,6 +6,8 @@ using System; using System.Collections.Immutable; +using System.Threading; +using System.Threading.Tasks; using Microsoft.CodeAnalysis; using Microsoft.VisualStudio.Shell.Interop; @@ -32,17 +34,16 @@ private static string GetSearchText(VSOBSEARCHCRITERIA2[] pobSrch) return searchText; } - public IVsSimpleObjectList2 GetSearchList( + public async Task GetSearchListAsync( ObjectListKind listKind, uint flags, VSOBSEARCHCRITERIA2[] pobSrch, - ImmutableHashSet> projectAndAssemblySet) + ImmutableHashSet<(ProjectId, IAssemblySymbol)> projectAndAssemblySet, + CancellationToken cancellationToken) { var searchText = GetSearchText(pobSrch); if (searchText == null) - { return null; - } // TODO: Support wildcards (e.g. *xyz, *xyz* and xyz*) like the old language service did. @@ -72,11 +73,9 @@ public IVsSimpleObjectList2 GetSearchList( var projectId = projectIdAndAssembly.Item1; var assemblySymbol = projectIdAndAssembly.Item2; - var compilation = this.GetCompilation(projectId); + var compilation = await this.GetCompilationAsync(projectId, cancellationToken).ConfigureAwait(true); if (compilation == null) - { return null; - } CollectTypeListItems(assemblySymbol, compilation, projectId, builder, searchText); } @@ -93,11 +92,9 @@ public IVsSimpleObjectList2 GetSearchList( var projectId = projectIdAndAssembly.Item1; var assemblySymbol = projectIdAndAssembly.Item2; - var compilation = this.GetCompilation(projectId); + var compilation = await this.GetCompilationAsync(projectId, cancellationToken).ConfigureAwait(true); if (compilation == null) - { return null; - } CollectMemberListItems(assemblySymbol, compilation, projectId, builder, searchText); } diff --git a/src/VisualStudio/Core/Def/Library/ObjectBrowser/ObjectBrowserTaskExtensions.cs b/src/VisualStudio/Core/Def/Library/ObjectBrowser/ObjectBrowserTaskExtensions.cs deleted file mode 100644 index 5ab1329523c81..0000000000000 --- a/src/VisualStudio/Core/Def/Library/ObjectBrowser/ObjectBrowserTaskExtensions.cs +++ /dev/null @@ -1,27 +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. - -#nullable disable - -using System.Threading.Tasks; -using Roslyn.Utilities; -using System.Threading; - -namespace Microsoft.VisualStudio.LanguageServices.Implementation.Library.ObjectBrowser; - -internal static class ObjectBrowserTaskExtensions -{ - /// - /// Does a for ObjectBrowser. - /// - /// - /// This function is the exact same as , except it opts out - /// of enforcement that it can be called on non-UI threads. ObjectBrowser, since it must implement a highly blocking API, - /// has no choice but to use WaitAndGetResult in a bunch of places. But that's not a good reason to require the tests - /// to have thread affinity, since the tests have no specific threading requirements. Thus, it's acceptable for ObjectBrowser - /// to call the _CanCallOnBackground variant. We hope to audit _CanCallOnBackground periodically, and so rather than - /// having to understand that each of those uses are ObjectBrowser and thus get a special pass. - public static T WaitAndGetResult_ObjectBrowser(this Task task, CancellationToken cancellationToken) - => task.WaitAndGetResult_CanCallOnBackground(cancellationToken); -} diff --git a/src/VisualStudio/Core/Def/Library/ObjectBrowser/ObjectList.cs b/src/VisualStudio/Core/Def/Library/ObjectBrowser/ObjectList.cs index afbabdf35f36d..4c2cf1851cb5f 100644 --- a/src/VisualStudio/Core/Def/Library/ObjectBrowser/ObjectList.cs +++ b/src/VisualStudio/Core/Def/Library/ObjectBrowser/ObjectList.cs @@ -396,7 +396,8 @@ protected override void GetDisplayData(uint index, ref VSTREEDISPLAYDATA data) } } - protected override bool GetExpandable(uint index, uint listTypeExcluded) + protected override async Task GetExpandableAsync( + uint index, uint listTypeExcluded, CancellationToken cancellationToken) { switch (Kind) { @@ -408,20 +409,21 @@ protected override bool GetExpandable(uint index, uint listTypeExcluded) case ObjectListKind.BaseTypes: case ObjectListKind.Types: - return IsExpandableType(index); + return await IsExpandableTypeAsync(index, cancellationToken).ConfigureAwait(true); } return false; } - private bool IsExpandableType(uint index) + private async Task IsExpandableTypeAsync(uint index, CancellationToken cancellationToken) { if (GetListItem(index) is not TypeListItem typeListItem) { return false; } - var compilation = typeListItem.GetCompilation(this.LibraryManager.Workspace); + var compilation = await typeListItem.GetCompilationAsync( + this.LibraryManager.Workspace, cancellationToken).ConfigureAwait(true); if (compilation == null) { return false; @@ -456,7 +458,8 @@ private bool IsExpandableType(uint index) protected override uint GetItemCount() => (uint)_items.Length; - protected override IVsSimpleObjectList2 GetList(uint index, uint listType, uint flags, VSOBSEARCHCRITERIA2[] pobSrch) + protected override async Task GetListAsync( + uint index, uint listType, uint flags, VSOBSEARCHCRITERIA2[] pobSrch, CancellationToken cancellationToken) { var listItem = GetListItem(index); @@ -496,15 +499,16 @@ protected override IVsSimpleObjectList2 GetList(uint index, uint listType, uint var lookInReferences = (flags & ((uint)_VSOBSEARCHOPTIONS.VSOBSO_LOOKINREFS | (uint)_VSOBSEARCHOPTIONS2.VSOBSO_LISTREFERENCES)) != 0; - var projectAndAssemblySet = this.LibraryManager.GetAssemblySet(project, lookInReferences, CancellationToken.None); - return this.LibraryManager.GetSearchList(listKind, flags, pobSrch, projectAndAssemblySet); + var projectAndAssemblySet = await this.LibraryManager.GetAssemblySetAsync( + project, lookInReferences, cancellationToken).ConfigureAwait(true); + return await this.LibraryManager.GetSearchListAsync( + listKind, flags, pobSrch, projectAndAssemblySet, cancellationToken).ConfigureAwait(true); } - var compilation = listItem.GetCompilation(this.LibraryManager.Workspace); + var compilation = await listItem.GetCompilationAsync( + this.LibraryManager.Workspace, cancellationToken).ConfigureAwait(true); if (compilation == null) - { return null; - } switch (listKind) { @@ -525,14 +529,14 @@ protected override IVsSimpleObjectList2 GetList(uint index, uint listType, uint throw new NotImplementedException(); } - protected override object GetBrowseObject(uint index) + protected override Task GetBrowseObjectAsync(uint index, CancellationToken cancellationToken) { if (GetListItem(index) is SymbolListItem symbolListItem) { - return this.LibraryManager.Workspace.GetBrowseObject(symbolListItem); + return this.LibraryManager.Workspace.GetBrowseObjectAsync(symbolListItem, cancellationToken); } - return base.GetBrowseObject(index); + return base.GetBrowseObjectAsync(index, cancellationToken); } protected override bool SupportsNavInfo @@ -540,7 +544,8 @@ protected override bool SupportsNavInfo get { return true; } } - protected override IVsNavInfo GetNavInfo(uint index) + protected override async Task GetNavInfoAsync( + uint index, CancellationToken cancellationToken) { var listItem = GetListItem(index); if (listItem == null) @@ -564,7 +569,8 @@ protected override IVsNavInfo GetNavInfo(uint index) if (listItem is SymbolListItem symbolListItem) { - return this.LibraryManager.GetNavInfo(symbolListItem, useExpandedHierarchy: IsClassView()); + return await this.LibraryManager.GetNavInfoAsync( + symbolListItem, useExpandedHierarchy: IsClassView(), cancellationToken).ConfigureAwait(true); } return null; @@ -648,28 +654,26 @@ protected override bool SupportsDescription get { return true; } } - protected override bool TryFillDescription(uint index, _VSOBJDESCOPTIONS options, IVsObjectBrowserDescription3 description) + protected override Task TryFillDescriptionAsync( + uint index, _VSOBJDESCOPTIONS options, IVsObjectBrowserDescription3 description, CancellationToken cancellationToken) { var listItem = GetListItem(index); - return this.LibraryManager.TryFillDescription(listItem, description, options); + return this.LibraryManager.TryFillDescriptionAsync( + listItem, description, options, cancellationToken); } - protected override bool TryGetProperty(uint index, _VSOBJLISTELEMPROPID propertyId, out object pvar) + protected override async Task<(bool success, object pvar)> TryGetPropertyAsync( + uint index, _VSOBJLISTELEMPROPID propertyId, CancellationToken cancellationToken) { - pvar = null; - var listItem = GetListItem(index); if (listItem == null) - { - return false; - } + return default; switch (propertyId) { case _VSOBJLISTELEMPROPID.VSOBJLISTELEMPROPID_FULLNAME: - pvar = listItem.FullNameText; - return true; + return (true, listItem.FullNameText); case _VSOBJLISTELEMPROPID.VSOBJLISTELEMPROPID_HELPKEYWORD: if (listItem is SymbolListItem symbolListItem) @@ -677,25 +681,21 @@ protected override bool TryGetProperty(uint index, _VSOBJLISTELEMPROPID property var project = this.LibraryManager.Workspace.CurrentSolution.GetProject(symbolListItem.ProjectId); if (project != null) { - var compilation = project - .GetCompilationAsync(CancellationToken.None) - .WaitAndGetResult_ObjectBrowser(CancellationToken.None); + var compilation = await project.GetCompilationAsync(cancellationToken).ConfigureAwait(true); var symbol = symbolListItem.ResolveSymbol(compilation); if (symbol != null) { var helpContextService = project.Services.GetService(); - - pvar = helpContextService.FormatSymbol(symbol); - return true; + return (true, helpContextService.FormatSymbol(symbol)); } } } - return false; + return default; } - return false; + return default; } protected override bool TryCountSourceItems(uint index, out IVsHierarchy hierarchy, out uint itemid, out uint items) @@ -741,7 +741,7 @@ protected override async Task GoToSourceAsync(uint index, VSOBJGOTOSRCTYPE srcTy { var operationExecutor = LibraryManager.ComponentModel.GetService(); - using var context = operationExecutor.BeginExecute(ServicesVSResources.IntelliSense, EditorFeaturesResources.Navigating, allowCancellation: true, showProgress: false); + using var context = operationExecutor.BeginExecute(EditorFeaturesResources.IntelliSense, EditorFeaturesResources.Navigating, allowCancellation: true, showProgress: false); var cancellationToken = context.UserCancellationToken; if (srcType == VSOBJGOTOSRCTYPE.GS_DEFINITION && diff --git a/src/VisualStudio/Core/Def/Library/ObjectBrowser/ObjectListItem.cs b/src/VisualStudio/Core/Def/Library/ObjectBrowser/ObjectListItem.cs index 3621441506afc..8830aeba89fce 100644 --- a/src/VisualStudio/Core/Def/Library/ObjectBrowser/ObjectListItem.cs +++ b/src/VisualStudio/Core/Def/Library/ObjectBrowser/ObjectListItem.cs @@ -6,6 +6,7 @@ using System.Diagnostics; using System.Threading; +using System.Threading.Tasks; using Microsoft.CodeAnalysis; using Microsoft.VisualStudio.Language.Intellisense; @@ -69,17 +70,13 @@ public ObjectListKind ParentListKind public ProjectId ProjectId { get; } - public Compilation GetCompilation(Workspace workspace) + public async Task GetCompilationAsync(Workspace workspace, CancellationToken cancellationToken) { var project = workspace.CurrentSolution.GetProject(ProjectId); if (project == null) - { return null; - } - return project - .GetCompilationAsync(CancellationToken.None) - .WaitAndGetResult_ObjectBrowser(CancellationToken.None); + return await project.GetCompilationAsync(cancellationToken).ConfigureAwait(true); } public ushort GlyphIndex { get; } diff --git a/src/VisualStudio/Core/Def/MoveStaticMembers/MoveStaticMembersDialog.xaml b/src/VisualStudio/Core/Def/MoveStaticMembers/MoveStaticMembersDialog.xaml index d656667ae1413..30a8d66022367 100644 --- a/src/VisualStudio/Core/Def/MoveStaticMembers/MoveStaticMembersDialog.xaml +++ b/src/VisualStudio/Core/Def/MoveStaticMembers/MoveStaticMembersDialog.xaml @@ -124,13 +124,13 @@ Grid.Column="0" HorizontalAlignment="Right" x:Name="Namespace" - Text="{Binding PrependedNamespace}" + Text="{Binding TypeName_NamespaceOnly}" TextTrimming="CharacterEllipsis"/> + Text="{Binding TypeName_NameOnly}"/> diff --git a/src/VisualStudio/Core/Def/MoveStaticMembers/MoveStaticMembersDialog.xaml.cs b/src/VisualStudio/Core/Def/MoveStaticMembers/MoveStaticMembersDialog.xaml.cs index cebf1d10498e1..8b52b989fd8b6 100644 --- a/src/VisualStudio/Core/Def/MoveStaticMembers/MoveStaticMembersDialog.xaml.cs +++ b/src/VisualStudio/Core/Def/MoveStaticMembers/MoveStaticMembersDialog.xaml.cs @@ -5,6 +5,7 @@ using System.Windows; using System.Windows.Controls; using System.Windows.Input; +using Microsoft.CodeAnalysis; using Microsoft.VisualStudio.PlatformUI; namespace Microsoft.VisualStudio.LanguageServices.Implementation.MoveStaticMembers; @@ -17,7 +18,7 @@ internal partial class MoveStaticMembersDialog : DialogWindow public string MoveStaticMembersDialogTitle => ServicesVSResources.Move_static_members_to_another_type_colon; public string DestinationLabelText => ServicesVSResources.Type_Name; public string OK => ServicesVSResources.OK; - public string Cancel => ServicesVSResources.Cancel; + public string Cancel => EditorFeaturesResources.Cancel; public string SelectMembers => ServicesVSResources.Select_members_colon; public MoveStaticMembersDialogViewModel ViewModel { get; } diff --git a/src/VisualStudio/Core/Def/MoveStaticMembers/MoveStaticMembersDialogViewModel.cs b/src/VisualStudio/Core/Def/MoveStaticMembers/MoveStaticMembersDialogViewModel.cs index 1932d2950132c..1ae7f5d069ba7 100644 --- a/src/VisualStudio/Core/Def/MoveStaticMembers/MoveStaticMembersDialogViewModel.cs +++ b/src/VisualStudio/Core/Def/MoveStaticMembers/MoveStaticMembersDialogViewModel.cs @@ -19,6 +19,7 @@ internal class MoveStaticMembersDialogViewModel : AbstractNotifyPropertyChanged public StaticMemberSelectionViewModel MemberSelectionViewModel { get; } private readonly ISyntaxFacts _syntaxFacts; + private readonly string _prependedNamespace; public MoveStaticMembersDialogViewModel( StaticMemberSelectionViewModel memberSelectionViewModel, @@ -30,14 +31,33 @@ public MoveStaticMembersDialogViewModel( MemberSelectionViewModel = memberSelectionViewModel; _syntaxFacts = syntaxFacts ?? throw new ArgumentNullException(nameof(syntaxFacts)); _searchText = defaultType; - _destinationName = new TypeNameItem(defaultType); + _prependedNamespace = string.IsNullOrEmpty(prependedNamespace) ? prependedNamespace : prependedNamespace + "."; + + _destinationName = new TypeNameItem(_prependedNamespace + defaultType); AvailableTypes = availableTypes; - PrependedNamespace = string.IsNullOrEmpty(prependedNamespace) ? prependedNamespace : prependedNamespace + "."; PropertyChanged += MoveMembersToTypeDialogViewModel_PropertyChanged; OnDestinationUpdated(); } + public string TypeName_NamespaceOnly + { + get + { + var lastDot = _destinationName.FullyQualifiedTypeName.LastIndexOf('.'); + return lastDot >= 0 ? _destinationName.FullyQualifiedTypeName[0..(lastDot + 1)] : ""; + } + } + + public string TypeName_NameOnly + { + get + { + var lastDot = _destinationName.FullyQualifiedTypeName.LastIndexOf('.'); + return lastDot >= 0 ? _destinationName.FullyQualifiedTypeName[(lastDot + 1)..] : _destinationName.FullyQualifiedTypeName; + } + } + private void MoveMembersToTypeDialogViewModel_PropertyChanged(object sender, PropertyChangedEventArgs e) { switch (e.PropertyName) @@ -54,14 +74,18 @@ private void MoveMembersToTypeDialogViewModel_PropertyChanged(object sender, Pro private void OnSearchTextUpdated() { - var foundItem = AvailableTypes.FirstOrDefault(t => t.TypeName == SearchText); + var foundItem = AvailableTypes.FirstOrDefault(t => t.FullyQualifiedTypeName == SearchText); if (foundItem is null) { - DestinationName = new(PrependedNamespace + SearchText); - return; + DestinationName = new(_prependedNamespace + SearchText); + } + else + { + DestinationName = foundItem; } - DestinationName = foundItem; + NotifyPropertyChanged(nameof(TypeName_NameOnly)); + NotifyPropertyChanged(nameof(TypeName_NamespaceOnly)); } public void OnDestinationUpdated() @@ -73,7 +97,7 @@ public void OnDestinationUpdated() return; } - CanSubmit = IsValidType(_destinationName.TypeName); + CanSubmit = IsValidType(_destinationName.FullyQualifiedTypeName); if (CanSubmit) { @@ -92,24 +116,17 @@ public void OnDestinationUpdated() private bool IsValidType(string typeName) { if (string.IsNullOrEmpty(typeName)) - { return false; - } foreach (var identifier in typeName.Split('.')) { - if (_syntaxFacts.IsValidIdentifier(identifier)) - { - continue; - } - - return false; + if (!_syntaxFacts.IsValidIdentifier(identifier)) + return false; } return true; } - public string PrependedNamespace { get; } public ImmutableArray AvailableTypes { get; } private TypeNameItem _destinationName; diff --git a/src/VisualStudio/Core/Def/MoveStaticMembers/StaticMemberSelectionViewModel.cs b/src/VisualStudio/Core/Def/MoveStaticMembers/StaticMemberSelectionViewModel.cs index 91986572a0256..efc1ccdf02cfe 100644 --- a/src/VisualStudio/Core/Def/MoveStaticMembers/StaticMemberSelectionViewModel.cs +++ b/src/VisualStudio/Core/Def/MoveStaticMembers/StaticMemberSelectionViewModel.cs @@ -103,6 +103,6 @@ private ImmutableHashSet FindDependents(ISymbol member) } } - return result.ToImmutableHashSet(); + return [.. result]; } } diff --git a/src/VisualStudio/Core/Def/MoveStaticMembers/TypeNameItem.cs b/src/VisualStudio/Core/Def/MoveStaticMembers/TypeNameItem.cs index 44c8afe367177..6dd304008c6ab 100644 --- a/src/VisualStudio/Core/Def/MoveStaticMembers/TypeNameItem.cs +++ b/src/VisualStudio/Core/Def/MoveStaticMembers/TypeNameItem.cs @@ -8,9 +8,9 @@ namespace Microsoft.VisualStudio.LanguageServices.Implementation.MoveStaticMembers; -internal class TypeNameItem +internal sealed class TypeNameItem { - public string TypeName { get; } + public string FullyQualifiedTypeName { get; } public INamedTypeSymbol? NamedType { get; } public string DeclarationFilePath { get; } public string DeclarationFileName { get; } @@ -22,22 +22,22 @@ public TypeNameItem(bool isFromHistory, string declarationFile, INamedTypeSymbol IsFromHistory = isFromHistory; IsNew = false; NamedType = type; - TypeName = type.ToDisplayString(); + FullyQualifiedTypeName = type.ToDisplayString(); DeclarationFileName = PathUtilities.GetFileName(declarationFile); DeclarationFilePath = declarationFile; } - public TypeNameItem(string @typeName) + public TypeNameItem(string fullyQualifiedTypeName) { IsFromHistory = false; IsNew = true; - TypeName = @typeName; + FullyQualifiedTypeName = fullyQualifiedTypeName; NamedType = null; DeclarationFileName = string.Empty; DeclarationFilePath = string.Empty; } - public override string ToString() => TypeName; + public override string ToString() => FullyQualifiedTypeName; public static int CompareTo(TypeNameItem x, TypeNameItem y) { @@ -48,8 +48,8 @@ public static int CompareTo(TypeNameItem x, TypeNameItem y) return x.IsFromHistory ? -1 : 1; } // compare by each namespace/finally type - var xnames = x.TypeName.Split('.'); - var ynames = y.TypeName.Split('.'); + var xnames = x.FullyQualifiedTypeName.Split('.'); + var ynames = y.FullyQualifiedTypeName.Split('.'); for (var i = 0; i < Math.Min(xnames.Length, ynames.Length); i++) { diff --git a/src/VisualStudio/Core/Def/MoveStaticMembers/VisualStudioMoveStaticMembersOptionsService.cs b/src/VisualStudio/Core/Def/MoveStaticMembers/VisualStudioMoveStaticMembersOptionsService.cs index 9f5deef8e5b6d..b22cf591ac5a4 100644 --- a/src/VisualStudio/Core/Def/MoveStaticMembers/VisualStudioMoveStaticMembersOptionsService.cs +++ b/src/VisualStudio/Core/Def/MoveStaticMembers/VisualStudioMoveStaticMembersOptionsService.cs @@ -25,25 +25,19 @@ namespace Microsoft.VisualStudio.LanguageServices.Implementation.MoveStaticMembers; [ExportWorkspaceService(typeof(IMoveStaticMembersOptionsService), ServiceLayer.Host), Shared] -internal class VisualStudioMoveStaticMembersOptionsService : IMoveStaticMembersOptionsService +[method: ImportingConstructor] +[method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] +internal sealed class VisualStudioMoveStaticMembersOptionsService( + IGlyphService glyphService, + IUIThreadOperationExecutor uiThreadOperationExecutor) : IMoveStaticMembersOptionsService { - private readonly IGlyphService _glyphService; - private readonly IUIThreadOperationExecutor _uiThreadOperationExecutor; + private readonly IGlyphService _glyphService = glyphService; + private readonly IUIThreadOperationExecutor _uiThreadOperationExecutor = uiThreadOperationExecutor; private const int HistorySize = 3; public readonly LinkedList History = new(); - [ImportingConstructor] - [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - public VisualStudioMoveStaticMembersOptionsService( - IGlyphService glyphService, - IUIThreadOperationExecutor uiThreadOperationExecutor) - { - _glyphService = glyphService; - _uiThreadOperationExecutor = uiThreadOperationExecutor; - } - public MoveStaticMembersOptions GetMoveMembersToTypeOptions(Document document, INamedTypeSymbol selectedType, ImmutableArray selectedNodeSymbols) { var viewModel = GetViewModel(document, selectedType, selectedNodeSymbols, History, _glyphService, _uiThreadOperationExecutor); @@ -67,7 +61,7 @@ internal static MoveStaticMembersOptions GenerateOptions(string language, MoveSt if (dialogResult) { // if the destination name contains extra namespaces, we want the last one as that is the real type name - var typeName = viewModel.DestinationName.TypeName.Split('.').Last(); + var typeName = viewModel.DestinationName.FullyQualifiedTypeName.Split('.').Last(); var newFileName = Path.ChangeExtension(typeName, language == LanguageNames.CSharp ? ".cs" : ".vb"); var selectedMembers = viewModel.MemberSelectionViewModel.CheckedMembers.SelectAsArray(vm => vm.Symbol); @@ -75,7 +69,7 @@ internal static MoveStaticMembersOptions GenerateOptions(string language, MoveSt { return new MoveStaticMembersOptions( newFileName, - viewModel.DestinationName.TypeName, + viewModel.DestinationName.FullyQualifiedTypeName, selectedMembers); } @@ -170,22 +164,33 @@ private static ImmutableArray MakeTypeNameItems( CancellationToken cancellationToken) { return currentNamespace.GetAllTypes(cancellationToken) - // only take symbols that are the same kind of type (class, module) - // and remove non-static types only when the current type is static - .Where(t => t.TypeKind == currentType.TypeKind && (t.IsStaticType() || !currentType.IsStaticType())) + // Remove non-static types only when the current type is static + .Where(destinationType => IsValidTypeToMoveBetween(destinationType, currentType) && (destinationType.IsStaticType() || !currentType.IsStaticType())) .SelectMany(t => { // for partially declared classes, we may want multiple entries for a single type. // filter to those actually in a real file, and that is not our current location. return t.Locations - .Where(l => l.IsInSource && - (currentType.Name != t.Name || GetFile(l) != currentDocument.FilePath)) + .Where(l => l.IsInSource && (currentType.Name != t.Name || GetFile(l) != currentDocument.FilePath)) .Select(l => new TypeNameItem( history.Contains(t), GetFile(l), t)); }) - .ToImmutableArrayOrEmpty() - .Sort(comparison: TypeNameItem.CompareTo); + .ToImmutableArrayOrEmpty() + .Sort(comparison: TypeNameItem.CompareTo); + } + + private static bool IsValidTypeToMoveBetween(INamedTypeSymbol destinationType, INamedTypeSymbol sourceType) + { + // Can only moved to named typed that can actually contain members. + if (destinationType.TypeKind is not (TypeKind.Class or TypeKind.Interface or TypeKind.Module or TypeKind.Struct)) + return false; + + // Very unlikely to be moving from a non-interface to an interface. Filter out for now. + if (sourceType.TypeKind != TypeKind.Interface && destinationType.TypeKind == TypeKind.Interface) + return false; + + return true; } } diff --git a/src/VisualStudio/Core/Def/MoveToNamespace/MoveToNamespaceDialog.xaml.cs b/src/VisualStudio/Core/Def/MoveToNamespace/MoveToNamespaceDialog.xaml.cs index c4227c57a1e87..b9e088ec6f740 100644 --- a/src/VisualStudio/Core/Def/MoveToNamespace/MoveToNamespaceDialog.xaml.cs +++ b/src/VisualStudio/Core/Def/MoveToNamespace/MoveToNamespaceDialog.xaml.cs @@ -7,6 +7,7 @@ using System.Windows; using System.Windows.Controls; using System.Windows.Input; +using Microsoft.CodeAnalysis; using Microsoft.VisualStudio.PlatformUI; namespace Microsoft.VisualStudio.LanguageServices.Implementation.MoveToNamespace; @@ -21,7 +22,7 @@ internal partial class MoveToNamespaceDialog : DialogWindow public string MoveToNamespaceDialogTitle => ServicesVSResources.Move_to_namespace; public string NamespaceLabelText => ServicesVSResources.Target_Namespace_colon; public string OK => ServicesVSResources.OK; - public string Cancel => ServicesVSResources.Cancel; + public string Cancel => EditorFeaturesResources.Cancel; internal MoveToNamespaceDialog(MoveToNamespaceDialogViewModel viewModel) : base() diff --git a/src/VisualStudio/Core/Def/MoveToNamespace/MoveToNamespaceDialogViewModel.cs b/src/VisualStudio/Core/Def/MoveToNamespace/MoveToNamespaceDialogViewModel.cs index a1a943894954a..886d660f69b73 100644 --- a/src/VisualStudio/Core/Def/MoveToNamespace/MoveToNamespaceDialogViewModel.cs +++ b/src/VisualStudio/Core/Def/MoveToNamespace/MoveToNamespaceDialogViewModel.cs @@ -26,9 +26,12 @@ public MoveToNamespaceDialogViewModel( { _syntaxFacts = syntaxFacts ?? throw new ArgumentNullException(nameof(syntaxFacts)); _namespaceName = defaultNamespace; - AvailableNamespaces = namespaceHistory.Select(n => new NamespaceItem(true, n)) - .Concat(availableNamespaces.Except(namespaceHistory).Select(n => new NamespaceItem(false, n))) - .ToImmutableArray(); + AvailableNamespaces = + [ + .. namespaceHistory.Select(n => new NamespaceItem(true, n)) +, + .. availableNamespaces.Except(namespaceHistory).Select(n => new NamespaceItem(false, n)), + ]; PropertyChanged += MoveToNamespaceDialogViewModel_PropertyChanged; } diff --git a/src/VisualStudio/Core/Def/MoveToNamespace/VisualStudioMoveToNamespaceOptionsService.cs b/src/VisualStudio/Core/Def/MoveToNamespace/VisualStudioMoveToNamespaceOptionsService.cs index daf4704601c11..9dc66c319c683 100644 --- a/src/VisualStudio/Core/Def/MoveToNamespace/VisualStudioMoveToNamespaceOptionsService.cs +++ b/src/VisualStudio/Core/Def/MoveToNamespace/VisualStudioMoveToNamespaceOptionsService.cs @@ -43,7 +43,7 @@ public MoveToNamespaceOptionsResult GetChangeNamespaceOptions( defaultNamespace, availableNamespaces, syntaxFactsService, - History.WhereNotNull().ToImmutableArray()); + [.. History.WhereNotNull()]); var result = _showDialog(viewModel); diff --git a/src/VisualStudio/Core/Def/NavigateTo/RoslynSearchResultViewFactory.cs b/src/VisualStudio/Core/Def/NavigateTo/RoslynSearchResultViewFactory.cs index c189b86b8045d..f1835009180b4 100644 --- a/src/VisualStudio/Core/Def/NavigateTo/RoslynSearchResultViewFactory.cs +++ b/src/VisualStudio/Core/Def/NavigateTo/RoslynSearchResultViewFactory.cs @@ -40,7 +40,7 @@ public SearchResultViewBase CreateSearchResultView(SearchResult result) searchResult, new HighlightedText( searchResult.NavigableItem.DisplayTaggedParts.JoinText(), - searchResult.NameMatchSpans.NullToEmpty().Select(m => m.ToSpan()).ToArray()), + [.. searchResult.NameMatchSpans.NullToEmpty().Select(m => m.ToSpan())]), new HighlightedText( searchResult.AdditionalInformation, []), diff --git a/src/VisualStudio/Core/Def/Notification/VisualStudioGlobalOperationNotificationService.cs b/src/VisualStudio/Core/Def/Notification/VisualStudioGlobalOperationNotificationService.cs index 8c16460fa15f0..b308cfcce306c 100644 --- a/src/VisualStudio/Core/Def/Notification/VisualStudioGlobalOperationNotificationService.cs +++ b/src/VisualStudio/Core/Def/Notification/VisualStudioGlobalOperationNotificationService.cs @@ -4,6 +4,7 @@ using System; using System.Composition; +using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Notification; using Microsoft.CodeAnalysis.Shared.TestHooks; @@ -11,13 +12,9 @@ namespace Microsoft.VisualStudio.LanguageServices.Implementation.Notification; [Export(typeof(IGlobalOperationNotificationService)), Shared] -internal partial class VisualStudioGlobalOperationNotificationService : AbstractGlobalOperationNotificationService -{ - [ImportingConstructor] - [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - public VisualStudioGlobalOperationNotificationService( - IAsynchronousOperationListenerProvider listenerProvider) - : base(listenerProvider) - { - } -} +[method: ImportingConstructor] +[method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] +internal partial class VisualStudioGlobalOperationNotificationService( + IThreadingContext threadingContext, + IAsynchronousOperationListenerProvider listenerProvider) + : AbstractGlobalOperationNotificationService(listenerProvider, threadingContext.DisposalToken); diff --git a/src/VisualStudio/Core/Def/Options/VisualStudioOptionStorage.cs b/src/VisualStudio/Core/Def/Options/VisualStudioOptionStorage.cs index 96995ad0c8d53..a830da016df2c 100644 --- a/src/VisualStudio/Core/Def/Options/VisualStudioOptionStorage.cs +++ b/src/VisualStudio/Core/Def/Options/VisualStudioOptionStorage.cs @@ -85,25 +85,19 @@ public bool TryFetch(FeatureFlagPersister persister, OptionKey2 optionKey, out o => persister.TryFetch(optionKey, FlagName, out value); } - internal sealed class LocalUserProfileStorage : VisualStudioOptionStorage + internal sealed class LocalUserProfileStorage(string path, string key) : VisualStudioOptionStorage { - private readonly string _path; - private readonly string _key; - - public LocalUserProfileStorage(string path, string key) - { - _path = path; - _key = key; - } + public string Path => path; + public string Key => key; public Task PersistAsync(LocalUserRegistryOptionPersister persister, OptionKey2 optionKey, object? value) { - persister.Persist(optionKey, _path, _key, value); + persister.Persist(optionKey, path, key, value); return Task.CompletedTask; } public bool TryFetch(LocalUserRegistryOptionPersister persister, OptionKey2 optionKey, out object? value) - => persister.TryFetch(optionKey, _path, _key, out value); + => persister.TryFetch(optionKey, path, key, out value); } public static readonly IReadOnlyDictionary Storages = new Dictionary() @@ -280,6 +274,7 @@ public bool TryFetch(LocalUserRegistryOptionPersister persister, OptionKey2 opti {"dotnet_allow_best_effort_when_extracting_method", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Specific.Allow Best Effort")}, {"dotnet_fade_out_unreachable_code", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Specific.FadeOutUnreachableCode")}, {"dotnet_fade_out_unused_imports", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Specific.FadeOutUnusedImports")}, + {"dotnet_fade_out_unused_members", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Specific.FadeOutUnusedMembers")}, {"dotnet_add_imports_on_paste", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Specific.AddImportsOnPaste2")}, {"dotnet_always_use_default_symbol_servers", new RoamingProfileStorage("TextEditor.AlwaysUseDefaultSymbolServers")}, {"csharp_insert_block_comment_start_string", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Specific.Auto Insert Block Comment Start String")}, @@ -296,7 +291,6 @@ public bool TryFetch(LocalUserRegistryOptionPersister persister, OptionKey2 opti {"dotnet_navigate_to_decompiled_sources", new RoamingProfileStorage("TextEditor.NavigateToDecompiledSources")}, {"dotnet_navigate_to_source_link_and_embedded_sources", new RoamingProfileStorage("TextEditor.NavigateToSourceLinkAndEmbeddedSources")}, {"dotnet_offer_remove_unused_references", new RoamingProfileStorage("TextEditor.OfferRemoveUnusedReferences")}, - {"dotnet_offer_remove_unused_references_feature_flag", new FeatureFlagStorage(@"Roslyn.RemoveUnusedReferences")}, {"dotnet_enter_outlining_mode_on_file_open", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Specific.Outlining")}, {"visual_basic_pretty_listing", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Specific.PrettyListing")}, #pragma warning disable CS0612 // Type or member is obsolete diff --git a/src/VisualStudio/Core/Def/Packaging/PackageInstallerServiceFactory.cs b/src/VisualStudio/Core/Def/Packaging/PackageInstallerServiceFactory.cs index 662c15204f45d..a602ba3b033f2 100644 --- a/src/VisualStudio/Core/Def/Packaging/PackageInstallerServiceFactory.cs +++ b/src/VisualStudio/Core/Def/Packaging/PackageInstallerServiceFactory.cs @@ -155,7 +155,7 @@ public ImmutableArray TryGetPackageSources() { // The result was not available yet (or it was canceled/faulted). Just return an empty result to // signify we couldn't get this right now. - return ImmutableArray.Empty; + return []; } } @@ -178,7 +178,7 @@ private async Task> GetPackageSourcesAsync() // https://github.com/dotnet/roslyn/issues/40857 } - return ImmutableArray.Empty; + return []; } [MemberNotNullWhen(true, nameof(_packageInstaller))] @@ -630,7 +630,7 @@ public ImmutableArray GetInstalledVersions(string packageName) return diff != 0 ? diff : -v1.Version.CompareTo(v2.Version); }); - return versionsAndSplits.Select(v => v.Version).ToImmutableArray(); + return [.. versionsAndSplits.Select(v => v.Version)]; } private static int CompareSplit(string[] split1, string[] split2) diff --git a/src/VisualStudio/Core/Def/PickMembers/PickMembersDialog.xaml.cs b/src/VisualStudio/Core/Def/PickMembers/PickMembersDialog.xaml.cs index 8304e5a6b2404..13e3b0fc02a85 100644 --- a/src/VisualStudio/Core/Def/PickMembers/PickMembersDialog.xaml.cs +++ b/src/VisualStudio/Core/Def/PickMembers/PickMembersDialog.xaml.cs @@ -10,6 +10,7 @@ using System.Windows; using System.Windows.Controls; using System.Windows.Input; +using Microsoft.CodeAnalysis; using Microsoft.VisualStudio.LanguageServices.Implementation.Utilities; using Microsoft.VisualStudio.LanguageServices.Utilities; using Microsoft.VisualStudio.PlatformUI; @@ -30,7 +31,7 @@ internal partial class PickMembersDialog : DialogWindow public string SelectAll => ServicesVSResources.Select_All; public string DeselectAll => ServicesVSResources.Deselect_All; public string OK => ServicesVSResources.OK; - public string Cancel => ServicesVSResources.Cancel; + public string Cancel => EditorFeaturesResources.Cancel; internal PickMembersDialog(PickMembersDialogViewModel viewModel, string title) { diff --git a/src/VisualStudio/Core/Def/PickMembers/PickMembersDialogViewModel.cs b/src/VisualStudio/Core/Def/PickMembers/PickMembersDialogViewModel.cs index 13447872513ab..85a8a3558835c 100644 --- a/src/VisualStudio/Core/Def/PickMembers/PickMembersDialogViewModel.cs +++ b/src/VisualStudio/Core/Def/PickMembers/PickMembersDialogViewModel.cs @@ -34,9 +34,9 @@ internal PickMembersDialogViewModel( ImmutableArray options, bool selectAll) { - _allMembers = members.Select(m => new MemberSymbolViewModel(m, glyphService)).ToList(); + _allMembers = [.. members.Select(m => new MemberSymbolViewModel(m, glyphService))]; MemberContainers = _allMembers; - Options = options.Select(o => new OptionViewModel(o)).ToList(); + Options = [.. options.Select(o => new OptionViewModel(o))]; if (selectAll) { @@ -53,7 +53,7 @@ internal void Filter(string searchText) searchText = searchText.Trim(); MemberContainers = searchText.Length == 0 ? _allMembers - : _allMembers.Where(m => m.SymbolAutomationText.IndexOf(searchText, StringComparison.OrdinalIgnoreCase) >= 0).ToList(); + : [.. _allMembers.Where(m => m.SymbolAutomationText.IndexOf(searchText, StringComparison.OrdinalIgnoreCase) >= 0)]; NotifyPropertyChanged(nameof(MemberContainers)); } diff --git a/src/VisualStudio/Core/Def/PickMembers/VisualStudioPickMembersService.cs b/src/VisualStudio/Core/Def/PickMembers/VisualStudioPickMembersService.cs index bcf38baa01c80..ff558c9c893df 100644 --- a/src/VisualStudio/Core/Def/PickMembers/VisualStudioPickMembersService.cs +++ b/src/VisualStudio/Core/Def/PickMembers/VisualStudioPickMembersService.cs @@ -38,9 +38,7 @@ public PickMembersResult PickMembers( if (result == true) { return new PickMembersResult( - viewModel.MemberContainers.Where(c => c.IsChecked) - .Select(c => c.Symbol) - .ToImmutableArray(), + [.. viewModel.MemberContainers.Where(c => c.IsChecked).Select(c => c.Symbol)], options, viewModel.SelectedAll); } diff --git a/src/VisualStudio/Core/Def/Preview/FileChange.cs b/src/VisualStudio/Core/Def/Preview/FileChange.cs index 1bfd9a52fb3f7..dd71eeab868a5 100644 --- a/src/VisualStudio/Core/Def/Preview/FileChange.cs +++ b/src/VisualStudio/Core/Def/Preview/FileChange.cs @@ -135,7 +135,7 @@ private static string GetDisplayText(string excerpt) { if (excerpt.Contains("\r\n")) { - var split = excerpt.Split(new[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries); + var split = excerpt.Split(["\r\n"], StringSplitOptions.RemoveEmptyEntries); if (split.Length > 1) { return string.Format("{0} ... {1}", split[0].Trim(), split[^1].Trim()); diff --git a/src/VisualStudio/Core/Def/Progression/GraphBuilder.cs b/src/VisualStudio/Core/Def/Progression/GraphBuilder.cs index 47c0201ce4ad2..5caae9a75ac52 100644 --- a/src/VisualStudio/Core/Def/Progression/GraphBuilder.cs +++ b/src/VisualStudio/Core/Def/Progression/GraphBuilder.cs @@ -210,7 +210,7 @@ public async Task AddNodeAsync( // We may need to look up source code within this solution if (preferredLocation == null && symbol.Locations.Any(static loc => loc.IsInMetadata)) { - var newSymbol = await SymbolFinder.FindSourceDefinitionAsync(symbol, contextProject.Solution, cancellationToken).ConfigureAwait(false); + var newSymbol = SymbolFinder.FindSourceDefinition(symbol, contextProject.Solution, cancellationToken); if (newSymbol != null) preferredLocation = newSymbol.Locations.Where(loc => loc.IsInSource).FirstOrDefault(); } @@ -849,7 +849,7 @@ public ImmutableArray GetCreatedNodes(CancellationToken cancellationT { using (_gate.DisposableWait(cancellationToken)) { - return _createdNodes.ToImmutableArray(); + return [.. _createdNodes]; } } } diff --git a/src/VisualStudio/Core/Def/Progression/GraphNodeIdCreation.cs b/src/VisualStudio/Core/Def/Progression/GraphNodeIdCreation.cs index 982dcfd253d82..7038949464e5f 100644 --- a/src/VisualStudio/Core/Def/Progression/GraphNodeIdCreation.cs +++ b/src/VisualStudio/Core/Def/Progression/GraphNodeIdCreation.cs @@ -192,7 +192,7 @@ private static async Task GetPartialForNamedTypeAsync(INamedTypeSym foreach (var arg in namedType.TypeArguments) { var nodes = await GetPartialsForNamespaceAndTypeAsync(arg, includeNamespace: true, solution: solution, cancellationToken: cancellationToken, isInGenericArguments: true).ConfigureAwait(false); - genericArguments.Add(GraphNodeId.GetNested(nodes.ToArray())); + genericArguments.Add(GraphNodeId.GetNested([.. nodes])); } partials.Add(GraphNodeId.GetArray( @@ -266,7 +266,7 @@ private static async Task GetPartialForTypeParameterSymbolAsync(ITy { var nodes = await GetPartialsForNamespaceAndTypeAsync(typeParameterSymbol, false, solution, cancellationToken).ConfigureAwait(false); return GraphNodeId.GetPartial(nodeName, - new GraphNodeIdCollection(false, nodes.ToArray())); + new GraphNodeIdCollection(false, [.. nodes])); } } diff --git a/src/VisualStudio/Core/Def/Progression/GraphProvider.cs b/src/VisualStudio/Core/Def/Progression/GraphProvider.cs index 8fcf3e7e52387..1ab0c1d885dd7 100644 --- a/src/VisualStudio/Core/Def/Progression/GraphProvider.cs +++ b/src/VisualStudio/Core/Def/Progression/GraphProvider.cs @@ -344,16 +344,16 @@ private static bool IsAnyTypeKind(GraphNode node, params TypeKind[] typeKinds) => typeKinds.Any(k => node[RoslynGraphProperties.TypeKind].Equals(k)); private static readonly GraphCommandDefinition s_overridesCommandDefinition = - new("Overrides", ServicesVSResources.Overrides_, GraphContextDirection.Target, 700); + new("Overrides", EditorFeaturesResources.Overrides_, GraphContextDirection.Target, 700); private static readonly GraphCommandDefinition s_overriddenByCommandDefinition = - new("OverriddenBy", ServicesVSResources.Overridden_By, GraphContextDirection.Source, 700); + new("OverriddenBy", EditorFeaturesResources.Overridden_By, GraphContextDirection.Source, 700); private static readonly GraphCommandDefinition s_implementsCommandDefinition = - new("Implements", ServicesVSResources.Implements_, GraphContextDirection.Target, 600); + new("Implements", EditorFeaturesResources.Implements_, GraphContextDirection.Target, 600); private static readonly GraphCommandDefinition s_implementedByCommandDefinition = - new("ImplementedBy", ServicesVSResources.Implemented_By, GraphContextDirection.Source, 600); + new("ImplementedBy", EditorFeaturesResources.Implemented_By, GraphContextDirection.Source, 600); public T? GetExtension(GraphObject graphObject, T previous) where T : class { diff --git a/src/VisualStudio/Core/Def/Progression/GraphQueryManager.cs b/src/VisualStudio/Core/Def/Progression/GraphQueryManager.cs index a906c02352373..034074da3a89b 100644 --- a/src/VisualStudio/Core/Def/Progression/GraphQueryManager.cs +++ b/src/VisualStudio/Core/Def/Progression/GraphQueryManager.cs @@ -26,7 +26,7 @@ internal class GraphQueryManager /// This gate locks manipulation of . /// private readonly object _gate = new(); - private ImmutableArray<(WeakReference context, ImmutableArray queries)> _trackedQueries = ImmutableArray<(WeakReference, ImmutableArray)>.Empty; + private ImmutableArray<(WeakReference context, ImmutableArray queries)> _trackedQueries = []; private readonly AsyncBatchingWorkQueue _updateQueue; diff --git a/src/VisualStudio/Core/Def/ProjectSystem/BrokeredService/WorkspaceProject.cs b/src/VisualStudio/Core/Def/ProjectSystem/BrokeredService/WorkspaceProject.cs index 990197d678258..93b10cabb5755 100644 --- a/src/VisualStudio/Core/Def/ProjectSystem/BrokeredService/WorkspaceProject.cs +++ b/src/VisualStudio/Core/Def/ProjectSystem/BrokeredService/WorkspaceProject.cs @@ -165,7 +165,7 @@ public async Task SetBuildSystemPropertiesAsync(IReadOnlyDictionary arguments, CancellationToken cancellationToken) { - _project.SetOptions(arguments.ToImmutableArray()); + _project.SetOptions([.. arguments]); return Task.CompletedTask; } diff --git a/src/VisualStudio/Core/Def/ProjectSystem/CPS/IWorkspaceProjectContextFactory.cs b/src/VisualStudio/Core/Def/ProjectSystem/CPS/IWorkspaceProjectContextFactory.cs index 68b26e2571691..9bc7159e1e56e 100644 --- a/src/VisualStudio/Core/Def/ProjectSystem/CPS/IWorkspaceProjectContextFactory.cs +++ b/src/VisualStudio/Core/Def/ProjectSystem/CPS/IWorkspaceProjectContextFactory.cs @@ -89,7 +89,7 @@ internal abstract class EvaluationData /// The is not listed in /// public virtual ImmutableArray GetItemValues(string name) - => ImmutableArray.Empty; + => []; public string GetRequiredPropertyValue(string name) { diff --git a/src/VisualStudio/Core/Def/ProjectSystem/FileChangeWatcher.cs b/src/VisualStudio/Core/Def/ProjectSystem/FileChangeWatcher.cs index 8d3e56b3365fb..c4c5124e4bf76 100644 --- a/src/VisualStudio/Core/Def/ProjectSystem/FileChangeWatcher.cs +++ b/src/VisualStudio/Core/Def/ProjectSystem/FileChangeWatcher.cs @@ -166,7 +166,7 @@ private WatcherOperation(Kind kind, OneOrMany files, _VSFILECHANGEFLAGS _tokens = tokens; // Other watching fields are not used for this kind - _filters = ImmutableArray.Empty; + _filters = []; _cookies = null!; } @@ -178,7 +178,7 @@ private WatcherOperation(Kind kind, List cookies) _cookies = cookies; // Other watching fields are not used for this kind - _filters = ImmutableArray.Empty; + _filters = []; _fileChangeFlags = 0; _sink = null!; _tokens = OneOrMany.Empty; @@ -193,7 +193,7 @@ private WatcherOperation(Kind kind, OneOrMany tokens _tokens = tokens; // Other watching fields are not used for this kind - _filters = ImmutableArray.Empty; + _filters = []; _fileChangeFlags = 0; _sink = null!; _cookies = null!; @@ -307,7 +307,7 @@ public async ValueTask ApplyAsync(IVsAsyncFileChangeEx2 service, CancellationTok _cookies.Add(cookie); if (_filters.Length > 0) - await service.FilterDirectoryChangesAsync(cookie, _filters.ToArray(), cancellationToken).ConfigureAwait(false); + await service.FilterDirectoryChangesAsync(cookie, [.. _filters], cancellationToken).ConfigureAwait(false); return; @@ -386,7 +386,7 @@ public void Dispose() } _fileChangeWatcher._taskQueue.AddWork(WatcherOperation.UnwatchDirectories(_directoryWatchCookies)); - _fileChangeWatcher._taskQueue.AddWork(WatcherOperation.UnwatchFiles(_activeFileWatchingTokens.ToImmutableArray())); + _fileChangeWatcher._taskQueue.AddWork(WatcherOperation.UnwatchFiles([.. _activeFileWatchingTokens])); } public IWatchedFile EnqueueWatchingFile(string filePath) diff --git a/src/VisualStudio/Core/Def/ProjectSystem/Legacy/AbstractLegacyProject.cs b/src/VisualStudio/Core/Def/ProjectSystem/Legacy/AbstractLegacyProject.cs index 8e9aeb5717d2b..4618fc78423ca 100644 --- a/src/VisualStudio/Core/Def/ProjectSystem/Legacy/AbstractLegacyProject.cs +++ b/src/VisualStudio/Core/Def/ProjectSystem/Legacy/AbstractLegacyProject.cs @@ -67,8 +67,8 @@ public AbstractLegacyProject( IThreadingContext threadingContext, string externalErrorReportingPrefix) { - _threadingContext = threadingContext; - _threadingContext.ThrowIfNotOnUIThread(); + ThreadingContext = threadingContext; + ThreadingContext.ThrowIfNotOnUIThread(); Contract.ThrowIfNull(hierarchy); var componentModel = (IComponentModel)serviceProvider.GetService(typeof(SComponentModel)); @@ -177,7 +177,7 @@ protected void AddFile( string filename, SourceCodeKind sourceCodeKind) { - _threadingContext.ThrowIfNotOnUIThread(); + ThreadingContext.ThrowIfNotOnUIThread(); // We have tests that assert that XOML files should not get added; this was similar // behavior to how ASP.NET projects would add .aspx files even though we ultimately ignored @@ -209,7 +209,7 @@ protected void AddFile( if (!string.IsNullOrEmpty(linkMetadata)) { var linkFolderPath = Path.GetDirectoryName(linkMetadata); - folders = linkFolderPath.Split(PathSeparatorCharacters, StringSplitOptions.RemoveEmptyEntries).ToImmutableArray(); + folders = [.. linkFolderPath.Split(PathSeparatorCharacters, StringSplitOptions.RemoveEmptyEntries)]; } else if (!string.IsNullOrEmpty(ProjectSystemProject.FilePath)) { @@ -306,7 +306,7 @@ private static Guid GetProjectIDGuid(IVsHierarchy hierarchy) /// Using item IDs as a key like this in a long-lived way is considered unsupported by CPS and other /// IVsHierarchy providers, but this code (which is fairly old) still makes the assumptions anyways. private readonly Dictionary> _folderNameMap = []; - private readonly IThreadingContext _threadingContext; + protected readonly IThreadingContext ThreadingContext; private ImmutableArray GetFolderNamesForDocument(string filename) { @@ -321,7 +321,7 @@ private ImmutableArray GetFolderNamesForDocument(string filename) private ImmutableArray GetFolderNamesForDocument(uint documentItemID) { - _threadingContext.ThrowIfNotOnUIThread(); + ThreadingContext.ThrowIfNotOnUIThread(); if (documentItemID != (uint)VSConstants.VSITEMID.Nil && Hierarchy.GetProperty(documentItemID, (int)VsHierarchyPropID.Parent, out var parentObj) == VSConstants.S_OK) { @@ -332,12 +332,12 @@ private ImmutableArray GetFolderNamesForDocument(uint documentItemID) } } - return ImmutableArray.Empty; + return []; } private ImmutableArray GetFolderNamesForFolder(uint folderItemID) { - _threadingContext.ThrowIfNotOnUIThread(); + ThreadingContext.ThrowIfNotOnUIThread(); using var pooledObject = SharedPools.Default>().GetPooledObject(); @@ -346,7 +346,7 @@ private ImmutableArray GetFolderNamesForFolder(uint folderItemID) if (!_folderNameMap.TryGetValue(folderItemID, out var folderNames)) { ComputeFolderNames(folderItemID, newFolderNames, Hierarchy); - folderNames = newFolderNames.ToImmutableArray(); + folderNames = [.. newFolderNames]; _folderNameMap.Add(folderItemID, folderNames); } else @@ -357,7 +357,7 @@ private ImmutableArray GetFolderNamesForFolder(uint folderItemID) ComputeFolderNames(folderItemID, newFolderNames, Hierarchy); if (!Enumerable.SequenceEqual(folderNames, newFolderNames)) { - folderNames = newFolderNames.ToImmutableArray(); + folderNames = [.. newFolderNames]; _folderNameMap[folderItemID] = folderNames; } } diff --git a/src/VisualStudio/Core/Def/ProjectSystem/MetadataReferences/VisualStudioMetadataReferenceManager.cs b/src/VisualStudio/Core/Def/ProjectSystem/MetadataReferences/VisualStudioMetadataReferenceManager.cs index 7e9cd704155f0..b623f91df8704 100644 --- a/src/VisualStudio/Core/Def/ProjectSystem/MetadataReferences/VisualStudioMetadataReferenceManager.cs +++ b/src/VisualStudio/Core/Def/ProjectSystem/MetadataReferences/VisualStudioMetadataReferenceManager.cs @@ -135,14 +135,14 @@ internal static IEnumerable GetReferencePaths() private static ImmutableArray GetRuntimeDirectories() { - return GetReferencePaths().Concat( + return [.. GetReferencePaths().Concat( new string[] { Environment.GetFolderPath(Environment.SpecialFolder.Windows), Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles), Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86), RuntimeEnvironment.GetRuntimeDirectory() - }).Select(FileUtilities.NormalizeDirectoryPath).ToImmutableArray(); + }).Select(FileUtilities.NormalizeDirectoryPath)]; } /// diff --git a/src/VisualStudio/Core/Def/ProjectSystem/MiscellaneousFilesWorkspace.cs b/src/VisualStudio/Core/Def/ProjectSystem/MiscellaneousFilesWorkspace.cs index 272c0e8c93bd1..dff438e9f3d47 100644 --- a/src/VisualStudio/Core/Def/ProjectSystem/MiscellaneousFilesWorkspace.cs +++ b/src/VisualStudio/Core/Def/ProjectSystem/MiscellaneousFilesWorkspace.cs @@ -69,7 +69,7 @@ public MiscellaneousFilesWorkspace( _openTextBufferProvider = openTextBufferProvider; _fileTrackingMetadataAsSourceService = fileTrackingMetadataAsSourceService; - _metadataReferences = ImmutableArray.CreateRange(CreateMetadataReferences()); + _metadataReferences = [.. CreateMetadataReferences()]; _openTextBufferProvider.AddListener(this); } diff --git a/src/VisualStudio/Core/Def/ProjectSystem/OpenTextBufferProvider.cs b/src/VisualStudio/Core/Def/ProjectSystem/OpenTextBufferProvider.cs index d874868638ae2..896ade40b3de4 100644 --- a/src/VisualStudio/Core/Def/ProjectSystem/OpenTextBufferProvider.cs +++ b/src/VisualStudio/Core/Def/ProjectSystem/OpenTextBufferProvider.cs @@ -40,7 +40,7 @@ internal sealed class OpenTextBufferProvider : IVsRunningDocTableEvents3, IDispo private readonly IVsEditorAdaptersFactoryService _editorAdaptersFactoryService; private readonly IVsRunningDocumentTable4 _runningDocumentTable; - private ImmutableArray _listeners = ImmutableArray.Empty; + private ImmutableArray _listeners = []; /// /// The map from monikers to open text buffers; because we can only fetch the text buffer on the UI thread, all updates to this must be done from the UI thread. diff --git a/src/VisualStudio/Core/Def/ProjectSystem/VisualStudioWorkspace.cs b/src/VisualStudio/Core/Def/ProjectSystem/VisualStudioWorkspace.cs index 56c6efe24ddac..d3ee904c6eb51 100644 --- a/src/VisualStudio/Core/Def/ProjectSystem/VisualStudioWorkspace.cs +++ b/src/VisualStudio/Core/Def/ProjectSystem/VisualStudioWorkspace.cs @@ -58,7 +58,7 @@ internal VisualStudioWorkspace(HostServices hostServices) /// public abstract EnvDTE.FileCodeModel GetFileCodeModel(DocumentId documentId); - internal abstract object? GetBrowseObject(SymbolListItem symbolListItem); + internal abstract Task GetBrowseObjectAsync(SymbolListItem symbolListItem, CancellationToken cancellationToken); [Obsolete("Use TryGoToDefinitionAsync instead", error: false)] public abstract bool TryGoToDefinition(ISymbol symbol, Project project, CancellationToken cancellationToken); diff --git a/src/VisualStudio/Core/Def/ProjectSystem/VisualStudioWorkspaceImpl.RenameDocumentUndoUnit.cs b/src/VisualStudio/Core/Def/ProjectSystem/VisualStudioWorkspaceImpl.RenameDocumentUndoUnit.cs index cd469bc1128f1..d52e6ba1fa938 100644 --- a/src/VisualStudio/Core/Def/ProjectSystem/VisualStudioWorkspaceImpl.RenameDocumentUndoUnit.cs +++ b/src/VisualStudio/Core/Def/ProjectSystem/VisualStudioWorkspaceImpl.RenameDocumentUndoUnit.cs @@ -4,6 +4,7 @@ using System; using System.Linq; +using Microsoft.CodeAnalysis; using Microsoft.VisualStudio.OLE.Interop; namespace Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem; @@ -38,7 +39,7 @@ public void Do(IOleUndoManager pUndoManager) } public void GetDescription(out string pBstr) - => pBstr = string.Format(ServicesVSResources.Rename_0_to_1, _fromName, _toName); + => pBstr = string.Format(WorkspacesResources.Rename_0_to_1, _fromName, _toName); public void GetUnitType(out Guid pClsid, out int plID) => throw new NotImplementedException(); diff --git a/src/VisualStudio/Core/Def/PullMemberUp/MainDialog/BaseTypeTreeNodeViewModel.cs b/src/VisualStudio/Core/Def/PullMemberUp/MainDialog/BaseTypeTreeNodeViewModel.cs index c17be0a1f2e35..40c5e3e975edf 100644 --- a/src/VisualStudio/Core/Def/PullMemberUp/MainDialog/BaseTypeTreeNodeViewModel.cs +++ b/src/VisualStudio/Core/Def/PullMemberUp/MainDialog/BaseTypeTreeNodeViewModel.cs @@ -54,12 +54,11 @@ public static BaseTypeTreeNodeViewModel CreateBaseTypeTree( var currentTreeNode = queue.Dequeue(); var currentTypeSymbol = currentTreeNode.Symbol; - currentTreeNode.BaseTypeNodes = currentTypeSymbol.Interfaces + currentTreeNode.BaseTypeNodes = [.. currentTypeSymbol.Interfaces .Concat(currentTypeSymbol.BaseType) .Where(baseType => baseType != null && MemberAndDestinationValidator.IsDestinationValid(solution, baseType, cancellationToken)) .OrderBy(baseType => baseType.ToDisplayString()) - .Select(baseType => new BaseTypeTreeNodeViewModel(baseType, glyphService) { IsChecked = false, IsExpanded = true }) - .ToImmutableArray(); + .Select(baseType => new BaseTypeTreeNodeViewModel(baseType, glyphService) { IsChecked = false, IsExpanded = true })]; foreach (var node in currentTreeNode.BaseTypeNodes) { diff --git a/src/VisualStudio/Core/Def/PullMemberUp/MainDialog/PullMemberUpDialog.xaml.cs b/src/VisualStudio/Core/Def/PullMemberUp/MainDialog/PullMemberUpDialog.xaml.cs index 93bd4eb0ae623..c943237befa96 100644 --- a/src/VisualStudio/Core/Def/PullMemberUp/MainDialog/PullMemberUpDialog.xaml.cs +++ b/src/VisualStudio/Core/Def/PullMemberUp/MainDialog/PullMemberUpDialog.xaml.cs @@ -6,6 +6,7 @@ using System.Windows; using System.Windows.Input; +using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.PullMemberUp; using Microsoft.VisualStudio.LanguageServices.Implementation.CommonControls; using Microsoft.VisualStudio.LanguageServices.Implementation.PullMemberUp.WarningDialog; @@ -19,7 +20,7 @@ namespace Microsoft.VisualStudio.LanguageServices.Implementation.PullMemberUp.Ma internal partial class PullMemberUpDialog : DialogWindow { public string OK => ServicesVSResources.OK; - public string Cancel => ServicesVSResources.Cancel; + public string Cancel => EditorFeaturesResources.Cancel; public string PullMembersUpTitle => ServicesVSResources.Pull_Members_Up; public string SelectMembers => ServicesVSResources.Select_members_colon; public string SelectDestination => ServicesVSResources.Select_destination_colon; diff --git a/src/VisualStudio/Core/Def/PullMemberUp/SymbolDependentsBuilder.cs b/src/VisualStudio/Core/Def/PullMemberUp/SymbolDependentsBuilder.cs index 0020adf2af5d2..97168cd4e0557 100644 --- a/src/VisualStudio/Core/Def/PullMemberUp/SymbolDependentsBuilder.cs +++ b/src/VisualStudio/Core/Def/PullMemberUp/SymbolDependentsBuilder.cs @@ -48,7 +48,7 @@ public SymbolWalker( { _project = project; _declarationService = project.Services.GetRequiredService(); - _membersInType = membersInType.ToImmutableHashSet(); + _membersInType = [.. membersInType]; _member = member; _cancellationToken = cancellationToken; } @@ -63,7 +63,7 @@ public async Task> FindMemberDependentsAsync() Visit(compilation.GetSemanticModel(syntax.SyntaxTree).GetOperation(syntax, _cancellationToken)); } - return _dependents.ToImmutableArray(); + return [.. _dependents]; } public override void Visit(IOperation operation) diff --git a/src/VisualStudio/Core/Def/ServicesVSResources.resx b/src/VisualStudio/Core/Def/ServicesVSResources.resx index 0ecb04dcae98a..04b3813454cc3 100644 --- a/src/VisualStudio/Core/Def/ServicesVSResources.resx +++ b/src/VisualStudio/Core/Def/ServicesVSResources.resx @@ -156,21 +156,6 @@ Preview unavailable - - Overrides - - - Overridden By - - - Inherits - - - Implements - - - Implemented By - Invalid access. @@ -222,27 +207,12 @@ Assembly - - Exceptions: - Member of {0} - - Parameters: - Project - - Remarks: - - - Returns: - - - Summary: - Type Parameters: @@ -285,15 +255,9 @@ Use the dropdown to view and switch to other projects this file may belong to. The analyzer assembly '{0}' has changed. Diagnostics may be incorrect until Visual Studio is restarted. - - Cancel - _Deselect All - - Extract Interface - Generated name: @@ -321,9 +285,6 @@ Use the dropdown to view and switch to other projects this file may belong to. Add to _current file - - Change Signature - _Create new file @@ -408,15 +369,6 @@ Use the dropdown to view and switch to other projects this file may belong to. 1 reference - - '{0}' encountered an error and has been disabled. - - - Enable - - - Enable and ignore future errors - No Changes @@ -426,9 +378,6 @@ Use the dropdown to view and switch to other projects this file may belong to. Determining current block. - - IntelliSense - MissingAnalyzerReference @@ -477,12 +426,6 @@ Use the dropdown to view and switch to other projects this file may belong to. <Unknown> - - No - - - Yes - Enter a title for this Naming Style. @@ -631,9 +574,6 @@ Additional information: {1} Block Structure Guides - - Outlining - Show guides for code level constructs @@ -823,6 +763,9 @@ Additional information: {1} Analysis + + Fade out unused members + Fade out unreachable code @@ -838,6 +781,12 @@ Additional information: {1} In other operators + + Never + + + Title + Never if unnecessary @@ -1066,9 +1015,6 @@ Additional information: {1} A type and name must be provided. - - Rename {0} to {1} - class {Locked} This string can be found under "Tools | Options | Text Editor | C# | Code Style | Naming | Manage Specifications | + | Symbol kinds". All of the "NamingSpecification_CSharp_*" strings represent language constructs, and some of them are also actual keywords (including this one). @@ -1294,9 +1240,6 @@ Additional information: {1} Value to inject at call sites - - Value: - Editor Color Scheme @@ -1306,12 +1249,6 @@ Additional information: {1} Visual Studio 2017 - - Editor color scheme options are only available when using a color theme bundled with Visual Studio. The color theme can be configured from the Environment > General options page. - - - Some color scheme colors are being overridden by changes made in the Environment > Fonts and Colors options page. Choose `Use Defaults` in the Fonts and Colors page to revert all customizations. - Prefer simplified boolean expressions @@ -1364,9 +1301,6 @@ Additional information: {1} Infer from context - - None - Warning: duplicate parameter name @@ -1407,9 +1341,6 @@ Additional information: {1} Comments - - Inline Hints - Show hints for everything else @@ -1461,9 +1392,12 @@ Additional information: {1} Symbols without references - + Tab twice to insert arguments (experimental) + + Tab twice to insert arguments + Apply @@ -1501,9 +1435,6 @@ Additional information: {1} No unused references were found. - - Show "Remove Unused References" command in Solution Explorer (experimental) - Enable file logging for diagnostics (logged in '%Temp%\Roslyn' folder) @@ -1543,9 +1474,6 @@ Additional information: {1} Enabled - - Error - Whitespace @@ -1555,21 +1483,9 @@ Additional information: {1} Newline (\\n) - - Refactoring Only - - - Suggestion - - - Title - Value - - Warning - Search Settings @@ -1715,9 +1631,6 @@ Additional information: {1} For non interface members - - Never - Omit if default @@ -1754,9 +1667,6 @@ Additional information: {1} Close Tab - - Paste - Stack Trace {0} Header for numbered stack trace view tabs @@ -1780,9 +1690,6 @@ Additional information: {1} External Sources - - Call Hierarchy - Navigating @@ -1792,9 +1699,6 @@ Additional information: {1} Go To Definition - - Navigate asynchronously (experimental) - Always use default symbol servers for navigation @@ -1820,9 +1724,6 @@ Additional information: {1} Search Document Outline - - Rename - Rename asynchronously (experimental) @@ -1946,4 +1847,103 @@ Additional information: {1} Automatically reload updated analyzers and generators (requires restart) + + Insert Snippet + + + _Show procedure line separators + + + Editor Help + + + Highlight related _keywords under cursor + + + _Highlight references to symbol under cursor + + + Optimize for solution size + + + Large + + + Regular + + + Small + + + Performance + + + _Highlight matching portions of completion list items + + + Highlight matching portions of completion list items + + + Show completion item filters + + + Show completion item _filters + + + Snippets behavior + + + Show completion list after a character is deleted + + + Show completion list after a character is _deleted + + + Never include snippets + + + _Always add new line on enter + + + _Never add new line on enter + + + Highlighting + + + Show remarks in Quick Info + + + Show items from unimported namespaces + + + Unused local + + + Enter key behavior: + + + Enter key behavior + + + Show preview for rename _tracking + + + _Only add new line on enter after end of fully typed word + + + Only add new line on enter after end of fully typed word + + + Show "Remove Unused References" command in Solution Explorer + + + _Show completion list after a character is typed + + + Show completion list after a character is typed + + + Experimental feature + \ No newline at end of file diff --git a/src/VisualStudio/Core/Def/Snippets/AbstractSnippetExpansionLanguageHelper.cs b/src/VisualStudio/Core/Def/Snippets/AbstractSnippetExpansionLanguageHelper.cs index c4aa716835af8..188e9ddee7526 100644 --- a/src/VisualStudio/Core/Def/Snippets/AbstractSnippetExpansionLanguageHelper.cs +++ b/src/VisualStudio/Core/Def/Snippets/AbstractSnippetExpansionLanguageHelper.cs @@ -6,9 +6,11 @@ using System.Collections.Generic; using System.Linq; using System.Threading; +using System.Threading.Tasks; using System.Xml.Linq; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.AddImport; +using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.Formatting; using Microsoft.VisualStudio.LanguageServices.Implementation.Extensions; using Microsoft.VisualStudio.LanguageServices.Implementation.Snippets; @@ -20,13 +22,15 @@ namespace Microsoft.VisualStudio.LanguageServices.Snippets; -internal abstract class AbstractSnippetExpansionLanguageHelper +internal abstract class AbstractSnippetExpansionLanguageHelper(IThreadingContext threadingContext) : ISnippetExpansionLanguageHelper { + protected readonly IThreadingContext ThreadingContext = threadingContext; + public abstract Guid LanguageServiceGuid { get; } public abstract string FallbackDefaultLiteral { get; } - public abstract Document AddImports(Document document, AddImportPlacementOptions addImportOptions, SyntaxFormattingOptions formattingOptions, int position, XElement snippetNode, CancellationToken cancellationToken); + public abstract Task AddImportsAsync(Document document, AddImportPlacementOptions addImportOptions, SyntaxFormattingOptions formattingOptions, int position, XElement snippetNode, CancellationToken cancellationToken); public abstract ITrackingSpan? InsertEmptyCommentAndGetEndPositionTrackingSpan(IVsExpansionSession expansionSession, ITextView textView, ITextBuffer subjectBuffer); public bool TryGetSubjectBufferSpan(ITextView textView, ITextBuffer subjectBuffer, VsTextSpan surfaceBufferTextSpan, out SnapshotSpan subjectBufferSpan) diff --git a/src/VisualStudio/Core/Def/Snippets/ISnippetExpansionLanguageHelper.cs b/src/VisualStudio/Core/Def/Snippets/ISnippetExpansionLanguageHelper.cs index cdd3bde889e44..d7805cd975e01 100644 --- a/src/VisualStudio/Core/Def/Snippets/ISnippetExpansionLanguageHelper.cs +++ b/src/VisualStudio/Core/Def/Snippets/ISnippetExpansionLanguageHelper.cs @@ -4,6 +4,7 @@ using System; using System.Threading; +using System.Threading.Tasks; using System.Xml.Linq; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.AddImport; @@ -23,5 +24,5 @@ internal interface ISnippetExpansionLanguageHelper : ILanguageService bool TryGetSubjectBufferSpan(ITextView textView, ITextBuffer subjectBuffer, VsTextSpan surfaceBufferTextSpan, out SnapshotSpan subjectBufferSpan); ITrackingSpan? InsertEmptyCommentAndGetEndPositionTrackingSpan(IVsExpansionSession expansionSession, ITextView textView, ITextBuffer subjectBuffer); - Document AddImports(Document document, AddImportPlacementOptions addImportOptions, SyntaxFormattingOptions formattingOptions, int position, XElement snippetNode, CancellationToken cancellationToken); + Task AddImportsAsync(Document document, AddImportPlacementOptions addImportOptions, SyntaxFormattingOptions formattingOptions, int position, XElement snippetNode, CancellationToken cancellationToken); } diff --git a/src/VisualStudio/Core/Def/Snippets/SnippetExpansionClient.cs b/src/VisualStudio/Core/Def/Snippets/SnippetExpansionClient.cs index c8af6b722519b..3afa348c5053e 100644 --- a/src/VisualStudio/Core/Def/Snippets/SnippetExpansionClient.cs +++ b/src/VisualStudio/Core/Def/Snippets/SnippetExpansionClient.cs @@ -59,6 +59,7 @@ internal class SnippetExpansionClient : IVsExpansionClient /// A generated random string which is used to identify argument completion snippets from other snippets. /// private static readonly string s_fullMethodCallDescriptionSentinel = Guid.NewGuid().ToString("N"); + private readonly IThreadingContext _threadingContext; private readonly ISnippetExpansionLanguageHelper _languageHelper; private readonly SignatureHelpControllerProvider _signatureHelpControllerProvider; @@ -122,9 +123,7 @@ public ImmutableArray GetArgumentProviders(Workspace workspace // TODO: Move this to ArgumentProviderService: https://github.com/dotnet/roslyn/issues/50897 if (_argumentProviders.IsDefault) { - _argumentProviders = workspace.Services.SolutionServices - .SelectMatchingExtensionValues(ExtensionOrderer.Order(_allArgumentProviders), SubjectBuffer.ContentType) - .ToImmutableArray(); + _argumentProviders = [.. workspace.Services.SolutionServices.SelectMatchingExtensionValues(ExtensionOrderer.Order(_allArgumentProviders), SubjectBuffer.ContentType)]; } return _argumentProviders; @@ -229,8 +228,8 @@ public int FormatSpan(IVsTextLines pBuffer, VsTextSpan[] tsInSurfaceBuffer) // snippet xml will be available, and changing the buffer during OnAfterInsertion can // cause the underlying tracking spans to get out of sync. var currentStartPosition = snippetTrackingSpan.GetStartPoint(SubjectBuffer.CurrentSnapshot).Position; - AddReferencesAndImports( - ExpansionSession, currentStartPosition, cancellationToken); + _threadingContext.JoinableTaskFactory.Run(() => AddReferencesAndImportsAsync( + ExpansionSession, currentStartPosition, cancellationToken)); SetNewEndPosition(endPositionTrackingSpan); } @@ -551,7 +550,7 @@ private bool TryInsertArgumentCompletionSnippet(SnapshotSpan triggerSpan, Snapsh { // This is the method name as it appears in source text var methodName = dataBufferSpan.GetText(); - var snippet = CreateMethodCallSnippet(methodName, includeMethod: true, ImmutableArray.Empty, ImmutableDictionary.Empty); + var snippet = CreateMethodCallSnippet(methodName, includeMethod: true, [], ImmutableDictionary.Empty); var doc = (DOMDocument)new DOMDocumentClass(); if (doc.loadXML(snippet.ToString(SaveOptions.OmitDuplicateNamespaces))) @@ -704,8 +703,13 @@ private static XDocument CreateMethodCallSnippet(string methodName, bool include private void OnModelUpdated(object sender, ModelUpdatedEventsArgs e) { _threadingContext.ThrowIfNotOnUIThread(); + _threadingContext.JoinableTaskFactory.Run(() => OnModelUpdatedAsync(e.NewModel, CancellationToken.None)); + } - if (e.NewModel is null) + private async Task OnModelUpdatedAsync( + Model? newModel, CancellationToken cancellationToken) + { + if (newModel is null) { // Signature Help was dismissed, but it's possible for a user to bring it back with Ctrl+Shift+Space. // Leave the snippet session (if any) in its current state to allow it to process either a subsequent @@ -720,7 +724,7 @@ private void OnModelUpdated(object sender, ModelUpdatedEventsArgs e) return; } - if (!e.NewModel.UserSelected && _state._method is not null) + if (!newModel.UserSelected && _state._method is not null) { // This was an implicit signature change which was not triggered by user pressing up/down, and we are // already showing an initialized argument completion snippet session, so avoid switching sessions. @@ -738,13 +742,17 @@ private void OnModelUpdated(object sender, ModelUpdatedEventsArgs e) // TODO: The following blocks the UI thread without cancellation, but it only occurs when an argument value // completion session is active, which is behind an experimental feature flag. // https://github.com/dotnet/roslyn/issues/50634 - var compilation = _threadingContext.JoinableTaskFactory.Run(() => document.Project.GetRequiredCompilationAsync(CancellationToken.None)); - var newSymbolKey = (e.NewModel.SelectedItem as AbstractSignatureHelpProvider.SymbolKeySignatureHelpItem)?.SymbolKey ?? default; - var newSymbol = newSymbolKey.Resolve(compilation, cancellationToken: CancellationToken.None).GetAnySymbol(); + var compilation = await document.Project.GetRequiredCompilationAsync(cancellationToken).ConfigureAwait(true); + var newSymbolKey = (newModel.SelectedItem as AbstractSignatureHelpProvider.SymbolKeySignatureHelpItem)?.SymbolKey ?? default; + var newSymbol = newSymbolKey.Resolve(compilation, cancellationToken: cancellationToken).GetAnySymbol(); if (newSymbol is not IMethodSymbol method) return; - MoveToSpecificMethod(method, CancellationToken.None); + await MoveToSpecificMethodAsync( + document, method, cancellationToken).ConfigureAwait(true); + + // Don't let the compilation drop as MoveToSpecificMethodAsync wants to get the semantic model for the document. + GC.KeepAlive(compilation); } private static async Task> GetReferencedSymbolsToLeftOfCaretAsync( @@ -758,7 +766,7 @@ private static async Task> GetReferencedSymbolsToLeftOfC if (token.RawKind == 0) { // There is no touching word, so return empty immediately - return ImmutableArray.Empty; + return []; } var semanticInfo = semanticModel.GetSemanticInfo(token, document.Project.Solution.Services, cancellationToken); @@ -770,10 +778,12 @@ private static async Task> GetReferencedSymbolsToLeftOfC /// /// The currently-selected method in Signature Help. /// A cancellation token the operation may observe. - public void MoveToSpecificMethod(IMethodSymbol method, CancellationToken cancellationToken) + public async Task MoveToSpecificMethodAsync( + Document document, + IMethodSymbol method, + CancellationToken cancellationToken) { - _threadingContext.ThrowIfNotOnUIThread(); - + await _threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); if (ExpansionSession is null) { return; @@ -803,14 +813,6 @@ public void MoveToSpecificMethod(IMethodSymbol method, CancellationToken cancell return; } - var document = SubjectBuffer.CurrentSnapshot.GetOpenDocumentInCurrentContextWithChanges(); - if (document is null) - { - // Couldn't identify the current document - ExpansionSession.EndCurrentExpansion(fLeaveCaret: 1); - return; - } - var textViewModel = TextView.TextViewModel; if (textViewModel == null) { @@ -892,7 +894,7 @@ public void MoveToSpecificMethod(IMethodSymbol method, CancellationToken cancell } // Now compute the new arguments for the new call - var semanticModel = document.GetRequiredSemanticModelAsync(cancellationToken).AsTask().WaitAndGetResult(cancellationToken); + var semanticModel = await document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(true); var position = SubjectBuffer.CurrentSnapshot.GetPosition(adjustedTextSpan.iStartLine, adjustedTextSpan.iStartIndex); foreach (var parameter in method.Parameters) @@ -902,7 +904,7 @@ public void MoveToSpecificMethod(IMethodSymbol method, CancellationToken cancell foreach (var provider in GetArgumentProviders(document.Project.Solution.Workspace)) { var context = new ArgumentContext(provider, semanticModel, position, parameter, value, cancellationToken); - _threadingContext.JoinableTaskFactory.Run(() => provider.ProvideArgumentAsync(context)); + await provider.ProvideArgumentAsync(context).ConfigureAwait(true); if (context.DefaultValue is not null) { @@ -1045,7 +1047,7 @@ private void GetCaretPositionInSurfaceBuffer(out int caretLine, out int caretCol } } - private void AddReferencesAndImports( + private async Task AddReferencesAndImportsAsync( IVsExpansionSession pSession, int position, CancellationToken cancellationToken) @@ -1066,7 +1068,8 @@ private void AddReferencesAndImports( var addImportOptions = SubjectBuffer.GetAddImportPlacementOptions(EditorOptionsService, fallbackOptions, languageServices, documentWithImports.AllowImportsInHiddenRegions()); var formattingOptions = SubjectBuffer.GetSyntaxFormattingOptions(EditorOptionsService, fallbackOptions, languageServices, explicitFormat: false); - documentWithImports = _languageHelper.AddImports(documentWithImports, addImportOptions, formattingOptions, position, snippetNode, cancellationToken); + documentWithImports = await _languageHelper.AddImportsAsync( + documentWithImports, addImportOptions, formattingOptions, position, snippetNode, cancellationToken).ConfigureAwait(true); AddReferences(documentWithImports.Project, snippetNode); } diff --git a/src/VisualStudio/Core/Def/Snippets/SnippetExpansionClientFactory.cs b/src/VisualStudio/Core/Def/Snippets/SnippetExpansionClientFactory.cs index 7877a1ab0bfc6..ce6220f86dc6e 100644 --- a/src/VisualStudio/Core/Def/Snippets/SnippetExpansionClientFactory.cs +++ b/src/VisualStudio/Core/Def/Snippets/SnippetExpansionClientFactory.cs @@ -39,7 +39,7 @@ internal class SnippetExpansionClientFactory( private readonly SignatureHelpControllerProvider _signatureHelpControllerProvider = signatureHelpControllerProvider; private readonly IEditorCommandHandlerServiceFactory _editorCommandHandlerServiceFactory = editorCommandHandlerServiceFactory; private readonly IVsEditorAdaptersFactoryService _editorAdaptersFactoryService = editorAdaptersFactoryService; - private readonly ImmutableArray> _argumentProviders = argumentProviders.ToImmutableArray(); + private readonly ImmutableArray> _argumentProviders = [.. argumentProviders]; private readonly EditorOptionsService _editorOptionsService = editorOptionsService; public SnippetExpansionClient? TryGetSnippetExpansionClient(ITextView textView) diff --git a/src/VisualStudio/Core/Def/StackTraceExplorer/FrameViewModel.cs b/src/VisualStudio/Core/Def/StackTraceExplorer/FrameViewModel.cs index 5201ad4a39554..e18c771c30732 100644 --- a/src/VisualStudio/Core/Def/StackTraceExplorer/FrameViewModel.cs +++ b/src/VisualStudio/Core/Def/StackTraceExplorer/FrameViewModel.cs @@ -27,7 +27,7 @@ public FrameViewModel(IClassificationFormatMap formatMap, ClassificationTypeMap _classificationTypeMap = typeMap; } - public ImmutableArray Inlines => CreateInlines().ToImmutableArray(); + public ImmutableArray Inlines => [.. CreateInlines()]; protected abstract IEnumerable CreateInlines(); diff --git a/src/VisualStudio/Core/Def/StackTraceExplorer/StackFrameViewModel.cs b/src/VisualStudio/Core/Def/StackTraceExplorer/StackFrameViewModel.cs index aa9cc23b641ad..b97644aa038cc 100644 --- a/src/VisualStudio/Core/Def/StackTraceExplorer/StackFrameViewModel.cs +++ b/src/VisualStudio/Core/Def/StackTraceExplorer/StackFrameViewModel.cs @@ -234,7 +234,7 @@ private static ImmutableArray GetLeadingTrivia(StackFrameNode { if (node.ChildCount == 0) { - return ImmutableArray.Empty; + return []; } var child = node[0]; @@ -250,7 +250,7 @@ private static ImmutableArray GetTrailingTrivia(StackFrameNode { if (node.ChildCount == 0) { - return ImmutableArray.Empty; + return []; } var child = node[^1]; diff --git a/src/VisualStudio/Core/Def/SymbolSearch/VisualStudioSymbolSearchService.cs b/src/VisualStudio/Core/Def/SymbolSearch/VisualStudioSymbolSearchService.cs index 2e5295479ee3a..19413e6e6a687 100644 --- a/src/VisualStudio/Core/Def/SymbolSearch/VisualStudioSymbolSearchService.cs +++ b/src/VisualStudio/Core/Def/SymbolSearch/VisualStudioSymbolSearchService.cs @@ -25,7 +25,6 @@ using Microsoft.VisualStudio.Shell.Settings; using Microsoft.VisualStudio.Threading; using Roslyn.Utilities; -using VSShell = Microsoft.VisualStudio.Shell; namespace Microsoft.VisualStudio.LanguageServices.SymbolSearch; @@ -37,7 +36,20 @@ namespace Microsoft.VisualStudio.LanguageServices.SymbolSearch; /// date by downloading patches on a daily basis. /// [ExportWorkspaceService(typeof(ISymbolSearchService), ServiceLayer.Host), Shared] -internal partial class VisualStudioSymbolSearchService : AbstractDelayStartedService, ISymbolSearchService, IDisposable +[method: ImportingConstructor] +[method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] +internal partial class VisualStudioSymbolSearchService( + IThreadingContext threadingContext, + IAsynchronousOperationListenerProvider listenerProvider, + VisualStudioWorkspaceImpl workspace, + IGlobalOptionService globalOptions, + SVsServiceProvider serviceProvider) + : AbstractDelayStartedService(threadingContext, + globalOptions, + workspace, + listenerProvider, + SymbolSearchGlobalOptionsStorage.Enabled, + [SymbolSearchOptionsStorage.SearchReferenceAssemblies, SymbolSearchOptionsStorage.SearchNuGetPackages]), ISymbolSearchService, IDisposable { // Our usage of SemaphoreSlim is fine. We don't perform blocking waits for it on the UI thread. #pragma warning disable RS0030 // Do not use banned APIs @@ -48,30 +60,11 @@ internal partial class VisualStudioSymbolSearchService : AbstractDelayStartedSer // but we want to keep it alive until the VS is closed, so we don't dispose it. private ISymbolSearchUpdateEngine? _lazyUpdateEngine; - private readonly SVsServiceProvider _serviceProvider; - private readonly IPackageInstallerService _installerService; + private readonly SVsServiceProvider _serviceProvider = serviceProvider; + private readonly IPackageInstallerService _installerService = workspace.Services.GetRequiredService(); private string? _localSettingsDirectory; - [ImportingConstructor] - [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - public VisualStudioSymbolSearchService( - IThreadingContext threadingContext, - IAsynchronousOperationListenerProvider listenerProvider, - VisualStudioWorkspaceImpl workspace, - IGlobalOptionService globalOptions, - VSShell.SVsServiceProvider serviceProvider) - : base(threadingContext, - globalOptions, - workspace, - listenerProvider, - SymbolSearchGlobalOptionsStorage.Enabled, - [SymbolSearchOptionsStorage.SearchReferenceAssemblies, SymbolSearchOptionsStorage.SearchNuGetPackages]) - { - _serviceProvider = serviceProvider; - _installerService = workspace.Services.GetRequiredService(); - } - public void Dispose() { // Once we're disposed, swap out our engine with a no-op one so we don't try to do any more work, and dispose of @@ -105,21 +98,19 @@ protected override async Task EnableServiceAsync(CancellationToken cancellationT // When our service is enabled hook up to package source changes. // We need to know when the list of sources have changed so we can // kick off the work to process them. - _installerService.PackageSourcesChanged += OnPackageSourcesChanged; + _installerService.PackageSourcesChanged += (_, _) => StartWorking(_localSettingsDirectory); // Kick off the initial work to pull down the nuget index. - this.StartWorking(); + this.StartWorking(_localSettingsDirectory); } - private void OnPackageSourcesChanged(object sender, EventArgs e) - => StartWorking(); - - private void StartWorking() + private void StartWorking(string localSettingsDirectory) { // Always pull down the nuget.org index. It contains the MS reference assembly index // inside of it. var cancellationToken = ThreadingContext.DisposalToken; - Task.Run(() => UpdateSourceInBackgroundAsync(PackageSourceHelper.NugetOrgSourceName, cancellationToken), cancellationToken); + Task.Run(() => UpdateSourceInBackgroundAsync( + PackageSourceHelper.NugetOrgSourceName, localSettingsDirectory, cancellationToken), cancellationToken); } private async Task GetEngineAsync(CancellationToken cancellationToken) @@ -131,18 +122,19 @@ private async Task GetEngineAsync(CancellationToken c } } - private async Task UpdateSourceInBackgroundAsync(string sourceName, CancellationToken cancellationToken) + private async Task UpdateSourceInBackgroundAsync( + string sourceName, string localSettingsDirectory, CancellationToken cancellationToken) { var engine = await GetEngineAsync(cancellationToken).ConfigureAwait(false); - await engine.UpdateContinuouslyAsync(sourceName, _localSettingsDirectory, cancellationToken).ConfigureAwait(false); + await engine.UpdateContinuouslyAsync(sourceName, localSettingsDirectory, cancellationToken).ConfigureAwait(false); } - public async ValueTask> FindPackagesWithTypeAsync( - string source, string name, int arity, CancellationToken cancellationToken) + public async ValueTask> FindPackagesAsync( + string source, TypeQuery typeQuery, NamespaceQuery namespaceQuery, CancellationToken cancellationToken) { var engine = await GetEngineAsync(cancellationToken).ConfigureAwait(false); - var allPackagesWithType = await engine.FindPackagesWithTypeAsync( - source, name, arity, cancellationToken).ConfigureAwait(false); + var allPackagesWithType = await engine.FindPackagesAsync( + source, typeQuery, namespaceQuery, cancellationToken).ConfigureAwait(false); return FilterAndOrderPackages(allPackagesWithType); } @@ -158,7 +150,7 @@ public async ValueTask> FindPackagesWi } private ImmutableArray FilterAndOrderPackages( - ImmutableArray allPackages) where TPackageResult : PackageResult + ImmutableArray allPackages) where TPackageResult : AbstractPackageResult { // The ranking threshold under while we start aggressively filtering out packages if they don't have a high // enough rank. Above this and we will always include the item as it's shown more than enough usage to @@ -208,11 +200,11 @@ private ImmutableArray FilterAndOrderPackages( return result.ToImmutableAndFree(); } - public async ValueTask> FindReferenceAssembliesWithTypeAsync( - string name, int arity, CancellationToken cancellationToken) + public async ValueTask> FindReferenceAssembliesAsync( + TypeQuery typeQuery, NamespaceQuery namespaceQuery, CancellationToken cancellationToken) { var engine = await GetEngineAsync(cancellationToken).ConfigureAwait(false); - return await engine.FindReferenceAssembliesWithTypeAsync( - name, arity, cancellationToken).ConfigureAwait(false); + return await engine.FindReferenceAssembliesAsync( + typeQuery, namespaceQuery, cancellationToken).ConfigureAwait(false); } } diff --git a/src/VisualStudio/Core/Def/TableDataSource/Suppression/VisualStudioSuppressionFixService.cs b/src/VisualStudio/Core/Def/TableDataSource/Suppression/VisualStudioSuppressionFixService.cs index 700d475b415b7..23cd3cc49e643 100644 --- a/src/VisualStudio/Core/Def/TableDataSource/Suppression/VisualStudioSuppressionFixService.cs +++ b/src/VisualStudio/Core/Def/TableDataSource/Suppression/VisualStudioSuppressionFixService.cs @@ -20,7 +20,6 @@ using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Progress; -using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.TestHooks; using Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem; using Microsoft.VisualStudio.LanguageServices.Implementation.TableDataSource; @@ -40,54 +39,33 @@ namespace Microsoft.VisualStudio.LanguageServices.Implementation.Suppression; /// [Export(typeof(IVisualStudioSuppressionFixService))] [Export(typeof(VisualStudioSuppressionFixService))] -internal sealed class VisualStudioSuppressionFixService : IVisualStudioSuppressionFixService +[method: ImportingConstructor] +[method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] +internal sealed class VisualStudioSuppressionFixService( + IThreadingContext threadingContext, + VisualStudioWorkspaceImpl workspace, + IDiagnosticAnalyzerService diagnosticService, + ICodeFixService codeFixService, + ICodeActionEditHandlerService editHandlerService, + VisualStudioDiagnosticListSuppressionStateService suppressionStateService, + IUIThreadOperationExecutor uiThreadOperationExecutor, + IVsHierarchyItemManager vsHierarchyItemManager, + IAsynchronousOperationListenerProvider listenerProvider) : IVisualStudioSuppressionFixService { - private readonly IThreadingContext _threadingContext; - private readonly VisualStudioWorkspaceImpl _workspace; - private readonly IAsynchronousOperationListener _listener; - private readonly IDiagnosticAnalyzerService _diagnosticService; - private readonly ExternalErrorDiagnosticUpdateSource _buildErrorDiagnosticService; - private readonly ICodeFixService _codeFixService; - private readonly IFixMultipleOccurrencesService _fixMultipleOccurencesService; - private readonly ICodeActionEditHandlerService _editHandlerService; - private readonly VisualStudioDiagnosticListSuppressionStateService _suppressionStateService; - private readonly IUIThreadOperationExecutor _uiThreadOperationExecutor; - private readonly IVsHierarchyItemManager _vsHierarchyItemManager; - private readonly IHierarchyItemToProjectIdMap _projectMap; - private readonly IGlobalOptionService _globalOptions; + private readonly IThreadingContext _threadingContext = threadingContext; + private readonly VisualStudioWorkspaceImpl _workspace = workspace; + private readonly IAsynchronousOperationListener _listener = listenerProvider.GetListener(FeatureAttribute.ErrorList); + private readonly IDiagnosticAnalyzerService _diagnosticService = diagnosticService; + private readonly ICodeFixService _codeFixService = codeFixService; + private readonly IFixMultipleOccurrencesService _fixMultipleOccurencesService = workspace.Services.GetRequiredService(); + private readonly ICodeActionEditHandlerService _editHandlerService = editHandlerService; + private readonly VisualStudioDiagnosticListSuppressionStateService _suppressionStateService = suppressionStateService; + private readonly IUIThreadOperationExecutor _uiThreadOperationExecutor = uiThreadOperationExecutor; + private readonly IVsHierarchyItemManager _vsHierarchyItemManager = vsHierarchyItemManager; + private readonly IHierarchyItemToProjectIdMap _projectMap = workspace.Services.GetRequiredService(); private IWpfTableControl? _tableControl; - [ImportingConstructor] - [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - public VisualStudioSuppressionFixService( - IThreadingContext threadingContext, - SVsServiceProvider serviceProvider, - VisualStudioWorkspaceImpl workspace, - IDiagnosticAnalyzerService diagnosticService, - ICodeFixService codeFixService, - ICodeActionEditHandlerService editHandlerService, - VisualStudioDiagnosticListSuppressionStateService suppressionStateService, - IUIThreadOperationExecutor uiThreadOperationExecutor, - IVsHierarchyItemManager vsHierarchyItemManager, - IAsynchronousOperationListenerProvider listenerProvider, - IGlobalOptionService globalOptions) - { - _threadingContext = threadingContext; - _workspace = workspace; - _diagnosticService = diagnosticService; - _buildErrorDiagnosticService = workspace.ExternalErrorDiagnosticUpdateSource; - _codeFixService = codeFixService; - _suppressionStateService = suppressionStateService; - _editHandlerService = editHandlerService; - _uiThreadOperationExecutor = uiThreadOperationExecutor; - _vsHierarchyItemManager = vsHierarchyItemManager; - _fixMultipleOccurencesService = workspace.Services.GetRequiredService(); - _projectMap = workspace.Services.GetRequiredService(); - _listener = listenerProvider.GetListener(FeatureAttribute.ErrorList); - _globalOptions = globalOptions; - } - public async Task InitializeAsync(IAsyncServiceProvider serviceProvider) { var errorList = await serviceProvider.GetServiceAsync(_threadingContext.JoinableTaskFactory, throwOnFailure: false).ConfigureAwait(false); @@ -96,44 +74,57 @@ public async Task InitializeAsync(IAsyncServiceProvider serviceProvider) public bool AddSuppressions(IVsHierarchy? projectHierarchy) { - if (_tableControl == null) + return _threadingContext.JoinableTaskFactory.Run(async () => { - return false; - } + if (_tableControl == null) + return false; - var shouldFixInProject = GetShouldFixInProjectDelegate(_vsHierarchyItemManager, _projectMap, projectHierarchy); + var shouldFixInProject = GetShouldFixInProjectDelegate(_vsHierarchyItemManager, _projectMap, projectHierarchy); - // Apply suppressions fix in global suppressions file for non-compiler diagnostics and - // in source only for compiler diagnostics. - var diagnosticsToFix = GetDiagnosticsToFix(selectedEntriesOnly: false, isAddSuppression: true); - if (!ApplySuppressionFix(diagnosticsToFix, shouldFixInProject, filterStaleDiagnostics: false, isAddSuppression: true, isSuppressionInSource: false, onlyCompilerDiagnostics: false, showPreviewChangesDialog: false)) - { - return false; - } + // Apply suppressions fix in global suppressions file for non-compiler diagnostics and + // in source only for compiler diagnostics. + var diagnosticsToFix = await GetDiagnosticsToFixAsync(selectedEntriesOnly: false, isAddSuppression: true).ConfigureAwait(true); + if (!ApplySuppressionFix(diagnosticsToFix, shouldFixInProject, filterStaleDiagnostics: false, isAddSuppression: true, isSuppressionInSource: false, onlyCompilerDiagnostics: false, showPreviewChangesDialog: false)) + return false; - return ApplySuppressionFix(diagnosticsToFix, shouldFixInProject, filterStaleDiagnostics: false, isAddSuppression: true, isSuppressionInSource: true, onlyCompilerDiagnostics: true, showPreviewChangesDialog: false); + return ApplySuppressionFix(diagnosticsToFix, shouldFixInProject, filterStaleDiagnostics: false, isAddSuppression: true, isSuppressionInSource: true, onlyCompilerDiagnostics: true, showPreviewChangesDialog: false); + }); } public bool AddSuppressions(bool selectedErrorListEntriesOnly, bool suppressInSource, IVsHierarchy? projectHierarchy) { - if (_tableControl == null) + return _threadingContext.JoinableTaskFactory.Run(async () => { - return false; - } - - var shouldFixInProject = GetShouldFixInProjectDelegate(_vsHierarchyItemManager, _projectMap, projectHierarchy); - return ApplySuppressionFix(shouldFixInProject, selectedErrorListEntriesOnly, isAddSuppression: true, isSuppressionInSource: suppressInSource, onlyCompilerDiagnostics: false, showPreviewChangesDialog: true); + if (_tableControl == null) + return false; + + var shouldFixInProject = GetShouldFixInProjectDelegate(_vsHierarchyItemManager, _projectMap, projectHierarchy); + return await ApplySuppressionFixAsync( + shouldFixInProject, + selectedErrorListEntriesOnly, + isAddSuppression: true, + isSuppressionInSource: suppressInSource, + onlyCompilerDiagnostics: false, + showPreviewChangesDialog: true).ConfigureAwait(true); + }); } public bool RemoveSuppressions(bool selectedErrorListEntriesOnly, IVsHierarchy? projectHierarchy) { - if (_tableControl == null) + return _threadingContext.JoinableTaskFactory.Run(async () => { - return false; - } - - var shouldFixInProject = GetShouldFixInProjectDelegate(_vsHierarchyItemManager, _projectMap, projectHierarchy); - return ApplySuppressionFix(shouldFixInProject, selectedErrorListEntriesOnly, isAddSuppression: false, isSuppressionInSource: false, onlyCompilerDiagnostics: false, showPreviewChangesDialog: true); + if (_tableControl == null) + return false; + + var shouldFixInProject = GetShouldFixInProjectDelegate(_vsHierarchyItemManager, _projectMap, projectHierarchy); + return await ApplySuppressionFixAsync( + shouldFixInProject, + selectedErrorListEntriesOnly, + isAddSuppression: false, + isSuppressionInSource: false, + onlyCompilerDiagnostics: false, + showPreviewChangesDialog: true).ConfigureAwait(true); + }); } private static Func GetShouldFixInProjectDelegate(IVsHierarchyItemManager vsHierarchyItemManager, IHierarchyItemToProjectIdMap projectMap, IVsHierarchy? projectHierarchy) @@ -157,38 +148,39 @@ private static string GetFixTitle(bool isAddSuppression) private static string GetWaitDialogMessage(bool isAddSuppression) => isAddSuppression ? ServicesVSResources.Computing_suppressions_fix : ServicesVSResources.Computing_remove_suppressions_fix; - private IEnumerable? GetDiagnosticsToFix(bool selectedEntriesOnly, bool isAddSuppression) + private async Task?> GetDiagnosticsToFixAsync( + bool selectedEntriesOnly, + bool isAddSuppression) { var diagnosticsToFix = ImmutableHashSet.Empty; - void computeDiagnosticsToFix(IUIThreadOperationContext context) - { - var cancellationToken = context.UserCancellationToken; + var result = await InvokeWithWaitDialogAsync(async cancellationToken => + { // If we are fixing selected diagnostics in error list, then get the diagnostics from error list entry // snapshots. Otherwise, get all diagnostics from the diagnostic service. - var diagnosticsToFixTask = selectedEntriesOnly - ? _suppressionStateService.GetSelectedItemsAsync(isAddSuppression, cancellationToken) - : Task.FromResult>([]); + var diagnosticsToFixArray = selectedEntriesOnly + ? await _suppressionStateService.GetSelectedItemsAsync(isAddSuppression, cancellationToken).ConfigureAwait(true) + : []; - diagnosticsToFix = diagnosticsToFixTask.WaitAndGetResult(cancellationToken).ToImmutableHashSet(); - } + diagnosticsToFix = [.. diagnosticsToFixArray]; - var title = GetFixTitle(isAddSuppression); - var waitDialogMessage = GetWaitDialogMessage(isAddSuppression); - var result = InvokeWithWaitDialog(computeDiagnosticsToFix, title, waitDialogMessage); + }, GetFixTitle(isAddSuppression), GetWaitDialogMessage(isAddSuppression)).ConfigureAwait(true); - // Bail out if the user cancelled. if (result == UIThreadOperationStatus.Canceled) - { return null; - } return diagnosticsToFix; } - private bool ApplySuppressionFix(Func shouldFixInProject, bool selectedEntriesOnly, bool isAddSuppression, bool isSuppressionInSource, bool onlyCompilerDiagnostics, bool showPreviewChangesDialog) + private async Task ApplySuppressionFixAsync( + Func shouldFixInProject, + bool selectedEntriesOnly, + bool isAddSuppression, + bool isSuppressionInSource, + bool onlyCompilerDiagnostics, + bool showPreviewChangesDialog) { - var diagnosticsToFix = GetDiagnosticsToFix(selectedEntriesOnly, isAddSuppression); + var diagnosticsToFix = await GetDiagnosticsToFixAsync(selectedEntriesOnly, isAddSuppression).ConfigureAwait(true); return ApplySuppressionFix(diagnosticsToFix, shouldFixInProject, selectedEntriesOnly, isAddSuppression, isSuppressionInSource, onlyCompilerDiagnostics, showPreviewChangesDialog); } @@ -278,7 +270,7 @@ private async Task ApplySuppressionFixAsync( if (suppressionFixer != null) { var suppressionFixAllProvider = suppressionFixer.GetFixAllProvider(); - newSolution = _fixMultipleOccurencesService.GetFix( + newSolution = await _fixMultipleOccurencesService.GetFixAsync( documentDiagnosticsPerLanguage, _workspace, suppressionFixer, @@ -287,7 +279,7 @@ private async Task ApplySuppressionFixAsync( title, waitDialogMessage, progress, - cancellationToken); + cancellationToken).ConfigureAwait(false); if (newSolution == null) { // User cancelled or fixer threw an exception, so we just bail out. @@ -303,7 +295,7 @@ private async Task ApplySuppressionFixAsync( if (suppressionFixer != null) { var suppressionFixAllProvider = suppressionFixer.GetFixAllProvider(); - newSolution = _fixMultipleOccurencesService.GetFix( + newSolution = await _fixMultipleOccurencesService.GetFixAsync( projectDiagnosticsPerLanguage, _workspace, suppressionFixer, @@ -312,7 +304,7 @@ private async Task ApplySuppressionFixAsync( title, waitDialogMessage, progress, - cancellationToken); + cancellationToken).ConfigureAwait(false); if (newSolution == null) { return; @@ -395,28 +387,22 @@ private static IEnumerable FilterDiagnostics(IEnumerable action, string waitDialogTitle, string waitDialogMessage) + private async Task InvokeWithWaitDialogAsync( + Func action, string waitDialogTitle, string waitDialogMessage) { + using var waitContext = _uiThreadOperationExecutor.BeginExecute(waitDialogTitle, waitDialogMessage, allowCancellation: true, showProgress: true); + var cancelled = false; - var result = _uiThreadOperationExecutor.Execute( - waitDialogTitle, - waitDialogMessage, - allowCancellation: true, - showProgress: true, - action: waitContext => - { - try - { - action(waitContext); - } - catch (OperationCanceledException) - { - cancelled = true; - } - }); + try + { + await action(waitContext.UserCancellationToken).ConfigureAwait(true); + } + catch (OperationCanceledException) + { + cancelled = true; + } - return cancelled ? UIThreadOperationStatus.Canceled : result; + return cancelled ? UIThreadOperationStatus.Canceled : UIThreadOperationStatus.Completed; } private static ImmutableDictionary> GetDocumentDiagnosticsMappedToNewSolution(ImmutableDictionary> documentDiagnosticsToFixMap, Solution newSolution, string language) @@ -507,7 +493,7 @@ private async Task>> Ge latestDocumentDiagnosticsMap.Clear(); foreach (var kvp in latestProjectDiagnostics.Where(d => d.DocumentId != null).GroupBy(d => d.DocumentId!)) { - latestDocumentDiagnosticsMap.Add(kvp.Key, kvp.ToImmutableHashSet()); + latestDocumentDiagnosticsMap.Add(kvp.Key, [.. kvp]); } } @@ -527,7 +513,7 @@ private async Task>> Ge if (!latestDocumentDiagnosticsMap.TryGetValue(document.Id, out var latestDocumentDiagnostics)) { // Ignore stale diagnostics in error list. - latestDocumentDiagnostics = ImmutableHashSet.Empty; + latestDocumentDiagnostics = []; } // Filter out stale diagnostics in error list. diff --git a/src/VisualStudio/Core/Def/TaskList/ExternalErrorDiagnosticUpdateSource.cs b/src/VisualStudio/Core/Def/TaskList/ExternalErrorDiagnosticUpdateSource.cs index 973987c5a0764..e370f5eee08c0 100644 --- a/src/VisualStudio/Core/Def/TaskList/ExternalErrorDiagnosticUpdateSource.cs +++ b/src/VisualStudio/Core/Def/TaskList/ExternalErrorDiagnosticUpdateSource.cs @@ -363,7 +363,7 @@ ImmutableHashSet ComputeSupportedDiagnosticIds() if (project == null) { // projectId no longer exist - return ImmutableHashSet.Empty; + return []; } // set ids set diff --git a/src/VisualStudio/Core/Def/Telemetry/FileLogger.cs b/src/VisualStudio/Core/Def/Telemetry/FileLogger.cs index 3f63914b61ccc..916429085c48e 100644 --- a/src/VisualStudio/Core/Def/Telemetry/FileLogger.cs +++ b/src/VisualStudio/Core/Def/Telemetry/FileLogger.cs @@ -5,13 +5,16 @@ using System; using System.Globalization; using System.IO; -using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Collections; using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.Internal.Log; using Microsoft.CodeAnalysis.Options; +using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.TestHooks; using Microsoft.CodeAnalysis.Shared.Utilities; using Roslyn.Utilities; @@ -23,29 +26,24 @@ namespace Microsoft.VisualStudio.LanguageServices.Telemetry; /// internal sealed class FileLogger : ILogger { - private readonly object _gate; private readonly string _logFilePath; - private readonly StringBuilder _buffer; private bool _enabled; /// - /// Task queue to serialize all the IO to the log file. + /// Work queue to serialize all the IO to the log file. /// - private readonly TaskQueue _taskQueue; + private readonly AsyncBatchingWorkQueue<(FunctionId functionId, string message)> _workQueue; - public FileLogger(IGlobalOptionService globalOptions, string logFilePath) - { - _logFilePath = logFilePath; - _gate = new(); - _buffer = new(); - _taskQueue = new(AsynchronousOperationListenerProvider.NullListener, TaskScheduler.Default); - _enabled = globalOptions.GetOption(VisualStudioLoggingOptionsStorage.EnableFileLoggingForDiagnostics); - globalOptions.AddOptionChangedHandler(this, OptionService_OptionChanged); - } - - public FileLogger(IGlobalOptionService optionService) - : this(optionService, Path.Combine(Path.GetTempPath(), "Roslyn", "Telemetry", GetLogFileName())) + public FileLogger(IGlobalOptionService optionService, IThreadingContext threadingContext) { + _logFilePath = Path.Combine(Path.GetTempPath(), "Roslyn", "Telemetry", GetLogFileName()); + _workQueue = new( + DelayTimeSpan.Short, + ProcessWorkQueueAsync, + AsynchronousOperationListenerProvider.NullListener, + threadingContext.DisposalToken); + _enabled = optionService.GetOption(VisualStudioLoggingOptionsStorage.EnableFileLoggingForDiagnostics); + optionService.AddOptionChangedHandler(this, OptionService_OptionChanged); } private static string GetLogFileName() @@ -81,26 +79,7 @@ public bool IsEnabled(FunctionId functionId) } private void Log(FunctionId functionId, string message) - { - _taskQueue.ScheduleTask(nameof(FileLogger), () => - { - lock (_gate) - { - _buffer.AppendLine($"{DateTime.Now} ({functionId}) : {message}"); - - IOUtilities.PerformIO(() => - { - if (!File.Exists(_logFilePath)) - { - Directory.CreateDirectory(PathUtilities.GetDirectoryName(_logFilePath)); - } - - File.AppendAllText(_logFilePath, _buffer.ToString()); - _buffer.Clear(); - }); - } - }, CancellationToken.None); - } + => _workQueue.AddWork((functionId, message)); public void Log(FunctionId functionId, LogMessage logMessage) => Log(functionId, logMessage.GetMessage()); @@ -113,4 +92,24 @@ public void LogBlockEnd(FunctionId functionId, LogMessage logMessage, int unique private void LogBlockEvent(FunctionId functionId, LogMessage logMessage, int uniquePairId, string blockEvent) => Log(functionId, $"[{blockEvent} - {uniquePairId}] {logMessage.GetMessage()}"); + + private ValueTask ProcessWorkQueueAsync( + ImmutableSegmentedList<(FunctionId functionId, string message)> list, CancellationToken cancellationToken) + { + using var _ = PooledStringBuilder.GetInstance(out var buffer); + foreach (var (functionId, message) in list) + buffer.AppendLine($"{DateTime.Now} ({functionId}) : {message}"); + + IOUtilities.PerformIO(() => + { + if (!File.Exists(_logFilePath)) + { + Directory.CreateDirectory(PathUtilities.GetDirectoryName(_logFilePath)); + } + + File.AppendAllText(_logFilePath, buffer.ToString()); + }); + + return ValueTaskFactory.CompletedTask; + } } diff --git a/src/VisualStudio/Core/Def/Telemetry/VisualStudioWorkspaceTelemetryService.cs b/src/VisualStudio/Core/Def/Telemetry/VisualStudioWorkspaceTelemetryService.cs index 0fb0947443a35..3b3a85b6b5fe4 100644 --- a/src/VisualStudio/Core/Def/Telemetry/VisualStudioWorkspaceTelemetryService.cs +++ b/src/VisualStudio/Core/Def/Telemetry/VisualStudioWorkspaceTelemetryService.cs @@ -36,7 +36,7 @@ protected override ILogger CreateLogger(TelemetrySession telemetrySession, bool CodeMarkerLogger.Instance, new EtwLogger(FunctionIdOptions.CreateFunctionIsEnabledPredicate(_globalOptions)), TelemetryLogger.Create(telemetrySession, logDelta), - new FileLogger(_globalOptions), + new FileLogger(_globalOptions, _threadingContext), Logger.GetLogger()); protected override void TelemetrySessionInitialized() diff --git a/src/VisualStudio/Core/Def/UnusedReferences/Dialog/RemoveUnusedReferencesDialog.xaml.cs b/src/VisualStudio/Core/Def/UnusedReferences/Dialog/RemoveUnusedReferencesDialog.xaml.cs index b44cc50fd0cdf..9e777d198af01 100644 --- a/src/VisualStudio/Core/Def/UnusedReferences/Dialog/RemoveUnusedReferencesDialog.xaml.cs +++ b/src/VisualStudio/Core/Def/UnusedReferences/Dialog/RemoveUnusedReferencesDialog.xaml.cs @@ -19,7 +19,7 @@ internal partial class RemoveUnusedReferencesDialog : DialogWindow public string RemoveUnusedReferences => ServicesVSResources.Remove_Unused_References; public string HelpText => ServicesVSResources.Choose_which_action_you_would_like_to_perform_on_the_unused_references; public string Apply => ServicesVSResources.Apply; - public string Cancel => ServicesVSResources.Cancel; + public string Cancel => EditorFeaturesResources.Cancel; private readonly UnusedReferencesTableProvider _tableProvider; diff --git a/src/VisualStudio/Core/Def/UnusedReferences/Dialog/UnusedReferencesTableProvider.DataSource.cs b/src/VisualStudio/Core/Def/UnusedReferences/Dialog/UnusedReferencesTableProvider.DataSource.cs index 239eb4b2d3117..915c58ffb5f44 100644 --- a/src/VisualStudio/Core/Def/UnusedReferences/Dialog/UnusedReferencesTableProvider.DataSource.cs +++ b/src/VisualStudio/Core/Def/UnusedReferences/Dialog/UnusedReferencesTableProvider.DataSource.cs @@ -22,8 +22,8 @@ internal class UnusedReferencesDataSource : ITableDataSource public string Identifier => Name; public string? DisplayName => null; - private ImmutableList _managers = ImmutableList.Empty; - private ImmutableArray _currentEntries = ImmutableArray.Empty; + private ImmutableList _managers = []; + private ImmutableArray _currentEntries = []; public IDisposable Subscribe(ITableDataSink sink) { @@ -53,7 +53,7 @@ public void RemoveAllTableData() manager.Sink.RemoveAllEntries(); } - _currentEntries = ImmutableArray.Empty; + _currentEntries = []; } internal void AddSinkManager(SinkManager manager) diff --git a/src/VisualStudio/Core/Def/UnusedReferences/RemoveUnusedReferencesCommandHandler.cs b/src/VisualStudio/Core/Def/UnusedReferences/RemoveUnusedReferencesCommandHandler.cs index cceb5f5ba293c..1a78d42e1f6a4 100644 --- a/src/VisualStudio/Core/Def/UnusedReferences/RemoveUnusedReferencesCommandHandler.cs +++ b/src/VisualStudio/Core/Def/UnusedReferences/RemoveUnusedReferencesCommandHandler.cs @@ -77,9 +77,9 @@ private void OnRemoveUnusedReferencesForSelectedProjectStatus(object sender, Eve { var command = (OleMenuCommand)sender; - // If the option hasn't been expicitly set then fallback to whether this is enabled as part of an experiment. - var isOptionEnabled = _globalOptions.GetOption(FeatureOnOffOptions.OfferRemoveUnusedReferences) - ?? _globalOptions.GetOption(FeatureOnOffOptions.OfferRemoveUnusedReferencesFeatureFlag); + // If the value is null it means user loads the value from previous build (at that moment it is in experiment) + // Since the feature is on by default now, just set it to true + var isOptionEnabled = _globalOptions.GetOption(FeatureOnOffOptions.OfferRemoveUnusedReferences) ?? true; var isDotNetCpsProject = VisualStudioCommandHandlerHelpers.TryGetSelectedProjectHierarchy(_serviceProvider, out var hierarchy) && hierarchy.IsCapabilityMatch("CPS") && @@ -170,13 +170,13 @@ private void OnRemoveUnusedReferencesForSelectedProject(object sender, EventArgs { if (!TryGetPropertyValue(projectHierarchy, ProjectAssetsFilePropertyName, out var projectAssetsFile)) { - return (null, null, ImmutableArray.Empty); + return (null, null, []); } var projectFilePath = projectHierarchy.TryGetProjectFilePath(); if (string.IsNullOrEmpty(projectFilePath)) { - return (null, null, ImmutableArray.Empty); + return (null, null, []); } var solution = _workspace.CurrentSolution; diff --git a/src/VisualStudio/Core/Def/UnusedReferences/UnusedReferenceAnalysisService.cs b/src/VisualStudio/Core/Def/UnusedReferences/UnusedReferenceAnalysisService.cs index 06966c596d59f..76de9bbfef6a7 100644 --- a/src/VisualStudio/Core/Def/UnusedReferences/UnusedReferenceAnalysisService.cs +++ b/src/VisualStudio/Core/Def/UnusedReferences/UnusedReferenceAnalysisService.cs @@ -36,7 +36,7 @@ public async Task> GetUnusedReferencesAsync(Soluti if (!result.HasValue) { - return ImmutableArray.Empty; + return []; } return result.Value; diff --git a/src/VisualStudio/Core/Def/UnusedReferences/UnusedReferenceExtensions.cs b/src/VisualStudio/Core/Def/UnusedReferences/UnusedReferenceExtensions.cs index 709928cff419b..5c6251c350a89 100644 --- a/src/VisualStudio/Core/Def/UnusedReferences/UnusedReferenceExtensions.cs +++ b/src/VisualStudio/Core/Def/UnusedReferences/UnusedReferenceExtensions.cs @@ -17,8 +17,8 @@ public static ReferenceInfo ToReferenceInfo(this ProjectSystemReferenceInfo proj (ReferenceType)projectSystemReference.ReferenceType, projectSystemReference.ItemSpecification, projectSystemReference.TreatAsUsed, - ImmutableArray.Empty, - ImmutableArray.Empty); + [], + []); } public static ProjectSystemReferenceUpdate ToProjectSystemReferenceUpdate(this ReferenceUpdate referenceUpdate) diff --git a/src/VisualStudio/Core/Def/UnusedReferences/VisualStudioReferenceCleanupService.cs b/src/VisualStudio/Core/Def/UnusedReferences/VisualStudioReferenceCleanupService.cs index 1b68106aaee9e..7ae05f4955b91 100644 --- a/src/VisualStudio/Core/Def/UnusedReferences/VisualStudioReferenceCleanupService.cs +++ b/src/VisualStudio/Core/Def/UnusedReferences/VisualStudioReferenceCleanupService.cs @@ -32,7 +32,7 @@ public VisualStudioReferenceCleanupService(IProjectSystemReferenceCleanupService public async Task> GetProjectReferencesAsync(string projectPath, CancellationToken cancellationToken) { var projectSystemReferences = await _projectSystemReferenceUpdateService.GetProjectReferencesAsync(projectPath, cancellationToken).ConfigureAwait(false); - return projectSystemReferences.Select(reference => reference.ToReferenceInfo()).ToImmutableArray(); + return [.. projectSystemReferences.Select(reference => reference.ToReferenceInfo())]; } public async Task TryUpdateReferenceAsync(string projectPath, ReferenceUpdate referenceUpdate, CancellationToken cancellationToken) diff --git a/src/VisualStudio/Core/Def/ValueTracking/TreeItemViewModel.cs b/src/VisualStudio/Core/Def/ValueTracking/TreeItemViewModel.cs index 88e5a5ef246bd..e7a0132501ea3 100644 --- a/src/VisualStudio/Core/Def/ValueTracking/TreeItemViewModel.cs +++ b/src/VisualStudio/Core/Def/ValueTracking/TreeItemViewModel.cs @@ -103,7 +103,7 @@ private ImmutableArray CalculateInlines() { if (ClassifiedSpans.IsDefaultOrEmpty) { - return ImmutableArray.Empty; + return []; } var classifiedTexts = ClassifiedSpans.SelectAsArray( @@ -115,7 +115,7 @@ private ImmutableArray CalculateInlines() var spanStartPosition = TextSpan.Start - ClassifiedSpans[0].TextSpan.Start; var highlightSpan = new TextSpan(spanStartPosition, TextSpan.Length); - return classifiedTexts.ToInlines( + return [.. classifiedTexts.ToInlines( TreeViewModel.ClassificationFormatMap, TreeViewModel.ClassificationTypeMap, (run, classifiedText, position) => @@ -133,6 +133,6 @@ private ImmutableArray CalculateInlines() TreeViewModel.HighlightBrush); } } - }).ToImmutableArray(); + })]; } } diff --git a/src/VisualStudio/Core/Def/ValueTracking/ValueTrackedTreeItemViewModel.cs b/src/VisualStudio/Core/Def/ValueTracking/ValueTrackedTreeItemViewModel.cs index 5c79c2302188a..1c86ed3963466 100644 --- a/src/VisualStudio/Core/Def/ValueTracking/ValueTrackedTreeItemViewModel.cs +++ b/src/VisualStudio/Core/Def/ValueTracking/ValueTrackedTreeItemViewModel.cs @@ -194,7 +194,7 @@ private async Task> CalculateChildrenAsync(Can return await valueTrackedItems.SelectAsArrayAsync(static (item, self, cancellationToken) => CreateAsync( - self._solution, item, children: ImmutableArray.Empty, + self._solution, item, children: [], self.TreeViewModel, self._glyphService, self._valueTrackingService, self._globalOptions, self.ThreadingContext, self._listener, self._threadOperationExecutor, cancellationToken), this, cancellationToken).ConfigureAwait(false); } diff --git a/src/VisualStudio/Core/Def/ValueTracking/ValueTrackingCommandHandler.cs b/src/VisualStudio/Core/Def/ValueTracking/ValueTrackingCommandHandler.cs index ae01acf320f5c..ccf51298a64f2 100644 --- a/src/VisualStudio/Core/Def/ValueTracking/ValueTrackingCommandHandler.cs +++ b/src/VisualStudio/Core/Def/ValueTracking/ValueTrackingCommandHandler.cs @@ -134,7 +134,7 @@ private async Task ShowToolWindowAsync(ITextView textView, Document document, Im foreach (var child in children) { var root = await ValueTrackedTreeItemViewModel.CreateAsync( - solution, child, children: ImmutableArray.Empty, toolWindow.ViewModel, _glyphService, valueTrackingService, _globalOptions, _threadingContext, _listener, _threadOperationExecutor, cancellationToken).ConfigureAwait(false); + solution, child, children: [], toolWindow.ViewModel, _glyphService, valueTrackingService, _globalOptions, _threadingContext, _listener, _threadOperationExecutor, cancellationToken).ConfigureAwait(false); rootItems.Add(root); } } @@ -144,7 +144,7 @@ private async Task ShowToolWindowAsync(ITextView textView, Document document, Im foreach (var child in children) { var childViewModel = await ValueTrackedTreeItemViewModel.CreateAsync( - solution, child, children: ImmutableArray.Empty, toolWindow.ViewModel, _glyphService, valueTrackingService, _globalOptions, _threadingContext, _listener, _threadOperationExecutor, cancellationToken).ConfigureAwait(false); + solution, child, children: [], toolWindow.ViewModel, _glyphService, valueTrackingService, _globalOptions, _threadingContext, _listener, _threadOperationExecutor, cancellationToken).ConfigureAwait(false); childItems.Add(childViewModel); } diff --git a/src/VisualStudio/Core/Def/Venus/ContainedDocument.DocumentServiceProvider.cs b/src/VisualStudio/Core/Def/Venus/ContainedDocument.DocumentServiceProvider.cs index 8d575f832e45d..aa50653b0303e 100644 --- a/src/VisualStudio/Core/Def/Venus/ContainedDocument.DocumentServiceProvider.cs +++ b/src/VisualStudio/Core/Def/Venus/ContainedDocument.DocumentServiceProvider.cs @@ -245,7 +245,7 @@ private static async Task> GetClassifiedSpansOnCo } } - return builder.ToImmutableArray(); + return [.. builder]; } private static int GetNonWhitespaceStartPositionOnContent(SnapshotSpan spanOnPrimarySnapshot) diff --git a/src/VisualStudio/Core/Def/Venus/ContainedLanguageCodeSupport.cs b/src/VisualStudio/Core/Def/Venus/ContainedLanguageCodeSupport.cs index 08c7c22dc6219..749fec43366db 100644 --- a/src/VisualStudio/Core/Def/Venus/ContainedLanguageCodeSupport.cs +++ b/src/VisualStudio/Core/Def/Venus/ContainedLanguageCodeSupport.cs @@ -330,7 +330,7 @@ public static bool TryRenameElement( var newSolution = Renamer.RenameSymbolAsync(document.Project.Solution, symbol, options, newName, cancellationToken).WaitAndGetResult_Venus(cancellationToken); var changedDocuments = newSolution.GetChangedDocuments(document.Project.Solution); - var undoTitle = string.Format(EditorFeaturesResources.Rename_0_to_1, symbol.Name, newName); + var undoTitle = string.Format(WorkspacesResources.Rename_0_to_1, symbol.Name, newName); using (var workspaceUndoTransaction = workspace.OpenGlobalUndoTransaction(undoTitle)) { // Notify third parties about the coming rename operation on the workspace, and let diff --git a/src/VisualStudio/Core/Def/Venus/VenusCommandFilter.cs b/src/VisualStudio/Core/Def/Venus/VenusCommandFilter.cs index 6675780394689..4749f29b355ae 100644 --- a/src/VisualStudio/Core/Def/Venus/VenusCommandFilter.cs +++ b/src/VisualStudio/Core/Def/Venus/VenusCommandFilter.cs @@ -6,6 +6,7 @@ using System.Diagnostics; using System.Linq; +using System.Threading.Tasks; using Microsoft.VisualStudio.ComponentModelHost; using Microsoft.VisualStudio.Editor; using Microsoft.VisualStudio.LanguageServices.Implementation.Extensions; @@ -43,14 +44,13 @@ public VenusCommandFilter( protected override ITextBuffer GetSubjectBufferContainingCaret() => _subjectBuffer; - protected override int GetDataTipTextImpl(TextSpan[] pSpan, out string pbstrText) + protected override async Task<(string pbstrText, int result)> GetDataTipTextImplAsync(TextSpan[] pSpan) { var textViewModel = WpfTextView.TextViewModel; if (textViewModel == null) { Debug.Assert(WpfTextView.IsClosed); - pbstrText = null; - return VSConstants.E_FAIL; + return (null, VSConstants.E_FAIL); } // We need to map the TextSpan from the DataBuffer to our subject buffer. @@ -72,7 +72,7 @@ protected override int GetDataTipTextImpl(TextSpan[] pSpan, out string pbstrText // Next, we'll check to see if there is actually a DataTip for this candidate. // If there is, we'll map this span back to the DataBuffer and return it. var subjectBufferSpanData = new TextSpan[] { candidateSpan.ToVsTextSpan() }; - var hr = GetDataTipTextImpl(_subjectBuffer, subjectBufferSpanData, out pbstrText); + var (pbstrText, hr) = await GetDataTipTextImplAsync(_subjectBuffer, subjectBufferSpanData).ConfigureAwait(true); if (ErrorHandler.Succeeded(hr)) { var subjectSpan = _subjectBuffer.CurrentSnapshot.GetSpan(subjectBufferSpanData[0]); @@ -85,18 +85,14 @@ protected override int GetDataTipTextImpl(TextSpan[] pSpan, out string pbstrText .SingleOrDefault(x => x.IntersectsWith(span)); if (surfaceSpan == default) - { - pbstrText = null; - return VSConstants.E_FAIL; - } + return (null, VSConstants.E_FAIL); // pSpan is an in/out parameter pSpan[0] = surfaceSpan.ToVsTextSpan(); - return hr; + return (pbstrText, hr); } } - pbstrText = null; - return VSConstants.E_FAIL; + return (null, VSConstants.E_FAIL); } } diff --git a/src/VisualStudio/Core/Def/Workspace/VisualStudioActiveDocumentTracker.cs b/src/VisualStudio/Core/Def/Workspace/VisualStudioActiveDocumentTracker.cs index 73ead9d0ebedc..d4f9ac3a13b95 100644 --- a/src/VisualStudio/Core/Def/Workspace/VisualStudioActiveDocumentTracker.cs +++ b/src/VisualStudio/Core/Def/Workspace/VisualStudioActiveDocumentTracker.cs @@ -37,7 +37,7 @@ internal sealed class VisualStudioActiveDocumentTracker : IVsSelectionEvents /// /// The list of tracked frames. This can only be written by the UI thread, although can be read (with care) from any thread. /// - private ImmutableList _visibleFrames = ImmutableList.Empty; + private ImmutableList _visibleFrames = []; /// /// The active IVsWindowFrame. This can only be written by the UI thread, although can be read (with care) from any thread. diff --git a/src/VisualStudio/Core/Def/Workspace/VisualStudioSymbolRenamedCodeActionOperationFactoryWorkspaceService.cs b/src/VisualStudio/Core/Def/Workspace/VisualStudioSymbolRenamedCodeActionOperationFactoryWorkspaceService.cs index 072283f283ee3..84ea08267b0c5 100644 --- a/src/VisualStudio/Core/Def/Workspace/VisualStudioSymbolRenamedCodeActionOperationFactoryWorkspaceService.cs +++ b/src/VisualStudio/Core/Def/Workspace/VisualStudioSymbolRenamedCodeActionOperationFactoryWorkspaceService.cs @@ -81,6 +81,6 @@ public override void Apply(Workspace workspace, CancellationToken cancellationTo } } - public override string Title => string.Format(EditorFeaturesResources.Rename_0_to_1, _symbol.Name, _newName); + public override string Title => string.Format(WorkspacesResources.Rename_0_to_1, _symbol.Name, _newName); } } diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.cs.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.cs.xlf index d91a3f989f186..5976112924b9d 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.cs.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.cs.xlf @@ -72,6 +72,11 @@ Vždy + + _Always add new line on enter + _Always add new line on enter + + Always for clarity Vždy kvůli srozumitelnosti @@ -187,11 +192,6 @@ Počítají se závislosti... - - Call Hierarchy - Hierarchie volání - - Call site value: Hodnota lokality volání: @@ -392,9 +392,9 @@ Barevné schéma editoru - - Editor color scheme options are only available when using a color theme bundled with Visual Studio. The color theme can be configured from the Environment > General options page. - Možnosti barevného schématu editoru jsou k dispozici jen v případě, že se používá barva motivu dodávaná spolu se sadou Visual Studio. Barva motivu se dá nakonfigurovat na stránce možností Prostředí > Obecné. + + Editor Help + Editor Help @@ -432,6 +432,16 @@ Zadejte hodnotu místa volání, nebo zvolte jiný druh vložení hodnoty. + + Enter key behavior + Enter key behavior + + + + Enter key behavior: + Enter key behavior: + + Entire repository Celé úložiště @@ -447,16 +457,16 @@ Celé řešení a externí zdroje - - Error - Chyba - - Error updating suppressions: {0} Chyba při aktualizaci potlačení: {0} + + Experimental feature + Experimental feature + + External Sources Externí zdroje @@ -472,6 +482,11 @@ Extrahovat základní Record {Locked="Record"} "Record" is a language construct for C# and should not be localized + + Fade out unused members + Fade out unused members + + Finish Dokončit @@ -522,11 +537,31 @@ Přejít k definici + + Highlight matching portions of completion list items + Highlight matching portions of completion list items + + + + _Highlight references to symbol under cursor + _Highlight references to symbol under cursor + + Highlight related components under cursor Zvýrazňovat související komponenty pod kurzorem + + Highlight related _keywords under cursor + Highlight related _keywords under cursor + + + + Highlighting + Highlighting + + Id ID @@ -582,9 +617,9 @@ Zděděná rozhraní - - Inline Hints - Vložené nápovědy + + Insert Snippet + Insert Snippet @@ -627,6 +662,11 @@ Druh + + Large + Large + + Loaded items Načtené položky @@ -857,11 +897,6 @@ Pravidla pojmenování - - Navigate asynchronously (experimental) - Asynchronní navigace (experimentální) - - Navigate to '{0}' Přejít na {0} @@ -879,7 +914,12 @@ Never - Nikdy + Never + + + + _Never add new line on enter + _Never add new line on enter @@ -887,6 +927,11 @@ Nikdy, pokud jsou nadbytečné + + Never include snippets + Never include snippets + + New Type Name: Název nového typu: @@ -917,11 +962,6 @@ Neveřejné metody - - None - žádné - - Not applicable Neužívá se @@ -937,6 +977,11 @@ Vynechat (jen pro nepovinné parametry) + + Only add new line on enter after end of fully typed word + Only add new line on enter after end of fully typed word + + Open documents Otevřené dokumenty @@ -947,6 +992,11 @@ Umístění operátora při zalamování + + Optimize for solution size + Optimize for solution size + + Optional parameters must provide a default value Nepovinné parametry musí poskytovat výchozí hodnotu. @@ -1022,16 +1072,16 @@ Předvolby závorek: - - Paste - Vložit - - Paste a stack trace to view and navigate it's values. Pokud chcete zobrazit a procházet jeho hodnoty, vložte trasování zásobníku. "Stack Trace" is a language term and should be kept the same. + + Performance + Performance + + Please enter a type name Zadejte prosím název typu. @@ -1157,16 +1207,16 @@ Rychlé akce - - Refactoring Only - Pouze refaktoring - - Reference Odkaz + + Regular + Regular + + Regular Expressions Regulární výrazy @@ -1182,16 +1232,6 @@ Odebrat nepotřebné direktivy using - - Rename - Přejmenovat - - - - Rename {0} to {1} - Přejmenovat {0} na {1} - - Rename asynchronously (experimental) Asynchronní přejmenování (experimentální) @@ -1342,9 +1382,9 @@ Výsledky sémantického vyhledávání - - Show "Remove Unused References" command in Solution Explorer (experimental) - Zobrazit příkaz Odebrat nepoužívané odkazy v Průzkumníkovi řešení (experimentální) + + Show "Remove Unused References" command in Solution Explorer + Show "Remove Unused References" command in Solution Explorer @@ -1362,11 +1402,36 @@ Zobrazit chyby a upozornění kompilátoru pro: + + Show completion item _filters + Show completion item _filters + + + + Show completion item filters + Show completion item filters + + Show completion list Zobrazit seznam pro doplňování + + Show completion list after a character is _deleted + Show completion list after a character is _deleted + + + + Show completion list after a character is deleted + Show completion list after a character is deleted + + + + Show completion list after a character is typed + Show completion list after a character is typed + + Show guides for comments and preprocessor regions Zobrazit vodítka pro komentáře a oblasti pro preprocesor @@ -1412,14 +1477,39 @@ Zobrazit míru dědičnosti + + Show items from unimported namespaces + Show items from unimported namespaces + + + + Show preview for rename _tracking + Show preview for rename _tracking + + + + _Show procedure line separators + _Show procedure line separators + + + + Show remarks in Quick Info + Show remarks in Quick Info + + Skip analyzers for implicitly triggered builds Přeskočit analyzátory pro implicitně aktivované buildy - - Some color scheme colors are being overridden by changes made in the Environment > Fonts and Colors options page. Choose `Use Defaults` in the Fonts and Colors page to revert all customizations. - Některé barvy barevného schématu se přepsaly změnami na stránce možností Prostředí > Písma a barvy. Pokud chcete zrušit všechna přizpůsobení, vyberte na stránce Písma a barvy možnost Použít výchozí. + + Small + Small + + + + Snippets behavior + Snippets behavior @@ -1452,11 +1542,6 @@ Přeškrtnout zastaralé symboly - - Suggestion - Návrh - - Suppress hints when argument matches parameter name Potlačit nápovědy, když argument odpovídá názvu parametru @@ -1493,8 +1578,13 @@ {Locked="System.Void"} "System.Void" represents CLR's type and should not be localized + Tab twice to insert arguments + Stisknout dvakrát tabulátor, aby se vložily argumenty (experimentální) + + + Tab twice to insert arguments (experimental) - Stisknout dvakrát tabulátor, aby se vložily argumenty (experimentální) + Tab twice to insert arguments (experimental) @@ -1539,7 +1629,7 @@ Title - Název + Title @@ -1567,6 +1657,11 @@ Podtrhnout znovu přiřazené proměnné + + Unused local + Unused local + + Unused value is explicitly assigned to an unused local Nepoužitá hodnota se explicitně přiřadí nepoužité lokální hodnotě. @@ -1622,11 +1717,6 @@ Zde přiřazená hodnota se nikdy nepoužije. - - Value: - Hodnota: - - Value returned by invocation is implicitly ignored Hodnota vrácená voláním je implicitně ignorována. @@ -1652,11 +1742,6 @@ Nastavení sady Visual Studio - - Warning - Upozornění - - Warning: duplicate parameter name Upozornění: duplicitní název parametru @@ -1752,31 +1837,6 @@ Náhled není k dispozici. - - Overrides - Přepisuje - - - - Overridden By - Přepsáno čím: - - - - Inherits - Dědí - - - - Implements - Implementuje - - - - Implemented By - Implementoval: - - Invalid access. Neplatný přístup @@ -1822,6 +1882,21 @@ {0} se změní na veřejný. + + _Highlight matching portions of completion list items + _Highlight matching portions of completion list items + + + + _Only add new line on enter after end of fully typed word + _Only add new line on enter after end of fully typed word + + + + _Show completion list after a character is typed + _Show completion list after a character is typed + + at the end of the line of code na konci řádku kódu @@ -1902,41 +1977,16 @@ Sestavení - - Exceptions: - Výjimky: - - Member of {0} Člen v {0} - - Parameters: - Parametry: - - Project Projekt - - Remarks: - Poznámky: - - - - Returns: - Vrácení: - - - - Summary: - Souhrn: - - Type Parameters: Parametry typu: @@ -2009,21 +2059,11 @@ V rozevíracím seznamu si můžete zobrazit jiné projekty, ke kterým by tento Sestavení analyzátoru {0} se změnilo. Diagnostika možná nebude odpovídat skutečnosti, dokud se Visual Studio nerestartuje. - - Cancel - Storno - - _Deselect All _Zrušit výběr - - Extract Interface - Extrahovat rozhraní - - Generated name: Vygenerovaný název: @@ -2064,11 +2104,6 @@ V rozevíracím seznamu si můžete zobrazit jiné projekty, ke kterým by tento Přidat do _existujícího souboru - - Change Signature - Změnit signaturu - - _Create new file _Vytvořit nový soubor @@ -2204,21 +2239,6 @@ V rozevíracím seznamu si můžete zobrazit jiné projekty, ke kterým by tento 1 odkaz - - '{0}' encountered an error and has been disabled. - 'U analyzátoru {0} došlo k chybě a byl zakázán. - - - - Enable - Povolit - - - - Enable and ignore future errors - Povolit a ignorovat budoucí chyby - - No Changes Beze změn @@ -2234,11 +2254,6 @@ V rozevíracím seznamu si můžete zobrazit jiné projekty, ke kterým by tento Určuje se aktuální blok. - - IntelliSense - IntelliSense - - MissingAnalyzerReference MissingAnalyzerReference @@ -2314,16 +2329,6 @@ V rozevíracím seznamu si můžete zobrazit jiné projekty, ke kterým by tento <Neznámý> - - No - Ne - - - - Yes - Ano - - Enter a title for this Naming Style. Zadejte název tohoto stylu pojmenování. @@ -2562,11 +2567,6 @@ Další informace: {1} Vodítka pro strukturu bloku - - Outlining - Sbalení - - Show guides for code level constructs Zobrazit vodítka pro konstrukty na úrovni kódu diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.de.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.de.xlf index 7871ddf6c880b..858b0e87fabe8 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.de.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.de.xlf @@ -72,6 +72,11 @@ Immer + + _Always add new line on enter + _Always add new line on enter + + Always for clarity Immer zur besseren Unterscheidung @@ -187,11 +192,6 @@ Abhängige Objekte werden berechnet... - - Call Hierarchy - Aufrufhierarchie - - Call site value: Wert der Aufrufsite: @@ -392,9 +392,9 @@ Editor-Farbschema - - Editor color scheme options are only available when using a color theme bundled with Visual Studio. The color theme can be configured from the Environment > General options page. - Optionen für das Editor-Farbschema sind nur bei Verwendung eines im Lieferumfang von Visual Studio enthaltenen Farbdesigns verfügbar. Das Farbdesign kann über die Seite "Umgebung" > "Allgemeine Optionen" konfiguriert werden. + + Editor Help + Editor Help @@ -432,6 +432,16 @@ Geben Sie einen Aufrufsitewert ein, oder wählen Sie eine andere Art der Werteingabe aus. + + Enter key behavior + Enter key behavior + + + + Enter key behavior: + Enter key behavior: + + Entire repository Gesamtes Repository @@ -447,16 +457,16 @@ Gesamte Projektmappe und externe Quellen - - Error - Fehler - - Error updating suppressions: {0} Fehler bei der Aktualisierung von Unterdrückungen: {0} + + Experimental feature + Experimental feature + + External Sources Externe Quellen @@ -472,6 +482,11 @@ Base Record extrahieren {Locked="Record"} "Record" is a language construct for C# and should not be localized + + Fade out unused members + Fade out unused members + + Finish Beenden @@ -522,11 +537,31 @@ Zu Definition wechseln + + Highlight matching portions of completion list items + Highlight matching portions of completion list items + + + + _Highlight references to symbol under cursor + _Highlight references to symbol under cursor + + Highlight related components under cursor Zugehörige Komponenten unter dem Cursor markieren + + Highlight related _keywords under cursor + Highlight related _keywords under cursor + + + + Highlighting + Highlighting + + Id ID @@ -582,9 +617,9 @@ Geerbte Schnittstelle - - Inline Hints - Inlinehinweise + + Insert Snippet + Insert Snippet @@ -627,6 +662,11 @@ Art + + Large + Large + + Loaded items Geladene Elemente @@ -857,11 +897,6 @@ Benennungsregeln - - Navigate asynchronously (experimental) - Asynchron navigieren (experimentell) - - Navigate to '{0}' Zu "{0}" navigieren @@ -879,7 +914,12 @@ Never - Nie + Never + + + + _Never add new line on enter + _Never add new line on enter @@ -887,6 +927,11 @@ Nie, wenn nicht erforderlich + + Never include snippets + Never include snippets + + New Type Name: Neuer Typname: @@ -917,11 +962,6 @@ Nicht öffentliche Methoden - - None - NONE - - Not applicable Nicht zutreffend @@ -937,6 +977,11 @@ Auslassen (nur bei optionalen Parametern) + + Only add new line on enter after end of fully typed word + Only add new line on enter after end of fully typed word + + Open documents Geöffnete Dokumente @@ -947,6 +992,11 @@ Operatorplatzierung beim Umschließen + + Optimize for solution size + Optimize for solution size + + Optional parameters must provide a default value Optionale Parameter müssen einen Standardwert angeben. @@ -1022,16 +1072,16 @@ Voreinstellungen für Klammern: - - Paste - Einfügen - - Paste a stack trace to view and navigate it's values. Fügen Sie eine Stapelüberwachung ein, und navigieren Sie durch ihre Werte. "Stack Trace" is a language term and should be kept the same. + + Performance + Performance + + Please enter a type name Geben Sie einen Typnamen ein. @@ -1157,16 +1207,16 @@ Schnelle Aktionen - - Refactoring Only - Nur Refactoring - - Reference Verweis + + Regular + Regular + + Regular Expressions Reguläre Ausdrücke @@ -1182,16 +1232,6 @@ Nicht benötigte Using-Direktiven entfernen - - Rename - umbenennen - - - - Rename {0} to {1} - "{0}" in "{1}" umbenennen - - Rename asynchronously (experimental) Asynchron umbenennen (experimentell) @@ -1342,9 +1382,9 @@ Semantische Suchergebnisse - - Show "Remove Unused References" command in Solution Explorer (experimental) - Befehl "Nicht verwendete Verweise entfernen" in Projektmappen-Explorer anzeigen (experimentell) + + Show "Remove Unused References" command in Solution Explorer + Show "Remove Unused References" command in Solution Explorer @@ -1362,11 +1402,36 @@ Compilerfehler und -warnungen anzeigen für: + + Show completion item _filters + Show completion item _filters + + + + Show completion item filters + Show completion item filters + + Show completion list Vervollständigungsliste anzeigen + + Show completion list after a character is _deleted + Show completion list after a character is _deleted + + + + Show completion list after a character is deleted + Show completion list after a character is deleted + + + + Show completion list after a character is typed + Show completion list after a character is typed + + Show guides for comments and preprocessor regions Führungslinien für Kommentare und Präprozessorregionen anzeigen @@ -1412,14 +1477,39 @@ Vererbungsrand anzeigen + + Show items from unimported namespaces + Show items from unimported namespaces + + + + Show preview for rename _tracking + Show preview for rename _tracking + + + + _Show procedure line separators + _Show procedure line separators + + + + Show remarks in Quick Info + Show remarks in Quick Info + + Skip analyzers for implicitly triggered builds Analysetools für implizit ausgelöste Builds überspringen - - Some color scheme colors are being overridden by changes made in the Environment > Fonts and Colors options page. Choose `Use Defaults` in the Fonts and Colors page to revert all customizations. - Einige Farbschemafarben werden durch Änderungen überschrieben, die auf der Optionsseite "Umgebung" > "Schriftarten und Farben" vorgenommen wurden. Wählen Sie auf der Seite "Schriftarten und Farben" die Option "Standardwerte verwenden" aus, um alle Anpassungen rückgängig zu machen. + + Small + Small + + + + Snippets behavior + Snippets behavior @@ -1452,11 +1542,6 @@ Veraltete Symbole streichen - - Suggestion - Vorschlag - - Suppress hints when argument matches parameter name Hinweise unterdrücken, wenn das Argument mit dem Namen des Parameters übereinstimmt @@ -1493,8 +1578,13 @@ {Locked="System.Void"} "System.Void" represents CLR's type and should not be localized + Tab twice to insert arguments + Zweimaliges Drücken der TAB-Taste zum Einfügen von Argumenten (experimentell) + + + Tab twice to insert arguments (experimental) - Zweimaliges Drücken der TAB-Taste zum Einfügen von Argumenten (experimentell) + Tab twice to insert arguments (experimental) @@ -1539,7 +1629,7 @@ Title - Titel + Title @@ -1567,6 +1657,11 @@ Neu zugewiesene Variablen unterstreichen + + Unused local + Unused local + + Unused value is explicitly assigned to an unused local Der nicht verwendete Wert wird explizit einer nicht verwendeten lokalen Variablen zugewiesen. @@ -1622,11 +1717,6 @@ Der hier zugewiesene Wert wird nie verwendet. - - Value: - Wert: - - Value returned by invocation is implicitly ignored Der vom Aufruf zurückgegebene Wert wird implizit ignoriert. @@ -1652,11 +1742,6 @@ Visual Studio-Einstellungen - - Warning - Warnung - - Warning: duplicate parameter name Warnung: doppelter Parametername @@ -1752,31 +1837,6 @@ Vorschau nicht verfügbar. - - Overrides - Überschreibungen - - - - Overridden By - Überschrieben von - - - - Inherits - Erbt - - - - Implements - Implementiert - - - - Implemented By - Implementiert von - - Invalid access. Ungültiger Zugriff. @@ -1822,6 +1882,21 @@ "{0}" wird in öffentlichen Wert geändert. + + _Highlight matching portions of completion list items + _Highlight matching portions of completion list items + + + + _Only add new line on enter after end of fully typed word + _Only add new line on enter after end of fully typed word + + + + _Show completion list after a character is typed + _Show completion list after a character is typed + + at the end of the line of code am Ende der Codezeile @@ -1902,41 +1977,16 @@ Assembly - - Exceptions: - Ausnahmen: - - Member of {0} Member von "{0}" - - Parameters: - Parameter: - - Project Projekt - - Remarks: - Hinweise: - - - - Returns: - Rückgabewerte: - - - - Summary: - Zusammenfassung: - - Type Parameters: Typparameter: @@ -2009,21 +2059,11 @@ Verwenden Sie die Dropdownliste, um weitere zu dieser Datei gehörige Projekte a Die Analysetoolassembly "{0}" wurde geändert. Die Diagnose ist bis zu einem Neustart von Visual Studio möglicherweise nicht korrekt. - - Cancel - Abbrechen - - _Deselect All Auswahl _aufheben - - Extract Interface - Schnittstelle extrahieren - - Generated name: Generierter Name: @@ -2064,11 +2104,6 @@ Verwenden Sie die Dropdownliste, um weitere zu dieser Datei gehörige Projekte a Zu _vorhandener Datei hinzufügen - - Change Signature - Signatur ändern - - _Create new file Neue Datei _erstellen @@ -2204,21 +2239,6 @@ Verwenden Sie die Dropdownliste, um weitere zu dieser Datei gehörige Projekte a 1 Verweis - - '{0}' encountered an error and has been disabled. - "{0}" hat einen Fehler festgestellt und wurde deaktiviert. - - - - Enable - Aktivieren - - - - Enable and ignore future errors - Aktivieren und weitere Fehler ignorieren - - No Changes Keine Änderungen @@ -2234,11 +2254,6 @@ Verwenden Sie die Dropdownliste, um weitere zu dieser Datei gehörige Projekte a Der aktuelle Block wird bestimmt. - - IntelliSense - IntelliSense - - MissingAnalyzerReference MissingAnalyzerReference @@ -2314,16 +2329,6 @@ Verwenden Sie die Dropdownliste, um weitere zu dieser Datei gehörige Projekte a <Unbekannt> - - No - Nein - - - - Yes - Ja - - Enter a title for this Naming Style. Geben Sie einen Titel für diesen Benennungsstil ein. @@ -2562,11 +2567,6 @@ Zusätzliche Informationen: {1} Führungslinien für Blockstruktur - - Outlining - Gliederung - - Show guides for code level constructs Führungslinien für Konstrukte auf Codeebene anzeigen diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.es.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.es.xlf index 4fb93d83b07a3..a1e1f42566352 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.es.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.es.xlf @@ -72,6 +72,11 @@ Siempre + + _Always add new line on enter + _Always add new line on enter + + Always for clarity Siempre por claridad @@ -187,11 +192,6 @@ Calculando dependientes... - - Call Hierarchy - Jerarquía de llamadas - - Call site value: Valor del sitio de llamada: @@ -392,9 +392,9 @@ Combinación de colores del editor - - Editor color scheme options are only available when using a color theme bundled with Visual Studio. The color theme can be configured from the Environment > General options page. - Las opciones de combinación de colores del editor solo están disponibles cuando se usa un tema de color incluido con Visual Studio. Dicho tema se puede configurar desde la página de Entorno > Opciones generales. + + Editor Help + Editor Help @@ -432,6 +432,16 @@ Escriba un valor de sitio de llamada o elija otro tipo de inserción de valor. + + Enter key behavior + Enter key behavior + + + + Enter key behavior: + Enter key behavior: + + Entire repository Todo el repositorio @@ -447,16 +457,16 @@ Solución completa y orígenes externos - - Error - Error - - Error updating suppressions: {0} Actualización de errores de forma periódica: {0} + + Experimental feature + Experimental feature + + External Sources Orígenes externos @@ -472,6 +482,11 @@ Extraer Record base {Locked="Record"} "Record" is a language construct for C# and should not be localized + + Fade out unused members + Fade out unused members + + Finish Finalizar @@ -522,11 +537,31 @@ Ir a definición + + Highlight matching portions of completion list items + Highlight matching portions of completion list items + + + + _Highlight references to symbol under cursor + _Highlight references to symbol under cursor + + Highlight related components under cursor Resaltar componentes relacionados bajo el cursor + + Highlight related _keywords under cursor + Highlight related _keywords under cursor + + + + Highlighting + Highlighting + + Id Id. @@ -582,9 +617,9 @@ Interfaces heredadas - - Inline Hints - Sugerencias insertadas + + Insert Snippet + Insert Snippet @@ -627,6 +662,11 @@ Tipo + + Large + Large + + Loaded items Elementos cargados @@ -857,11 +897,6 @@ Reglas de nomenclatura - - Navigate asynchronously (experimental) - Navegar de forma asincrónica (experimental) - - Navigate to '{0}' Navegar a "{0}" @@ -879,7 +914,12 @@ Never - Nunca + Never + + + + _Never add new line on enter + _Never add new line on enter @@ -887,6 +927,11 @@ Nunca si es innecesario + + Never include snippets + Never include snippets + + New Type Name: Nombre de tipo nuevo: @@ -917,11 +962,6 @@ Miembros no públicos - - None - NONE - - Not applicable No aplicable @@ -937,6 +977,11 @@ Omitir (solo para parámetros opcionales) + + Only add new line on enter after end of fully typed word + Only add new line on enter after end of fully typed word + + Open documents Documentos abiertos @@ -947,6 +992,11 @@ Colocación del operador al ajustar + + Optimize for solution size + Optimize for solution size + + Optional parameters must provide a default value Los parámetros opcionales deben proporcionar un valor predeterminado. @@ -1022,16 +1072,16 @@ Preferencias de paréntesis: - - Paste - Pegar - - Paste a stack trace to view and navigate it's values. Pegar un seguimiento de pila para ver y navegar sus valores. "Stack Trace" is a language term and should be kept the same. + + Performance + Performance + + Please enter a type name Escriba un nombre de tipo. @@ -1157,16 +1207,16 @@ Acciones rápidas - - Refactoring Only - Solo refactorización - - Reference Referencia + + Regular + Regular + + Regular Expressions Expresiones regulares @@ -1182,16 +1232,6 @@ Eliminar instrucciones Using innecesarias - - Rename - Cambiar nombre - - - - Rename {0} to {1} - Cambiar nombre de {0} a {1} - - Rename asynchronously (experimental) Cambiar el nombre de forma asincrónica (experimental) @@ -1342,9 +1382,9 @@ Resultados de búsqueda semántica - - Show "Remove Unused References" command in Solution Explorer (experimental) - Mostrar el comando "Quitar referencias sin usar" en el Explorador de soluciones (experimental) + + Show "Remove Unused References" command in Solution Explorer + Show "Remove Unused References" command in Solution Explorer @@ -1362,11 +1402,36 @@ Mostrar errores y advertencias del compilador para: + + Show completion item _filters + Show completion item _filters + + + + Show completion item filters + Show completion item filters + + Show completion list Mostrar lista de finalización + + Show completion list after a character is _deleted + Show completion list after a character is _deleted + + + + Show completion list after a character is deleted + Show completion list after a character is deleted + + + + Show completion list after a character is typed + Show completion list after a character is typed + + Show guides for comments and preprocessor regions Mostrar guías para regiones de preprocesador y comentarios @@ -1412,14 +1477,39 @@ Mostrar margen de herencia + + Show items from unimported namespaces + Show items from unimported namespaces + + + + Show preview for rename _tracking + Show preview for rename _tracking + + + + _Show procedure line separators + _Show procedure line separators + + + + Show remarks in Quick Info + Show remarks in Quick Info + + Skip analyzers for implicitly triggered builds Omitir analizadores para compilaciones desencadenadas implícitamente - - Some color scheme colors are being overridden by changes made in the Environment > Fonts and Colors options page. Choose `Use Defaults` in the Fonts and Colors page to revert all customizations. - Algunos de los colores de la combinación se reemplazan por los cambios realizados en la página de opciones de Entorno > Fuentes y colores. Elija "Usar valores predeterminados" en la página Fuentes y colores para revertir todas las personalizaciones. + + Small + Small + + + + Snippets behavior + Snippets behavior @@ -1452,11 +1542,6 @@ Tachado de símbolos obsoletos - - Suggestion - Sugerencia - - Suppress hints when argument matches parameter name Suprimir las sugerencias cuando el argumento coincide con el nombre del parámetro @@ -1493,8 +1578,13 @@ {Locked="System.Void"} "System.Void" represents CLR's type and should not be localized + Tab twice to insert arguments + Presionar dos veces la tecla Tab para insertar argumentos (experimental) + + + Tab twice to insert arguments (experimental) - Presionar dos veces la tecla Tab para insertar argumentos (experimental) + Tab twice to insert arguments (experimental) @@ -1539,7 +1629,7 @@ Title - Título + Title @@ -1567,6 +1657,11 @@ Subrayar variables reasignadas + + Unused local + Unused local + + Unused value is explicitly assigned to an unused local El valor sin usar se asigna explícitamente a una variable local sin usar @@ -1622,11 +1717,6 @@ El valor asignado aquí no se usa nunca - - Value: - Valor: - - Value returned by invocation is implicitly ignored El valor devuelto por la invocación se omite implícitamente @@ -1652,11 +1742,6 @@ Configuración de Visual Studio - - Warning - Advertencia - - Warning: duplicate parameter name Advertencia: Nombre de parámetro duplicado @@ -1752,31 +1837,6 @@ Vista previa no disponible - - Overrides - Invalidaciones - - - - Overridden By - Invalidado por - - - - Inherits - Hereda - - - - Implements - Implementa - - - - Implemented By - Implementado por - - Invalid access. Acceso no válido. @@ -1822,6 +1882,21 @@ "{0}" se cambiará a público. + + _Highlight matching portions of completion list items + _Highlight matching portions of completion list items + + + + _Only add new line on enter after end of fully typed word + _Only add new line on enter after end of fully typed word + + + + _Show completion list after a character is typed + _Show completion list after a character is typed + + at the end of the line of code al final de la línea de código @@ -1902,41 +1977,16 @@ Ensamblado - - Exceptions: - Excepciones: - - Member of {0} Miembro de {0} - - Parameters: - Parámetros: - - Project Proyecto - - Remarks: - Comentarios: - - - - Returns: - Devuelve: - - - - Summary: - Resumen: - - Type Parameters: Parámetros de tipo: @@ -2009,21 +2059,11 @@ Use la lista desplegable para ver y cambiar a otros proyectos a los que puede pe El ensamblado del analizador "{0}" cambió. Los diagnósticos podrían ser incorrectos hasta que se reinicie Visual Studio. - - Cancel - Cancelar - - _Deselect All _Anular toda la selección - - Extract Interface - Extraer interfaz - - Generated name: Nombre generado: @@ -2064,11 +2104,6 @@ Use la lista desplegable para ver y cambiar a otros proyectos a los que puede pe Agregar a archivo _existente - - Change Signature - Cambiar firma - - _Create new file _Crear nuevo archivo @@ -2204,21 +2239,6 @@ Use la lista desplegable para ver y cambiar a otros proyectos a los que puede pe 1 referencia - - '{0}' encountered an error and has been disabled. - "{0}" detectó un error y se ha deshabilitado. - - - - Enable - Habilitar - - - - Enable and ignore future errors - Habilitar y omitir futuros errores - - No Changes Sin cambios @@ -2234,11 +2254,6 @@ Use la lista desplegable para ver y cambiar a otros proyectos a los que puede pe Determinando el bloque actual. - - IntelliSense - IntelliSense - - MissingAnalyzerReference MissingAnalyzerReference @@ -2314,16 +2329,6 @@ Use la lista desplegable para ver y cambiar a otros proyectos a los que puede pe <Desconocido> - - No - No - - - - Yes - - - Enter a title for this Naming Style. Escriba un título para el estilo de nomenclatura. @@ -2562,11 +2567,6 @@ Información adicional: {1} Guías de estructura de bloque - - Outlining - Esquematización - - Show guides for code level constructs Mostrar guías para construcciones a nivel de código diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.fr.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.fr.xlf index 53fdd9e9e3008..c99a9fb09e594 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.fr.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.fr.xlf @@ -72,6 +72,11 @@ Toujours + + _Always add new line on enter + _Always add new line on enter + + Always for clarity Toujours pour plus de clarté @@ -187,11 +192,6 @@ Calcul des dépendants... - - Call Hierarchy - Hiérarchie d'appels - - Call site value: Valeur du site d'appel : @@ -392,9 +392,9 @@ Modèle de couleurs de l'éditeur - - Editor color scheme options are only available when using a color theme bundled with Visual Studio. The color theme can be configured from the Environment > General options page. - Les options relatives au modèle de couleurs de l'éditeur sont disponibles uniquement quand vous utilisez un thème de couleur fourni en bundle avec Visual Studio. Vous pouvez configurer le thème de couleur à partir de la page d'options Environnement > Général. + + Editor Help + Editor Help @@ -432,6 +432,16 @@ Entrer une valeur de site d'appel ou choisir un autre type d'injection de valeur + + Enter key behavior + Enter key behavior + + + + Enter key behavior: + Enter key behavior: + + Entire repository Dépôt entier @@ -447,16 +457,16 @@ Solution entière et sources externes - - Error - Erreur - - Error updating suppressions: {0} Erreur lors de la mise à jour des suppressions : {0} + + Experimental feature + Experimental feature + + External Sources Sources externes @@ -472,6 +482,11 @@ Extraire le Record de base {Locked="Record"} "Record" is a language construct for C# and should not be localized + + Fade out unused members + Fade out unused members + + Finish Terminer @@ -522,11 +537,31 @@ Accéder à la définition + + Highlight matching portions of completion list items + Highlight matching portions of completion list items + + + + _Highlight references to symbol under cursor + _Highlight references to symbol under cursor + + Highlight related components under cursor Surligner les composants liés sous le curseur + + Highlight related _keywords under cursor + Highlight related _keywords under cursor + + + + Highlighting + Highlighting + + Id ID @@ -582,9 +617,9 @@ Interfaces héritées - - Inline Hints - Indicateurs inline + + Insert Snippet + Insert Snippet @@ -627,6 +662,11 @@ Genre + + Large + Large + + Loaded items Éléments chargés @@ -857,11 +897,6 @@ Règles de nommage - - Navigate asynchronously (experimental) - Naviguer de façon asynchrone (expérimental) - - Navigate to '{0}' Accéder à « {0} » @@ -879,7 +914,12 @@ Never - Jamais + Never + + + + _Never add new line on enter + _Never add new line on enter @@ -887,6 +927,11 @@ Jamais si ce n'est pas nécessaire + + Never include snippets + Never include snippets + + New Type Name: Nouveau nom de type : @@ -917,11 +962,6 @@ Méthodes non publiques - - None - Aucun(e) - - Not applicable Non applicable @@ -937,6 +977,11 @@ Omettre (uniquement pour les paramètres facultatifs) + + Only add new line on enter after end of fully typed word + Only add new line on enter after end of fully typed word + + Open documents Documents ouverts @@ -947,6 +992,11 @@ Placement de l’opérateur lors du retour à la ligne + + Optimize for solution size + Optimize for solution size + + Optional parameters must provide a default value Les paramètres facultatifs doivent fournir une valeur par défaut @@ -1022,16 +1072,16 @@ Préférences relatives aux parenthèses : - - Paste - Coller - - Paste a stack trace to view and navigate it's values. Collez une trace de pile pour afficher et parcourir ses valeurs. "Stack Trace" is a language term and should be kept the same. + + Performance + Performance + + Please enter a type name Entrez un nom de type @@ -1157,16 +1207,16 @@ Actions rapides - - Refactoring Only - Refactoring Only - - Reference Référence + + Regular + Regular + + Regular Expressions Expressions régulières @@ -1182,16 +1232,6 @@ Supprimer les Usings inutiles - - Rename - renommer - - - - Rename {0} to {1} - Renommer {0} en {1} - - Rename asynchronously (experimental) Renommer de façon asynchrone (expérimentale) @@ -1342,9 +1382,9 @@ Résultats de la recherche sémantique - - Show "Remove Unused References" command in Solution Explorer (experimental) - Afficher la commande Supprimer les références inutilisées dans l'Explorateur de solutions (expérimental) + + Show "Remove Unused References" command in Solution Explorer + Show "Remove Unused References" command in Solution Explorer @@ -1362,11 +1402,36 @@ Afficher les erreurs et avertissements du compilateur pour : + + Show completion item _filters + Show completion item _filters + + + + Show completion item filters + Show completion item filters + + Show completion list Afficher la liste de saisie semi-automatique + + Show completion list after a character is _deleted + Show completion list after a character is _deleted + + + + Show completion list after a character is deleted + Show completion list after a character is deleted + + + + Show completion list after a character is typed + Show completion list after a character is typed + + Show guides for comments and preprocessor regions Afficher les repères pour les commentaires et les régions du préprocesseur @@ -1412,14 +1477,39 @@ Afficher la marge d’héritage + + Show items from unimported namespaces + Show items from unimported namespaces + + + + Show preview for rename _tracking + Show preview for rename _tracking + + + + _Show procedure line separators + _Show procedure line separators + + + + Show remarks in Quick Info + Show remarks in Quick Info + + Skip analyzers for implicitly triggered builds Ignorer les analyseurs pour les builds déclenchées implicitement - - Some color scheme colors are being overridden by changes made in the Environment > Fonts and Colors options page. Choose `Use Defaults` in the Fonts and Colors page to revert all customizations. - Certaines couleurs du modèle de couleurs sont substituées à la suite des changements apportés dans la page d'options Environnement > Polices et couleurs. Choisissez Utiliser les valeurs par défaut dans la page Polices et couleurs pour restaurer toutes les personnalisations. + + Small + Small + + + + Snippets behavior + Snippets behavior @@ -1452,11 +1542,6 @@ Symboles obsolètes barrés - - Suggestion - Suggestion - - Suppress hints when argument matches parameter name Supprimer les conseils lorsque l'argument correspond au nom du paramètre @@ -1493,8 +1578,13 @@ {Locked="System.Void"} "System.Void" represents CLR's type and should not be localized + Tab twice to insert arguments + Appuyer deux fois sur Tab pour insérer des arguments (expérimental) + + + Tab twice to insert arguments (experimental) - Appuyer deux fois sur Tab pour insérer des arguments (expérimental) + Tab twice to insert arguments (experimental) @@ -1539,7 +1629,7 @@ Title - Titre + Title @@ -1567,6 +1657,11 @@ Souligner les variables réaffectées + + Unused local + Unused local + + Unused value is explicitly assigned to an unused local La valeur inutilisée est explicitement affectée à une variable locale inutilisée @@ -1622,11 +1717,6 @@ La valeur affectée ici n'est jamais utilisée - - Value: - Valeur : - - Value returned by invocation is implicitly ignored La valeur retournée par invocation est implicitement ignorée @@ -1652,11 +1742,6 @@ Paramètres de Visual Studio - - Warning - Avertissement - - Warning: duplicate parameter name Avertissement : Nom de paramètre dupliqué @@ -1752,31 +1837,6 @@ Aperçu non disponible - - Overrides - Substitutions - - - - Overridden By - Remplacée par - - - - Inherits - Hérite - - - - Implements - Implémente - - - - Implemented By - Implémenté par - - Invalid access. Accès non valide. @@ -1822,6 +1882,21 @@ '{0}' va être changé en valeur publique. + + _Highlight matching portions of completion list items + _Highlight matching portions of completion list items + + + + _Only add new line on enter after end of fully typed word + _Only add new line on enter after end of fully typed word + + + + _Show completion list after a character is typed + _Show completion list after a character is typed + + at the end of the line of code à la fin de la ligne de code @@ -1902,41 +1977,16 @@ Assembly - - Exceptions: - Exceptions : - - Member of {0} Membre de {0} - - Parameters: - Paramètres : - - Project Projet - - Remarks: - Notes : - - - - Returns: - Retourne : - - - - Summary: - Résumé : - - Type Parameters: Paramètres de type : @@ -2009,21 +2059,11 @@ Utilisez le menu déroulant pour afficher et basculer vers d'autres projets auqu L'assembly d'analyseur '{0}' a été modifié. Les diagnostics seront incorrects jusqu'au redémarrage de Visual Studio. - - Cancel - Annuler - - _Deselect All _Désélectionner tout - - Extract Interface - Extraire l'interface - - Generated name: Nom généré : @@ -2064,11 +2104,6 @@ Utilisez le menu déroulant pour afficher et basculer vers d'autres projets auqu Ajouter au fichier e_xistant - - Change Signature - Modifier la signature - - _Create new file _Créer un fichier @@ -2204,21 +2239,6 @@ Utilisez le menu déroulant pour afficher et basculer vers d'autres projets auqu 1 référence - - '{0}' encountered an error and has been disabled. - '{0}' a rencontré une erreur et a été désactivé. - - - - Enable - Activer - - - - Enable and ignore future errors - Activer et ignorer les futures erreurs - - No Changes Aucune modification @@ -2234,11 +2254,6 @@ Utilisez le menu déroulant pour afficher et basculer vers d'autres projets auqu Détermination du bloc actif. - - IntelliSense - IntelliSense - - MissingAnalyzerReference MissingAnalyzerReference @@ -2314,16 +2329,6 @@ Utilisez le menu déroulant pour afficher et basculer vers d'autres projets auqu <Inconnu> - - No - Non - - - - Yes - Oui - - Enter a title for this Naming Style. Entrez un titre pour ce style de nommage. @@ -2562,11 +2567,6 @@ Informations supplémentaires : {1} Repères de structure de bloc - - Outlining - Mode plan - - Show guides for code level constructs Afficher les repères pour les constructions au niveau du code diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.it.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.it.xlf index 67fc723f5a99c..7dd8a02d5d733 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.it.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.it.xlf @@ -72,6 +72,11 @@ Sempre + + _Always add new line on enter + _Always add new line on enter + + Always for clarity Sempre per chiarezza @@ -187,11 +192,6 @@ Calcolo dei dipendenti... - - Call Hierarchy - Gerarchia di chiamata - - Call site value: Valore del sito di chiamata: @@ -392,9 +392,9 @@ Combinazione colori editor - - Editor color scheme options are only available when using a color theme bundled with Visual Studio. The color theme can be configured from the Environment > General options page. - Le opzioni della combinazione colori dell'editor sono disponibili solo quando si usa un tema colori fornito con Visual Studio. È possibile configurare il tema colore nella pagina Ambiente > Opzioni generali. + + Editor Help + Editor Help @@ -432,6 +432,16 @@ Immettere un valore per il sito di chiamata o scegliere un tipo di inserimento valori diverso + + Enter key behavior + Enter key behavior + + + + Enter key behavior: + Enter key behavior: + + Entire repository Intero repository @@ -447,16 +457,16 @@ Intera soluzione e origini esterne - - Error - Errore - - Error updating suppressions: {0} Errore durante l'aggiornamento delle eliminazioni: {0} + + Experimental feature + Experimental feature + + External Sources Origini esterne @@ -472,6 +482,11 @@ Estrai Record di base {Locked="Record"} "Record" is a language construct for C# and should not be localized + + Fade out unused members + Fade out unused members + + Finish Fine @@ -522,11 +537,31 @@ Vai alla definizione + + Highlight matching portions of completion list items + Highlight matching portions of completion list items + + + + _Highlight references to symbol under cursor + _Highlight references to symbol under cursor + + Highlight related components under cursor Evidenzia i componenti correlati sotto il cursore + + Highlight related _keywords under cursor + Highlight related _keywords under cursor + + + + Highlighting + Highlighting + + Id ID @@ -582,9 +617,9 @@ Interfacce ereditate - - Inline Hints - Suggerimenti inline + + Insert Snippet + Insert Snippet @@ -627,6 +662,11 @@ Tipo + + Large + Large + + Loaded items Elementi caricati @@ -857,11 +897,6 @@ Regole di denominazione - - Navigate asynchronously (experimental) - Naviga in modo asincrono (sperimentale) - - Navigate to '{0}' Passa a '{0}' @@ -879,7 +914,12 @@ Never - Mai + Never + + + + _Never add new line on enter + _Never add new line on enter @@ -887,6 +927,11 @@ Mai se non necessario + + Never include snippets + Never include snippets + + New Type Name: Nuovo nome di tipo: @@ -917,11 +962,6 @@ Metodi non pubblici - - None - Nessuno - - Not applicable Non applicabile @@ -937,6 +977,11 @@ Ometti (solo per parametri facoltativi) + + Only add new line on enter after end of fully typed word + Only add new line on enter after end of fully typed word + + Open documents Documenti aperti @@ -947,6 +992,11 @@ Posizionamento dell'operatore durante il ritorno a capo + + Optimize for solution size + Optimize for solution size + + Optional parameters must provide a default value I parametri facoltativi devono specificare un valore predefinito @@ -1022,16 +1072,16 @@ Preferenze per parentesi: - - Paste - Incolla - - Paste a stack trace to view and navigate it's values. Incollare un'analisi dello stack per visualizzare e spostarsi tra i valori. "Stack Trace" is a language term and should be kept the same. + + Performance + Performance + + Please enter a type name Immettere un nome di tipo @@ -1157,16 +1207,16 @@ Azioni rapide - - Refactoring Only - Refactoring Only - - Reference Riferimento + + Regular + Regular + + Regular Expressions Espressioni regolari @@ -1182,16 +1232,6 @@ Rimuovi istruzioni using non necessarie - - Rename - Rinomina - - - - Rename {0} to {1} - Rinomina {0} in {1} - - Rename asynchronously (experimental) Rinomina in modo asincrono (sperimentale) @@ -1342,9 +1382,9 @@ Risultati della ricerca semantica - - Show "Remove Unused References" command in Solution Explorer (experimental) - Mostra il comando "Rimuovi riferimenti inutilizzati" in Esplora soluzioni (sperimentale) + + Show "Remove Unused References" command in Solution Explorer + Show "Remove Unused References" command in Solution Explorer @@ -1362,11 +1402,36 @@ Mostra errori e avvisi del compilatore per: + + Show completion item _filters + Show completion item _filters + + + + Show completion item filters + Show completion item filters + + Show completion list Mostra l'elenco di completamento + + Show completion list after a character is _deleted + Show completion list after a character is _deleted + + + + Show completion list after a character is deleted + Show completion list after a character is deleted + + + + Show completion list after a character is typed + Show completion list after a character is typed + + Show guides for comments and preprocessor regions Mostra le guide per i commenti e le aree del preprocessore @@ -1412,14 +1477,39 @@ Mostra il margine di ereditarietà + + Show items from unimported namespaces + Show items from unimported namespaces + + + + Show preview for rename _tracking + Show preview for rename _tracking + + + + _Show procedure line separators + _Show procedure line separators + + + + Show remarks in Quick Info + Show remarks in Quick Info + + Skip analyzers for implicitly triggered builds Ignora gli analizzatori per compilazioni attivate in modo implicito - - Some color scheme colors are being overridden by changes made in the Environment > Fonts and Colors options page. Choose `Use Defaults` in the Fonts and Colors page to revert all customizations. - Alcuni colori della combinazione colori sono sostituiti dalle modifiche apportate nella pagina di opzioni Ambiente > Tipi di carattere e colori. Scegliere `Usa impostazioni predefinite` nella pagina Tipi di carattere e colori per ripristinare tutte le personalizzazioni. + + Small + Small + + + + Snippets behavior + Snippets behavior @@ -1452,11 +1542,6 @@ Barrare i simboli obsoleti - - Suggestion - Suggerimento - - Suppress hints when argument matches parameter name Elimina hint quando l'argomento corrisponde al nome del parametro @@ -1493,8 +1578,13 @@ {Locked="System.Void"} "System.Void" represents CLR's type and should not be localized + Tab twice to insert arguments + Premi due volte TAB per inserire gli argomenti (sperimentale) + + + Tab twice to insert arguments (experimental) - Premi due volte TAB per inserire gli argomenti (sperimentale) + Tab twice to insert arguments (experimental) @@ -1539,7 +1629,7 @@ Title - Titolo + Title @@ -1567,6 +1657,11 @@ Sottolinea variabili riassegnate + + Unused local + Unused local + + Unused value is explicitly assigned to an unused local Il valore inutilizzato viene assegnato in modo esplicito a una variabile locale inutilizzata @@ -1622,11 +1717,6 @@ Il valore assegnato qui non viene mai usato - - Value: - Valore: - - Value returned by invocation is implicitly ignored Il valore restituito dalla chiamata viene ignorato in modo implicito @@ -1652,11 +1742,6 @@ Impostazioni di Visual Studio - - Warning - Avviso - - Warning: duplicate parameter name Avviso: nome di parametro duplicato @@ -1752,31 +1837,6 @@ Anteprima non disponibile - - Overrides - Esegue l'override - - - - Overridden By - Sottoposto a override da - - - - Inherits - Eredita - - - - Implements - Implementa - - - - Implemented By - Implementato da - - Invalid access. L'accesso non è valido. @@ -1822,6 +1882,21 @@ '{0}' verrà modificato in pubblico. + + _Highlight matching portions of completion list items + _Highlight matching portions of completion list items + + + + _Only add new line on enter after end of fully typed word + _Only add new line on enter after end of fully typed word + + + + _Show completion list after a character is typed + _Show completion list after a character is typed + + at the end of the line of code alla fine della riga di codice @@ -1902,41 +1977,16 @@ Assembly - - Exceptions: - Eccezioni: - - Member of {0} Membro di {0} - - Parameters: - Parametri: - - Project Progetto - - Remarks: - Commenti: - - - - Returns: - Valori restituiti: - - - - Summary: - Riepilogo: - - Type Parameters: Parametri di tipo: @@ -2009,21 +2059,11 @@ Usare l'elenco a discesa per visualizzare e passare ad altri progetti a cui ques L'assembly '{0}' dell'analizzatore è stato modificato. È possibile che la diagnostica non sia corretta fino al riavvio di Visual Studio. - - Cancel - Annulla - - _Deselect All _Deseleziona tutto - - Extract Interface - Estrai interfaccia - - Generated name: Nome generato: @@ -2064,11 +2104,6 @@ Usare l'elenco a discesa per visualizzare e passare ad altri progetti a cui ques Aggiungi a file _esistente - - Change Signature - Cambia firma - - _Create new file _Crea nuovo file @@ -2204,21 +2239,6 @@ Usare l'elenco a discesa per visualizzare e passare ad altri progetti a cui ques 1 riferimento - - '{0}' encountered an error and has been disabled. - '{0}' ha rilevato un errore ed è stato disabilitato. - - - - Enable - Abilita - - - - Enable and ignore future errors - Abilita e ignora gli errori futuri - - No Changes Nessuna modifica @@ -2234,11 +2254,6 @@ Usare l'elenco a discesa per visualizzare e passare ad altri progetti a cui ques È in corso la determinazione del blocco corrente. - - IntelliSense - IntelliSense - - MissingAnalyzerReference MissingAnalyzerReference @@ -2314,16 +2329,6 @@ Usare l'elenco a discesa per visualizzare e passare ad altri progetti a cui ques <Sconosciuto> - - No - No - - - - Yes - - - Enter a title for this Naming Style. Immettere un titolo per questo stile di denominazione. @@ -2562,11 +2567,6 @@ Informazioni aggiuntive: {1} Guide per strutture a blocchi - - Outlining - Struttura - - Show guides for code level constructs Mostra le guide per i costrutti a livello di codice diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ja.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ja.xlf index b72e61051997f..19794050b6e59 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ja.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ja.xlf @@ -72,6 +72,11 @@ 常時 + + _Always add new line on enter + _Always add new line on enter + + Always for clarity わかりやすくするために常に @@ -187,11 +192,6 @@ 依存を計算しています... - - Call Hierarchy - 呼び出し階層 - - Call site value: 呼び出しサイトの値: @@ -392,9 +392,9 @@ エディターの配色 - - Editor color scheme options are only available when using a color theme bundled with Visual Studio. The color theme can be configured from the Environment > General options page. - エディターの配色オプションは、Visual Studio にバンドルされている配色テーマを使用している場合にのみ使用できます。配色テーマは、[環境] > [全般] オプション ページで構成できます。 + + Editor Help + Editor Help @@ -432,6 +432,16 @@ 呼び出しサイトの値を入力するか、別の値の挿入の種類を選択してください + + Enter key behavior + Enter key behavior + + + + Enter key behavior: + Enter key behavior: + + Entire repository リポジトリ全体 @@ -447,16 +457,16 @@ ソリューションと外部ソース全体 - - Error - エラー - - Error updating suppressions: {0} 抑制の更新でエラーが発生しました: {0} + + Experimental feature + Experimental feature + + External Sources 外部ソース @@ -472,6 +482,11 @@ 基底 Record の抽出 {Locked="Record"} "Record" is a language construct for C# and should not be localized + + Fade out unused members + Fade out unused members + + Finish 終了 @@ -522,11 +537,31 @@ 定義へ移動 + + Highlight matching portions of completion list items + Highlight matching portions of completion list items + + + + _Highlight references to symbol under cursor + _Highlight references to symbol under cursor + + Highlight related components under cursor カーソルの下にある関連コンポーネントをハイライトする + + Highlight related _keywords under cursor + Highlight related _keywords under cursor + + + + Highlighting + Highlighting + + Id ID @@ -582,9 +617,9 @@ 継承されたインターフェイス - - Inline Hints - インラインのヒント + + Insert Snippet + Insert Snippet @@ -627,6 +662,11 @@ 種類 + + Large + Large + + Loaded items 読み込まれた項目 @@ -857,11 +897,6 @@ 名前付けルール - - Navigate asynchronously (experimental) - 非同期に移動する (試験段階) - - Navigate to '{0}' '{0}' に移動する @@ -879,7 +914,12 @@ Never - 行わない + Never + + + + _Never add new line on enter + _Never add new line on enter @@ -887,6 +927,11 @@ 不必要なら保持しない + + Never include snippets + Never include snippets + + New Type Name: 新しい型名: @@ -917,11 +962,6 @@ パブリックでないメソッド - - None - なし - - Not applicable 適用なし @@ -937,6 +977,11 @@ 省略 (省略可能なパラメーターの場合のみ) + + Only add new line on enter after end of fully typed word + Only add new line on enter after end of fully typed word + + Open documents 開かれているドキュメント @@ -947,6 +992,11 @@ 折り返し時の演算子の配置 + + Optimize for solution size + Optimize for solution size + + Optional parameters must provide a default value 省略可能なパラメーターには、既定値を指定する必要があります @@ -1022,16 +1072,16 @@ かっこの優先順位: - - Paste - 貼り付け - - Paste a stack trace to view and navigate it's values. 有効なスタック トレースを貼り付けて、値を表示して移動します。 "Stack Trace" is a language term and should be kept the same. + + Performance + Performance + + Please enter a type name 型の名前を入力してください @@ -1157,16 +1207,16 @@ クイック アクション - - Refactoring Only - リファクタリングのみ - - Reference 参照 + + Regular + Regular + + Regular Expressions 正規表現 @@ -1182,16 +1232,6 @@ 不要な using の削除 - - Rename - 名前の変更 - - - - Rename {0} to {1} - {0} の名前を {1} に変更 - - Rename asynchronously (experimental) 非同期的な名前の変更 (試験段階) @@ -1342,9 +1382,9 @@ セマンティック検索結果 - - Show "Remove Unused References" command in Solution Explorer (experimental) - ソリューション エクスプローラーで [未使用の参照を削除する] コマンドを表示する (試験段階) + + Show "Remove Unused References" command in Solution Explorer + Show "Remove Unused References" command in Solution Explorer @@ -1362,11 +1402,36 @@ 次のコンパイラ エラーと警告を表示する: + + Show completion item _filters + Show completion item _filters + + + + Show completion item filters + Show completion item filters + + Show completion list 入力候補一覧の表示 + + Show completion list after a character is _deleted + Show completion list after a character is _deleted + + + + Show completion list after a character is deleted + Show completion list after a character is deleted + + + + Show completion list after a character is typed + Show completion list after a character is typed + + Show guides for comments and preprocessor regions コメントとプリプロセッサ領域のガイドを表示する @@ -1412,14 +1477,39 @@ 継承の余白を表示する + + Show items from unimported namespaces + Show items from unimported namespaces + + + + Show preview for rename _tracking + Show preview for rename _tracking + + + + _Show procedure line separators + _Show procedure line separators + + + + Show remarks in Quick Info + Show remarks in Quick Info + + Skip analyzers for implicitly triggered builds 暗黙的にトリガーされたビルドに対してアナライザーをスキップします - - Some color scheme colors are being overridden by changes made in the Environment > Fonts and Colors options page. Choose `Use Defaults` in the Fonts and Colors page to revert all customizations. - 一部の配色パターンの色は、[環境] > [フォントおよび色] オプション ページで行われた変更によって上書きされます。[フォントおよび色] オプション ページで [既定値を使用] を選択すると、すべてのカスタマイズが元に戻ります。 + + Small + Small + + + + Snippets behavior + Snippets behavior @@ -1452,11 +1542,6 @@ 古い記号に取り消し線を入れる - - Suggestion - 提案事項 - - Suppress hints when argument matches parameter name 引数がパラメーター名と一致するとき、ヒントを抑制する @@ -1493,8 +1578,13 @@ {Locked="System.Void"} "System.Void" represents CLR's type and should not be localized + Tab twice to insert arguments + タブを 2 回押して引数を挿入する (試験段階) + + + Tab twice to insert arguments (experimental) - タブを 2 回押して引数を挿入する (試験段階) + Tab twice to insert arguments (experimental) @@ -1539,7 +1629,7 @@ Title - タイトル + Title @@ -1567,6 +1657,11 @@ 再割り当てされる変数に下線を引く + + Unused local + Unused local + + Unused value is explicitly assigned to an unused local 未使用のローカルに未使用の値が明示的に割り当てられます @@ -1622,11 +1717,6 @@ ここで割り当てた値は一度も使用されません - - Value: - 値: - - Value returned by invocation is implicitly ignored 呼び出しによって返された値が暗黙的に無視されます @@ -1652,11 +1742,6 @@ Visual Studio の設定 - - Warning - 警告 - - Warning: duplicate parameter name 警告: パラメーター名が重複しています @@ -1752,31 +1837,6 @@ プレビューを利用できません - - Overrides - オーバーライド - - - - Overridden By - オーバーライド元 - - - - Inherits - 継承 - - - - Implements - 実装 - - - - Implemented By - 実装先 - - Invalid access. アクセスが無効です。 @@ -1822,6 +1882,21 @@ '{0}' はパブリックに変更されます。 + + _Highlight matching portions of completion list items + _Highlight matching portions of completion list items + + + + _Only add new line on enter after end of fully typed word + _Only add new line on enter after end of fully typed word + + + + _Show completion list after a character is typed + _Show completion list after a character is typed + + at the end of the line of code コード行の末尾で @@ -1902,41 +1977,16 @@ アセンブリ - - Exceptions: - 例外: - - Member of {0} {0} のメンバー - - Parameters: - パラメーター: - - Project プロジェクト - - Remarks: - コメント: - - - - Returns: - 戻り値: - - - - Summary: - 概要: - - Type Parameters: 型パラメーター: @@ -2009,21 +2059,11 @@ Use the dropdown to view and switch to other projects this file may belong to.アナライザー アセンブリ '{0}' が変更されました。Visual Studio を再起動するまで正しい診断ができない可能性があります。 - - Cancel - キャンセル - - _Deselect All すべて選択解除(_D) - - Extract Interface - インターフェイスの抽出 - - Generated name: 生成された名前: @@ -2064,11 +2104,6 @@ Use the dropdown to view and switch to other projects this file may belong to.既存ファイルに追加(_E) - - Change Signature - 署名の変更 - - _Create new file 新しいファイルの作成(_C) @@ -2204,21 +2239,6 @@ Use the dropdown to view and switch to other projects this file may belong to.1 個の参照 - - '{0}' encountered an error and has been disabled. - '{0}' でエラーが生じ、無効になりました。 - - - - Enable - 有効にする - - - - Enable and ignore future errors - 有効化して今後のエラーを無視する - - No Changes 変更なし @@ -2234,11 +2254,6 @@ Use the dropdown to view and switch to other projects this file may belong to.現在のブロックを特定しています。 - - IntelliSense - IntelliSense - - MissingAnalyzerReference MissingAnalyzerReference @@ -2314,16 +2329,6 @@ Use the dropdown to view and switch to other projects this file may belong to.<不明> - - No - いいえ - - - - Yes - はい - - Enter a title for this Naming Style. この名前付けスタイルのタイトルを入力してください。 @@ -2562,11 +2567,6 @@ Additional information: {1} ブロック構造のガイド - - Outlining - アウトライン - - Show guides for code level constructs コード レベルのコンストラクトのガイドを表示する diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ko.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ko.xlf index de228ad9d8fd9..aa1c585d50351 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ko.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ko.xlf @@ -72,6 +72,11 @@ 항상 + + _Always add new line on enter + _Always add new line on enter + + Always for clarity 명확하게 하기 위해 항상 @@ -187,11 +192,6 @@ 종속 항목을 계산하는 중... - - Call Hierarchy - 호출 계층 구조 - - Call site value: 호출 사이트 값: @@ -392,9 +392,9 @@ 편집기 색 구성표 - - Editor color scheme options are only available when using a color theme bundled with Visual Studio. The color theme can be configured from the Environment > General options page. - 편집기 색 구성표 옵션은 Visual Studio와 함께 제공되는 색 테마를 사용하는 경우에만 사용할 수 있습니다. 색 테마는 [환경] > [일반] 옵션 페이지에서 구성할 수 있습니다. + + Editor Help + Editor Help @@ -432,6 +432,16 @@ 호출 사이트 값을 입력하거나 다른 값 삽입 종류를 선택하세요. + + Enter key behavior + Enter key behavior + + + + Enter key behavior: + Enter key behavior: + + Entire repository 전체 리포지토리 @@ -447,16 +457,16 @@ 전체 솔루션 및 외부 원본 - - Error - 오류 - - Error updating suppressions: {0} 표시 중지를 업데이트하는 동안 오류가 발생했습니다. {0} + + Experimental feature + Experimental feature + + External Sources 외부 원본 @@ -472,6 +482,11 @@ 기본 Record 추출 {Locked="Record"} "Record" is a language construct for C# and should not be localized + + Fade out unused members + Fade out unused members + + Finish 마침 @@ -522,11 +537,31 @@ 정의로 이동 + + Highlight matching portions of completion list items + Highlight matching portions of completion list items + + + + _Highlight references to symbol under cursor + _Highlight references to symbol under cursor + + Highlight related components under cursor 커서 아래의 관련 구성 요소 강조 + + Highlight related _keywords under cursor + Highlight related _keywords under cursor + + + + Highlighting + Highlighting + + Id ID @@ -582,9 +617,9 @@ 상속된 인터페이스 - - Inline Hints - 인라인 힌트 + + Insert Snippet + Insert Snippet @@ -627,6 +662,11 @@ 종류 + + Large + Large + + Loaded items 로드된 항목 @@ -857,11 +897,6 @@ 명명 규칙 - - Navigate asynchronously (experimental) - 비동기식 탐색(실험적) - - Navigate to '{0}' '{0}'(으)로 이동 @@ -879,7 +914,12 @@ Never - 안 함 + Never + + + + _Never add new line on enter + _Never add new line on enter @@ -887,6 +927,11 @@ 필요한 경우 사용 안 함 + + Never include snippets + Never include snippets + + New Type Name: 새 형식 이름: @@ -917,11 +962,6 @@ public이 아닌 메서드 - - None - None - - Not applicable 해당 사항 없음 @@ -937,6 +977,11 @@ 생략(선택적 매개 변수에만 해당) + + Only add new line on enter after end of fully typed word + Only add new line on enter after end of fully typed word + + Open documents 열린 문서 @@ -947,6 +992,11 @@ 래핑 시 연산자 배치 + + Optimize for solution size + Optimize for solution size + + Optional parameters must provide a default value 선택적 매개 변수는 기본값을 제공해야 합니다. @@ -1022,16 +1072,16 @@ 괄호 기본 설정: - - Paste - 붙여넣기 - - Paste a stack trace to view and navigate it's values. 값을 보고 탐색하려면 스택 추적을 붙여넣습니다. "Stack Trace" is a language term and should be kept the same. + + Performance + Performance + + Please enter a type name 형식 이름을 입력하세요. @@ -1157,16 +1207,16 @@ 빠른 작업 - - Refactoring Only - 리팩터링만 - - Reference 참조 + + Regular + Regular + + Regular Expressions 정규식 @@ -1182,16 +1232,6 @@ 불필요한 Using 제거 - - Rename - 이름 바꾸기 - - - - Rename {0} to {1} - {0} 이름을 {1}(으)로 바꾸기 - - Rename asynchronously (experimental) 비동기적으로 이름 바꾸기(실험적) @@ -1342,9 +1382,9 @@ 의미 체계 검색 결과 - - Show "Remove Unused References" command in Solution Explorer (experimental) - 솔루션 탐색기에서 "사용하지 않는 참조 제거" 명령 표시(실험적) + + Show "Remove Unused References" command in Solution Explorer + Show "Remove Unused References" command in Solution Explorer @@ -1362,11 +1402,36 @@ 다음에 대한 컴파일러 오류 및 경고 표시: + + Show completion item _filters + Show completion item _filters + + + + Show completion item filters + Show completion item filters + + Show completion list 완성 목록 표시 + + Show completion list after a character is _deleted + Show completion list after a character is _deleted + + + + Show completion list after a character is deleted + Show completion list after a character is deleted + + + + Show completion list after a character is typed + Show completion list after a character is typed + + Show guides for comments and preprocessor regions 설명 및 전처리기 영역에 대한 가이드 표시 @@ -1412,14 +1477,39 @@ 상속 여백 표시 + + Show items from unimported namespaces + Show items from unimported namespaces + + + + Show preview for rename _tracking + Show preview for rename _tracking + + + + _Show procedure line separators + _Show procedure line separators + + + + Show remarks in Quick Info + Show remarks in Quick Info + + Skip analyzers for implicitly triggered builds 암시적으로 트리거된 빌드에 대한 분석기 건너뛰기 - - Some color scheme colors are being overridden by changes made in the Environment > Fonts and Colors options page. Choose `Use Defaults` in the Fonts and Colors page to revert all customizations. - 색 구성표의 일부 색이 [환경] > [글꼴 및 색] 옵션 페이지에서 변경한 내용에 따라 재정의됩니다. 모든 사용자 지정을 되돌리려면 [글꼴 및 색] 페이지에서 '기본값 사용'을 선택하세요. + + Small + Small + + + + Snippets behavior + Snippets behavior @@ -1452,11 +1542,6 @@ 사용되지 않는 기호 취소 - - Suggestion - 제안 - - Suppress hints when argument matches parameter name 인수가 매개 변수 이름과 일치하는 경우 힌트 표시 안 함 @@ -1493,8 +1578,13 @@ {Locked="System.Void"} "System.Void" represents CLR's type and should not be localized + Tab twice to insert arguments + 두 번 탭하여 인수 삽입(실험적) + + + Tab twice to insert arguments (experimental) - 두 번 탭하여 인수 삽입(실험적) + Tab twice to insert arguments (experimental) @@ -1539,7 +1629,7 @@ Title - 제목 + Title @@ -1567,6 +1657,11 @@ 다시 할당된 변수에 밑줄 긋기 + + Unused local + Unused local + + Unused value is explicitly assigned to an unused local 사용되지 않는 값이 사용되지 않는 로컬에 명시적으로 할당됩니다. @@ -1622,11 +1717,6 @@ 여기에 할당된 값은 사용되지 않습니다. - - Value: - 값: - - Value returned by invocation is implicitly ignored 호출로 반환된 값은 암시적으로 무시됩니다. @@ -1652,11 +1742,6 @@ Visual Studio 설정 - - Warning - 경고 - - Warning: duplicate parameter name 경고: 매개 변수 이름이 중복되었습니다. @@ -1752,31 +1837,6 @@ 미리 보기를 사용할 수 없음 - - Overrides - 재정의 - - - - Overridden By - 재정의 수행자 - - - - Inherits - 상속 - - - - Implements - 구현 - - - - Implemented By - 구현자 - - Invalid access. 액세스가 잘못되었습니다. @@ -1822,6 +1882,21 @@ '{0}'이(가) 공용으로 변경됩니다. + + _Highlight matching portions of completion list items + _Highlight matching portions of completion list items + + + + _Only add new line on enter after end of fully typed word + _Only add new line on enter after end of fully typed word + + + + _Show completion list after a character is typed + _Show completion list after a character is typed + + at the end of the line of code 코드 줄의 끝에 @@ -1902,41 +1977,16 @@ 어셈블리 - - Exceptions: - 예외: - - Member of {0} {0}의 멤버 - - Parameters: - 매개 변수: - - Project 프로젝트 - - Remarks: - 설명: - - - - Returns: - 반환 값: - - - - Summary: - 요약: - - Type Parameters: 형식 매개 변수: @@ -2009,21 +2059,11 @@ Use the dropdown to view and switch to other projects this file may belong to.분석기 어셈블리 '{0}'이(가) 변경되었습니다. Visual Studio를 다시 시작할 때까지 진단이 올바르지 않을 수 있습니다. - - Cancel - 취소 - - _Deselect All 모두 선택 취소(_D) - - Extract Interface - 인터페이스 추출 - - Generated name: 생성된 이름: @@ -2064,11 +2104,6 @@ Use the dropdown to view and switch to other projects this file may belong to.기존 파일에 추가(_E) - - Change Signature - 시그니처 변경 - - _Create new file 새 파일 만들기(_C) @@ -2204,21 +2239,6 @@ Use the dropdown to view and switch to other projects this file may belong to.참조 1개 - - '{0}' encountered an error and has been disabled. - '{0}'에 오류가 발생하여 사용할 수 없습니다. - - - - Enable - 사용 - - - - Enable and ignore future errors - 추가 오류 무시하고 사용 - - No Changes 변경 내용 없음 @@ -2234,11 +2254,6 @@ Use the dropdown to view and switch to other projects this file may belong to.현재 블록을 확인하는 중입니다. - - IntelliSense - IntelliSense - - MissingAnalyzerReference MissingAnalyzerReference @@ -2314,16 +2329,6 @@ Use the dropdown to view and switch to other projects this file may belong to.<알 수 없음> - - No - 아니요 - - - - Yes - - - Enter a title for this Naming Style. 이 명명 스타일의 제목을 입력하세요. @@ -2562,11 +2567,6 @@ Additional information: {1} 블록 구조 가이드 - - Outlining - 개요 - - Show guides for code level constructs 코드 수준 구문에 대한 가이드 표시 diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.pl.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.pl.xlf index 78b9d65122bf6..905a7bddf662a 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.pl.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.pl.xlf @@ -72,6 +72,11 @@ Zawsze + + _Always add new line on enter + _Always add new line on enter + + Always for clarity Zawsze w celu zachowania jednoznaczności @@ -187,11 +192,6 @@ Obliczanie elementów zależnych... - - Call Hierarchy - Hierarchia wywołań - - Call site value: Wartość miejsca wywołania: @@ -392,9 +392,9 @@ Schemat kolorów edytora - - Editor color scheme options are only available when using a color theme bundled with Visual Studio. The color theme can be configured from the Environment > General options page. - Opcje schematu kolorów edytora są dostępne tylko w przypadku używania motywu kolorów wbudowanego w program Visual Studio. Motyw kolorów można skonfigurować za pomocą strony Środowisko > Opcje ogólne. + + Editor Help + Editor Help @@ -432,6 +432,16 @@ Wprowadź wartość lokalizacji wywołania lub wybierz inny rodzaj iniekcji wartości + + Enter key behavior + Enter key behavior + + + + Enter key behavior: + Enter key behavior: + + Entire repository Całe repozytorium @@ -447,16 +457,16 @@ Całe rozwiązanie i źródła zewnętrzne - - Error - Błąd - - Error updating suppressions: {0} Błąd podczas pomijania aktualizacji: {0} + + Experimental feature + Experimental feature + + External Sources Źródła zewnętrzne @@ -472,6 +482,11 @@ Wyodrębnij Record Podstawowy {Locked="Record"} "Record" is a language construct for C# and should not be localized + + Fade out unused members + Fade out unused members + + Finish Zakończ @@ -522,11 +537,31 @@ Przejdź do definicji + + Highlight matching portions of completion list items + Highlight matching portions of completion list items + + + + _Highlight references to symbol under cursor + _Highlight references to symbol under cursor + + Highlight related components under cursor Wyróżnij powiązane składniki pod kursorem + + Highlight related _keywords under cursor + Highlight related _keywords under cursor + + + + Highlighting + Highlighting + + Id Identyfikator @@ -582,9 +617,9 @@ Dziedziczone interfejsy - - Inline Hints - Wskazówki w tekście + + Insert Snippet + Insert Snippet @@ -627,6 +662,11 @@ Rodzaj + + Large + Large + + Loaded items Załadowane elementy @@ -857,11 +897,6 @@ Reguły nazewnictwa - - Navigate asynchronously (experimental) - Nawiguj asynchronicznie (eksperymentalne) - - Navigate to '{0}' Przejdź do pozycji „{0}” @@ -879,7 +914,12 @@ Never - Nigdy + Never + + + + _Never add new line on enter + _Never add new line on enter @@ -887,6 +927,11 @@ Nigdy, jeśli niepotrzebne + + Never include snippets + Never include snippets + + New Type Name: Nazwa nowego typu: @@ -917,11 +962,6 @@ Metody niepubliczne - - None - brak - - Not applicable Nie dotyczy @@ -937,6 +977,11 @@ Pomiń (tylko dla parametrów opcjonalnych) + + Only add new line on enter after end of fully typed word + Only add new line on enter after end of fully typed word + + Open documents Otwarte dokumenty @@ -947,6 +992,11 @@ Umieszczanie operatora podczas opakowywania + + Optimize for solution size + Optimize for solution size + + Optional parameters must provide a default value Parametry opcjonalne muszą określać wartość domyślną @@ -1022,16 +1072,16 @@ Preferencje dotyczące nawiasów: - - Paste - Wklej - - Paste a stack trace to view and navigate it's values. Wklej prawidłowy ślad stosu, aby wyświetlić jego wartości i nawigować po nich. "Stack Trace" is a language term and should be kept the same. + + Performance + Performance + + Please enter a type name Wprowadź nazwę typu @@ -1157,16 +1207,16 @@ Szybkie akcje - - Refactoring Only - Tylko refaktoryzacja - - Reference Odwołanie + + Regular + Regular + + Regular Expressions Wyrażenia regularne @@ -1182,16 +1232,6 @@ Usuń niepotrzebne użycia - - Rename - Zmień nazwę - - - - Rename {0} to {1} - Zmień nazwę {0} na {1} - - Rename asynchronously (experimental) Zmień nazwę asynchronicznie (eksperymentalne) @@ -1342,9 +1382,9 @@ Wyniki wyszukiwania semantycznego - - Show "Remove Unused References" command in Solution Explorer (experimental) - Pokaż polecenie „Usuń nieużywane odwołania” w Eksploratorze rozwiązań (eksperymentalne) + + Show "Remove Unused References" command in Solution Explorer + Show "Remove Unused References" command in Solution Explorer @@ -1362,11 +1402,36 @@ Pokaż błędy i ostrzeżenia kompilatora dla: + + Show completion item _filters + Show completion item _filters + + + + Show completion item filters + Show completion item filters + + Show completion list Pokaż listę uzupełniania + + Show completion list after a character is _deleted + Show completion list after a character is _deleted + + + + Show completion list after a character is deleted + Show completion list after a character is deleted + + + + Show completion list after a character is typed + Show completion list after a character is typed + + Show guides for comments and preprocessor regions Pokaż prowadnice dla regionów komentarzy i preprocesora @@ -1412,14 +1477,39 @@ Pokaż margines dziedziczenia + + Show items from unimported namespaces + Show items from unimported namespaces + + + + Show preview for rename _tracking + Show preview for rename _tracking + + + + _Show procedure line separators + _Show procedure line separators + + + + Show remarks in Quick Info + Show remarks in Quick Info + + Skip analyzers for implicitly triggered builds Pomiń analizatory dla niejawnie wyzwalanych kompilacji - - Some color scheme colors are being overridden by changes made in the Environment > Fonts and Colors options page. Choose `Use Defaults` in the Fonts and Colors page to revert all customizations. - Niektóre kolory w schemacie kolorów są przesłaniane przez zmiany wprowadzone na stronie opcji Środowisko > Czcionki i kolory. Wybierz pozycję „Użyj ustawień domyślnych” na stronie Czcionki i kolory, aby wycofać wszystkie dostosowania. + + Small + Small + + + + Snippets behavior + Snippets behavior @@ -1452,11 +1542,6 @@ Wykreśl przestarzałe symbole - - Suggestion - Sugestia - - Suppress hints when argument matches parameter name Pomiń wskazówki, gdy argument pasuje do nazwy parametru @@ -1493,8 +1578,13 @@ {Locked="System.Void"} "System.Void" represents CLR's type and should not be localized + Tab twice to insert arguments + Dwukrotnie naciśnij klawisz Tab, aby wstawić argumenty (eksperymentalna) + + + Tab twice to insert arguments (experimental) - Dwukrotnie naciśnij klawisz Tab, aby wstawić argumenty (eksperymentalna) + Tab twice to insert arguments (experimental) @@ -1539,7 +1629,7 @@ Title - Tytuł + Title @@ -1567,6 +1657,11 @@ Podkreślaj ponownie przypisane zmienne + + Unused local + Unused local + + Unused value is explicitly assigned to an unused local Nieużywana wartość jest jawnie przypisywana do nieużywanej zmiennej lokalnej @@ -1622,11 +1717,6 @@ Przypisana tu wartość nigdy nie jest używana - - Value: - Wartość: - - Value returned by invocation is implicitly ignored Wartość zwracana przez wywołanie jest niejawnie ignorowana @@ -1652,11 +1742,6 @@ Ustawienia programu Visual Studio - - Warning - Ostrzeżenie - - Warning: duplicate parameter name Ostrzeżenie: zduplikowana nazwa parametru @@ -1752,31 +1837,6 @@ Podgląd niedostępny - - Overrides - Przesłania - - - - Overridden By - Przesłonione przez - - - - Inherits - Dziedziczy - - - - Implements - Implementuje - - - - Implemented By - Zaimplementowane przez - - Invalid access. Nieprawidłowy dostęp. @@ -1822,6 +1882,21 @@ Element „{0}” zostanie zmieniony na publiczny. + + _Highlight matching portions of completion list items + _Highlight matching portions of completion list items + + + + _Only add new line on enter after end of fully typed word + _Only add new line on enter after end of fully typed word + + + + _Show completion list after a character is typed + _Show completion list after a character is typed + + at the end of the line of code na końcu wiersza kodu @@ -1902,41 +1977,16 @@ Zestaw - - Exceptions: - Wyjątki: - - Member of {0} Składowa {0} - - Parameters: - Parametry: - - Project Projekt - - Remarks: - Uwagi: - - - - Returns: - Zwraca: - - - - Summary: - Podsumowanie: - - Type Parameters: Parametry typu: @@ -2009,21 +2059,11 @@ Użyj listy rozwijanej, aby wyświetlać inne projekty, do których może należ Zmieniono zestaw analizatora „{0}”. Diagnostyka może nie działać poprawnie do czasu ponownego uruchomienia programu Visual Studio. - - Cancel - Anuluj - - _Deselect All _Odznacz wszystkie - - Extract Interface - Wyodrębnij interfejs - - Generated name: Wygenerowana nazwa: @@ -2064,11 +2104,6 @@ Użyj listy rozwijanej, aby wyświetlać inne projekty, do których może należ Dodaj do _istniejącego pliku - - Change Signature - Zmień sygnaturę - - _Create new file _Utwórz nowy plik @@ -2204,21 +2239,6 @@ Użyj listy rozwijanej, aby wyświetlać inne projekty, do których może należ Jedno odwołanie - - '{0}' encountered an error and has been disabled. - 'Element „{0}” napotkał błąd i został wyłączony. - - - - Enable - Włącz - - - - Enable and ignore future errors - Włącz i ignoruj przyszłe błędy - - No Changes Brak zmian @@ -2234,11 +2254,6 @@ Użyj listy rozwijanej, aby wyświetlać inne projekty, do których może należ Określanie bieżącego bloku. - - IntelliSense - IntelliSense - - MissingAnalyzerReference MissingAnalyzerReference @@ -2314,16 +2329,6 @@ Użyj listy rozwijanej, aby wyświetlać inne projekty, do których może należ <Nieznany> - - No - Nie - - - - Yes - Tak - - Enter a title for this Naming Style. Wprowadź tytuł dla tego stylu nazewnictwa. @@ -2562,11 +2567,6 @@ Dodatkowe informacje: {1} Prowadnice struktury blokowej - - Outlining - Konspekt - - Show guides for code level constructs Pokaż przewodniki dla konstrukcji na poziomie kodu diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.pt-BR.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.pt-BR.xlf index ebe333c7b4465..7051abaf2df8b 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.pt-BR.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.pt-BR.xlf @@ -72,6 +72,11 @@ Sempre + + _Always add new line on enter + _Always add new line on enter + + Always for clarity Sempre para esclarecimento @@ -187,11 +192,6 @@ Calculando dependentes... - - Call Hierarchy - Hierarquia de Chamada - - Call site value: Chamar valor do site: @@ -392,9 +392,9 @@ Esquema de Cores do Editor - - Editor color scheme options are only available when using a color theme bundled with Visual Studio. The color theme can be configured from the Environment > General options page. - As opções do esquema de cores do editor estão disponíveis somente ao usar um tema de cores agrupado com Visual Studio. O tema de cores pode ser configurado na página Ambiente > Opções gerais. + + Editor Help + Editor Help @@ -432,6 +432,16 @@ Insira um valor de site de chamada ou escolha um tipo de injeção de valor diferente + + Enter key behavior + Enter key behavior + + + + Enter key behavior: + Enter key behavior: + + Entire repository Repositório inteiro @@ -447,16 +457,16 @@ Solução Inteira e Fontes Externas - - Error - Erro - - Error updating suppressions: {0} Erro ao atualizar supressões: {0} + + Experimental feature + Experimental feature + + External Sources Fontes Externas @@ -472,6 +482,11 @@ Extrair Record Base {Locked="Record"} "Record" is a language construct for C# and should not be localized + + Fade out unused members + Fade out unused members + + Finish Concluir @@ -522,11 +537,31 @@ Ir para Definição + + Highlight matching portions of completion list items + Highlight matching portions of completion list items + + + + _Highlight references to symbol under cursor + _Highlight references to symbol under cursor + + Highlight related components under cursor Realçar componentes relacionados usando o cursor + + Highlight related _keywords under cursor + Highlight related _keywords under cursor + + + + Highlighting + Highlighting + + Id ID @@ -582,9 +617,9 @@ Interfaces herdadas - - Inline Hints - Dicas Embutidas + + Insert Snippet + Insert Snippet @@ -627,6 +662,11 @@ Tipo + + Large + Large + + Loaded items Itens carregados @@ -857,11 +897,6 @@ Regras de nomenclatura - - Navigate asynchronously (experimental) - Navegar de forma assíncrona (experimental) - - Navigate to '{0}' Navegar até '{0}' @@ -879,7 +914,12 @@ Never - Nunca + Never + + + + _Never add new line on enter + _Never add new line on enter @@ -887,6 +927,11 @@ Nunca se desnecessário + + Never include snippets + Never include snippets + + New Type Name: Novo Nome de Tipo: @@ -917,11 +962,6 @@ Métodos não públicos - - None - NENHUM - - Not applicable Não aplicável @@ -937,6 +977,11 @@ Omitir (somente para parâmetros opcionais) + + Only add new line on enter after end of fully typed word + Only add new line on enter after end of fully typed word + + Open documents Abrir documentos @@ -947,6 +992,11 @@ Posicionamento do operador a quebra de linha + + Optimize for solution size + Optimize for solution size + + Optional parameters must provide a default value Os parâmetros opcionais precisam especificar um valor padrão @@ -1022,16 +1072,16 @@ Preferências de parênteses: - - Paste - Colar - - Paste a stack trace to view and navigate it's values. Cole um rastreamento de pilha para exibir e navegar pelos seus valores. "Stack Trace" is a language term and should be kept the same. + + Performance + Performance + + Please enter a type name Insira um nome de tipo @@ -1157,16 +1207,16 @@ Ações Rápidas - - Refactoring Only - Somente Refatoração - - Reference Referência + + Regular + Regular + + Regular Expressions Expressões regulares @@ -1182,16 +1232,6 @@ Remover Usos Desnecessários - - Rename - renomear - - - - Rename {0} to {1} - Renomear {0} para {1} - - Rename asynchronously (experimental) Renomear de forma assíncrona (experimental) @@ -1342,9 +1382,9 @@ Resultados da Pesquisa Semântica - - Show "Remove Unused References" command in Solution Explorer (experimental) - Mostrar o comando "Remover as Referências Não Usadas" no Gerenciador de Soluções (experimental) + + Show "Remove Unused References" command in Solution Explorer + Show "Remove Unused References" command in Solution Explorer @@ -1362,11 +1402,36 @@ Mostrar erros e alertas do compilador para: + + Show completion item _filters + Show completion item _filters + + + + Show completion item filters + Show completion item filters + + Show completion list Mostrar a lista de conclusão + + Show completion list after a character is _deleted + Show completion list after a character is _deleted + + + + Show completion list after a character is deleted + Show completion list after a character is deleted + + + + Show completion list after a character is typed + Show completion list after a character is typed + + Show guides for comments and preprocessor regions Mostrar guias para regiões do pré-processador e comentários @@ -1412,14 +1477,39 @@ Mostrar margem de herança + + Show items from unimported namespaces + Show items from unimported namespaces + + + + Show preview for rename _tracking + Show preview for rename _tracking + + + + _Show procedure line separators + _Show procedure line separators + + + + Show remarks in Quick Info + Show remarks in Quick Info + + Skip analyzers for implicitly triggered builds Ignorar analisadores para compilações acionadas implicitamente - - Some color scheme colors are being overridden by changes made in the Environment > Fonts and Colors options page. Choose `Use Defaults` in the Fonts and Colors page to revert all customizations. - Algumas cores do esquema de cores estão sendo substituídas pelas alterações feitas na página de Ambiente > Opções de Fontes e Cores. Escolha 'Usar Padrões' na página Fontes e Cores para reverter todas as personalizações. + + Small + Small + + + + Snippets behavior + Snippets behavior @@ -1452,11 +1542,6 @@ Riscar os símbolos obsoletos - - Suggestion - Sugestão - - Suppress hints when argument matches parameter name Suprimir as dicas quando o argumento corresponder ao nome do parâmetro @@ -1493,8 +1578,13 @@ {Locked="System.Void"} "System.Void" represents CLR's type and should not be localized + Tab twice to insert arguments + Pressione Tab duas vezes para inserir argumentos (experimental) + + + Tab twice to insert arguments (experimental) - Pressione Tab duas vezes para inserir argumentos (experimental) + Tab twice to insert arguments (experimental) @@ -1539,7 +1629,7 @@ Title - Título + Title @@ -1567,6 +1657,11 @@ Sublinhar variáveis reatribuídas + + Unused local + Unused local + + Unused value is explicitly assigned to an unused local O valor não utilizado é explicitamente atribuído a um local não utilizado @@ -1622,11 +1717,6 @@ O valor atribuído aqui nunca é usado - - Value: - Valor: - - Value returned by invocation is implicitly ignored O valor retornado por chamada é implicitamente ignorado @@ -1652,11 +1742,6 @@ Configurações do Visual Studio - - Warning - Aviso - - Warning: duplicate parameter name Aviso: nome de parâmetro duplicado @@ -1752,31 +1837,6 @@ Visualização não disponível - - Overrides - Substitui - - - - Overridden By - Substituído por - - - - Inherits - Herda - - - - Implements - Implementos - - - - Implemented By - Implementado por - - Invalid access. Acesso inválido. @@ -1822,6 +1882,21 @@ '{0}' será alterado para público. + + _Highlight matching portions of completion list items + _Highlight matching portions of completion list items + + + + _Only add new line on enter after end of fully typed word + _Only add new line on enter after end of fully typed word + + + + _Show completion list after a character is typed + _Show completion list after a character is typed + + at the end of the line of code no final da linha de código @@ -1902,41 +1977,16 @@ Assembly - - Exceptions: - Exceções: - - Member of {0} Membro de {0} - - Parameters: - Parâmetros: - - Project Projeto - - Remarks: - Comentários: - - - - Returns: - Devoluções: - - - - Summary: - Resumo: - - Type Parameters: Parâmetros de Tipo: @@ -2009,21 +2059,11 @@ Use a lista suspensa para exibir e mudar entre outros projetos aos quais este ar O assembly do analisador '{0}' mudou. O diagnóstico pode estar incorreto até que o Visual Studio seja reiniciado. - - Cancel - Cancelar - - _Deselect All _Desmarcar Tudo - - Extract Interface - Extrair a Interface - - Generated name: Nome gerado: @@ -2064,11 +2104,6 @@ Use a lista suspensa para exibir e mudar entre outros projetos aos quais este ar Adicionar ao arquivo _existente - - Change Signature - Alterar Assinatura - - _Create new file _Criar novo arquivo @@ -2204,21 +2239,6 @@ Use a lista suspensa para exibir e mudar entre outros projetos aos quais este ar 1 referência - - '{0}' encountered an error and has been disabled. - '{0}' encontrou um erro e foi desabilitado. - - - - Enable - Habilitar - - - - Enable and ignore future errors - Habilitar e ignorar erros futuros - - No Changes Nenhuma Alteração @@ -2234,11 +2254,6 @@ Use a lista suspensa para exibir e mudar entre outros projetos aos quais este ar Determinando o bloco atual. - - IntelliSense - IntelliSense - - MissingAnalyzerReference MissingAnalyzerReference @@ -2314,16 +2329,6 @@ Use a lista suspensa para exibir e mudar entre outros projetos aos quais este ar <Desconhecido> - - No - Não - - - - Yes - Sim - - Enter a title for this Naming Style. Insira um título para esse Estilo de Nomenclatura. @@ -2562,11 +2567,6 @@ Informações adicionais: {1} Guias de Estrutura de Bloco - - Outlining - Estrutura de Tópicos - - Show guides for code level constructs Mostrar guias para construções de nível de código diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ru.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ru.xlf index 0de878a5a9af1..613bf1b919bd5 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ru.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ru.xlf @@ -72,6 +72,11 @@ Всегда + + _Always add new line on enter + _Always add new line on enter + + Always for clarity Всегда использовать для ясности @@ -187,11 +192,6 @@ Вычисление зависимостей… - - Call Hierarchy - Иерархия вызовов - - Call site value: Значение места вызова: @@ -392,9 +392,9 @@ Цветовая схема редактора - - Editor color scheme options are only available when using a color theme bundled with Visual Studio. The color theme can be configured from the Environment > General options page. - Параметры цветовой схемы редактора доступны только при использовании цветовой темы, поставляемой вместе с Visual Studio. Цветовую тему можно настроить на странице "Среда" > "Общие параметры". + + Editor Help + Editor Help @@ -432,6 +432,16 @@ Введите значение места вызова или выберите другой тип введения значения + + Enter key behavior + Enter key behavior + + + + Enter key behavior: + Enter key behavior: + + Entire repository Весь репозиторий @@ -447,16 +457,16 @@ Все решение и внешние источники - - Error - Ошибка - - Error updating suppressions: {0} Ошибка при обновлении подавлений: {0} + + Experimental feature + Experimental feature + + External Sources Внешние источники @@ -472,6 +482,11 @@ Извлечь базовый объект Record {Locked="Record"} "Record" is a language construct for C# and should not be localized + + Fade out unused members + Fade out unused members + + Finish Готово @@ -522,11 +537,31 @@ Перейти к определению + + Highlight matching portions of completion list items + Highlight matching portions of completion list items + + + + _Highlight references to symbol under cursor + _Highlight references to symbol under cursor + + Highlight related components under cursor Выделить связанные компоненты под курсором + + Highlight related _keywords under cursor + Highlight related _keywords under cursor + + + + Highlighting + Highlighting + + Id ИД @@ -582,9 +617,9 @@ Унаследованные интерфейсы - - Inline Hints - Встроенные подсказки + + Insert Snippet + Insert Snippet @@ -627,6 +662,11 @@ Вид + + Large + Large + + Loaded items Загруженные элементы @@ -857,11 +897,6 @@ Правила именования - - Navigate asynchronously (experimental) - Асинхронная навигация (экспериментальная функция) - - Navigate to '{0}' Перейти к {0} @@ -879,7 +914,12 @@ Never - Никогда + Never + + + + _Never add new line on enter + _Never add new line on enter @@ -887,6 +927,11 @@ Никогда, если не требуется + + Never include snippets + Never include snippets + + New Type Name: Новое имя типа: @@ -917,11 +962,6 @@ Методы, не являющиеся открытыми - - None - NONE - - Not applicable Неприменимо @@ -937,6 +977,11 @@ Опустить (только для необязательных параметров) + + Only add new line on enter after end of fully typed word + Only add new line on enter after end of fully typed word + + Open documents Открыть документы @@ -947,6 +992,11 @@ Размещение оператора при переносе + + Optimize for solution size + Optimize for solution size + + Optional parameters must provide a default value Для необязательных параметров необходимо указать значение по умолчанию. @@ -1022,16 +1072,16 @@ Параметры круглых скобок: - - Paste - Вставить - - Paste a stack trace to view and navigate it's values. Вставьте трассировку стека, чтобы просмотреть ее значения и перемещаться между ними. "Stack Trace" is a language term and should be kept the same. + + Performance + Performance + + Please enter a type name Введите имя типа @@ -1157,16 +1207,16 @@ Быстрые действия - - Refactoring Only - Только рефакторинг - - Reference Ссылка + + Regular + Regular + + Regular Expressions Регулярные выражения @@ -1182,16 +1232,6 @@ Удалить ненужные директивы using - - Rename - Переименование - - - - Rename {0} to {1} - Переименовать {0} в {1} - - Rename asynchronously (experimental) Асинхронное переименование (экспериментальная функция) @@ -1342,9 +1382,9 @@ Результаты семантического поиска - - Show "Remove Unused References" command in Solution Explorer (experimental) - Показать команду "Удалить неиспользуемые ссылки" в Обозревателе решений (экспериментальная версия) + + Show "Remove Unused References" command in Solution Explorer + Show "Remove Unused References" command in Solution Explorer @@ -1362,11 +1402,36 @@ Показывать ошибки и предупреждения компилятора для: + + Show completion item _filters + Show completion item _filters + + + + Show completion item filters + Show completion item filters + + Show completion list Показать список завершения + + Show completion list after a character is _deleted + Show completion list after a character is _deleted + + + + Show completion list after a character is deleted + Show completion list after a character is deleted + + + + Show completion list after a character is typed + Show completion list after a character is typed + + Show guides for comments and preprocessor regions Показывать направляющие для комментариев и областей препроцессора @@ -1412,14 +1477,39 @@ Показать границу наследования + + Show items from unimported namespaces + Show items from unimported namespaces + + + + Show preview for rename _tracking + Show preview for rename _tracking + + + + _Show procedure line separators + _Show procedure line separators + + + + Show remarks in Quick Info + Show remarks in Quick Info + + Skip analyzers for implicitly triggered builds Пропускать анализаторы для неявно запускаемых сборок - - Some color scheme colors are being overridden by changes made in the Environment > Fonts and Colors options page. Choose `Use Defaults` in the Fonts and Colors page to revert all customizations. - Некоторые цвета цветовой схемы переопределяются изменениями, сделанными на странице "Среда" > "Шрифты и цвета". Выберите "Использовать значения по умолчанию" на странице "Шрифты и цвета", чтобы отменить все настройки. + + Small + Small + + + + Snippets behavior + Snippets behavior @@ -1452,11 +1542,6 @@ Зачеркнутые устаревшие символы - - Suggestion - Рекомендация - - Suppress hints when argument matches parameter name Скрывать подсказки, когда аргумент соответствует имени параметра @@ -1493,8 +1578,13 @@ {Locked="System.Void"} "System.Void" represents CLR's type and should not be localized + Tab twice to insert arguments + Дважды нажмите клавишу TAB, чтобы вставить аргументы (экспериментальная функция) + + + Tab twice to insert arguments (experimental) - Дважды нажмите клавишу TAB, чтобы вставить аргументы (экспериментальная функция) + Tab twice to insert arguments (experimental) @@ -1539,7 +1629,7 @@ Title - Название + Title @@ -1567,6 +1657,11 @@ Подчеркивать переназначенные переменные + + Unused local + Unused local + + Unused value is explicitly assigned to an unused local Неиспользуемое значение явным образом задано неиспользуемой локальной переменной. @@ -1622,11 +1717,6 @@ Заданное здесь значение не используется. - - Value: - Значение: - - Value returned by invocation is implicitly ignored Значение, возвращаемое вызовом, неявным образом игнорируется. @@ -1652,11 +1742,6 @@ Параметры Visual Studio - - Warning - Предупреждение - - Warning: duplicate parameter name Предупреждение: повторяющееся имя параметра. @@ -1752,31 +1837,6 @@ Предпросмотр недоступен. - - Overrides - Переопределяет - - - - Overridden By - Переопределяется - - - - Inherits - Наследует - - - - Implements - Реализует - - - - Implemented By - Реализуется - - Invalid access. Недопустимый доступ. @@ -1822,6 +1882,21 @@ Элемент "{0}" будет изменен на открытый. + + _Highlight matching portions of completion list items + _Highlight matching portions of completion list items + + + + _Only add new line on enter after end of fully typed word + _Only add new line on enter after end of fully typed word + + + + _Show completion list after a character is typed + _Show completion list after a character is typed + + at the end of the line of code в конце строки кода @@ -1902,41 +1977,16 @@ Сборка - - Exceptions: - Исключения: - - Member of {0} Элемент объекта {0} - - Parameters: - Параметры: - - Project Проект - - Remarks: - Примечания. - - - - Returns: - Возврат: - - - - Summary: - Сводка: - - Type Parameters: Параметры типа: @@ -2009,21 +2059,11 @@ Use the dropdown to view and switch to other projects this file may belong to.Сборка анализатора "{0}" была изменена. Перезапустите Visual Studio, в противном случае диагностика может быть неправильной. - - Cancel - Отмена - - _Deselect All _Отменить все - - Extract Interface - Извлечь интерфейс - - Generated name: Созданное название: @@ -2064,11 +2104,6 @@ Use the dropdown to view and switch to other projects this file may belong to.Добавить в _существующий файл - - Change Signature - Изменить сигнатуру - - _Create new file _Создать файл @@ -2204,21 +2239,6 @@ Use the dropdown to view and switch to other projects this file may belong to.1 ссылка - - '{0}' encountered an error and has been disabled. - 'Произошла ошибка, и анализатор "{0}" отключен. - - - - Enable - Включить - - - - Enable and ignore future errors - Включить и пропускать будущие ошибки - - No Changes Изменений нет @@ -2234,11 +2254,6 @@ Use the dropdown to view and switch to other projects this file may belong to.Определение текущего блока. - - IntelliSense - IntelliSense - - MissingAnalyzerReference MissingAnalyzerReference @@ -2314,16 +2329,6 @@ Use the dropdown to view and switch to other projects this file may belong to.<нет данных> - - No - Нет - - - - Yes - Да - - Enter a title for this Naming Style. Введите название для этого стиля именования. @@ -2562,11 +2567,6 @@ Additional information: {1} Направляющие для структуры блоков - - Outlining - Структура - - Show guides for code level constructs Показывать направляющие для конструкций уровня кода diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.tr.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.tr.xlf index 7e4fed410494a..abb370afd9e0f 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.tr.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.tr.xlf @@ -72,6 +72,11 @@ Her zaman + + _Always add new line on enter + _Always add new line on enter + + Always for clarity Açıklık sağlamak için her zaman @@ -187,11 +192,6 @@ Bağımlılar hesaplanıyor... - - Call Hierarchy - Çağrı Hiyerarşisi - - Call site value: Çağrı konumu değeri: @@ -392,9 +392,9 @@ Düzenleyici Renk Düzeni - - Editor color scheme options are only available when using a color theme bundled with Visual Studio. The color theme can be configured from the Environment > General options page. - Düzenleyici renk düzeni seçenekleri yalnızca Visual Studio ile paketlenmiş bir renk teması ile birlikte kullanılabilir. Renk teması, Ortam > Genel seçenekler sayfasından yapılandırılabilir. + + Editor Help + Editor Help @@ -432,6 +432,16 @@ Bir çağrı sitesi değeri girin veya farklı bir değer yerleştirme tipi seçin + + Enter key behavior + Enter key behavior + + + + Enter key behavior: + Enter key behavior: + + Entire repository Tüm depo @@ -447,16 +457,16 @@ Tam Çözüm ve Dış Kaynaklar - - Error - Hata - - Error updating suppressions: {0} Gizlemeler güncellenirken hata oluştu: {0} + + Experimental feature + Experimental feature + + External Sources Dış Kaynaklar @@ -472,6 +482,11 @@ Temel Record Öğesini Ayıkla {Locked="Record"} "Record" is a language construct for C# and should not be localized + + Fade out unused members + Fade out unused members + + Finish Son @@ -522,11 +537,31 @@ Tanıma Git + + Highlight matching portions of completion list items + Highlight matching portions of completion list items + + + + _Highlight references to symbol under cursor + _Highlight references to symbol under cursor + + Highlight related components under cursor İmlecin altında ilgili bileşenleri vurgula + + Highlight related _keywords under cursor + Highlight related _keywords under cursor + + + + Highlighting + Highlighting + + Id Kimlik @@ -582,9 +617,9 @@ Devralınan arabirimler - - Inline Hints - Satır İçi İpuçları + + Insert Snippet + Insert Snippet @@ -627,6 +662,11 @@ Tür + + Large + Large + + Loaded items Öğeler yüklendi @@ -857,11 +897,6 @@ Adlandırma kuralları - - Navigate asynchronously (experimental) - Zaman uyumsuz olarak gezin (deneysel) - - Navigate to '{0}' '{0}' öğesine git @@ -879,7 +914,12 @@ Never - Hiçbir zaman + Never + + + + _Never add new line on enter + _Never add new line on enter @@ -887,6 +927,11 @@ Gereksizse hiçbir zaman + + Never include snippets + Never include snippets + + New Type Name: Yeni Tür Adı: @@ -917,11 +962,6 @@ Ortak olmayan yöntemler - - None - yok - - Not applicable Geçerli değil @@ -937,6 +977,11 @@ Atla (yalnızca isteğe bağlı parametreler için) + + Only add new line on enter after end of fully typed word + Only add new line on enter after end of fully typed word + + Open documents Açık belgeler @@ -947,6 +992,11 @@ Kaydırma sırasında operatör yerleştirme + + Optimize for solution size + Optimize for solution size + + Optional parameters must provide a default value İsteğe bağlı parametrelerde varsayılan değer sağlanmalıdır @@ -1022,16 +1072,16 @@ Parantez tercihleri: - - Paste - Yapıştır - - Paste a stack trace to view and navigate it's values. Değerlerini görüntülemek ve gezinmek için bir yığın izi yapıştırın. "Stack Trace" is a language term and should be kept the same. + + Performance + Performance + + Please enter a type name Lütfen bir tür adı yazın @@ -1157,16 +1207,16 @@ Hızlı Eylemler - - Refactoring Only - Sadece Yeniden Düzenlenme - - Reference Başvuru + + Regular + Regular + + Regular Expressions Normal İfadeler @@ -1182,16 +1232,6 @@ Gereksiz Kullanımları Kaldır - - Rename - Yeniden adlandır - - - - Rename {0} to {1} - {0} öğesini {1} olarak yeniden adlandır - - Rename asynchronously (experimental) Zaman uyumsuz olarak yeniden adlandırın (deneysel) @@ -1342,9 +1382,9 @@ Anlamsal Arama Sonuçları - - Show "Remove Unused References" command in Solution Explorer (experimental) - Çözüm Gezgini'nde "Kullanılmayan Başvuruları Kaldır" komutunu göster (deneysel) + + Show "Remove Unused References" command in Solution Explorer + Show "Remove Unused References" command in Solution Explorer @@ -1362,11 +1402,36 @@ Şunun için derleyici hatalarını ve uyarılarını göster: + + Show completion item _filters + Show completion item _filters + + + + Show completion item filters + Show completion item filters + + Show completion list Tamamlama listesini göster + + Show completion list after a character is _deleted + Show completion list after a character is _deleted + + + + Show completion list after a character is deleted + Show completion list after a character is deleted + + + + Show completion list after a character is typed + Show completion list after a character is typed + + Show guides for comments and preprocessor regions Açıklamalar ve ön işlemci bölgeleri için kılavuzları göster @@ -1412,14 +1477,39 @@ Devralma boşluğunu göster + + Show items from unimported namespaces + Show items from unimported namespaces + + + + Show preview for rename _tracking + Show preview for rename _tracking + + + + _Show procedure line separators + _Show procedure line separators + + + + Show remarks in Quick Info + Show remarks in Quick Info + + Skip analyzers for implicitly triggered builds Dolaylı olarak tetiklenen derlemeler için çözümleyicileri atla - - Some color scheme colors are being overridden by changes made in the Environment > Fonts and Colors options page. Choose `Use Defaults` in the Fonts and Colors page to revert all customizations. - Bazı renk düzeni renkleri, Ortam > Yazı Tipleri ve Renkler seçenek sayfasında yapılan değişiklikler tarafından geçersiz kılınıyor. Tüm özelleştirmeleri geri döndürmek için Yazı Tipleri ve Renkler sayfasında `Varsayılanları Kullan` seçeneğini belirleyin. + + Small + Small + + + + Snippets behavior + Snippets behavior @@ -1452,11 +1542,6 @@ Kullanımdan kaldıran sembollerin üzerini çiz - - Suggestion - Öneri - - Suppress hints when argument matches parameter name Bağımsız değişken parametre adıyla eşleştiğinde ipuçlarını bastır @@ -1493,8 +1578,13 @@ {Locked="System.Void"} "System.Void" represents CLR's type and should not be localized + Tab twice to insert arguments + Bağımsız değişkenleri eklemek için iki kez dokunun (deneysel) + + + Tab twice to insert arguments (experimental) - Bağımsız değişkenleri eklemek için iki kez dokunun (deneysel) + Tab twice to insert arguments (experimental) @@ -1539,7 +1629,7 @@ Title - Başlık + Title @@ -1567,6 +1657,11 @@ Yeniden atanan değişkenlerin altını çiz + + Unused local + Unused local + + Unused value is explicitly assigned to an unused local Kullanılmayan değer açıkça kullanılmayan bir yerele atandı @@ -1622,11 +1717,6 @@ Burada atanan değer hiçbir zaman kullanılmadı - - Value: - Değer: - - Value returned by invocation is implicitly ignored Çağrı ile döndürülen değer örtük olarak yok sayıldı @@ -1652,11 +1742,6 @@ Visual Studio Ayarları - - Warning - Uyarı - - Warning: duplicate parameter name Uyarı: Yinelenen parametre adı @@ -1752,31 +1837,6 @@ Önizleme kullanılamıyor - - Overrides - Geçersiz Kılan - - - - Overridden By - Geçersiz Kılınan - - - - Inherits - Devralınan - - - - Implements - Uygulanan - - - - Implemented By - Uygulayan - - Invalid access. Geçersiz erişim. @@ -1822,6 +1882,21 @@ '{0}' ortak olacak şekilde değiştirildi. + + _Highlight matching portions of completion list items + _Highlight matching portions of completion list items + + + + _Only add new line on enter after end of fully typed word + _Only add new line on enter after end of fully typed word + + + + _Show completion list after a character is typed + _Show completion list after a character is typed + + at the end of the line of code kod satırı sonunda @@ -1902,41 +1977,16 @@ Bütünleştirilmiş Kod - - Exceptions: - Özel Durumlar: - - Member of {0} {0} üyesi - - Parameters: - Parametreler: - - Project Proje - - Remarks: - Açıklamalar: - - - - Returns: - Döndürülenler: - - - - Summary: - Özet: - - Type Parameters: Tür Parametreleri: @@ -2009,21 +2059,11 @@ Bu dosyanın ait olabileceği diğer projeleri görüntülemek ve bunlara geçi Çözümleyici bütünleştirilmiş kodu '{0}' değiştirildi. Visual Studio yeniden başlatılmazsa tanılama yanlış olabilir. - - Cancel - İptal - - _Deselect All _Tüm Seçimleri Kaldır - - Extract Interface - Arabirimi Ayıkla - - Generated name: Oluşturulan ad: @@ -2064,11 +2104,6 @@ Bu dosyanın ait olabileceği diğer projeleri görüntülemek ve bunlara geçi _Mevcut dosyaya ekle - - Change Signature - İmzayı Değiştir - - _Create new file Yeni dosya _oluştur @@ -2204,21 +2239,6 @@ Bu dosyanın ait olabileceği diğer projeleri görüntülemek ve bunlara geçi 1 başvuru - - '{0}' encountered an error and has been disabled. - '{0}' bir hatayla karşılaştı ve devre dışı bırakıldı. - - - - Enable - Etkinleştir - - - - Enable and ignore future errors - Etkinleştir ve gelecekteki hataları yoksay - - No Changes Değişiklik Yok @@ -2234,11 +2254,6 @@ Bu dosyanın ait olabileceği diğer projeleri görüntülemek ve bunlara geçi Geçerli blok belirleniyor. - - IntelliSense - IntelliSense - - MissingAnalyzerReference MissingAnalyzerReference @@ -2314,16 +2329,6 @@ Bu dosyanın ait olabileceği diğer projeleri görüntülemek ve bunlara geçi <Bilinmiyor> - - No - Hayır - - - - Yes - Evet - - Enter a title for this Naming Style. Bu Adlandırma Stili için bir başlık girin. @@ -2562,11 +2567,6 @@ Ek bilgiler: {1} Blok Yapısı Kılavuzları - - Outlining - Ana Hat - - Show guides for code level constructs Kod düzeyinde yapılar için kılavuzları göster diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.zh-Hans.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.zh-Hans.xlf index d2d6395a11898..7ed65d0a3edbf 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.zh-Hans.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.zh-Hans.xlf @@ -72,6 +72,11 @@ 始终 + + _Always add new line on enter + _Always add new line on enter + + Always for clarity 为始终保持清楚起见 @@ -187,11 +192,6 @@ 正在计算依赖项... - - Call Hierarchy - 调用层次结构 - - Call site value: 调用站点值: @@ -392,9 +392,9 @@ 编辑器配色方案 - - Editor color scheme options are only available when using a color theme bundled with Visual Studio. The color theme can be configured from the Environment > General options page. - 只有在使用与 Visual Studio 绑定的颜色主题时,编辑器配色方案选项才可用。可在“环境”>“常规”选项页中配置颜色主题。 + + Editor Help + Editor Help @@ -432,6 +432,16 @@ 输入调用站点值或选择其他值注入类型 + + Enter key behavior + Enter key behavior + + + + Enter key behavior: + Enter key behavior: + + Entire repository 整个存储库 @@ -447,16 +457,16 @@ 整个解决方案和外部源 - - Error - 错误 - - Error updating suppressions: {0} 更新抑制时出现错误: {0} + + Experimental feature + Experimental feature + + External Sources 外部源 @@ -472,6 +482,11 @@ 提取基本 Record {Locked="Record"} "Record" is a language construct for C# and should not be localized + + Fade out unused members + Fade out unused members + + Finish 完成 @@ -522,11 +537,31 @@ 转到定义 + + Highlight matching portions of completion list items + Highlight matching portions of completion list items + + + + _Highlight references to symbol under cursor + _Highlight references to symbol under cursor + + Highlight related components under cursor 突出显示光标下的相关组件 + + Highlight related _keywords under cursor + Highlight related _keywords under cursor + + + + Highlighting + Highlighting + + Id ID @@ -582,9 +617,9 @@ 继承的接口 - - Inline Hints - 内联提示 + + Insert Snippet + Insert Snippet @@ -627,6 +662,11 @@ 种类 + + Large + Large + + Loaded items 加载的项 @@ -857,11 +897,6 @@ 命名规则 - - Navigate asynchronously (experimental) - 异步导航 (实验性) - - Navigate to '{0}' 导航到“{0}” @@ -879,7 +914,12 @@ Never - 从不 + Never + + + + _Never add new line on enter + _Never add new line on enter @@ -887,6 +927,11 @@ 从不(若无必要) + + Never include snippets + Never include snippets + + New Type Name: 新类型名称: @@ -917,11 +962,6 @@ 非公共成员 - - None - - - Not applicable 不适用 @@ -937,6 +977,11 @@ 省略(仅对于可选参数) + + Only add new line on enter after end of fully typed word + Only add new line on enter after end of fully typed word + + Open documents 打开的文档 @@ -947,6 +992,11 @@ 换行时运算符的位置 + + Optimize for solution size + Optimize for solution size + + Optional parameters must provide a default value 可选参数必须提供默认值 @@ -1022,16 +1072,16 @@ 括号首选项: - - Paste - 粘贴 - - Paste a stack trace to view and navigate it's values. 粘贴堆栈跟踪以查看和导航其值。 "Stack Trace" is a language term and should be kept the same. + + Performance + Performance + + Please enter a type name 请输入一个类型名称 @@ -1157,16 +1207,16 @@ 快速操作 - - Refactoring Only - 仅重构 - - Reference 引用 + + Regular + Regular + + Regular Expressions 正规表达式 @@ -1182,16 +1232,6 @@ 删除不必要的 Using - - Rename - 重命名 - - - - Rename {0} to {1} - 将 {0} 重命名为 {1} - - Rename asynchronously (experimental) 异步重命名(试验) @@ -1342,9 +1382,9 @@ 语义搜索结果 - - Show "Remove Unused References" command in Solution Explorer (experimental) - 在解决方案资源管理器中显示“删除未使用的引用”命令(实验性) + + Show "Remove Unused References" command in Solution Explorer + Show "Remove Unused References" command in Solution Explorer @@ -1362,11 +1402,36 @@ 显示以下的编译器错误和警告: + + Show completion item _filters + Show completion item _filters + + + + Show completion item filters + Show completion item filters + + Show completion list 显示完成列表 + + Show completion list after a character is _deleted + Show completion list after a character is _deleted + + + + Show completion list after a character is deleted + Show completion list after a character is deleted + + + + Show completion list after a character is typed + Show completion list after a character is typed + + Show guides for comments and preprocessor regions 显示注释和预处理器区域的指南 @@ -1412,14 +1477,39 @@ 显示继承边距 + + Show items from unimported namespaces + Show items from unimported namespaces + + + + Show preview for rename _tracking + Show preview for rename _tracking + + + + _Show procedure line separators + _Show procedure line separators + + + + Show remarks in Quick Info + Show remarks in Quick Info + + Skip analyzers for implicitly triggered builds 跳过隐式触发生成的分析器 - - Some color scheme colors are being overridden by changes made in the Environment > Fonts and Colors options page. Choose `Use Defaults` in the Fonts and Colors page to revert all customizations. - 在“环境”>“字体和颜色”选项页中所做的更改将替代某些配色方案颜色。在“字体和颜色”页中选择“使用默认值”,还原所有自定义项。 + + Small + Small + + + + Snippets behavior + Snippets behavior @@ -1452,11 +1542,6 @@ 划掉过时的符号 - - Suggestion - 建议 - - Suppress hints when argument matches parameter name 当参数与参数名称匹配时抑制提示 @@ -1493,8 +1578,13 @@ {Locked="System.Void"} "System.Void" represents CLR's type and should not be localized + Tab twice to insert arguments + 按两次 Tab 以插入参数(实验性) + + + Tab twice to insert arguments (experimental) - 按两次 Tab 以插入参数(实验性) + Tab twice to insert arguments (experimental) @@ -1539,7 +1629,7 @@ Title - 标题 + Title @@ -1567,6 +1657,11 @@ 为重新分配变量添加下划线 + + Unused local + Unused local + + Unused value is explicitly assigned to an unused local 未使用的值会显式分配给未使用的本地函数 @@ -1622,11 +1717,6 @@ 此处分配的值从未使用过 - - Value: - 值: - - Value returned by invocation is implicitly ignored 已隐式忽略调用所返回的值 @@ -1652,11 +1742,6 @@ Visual Studio 设置 - - Warning - 警告 - - Warning: duplicate parameter name 警告: 参数名重复 @@ -1752,31 +1837,6 @@ 预览不可用 - - Overrides - 重写 - - - - Overridden By - 重写者 - - - - Inherits - 继承 - - - - Implements - 实现 - - - - Implemented By - 实现者 - - Invalid access. 访问无效。 @@ -1822,6 +1882,21 @@ “{0}”将更改为“公共”。 + + _Highlight matching portions of completion list items + _Highlight matching portions of completion list items + + + + _Only add new line on enter after end of fully typed word + _Only add new line on enter after end of fully typed word + + + + _Show completion list after a character is typed + _Show completion list after a character is typed + + at the end of the line of code 在代码行的末尾 @@ -1902,41 +1977,16 @@ 程序集 - - Exceptions: - 异常: - - Member of {0} {0} 的成员 - - Parameters: - 参数: - - Project 项目 - - Remarks: - 备注: - - - - Returns: - 返回结果: - - - - Summary: - 摘要: - - Type Parameters: 类型参数: @@ -2009,21 +2059,11 @@ Use the dropdown to view and switch to other projects this file may belong to.分析器程序集“{0}”已更改。如果不重启 Visual Studio,诊断则可能出错。 - - Cancel - 取消 - - _Deselect All 取消全选(_D) - - Extract Interface - 提取接口 - - Generated name: 生成的名称: @@ -2064,11 +2104,6 @@ Use the dropdown to view and switch to other projects this file may belong to.添加到现有文件(_E) - - Change Signature - 更改签名 - - _Create new file 创建新文件(_C) @@ -2204,21 +2239,6 @@ Use the dropdown to view and switch to other projects this file may belong to.1 个引用 - - '{0}' encountered an error and has been disabled. - “{0}”遇到了错误,且已被禁用。 - - - - Enable - 启用 - - - - Enable and ignore future errors - 启用并忽略将来发生的错误 - - No Changes 未更改 @@ -2234,11 +2254,6 @@ Use the dropdown to view and switch to other projects this file may belong to.正在确定当前块。 - - IntelliSense - IntelliSense - - MissingAnalyzerReference MissingAnalyzerReference @@ -2314,16 +2329,6 @@ Use the dropdown to view and switch to other projects this file may belong to.<未知> - - No - - - - - Yes - - - Enter a title for this Naming Style. 为此命名样式输入标题。 @@ -2562,11 +2567,6 @@ Additional information: {1} 块结构指南 - - Outlining - 大纲 - - Show guides for code level constructs 显示代码级别构造的指南 diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.zh-Hant.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.zh-Hant.xlf index e45805de75cfc..477bc1190dfe7 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.zh-Hant.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.zh-Hant.xlf @@ -72,6 +72,11 @@ 一律 + + _Always add new line on enter + _Always add new line on enter + + Always for clarity 一律使用以明確表示 @@ -187,11 +192,6 @@ 正在計算相依項... - - Call Hierarchy - 呼叫階層 - - Call site value: 呼叫網站值: @@ -392,9 +392,9 @@ 編輯器色彩配置 - - Editor color scheme options are only available when using a color theme bundled with Visual Studio. The color theme can be configured from the Environment > General options page. - 只有在使用與 Visual Studio 配套的色彩佈景主題時,才可使用編輯器色彩配置選項。您可從 [環境] > [一般選項] 頁面設定色彩佈景主題。 + + Editor Help + Editor Help @@ -432,6 +432,16 @@ 請輸入呼叫位置值,或選擇其他值插入種類 + + Enter key behavior + Enter key behavior + + + + Enter key behavior: + Enter key behavior: + + Entire repository 整個存放庫 @@ -447,16 +457,16 @@ 整個解決方案與外部來源 - - Error - 錯誤 - - Error updating suppressions: {0} 更新歸併時發生錯誤: {0} + + Experimental feature + Experimental feature + + External Sources 外部來源 @@ -472,6 +482,11 @@ 擷取基底 Record {Locked="Record"} "Record" is a language construct for C# and should not be localized + + Fade out unused members + Fade out unused members + + Finish 完成 @@ -522,11 +537,31 @@ 移至定義 + + Highlight matching portions of completion list items + Highlight matching portions of completion list items + + + + _Highlight references to symbol under cursor + _Highlight references to symbol under cursor + + Highlight related components under cursor 反白資料指標下的相關元件 + + Highlight related _keywords under cursor + Highlight related _keywords under cursor + + + + Highlighting + Highlighting + + Id 識別碼 @@ -582,9 +617,9 @@ 繼承介面 - - Inline Hints - 內嵌提示 + + Insert Snippet + Insert Snippet @@ -627,6 +662,11 @@ 種類 + + Large + Large + + Loaded items 已載入的項目 @@ -857,11 +897,6 @@ 命名規則 - - Navigate asynchronously (experimental) - 非同步瀏覽 (實驗性) - - Navigate to '{0}' 瀏覽至 '{0}' @@ -879,7 +914,12 @@ Never - 永不 + Never + + + + _Never add new line on enter + _Never add new line on enter @@ -887,6 +927,11 @@ 不需要時一律不要 + + Never include snippets + Never include snippets + + New Type Name: 新的型別名稱: @@ -917,11 +962,6 @@ 非公用方法 - - None - - - Not applicable 不適用 @@ -937,6 +977,11 @@ 省略 (僅適用於選擇性參數) + + Only add new line on enter after end of fully typed word + Only add new line on enter after end of fully typed word + + Open documents 開啟的文件 @@ -947,6 +992,11 @@ 換行時運算子的位置 + + Optimize for solution size + Optimize for solution size + + Optional parameters must provide a default value 選擇性參數必須提供預設值 @@ -1022,16 +1072,16 @@ 括號喜好設定: - - Paste - 貼上 - - Paste a stack trace to view and navigate it's values. 貼上堆疊追蹤以檢視及瀏覽其值。 "Stack Trace" is a language term and should be kept the same. + + Performance + Performance + + Please enter a type name 請輸入類型名稱 @@ -1157,16 +1207,16 @@ 快速動作 - - Refactoring Only - 僅重構 - - Reference 參考 + + Regular + Regular + + Regular Expressions 規則運算式 @@ -1182,16 +1232,6 @@ 移除不必要的 Using - - Rename - 重新命名 - - - - Rename {0} to {1} - 將 {0} 重新命名為 {1} - - Rename asynchronously (experimental) 重新命名非同步 (實驗性) @@ -1342,9 +1382,9 @@ 語意搜尋結果 - - Show "Remove Unused References" command in Solution Explorer (experimental) - 在方案總管 (實驗性) 中顯示「移除未使用的參考」命令 + + Show "Remove Unused References" command in Solution Explorer + Show "Remove Unused References" command in Solution Explorer @@ -1362,11 +1402,36 @@ 顯示編譯器錯誤和警告: + + Show completion item _filters + Show completion item _filters + + + + Show completion item filters + Show completion item filters + + Show completion list 顯示自動完成清單 + + Show completion list after a character is _deleted + Show completion list after a character is _deleted + + + + Show completion list after a character is deleted + Show completion list after a character is deleted + + + + Show completion list after a character is typed + Show completion list after a character is typed + + Show guides for comments and preprocessor regions 顯示註解及前置處理器區域的指南 @@ -1412,14 +1477,39 @@ 顯示繼承邊界 + + Show items from unimported namespaces + Show items from unimported namespaces + + + + Show preview for rename _tracking + Show preview for rename _tracking + + + + _Show procedure line separators + _Show procedure line separators + + + + Show remarks in Quick Info + Show remarks in Quick Info + + Skip analyzers for implicitly triggered builds 跳過隱含已觸發組建的分析器 - - Some color scheme colors are being overridden by changes made in the Environment > Fonts and Colors options page. Choose `Use Defaults` in the Fonts and Colors page to revert all customizations. - [環境] > [字型和色彩選項] 頁面中所做的變更覆寫了某些色彩配置的色彩。請選擇 [字型和色彩] 頁面中的 [使用預設] 來還原所有自訂。 + + Small + Small + + + + Snippets behavior + Snippets behavior @@ -1452,11 +1542,6 @@ 刪去已淘汰的符號 - - Suggestion - 建議 - - Suppress hints when argument matches parameter name 當引數符合參數名稱時抑制提示 @@ -1493,8 +1578,13 @@ {Locked="System.Void"} "System.Void" represents CLR's type and should not be localized + Tab twice to insert arguments + 按 Tab 鍵兩次可插入引數 (實驗性) + + + Tab twice to insert arguments (experimental) - 按 Tab 鍵兩次可插入引數 (實驗性) + Tab twice to insert arguments (experimental) @@ -1539,7 +1629,7 @@ Title - 標題 + Title @@ -1567,6 +1657,11 @@ 為重新指派的變數加上底線 + + Unused local + Unused local + + Unused value is explicitly assigned to an unused local 未使用的值已明確指派至未使用的區域 @@ -1622,11 +1717,6 @@ 這裡指派的值從未使用過 - - Value: - 值: - - Value returned by invocation is implicitly ignored 明確地忽略引動過程傳回的值 @@ -1652,11 +1742,6 @@ Visual Studio 設定 - - Warning - 警告 - - Warning: duplicate parameter name 警告: 參數名稱重複 @@ -1752,31 +1837,6 @@ 無法使用預覽 - - Overrides - 覆寫 - - - - Overridden By - 覆寫者 - - - - Inherits - 繼承 - - - - Implements - 實作 - - - - Implemented By - 實作者 - - Invalid access. 存取無效。 @@ -1822,6 +1882,21 @@ '{0}' 會變更為公用。 + + _Highlight matching portions of completion list items + _Highlight matching portions of completion list items + + + + _Only add new line on enter after end of fully typed word + _Only add new line on enter after end of fully typed word + + + + _Show completion list after a character is typed + _Show completion list after a character is typed + + at the end of the line of code 在程式碼結尾 @@ -1902,41 +1977,16 @@ 組件 - - Exceptions: - 例外狀況: - - Member of {0} {0} 的成員 - - Parameters: - 參數: - - Project 專案 - - Remarks: - 備註: - - - - Returns: - 傳回: - - - - Summary: - 摘要: - - Type Parameters: 類型參數: @@ -2009,21 +2059,11 @@ Use the dropdown to view and switch to other projects this file may belong to.分析器組件 '{0}' 已變更。可能造成診斷錯誤,直到 Visual Studio 重新啟動為止。 - - Cancel - 取消 - - _Deselect All 全部取消選取(_D) - - Extract Interface - 擷取介面 - - Generated name: 產生的名稱: @@ -2064,11 +2104,6 @@ Use the dropdown to view and switch to other projects this file may belong to.新增至現有檔案(_E) - - Change Signature - 變更簽章 - - _Create new file 建立新檔案(_C) @@ -2204,21 +2239,6 @@ Use the dropdown to view and switch to other projects this file may belong to.1 個參考 - - '{0}' encountered an error and has been disabled. - '{0}' 發生錯誤並已停用。 - - - - Enable - 啟用 - - - - Enable and ignore future errors - 啟用並忽略未來的錯誤 - - No Changes 沒有變更 @@ -2234,11 +2254,6 @@ Use the dropdown to view and switch to other projects this file may belong to.正在判定目前的區塊。 - - IntelliSense - IntelliSense - - MissingAnalyzerReference MissingAnalyzerReference @@ -2314,16 +2329,6 @@ Use the dropdown to view and switch to other projects this file may belong to.<未知> - - No - - - - - Yes - - - Enter a title for this Naming Style. 輸入此命名樣式的標題。 @@ -2562,11 +2567,6 @@ Additional information: {1} 區塊結構輔助線 - - Outlining - 大綱 - - Show guides for code level constructs 顯示程式碼層級建構的指南 diff --git a/src/VisualStudio/Core/Impl/CodeModel/AbstractCodeModelService.cs b/src/VisualStudio/Core/Impl/CodeModel/AbstractCodeModelService.cs index ed69e95a31aac..5fd11bf5fc331 100644 --- a/src/VisualStudio/Core/Impl/CodeModel/AbstractCodeModelService.cs +++ b/src/VisualStudio/Core/Impl/CodeModel/AbstractCodeModelService.cs @@ -1037,7 +1037,7 @@ private Document FormatAnnotatedNode(Document document, SyntaxAnnotation annotat var formattingRules = Formatter.GetDefaultFormattingRules(document); if (additionalRules != null) { - formattingRules = additionalRules.Concat(formattingRules).ToImmutableArray(); + formattingRules = [.. additionalRules, .. formattingRules]; } return _threadingContext.JoinableTaskFactory.Run(async () => diff --git a/src/VisualStudio/Core/Impl/CodeModel/Collections/ExternalNamespaceCollection.cs b/src/VisualStudio/Core/Impl/CodeModel/Collections/ExternalNamespaceCollection.cs index d5cd28c9936b2..744f0fd55967e 100644 --- a/src/VisualStudio/Core/Impl/CodeModel/Collections/ExternalNamespaceCollection.cs +++ b/src/VisualStudio/Core/Impl/CodeModel/Collections/ExternalNamespaceCollection.cs @@ -43,14 +43,7 @@ internal ExternalNamespaceCollection(CodeModelState state, object parent, Projec { if (_children == null) { - var childrenBuilder = ArrayBuilder.GetInstance(); - - foreach (var child in ExternalNamespaceEnumerator.ChildrenOfNamespace(this.State, _projectId, _namespaceSymbolId)) - { - childrenBuilder.Add(child); - } - - _children = childrenBuilder.ToImmutableAndFree(); + _children = [.. ExternalNamespaceEnumerator.ChildrenOfNamespace(this.State, _projectId, _namespaceSymbolId)]; } return _children; diff --git a/src/VisualStudio/Core/Impl/CodeModel/Collections/InheritsImplementsCollection.cs b/src/VisualStudio/Core/Impl/CodeModel/Collections/InheritsImplementsCollection.cs index e10589427e33d..6cbdce8d418bb 100644 --- a/src/VisualStudio/Core/Impl/CodeModel/Collections/InheritsImplementsCollection.cs +++ b/src/VisualStudio/Core/Impl/CodeModel/Collections/InheritsImplementsCollection.cs @@ -58,13 +58,11 @@ internal override Snapshot CreateSnapshot() { var node = LookupNode(); var parentElement = (AbstractCodeElement)this.Parent; - - var nodesBuilder = ArrayBuilder.GetInstance(); - nodesBuilder.AddRange(CodeModelService.GetInheritsNodes(node)); - nodesBuilder.AddRange(CodeModelService.GetImplementsNodes(node)); - return new NodeSnapshot(this.State, _fileCodeModel, node, parentElement, - nodesBuilder.ToImmutableAndFree()); + [ + .. CodeModelService.GetInheritsNodes(node), + .. CodeModelService.GetImplementsNodes(node), + ]); } protected override bool TryGetItemByIndex(int index, out EnvDTE.CodeElement element) diff --git a/src/VisualStudio/Core/Impl/CodeModel/Collections/NamespaceCollection.cs b/src/VisualStudio/Core/Impl/CodeModel/Collections/NamespaceCollection.cs index 03f81d3b3432b..99fa14ff50151 100644 --- a/src/VisualStudio/Core/Impl/CodeModel/Collections/NamespaceCollection.cs +++ b/src/VisualStudio/Core/Impl/CodeModel/Collections/NamespaceCollection.cs @@ -95,15 +95,13 @@ internal override Snapshot CreateSnapshot() var parentElement = !this.IsRootNamespace ? (AbstractCodeElement)this.Parent : null; - - var nodesBuilder = ArrayBuilder.GetInstance(); - nodesBuilder.AddRange(CodeModelService.GetOptionNodes(node)); - nodesBuilder.AddRange(CodeModelService.GetImportNodes(node)); - nodesBuilder.AddRange(CodeModelService.GetAttributeNodes(node)); - nodesBuilder.AddRange(CodeModelService.GetLogicalSupportedMemberNodes(node)); - return new NodeSnapshot(this.State, _fileCodeModel, node, parentElement, - nodesBuilder.ToImmutableAndFree()); + [ + .. CodeModelService.GetOptionNodes(node), + .. CodeModelService.GetImportNodes(node), + .. CodeModelService.GetAttributeNodes(node), + .. CodeModelService.GetLogicalSupportedMemberNodes(node), + ]); } protected override bool TryGetItemByIndex(int index, out EnvDTE.CodeElement element) diff --git a/src/VisualStudio/Core/Impl/CodeModel/Collections/TypeCollection.cs b/src/VisualStudio/Core/Impl/CodeModel/Collections/TypeCollection.cs index d2c0aadccc8c8..c083e1a7863be 100644 --- a/src/VisualStudio/Core/Impl/CodeModel/Collections/TypeCollection.cs +++ b/src/VisualStudio/Core/Impl/CodeModel/Collections/TypeCollection.cs @@ -58,12 +58,8 @@ internal override Snapshot CreateSnapshot() { var node = LookupNode(); var parentElement = (AbstractCodeElement)this.Parent; - - var nodesBuilder = ArrayBuilder.GetInstance(); - nodesBuilder.AddRange(CodeModelService.GetLogicalSupportedMemberNodes(node)); - return new NodeSnapshot(this.State, _fileCodeModel, node, parentElement, - nodesBuilder.ToImmutableAndFree()); + [.. CodeModelService.GetLogicalSupportedMemberNodes(node)]); } protected override bool TryGetItemByIndex(int index, out EnvDTE.CodeElement element) diff --git a/src/VisualStudio/Core/Impl/CodeModel/FileCodeModel_CodeGen.cs b/src/VisualStudio/Core/Impl/CodeModel/FileCodeModel_CodeGen.cs index 0218a50da6a48..d0658ab9ef87e 100644 --- a/src/VisualStudio/Core/Impl/CodeModel/FileCodeModel_CodeGen.cs +++ b/src/VisualStudio/Core/Impl/CodeModel/FileCodeModel_CodeGen.cs @@ -213,7 +213,7 @@ internal EnvDTE.CodeClass AddClass(SyntaxNode containerNode, string name, object access, options, baseType: baseTypeSymbol, - implementedInterfaces: implementedInterfaceSymbols.ToImmutableArray()); + implementedInterfaces: [.. implementedInterfaceSymbols]); var insertionIndex = CodeModelService.PositionVariantToMemberInsertionIndex(position, containerNode, fileCodeModel: this); @@ -358,7 +358,7 @@ internal EnvDTE.CodeInterface AddInterface(SyntaxNode containerNode, string name CodeModelService.GetUnescapedName(name), access, options, - implementedInterfaces: implementedInterfaceSymbols.ToImmutableArray()); + implementedInterfaces: [.. implementedInterfaceSymbols]); var insertionIndex = CodeModelService.PositionVariantToMemberInsertionIndex(position, containerNode, fileCodeModel: this); @@ -428,7 +428,7 @@ internal EnvDTE.CodeStruct AddStruct(SyntaxNode containerNode, string name, obje CodeModelService.GetUnescapedName(name), access, options, - implementedInterfaces: implementedInterfaceSymbols.ToImmutableArray()); + implementedInterfaces: [.. implementedInterfaceSymbols]); var insertionIndex = CodeModelService.PositionVariantToMemberInsertionIndex(position, containerNode, fileCodeModel: this); diff --git a/src/VisualStudio/Core/Impl/CodeModel/InternalElements/CodeDelegate.cs b/src/VisualStudio/Core/Impl/CodeModel/InternalElements/CodeDelegate.cs index 3673ed610fb26..9358440772997 100644 --- a/src/VisualStudio/Core/Impl/CodeModel/InternalElements/CodeDelegate.cs +++ b/src/VisualStudio/Core/Impl/CodeModel/InternalElements/CodeDelegate.cs @@ -67,7 +67,7 @@ private IMethodSymbol LookupInvokeMethod() } internal override ImmutableArray GetParameters() - => ImmutableArray.CreateRange(CodeModelService.GetParameterNodes(LookupNode())); + => [.. CodeModelService.GetParameterNodes(LookupNode())]; public override EnvDTE.vsCMElement Kind { diff --git a/src/VisualStudio/Core/Impl/CodeModel/InternalElements/CodeFunction.cs b/src/VisualStudio/Core/Impl/CodeModel/InternalElements/CodeFunction.cs index 34849a71d7caf..1ed7cf0079cbc 100644 --- a/src/VisualStudio/Core/Impl/CodeModel/InternalElements/CodeFunction.cs +++ b/src/VisualStudio/Core/Impl/CodeModel/InternalElements/CodeFunction.cs @@ -73,7 +73,7 @@ private IMethodSymbol MethodSymbol } internal override ImmutableArray GetParameters() - => ImmutableArray.CreateRange(CodeModelService.GetParameterNodes(LookupNode())); + => [.. CodeModelService.GetParameterNodes(LookupNode())]; protected override object GetExtenderNames() => CodeModelService.GetFunctionExtenderNames(); diff --git a/src/VisualStudio/Core/Impl/CodeModel/InternalElements/CodeProperty.cs b/src/VisualStudio/Core/Impl/CodeModel/InternalElements/CodeProperty.cs index a47a1121b1bdd..95708af68f2bc 100644 --- a/src/VisualStudio/Core/Impl/CodeModel/InternalElements/CodeProperty.cs +++ b/src/VisualStudio/Core/Impl/CodeModel/InternalElements/CodeProperty.cs @@ -71,7 +71,7 @@ EnvDTE.CodeElements ICodeElementContainer.GetCollection() => this.Attributes; internal override ImmutableArray GetParameters() - => ImmutableArray.CreateRange(CodeModelService.GetParameterNodes(LookupNode())); + => [.. CodeModelService.GetParameterNodes(LookupNode())]; protected override object GetExtenderNames() => CodeModelService.GetPropertyExtenderNames(); diff --git a/src/VisualStudio/Core/Impl/Options/AbstractOptionPreviewViewModel.cs b/src/VisualStudio/Core/Impl/Options/AbstractOptionPreviewViewModel.cs index 71416ef4a42cb..979100a4c3ad6 100644 --- a/src/VisualStudio/Core/Impl/Options/AbstractOptionPreviewViewModel.cs +++ b/src/VisualStudio/Core/Impl/Options/AbstractOptionPreviewViewModel.cs @@ -138,9 +138,10 @@ public void UpdatePreview(string text) var fallbackFormattingOptions = OptionStore.GlobalOptions.GetSyntaxFormattingOptions(document.Project.Services); var formattingService = document.GetRequiredLanguageService(); var formattingOptions = formattingService.GetFormattingOptions(OptionStore); - var formatted = Formatter.FormatAsync(document, formattingOptions, CancellationToken.None).WaitAndGetResult(CancellationToken.None); + var root = document.GetSyntaxRootSynchronously(CancellationToken.None); + var formatted = Formatter.Format(root, document.Project.Solution.Services, formattingOptions, CancellationToken.None); - var textBuffer = _textBufferCloneService.Clone(formatted.GetTextSynchronously(CancellationToken.None), _contentType); + var textBuffer = _textBufferCloneService.Clone(SourceText.From(formatted.ToFullString(), Encoding.UTF8), _contentType); var container = textBuffer.AsTextContainer(); diff --git a/src/VisualStudio/Core/Impl/Options/Style/AbstractCodeStyleOptionViewModel.cs b/src/VisualStudio/Core/Impl/Options/Style/AbstractCodeStyleOptionViewModel.cs index a6157c436ec12..0e6a6e4182663 100644 --- a/src/VisualStudio/Core/Impl/Options/Style/AbstractCodeStyleOptionViewModel.cs +++ b/src/VisualStudio/Core/Impl/Options/Style/AbstractCodeStyleOptionViewModel.cs @@ -6,6 +6,7 @@ using System.Collections.Generic; using System.Linq; +using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CodeStyle; using Microsoft.CodeAnalysis.Options; using Microsoft.VisualStudio.Imaging; @@ -78,8 +79,8 @@ private static List GetDefaultPreferences() { return [ - new CodeStylePreference(ServicesVSResources.Yes, isChecked: true), - new CodeStylePreference(ServicesVSResources.No, isChecked: false), + new CodeStylePreference(EditorFeaturesResources.Yes, isChecked: true), + new CodeStylePreference(EditorFeaturesResources.No, isChecked: false), ]; } } diff --git a/src/VisualStudio/Core/Impl/Options/Style/EnumCodeStyleOptionViewModel.cs b/src/VisualStudio/Core/Impl/Options/Style/EnumCodeStyleOptionViewModel.cs index 11c72accad387..b8156f7ce1f45 100644 --- a/src/VisualStudio/Core/Impl/Options/Style/EnumCodeStyleOptionViewModel.cs +++ b/src/VisualStudio/Core/Impl/Options/Style/EnumCodeStyleOptionViewModel.cs @@ -48,8 +48,8 @@ public EnumCodeStyleOptionViewModel( Debug.Assert(preferences.Count == enumValues.Length); Debug.Assert(previews.Length == enumValues.Length); - _enumValues = enumValues.ToImmutableArray(); - _previews = previews.ToImmutableArray(); + _enumValues = [.. enumValues]; + _previews = [.. previews]; var codeStyleOption = optionStore.GetOption>(option, option.IsPerLanguage ? info.Language : null); diff --git a/src/VisualStudio/Core/Impl/Options/Style/NamingPreferences/ManageNamingStylesInfoDialog.xaml.cs b/src/VisualStudio/Core/Impl/Options/Style/NamingPreferences/ManageNamingStylesInfoDialog.xaml.cs index 56ee1228b32c2..846bc8fc8d6cd 100644 --- a/src/VisualStudio/Core/Impl/Options/Style/NamingPreferences/ManageNamingStylesInfoDialog.xaml.cs +++ b/src/VisualStudio/Core/Impl/Options/Style/NamingPreferences/ManageNamingStylesInfoDialog.xaml.cs @@ -6,6 +6,7 @@ using System.Windows; using System.Windows.Controls; +using Microsoft.CodeAnalysis; using Microsoft.VisualStudio.PlatformUI; namespace Microsoft.VisualStudio.LanguageServices.Implementation.Options.Style.NamingPreferences @@ -18,7 +19,7 @@ internal partial class ManageNamingStylesInfoDialog : DialogWindow private readonly IManageNamingStylesInfoDialogViewModel _viewModel; public string OK => ServicesVSResources.OK; - public string Cancel => ServicesVSResources.Cancel; + public string Cancel => EditorFeaturesResources.Cancel; public string CannotBeDeletedExplanation => ServicesVSResources.This_item_cannot_be_deleted_because_it_is_used_by_an_existing_Naming_Rule; public string AddItemAutomationText => ServicesVSResources.Add_item; public string EditButtonAutomationText => ServicesVSResources.Edit_item; diff --git a/src/VisualStudio/Core/Impl/Options/Style/NamingPreferences/NamingStyleOptionPageControl.xaml.cs b/src/VisualStudio/Core/Impl/Options/Style/NamingPreferences/NamingStyleOptionPageControl.xaml.cs index 35616f336f077..da938cca0868e 100644 --- a/src/VisualStudio/Core/Impl/Options/Style/NamingPreferences/NamingStyleOptionPageControl.xaml.cs +++ b/src/VisualStudio/Core/Impl/Options/Style/NamingPreferences/NamingStyleOptionPageControl.xaml.cs @@ -60,8 +60,8 @@ private NamingStyleOptionPageViewModel.NamingRuleViewModel CreateItemWithNoSelec { return new NamingStyleOptionPageViewModel.NamingRuleViewModel() { - Specifications = new ObservableCollection(_viewModel.Specifications), - NamingStyles = new ObservableCollection(_viewModel.NamingStyles), + Specifications = [.. _viewModel.Specifications], + NamingStyles = [.. _viewModel.NamingStyles], NotificationPreferences = _notifications }; } diff --git a/src/VisualStudio/Core/Impl/Options/Style/NamingPreferences/NamingStyleOptionPageViewModel.cs b/src/VisualStudio/Core/Impl/Options/Style/NamingPreferences/NamingStyleOptionPageViewModel.cs index a2f04599f1a7a..ecb87d42ec874 100644 --- a/src/VisualStudio/Core/Impl/Options/Style/NamingPreferences/NamingStyleOptionPageViewModel.cs +++ b/src/VisualStudio/Core/Impl/Options/Style/NamingPreferences/NamingStyleOptionPageViewModel.cs @@ -43,8 +43,8 @@ public NamingStyleOptionPageViewModel(NamingStylePreferences info) { var viewModel = new NamingRuleViewModel() { - NamingStyles = new ObservableCollection(info.NamingStyles.Select(n => new MutableNamingStyle(n))), - Specifications = new ObservableCollection(info.SymbolSpecifications), + NamingStyles = [.. info.NamingStyles.Select(n => new MutableNamingStyle(n))], + Specifications = [.. info.SymbolSpecifications], NotificationPreferences = new List(_notifications) }; @@ -56,8 +56,8 @@ public NamingStyleOptionPageViewModel(NamingStylePreferences info) } CodeStyleItems = new ObservableCollection(viewModels); - Specifications = new ObservableCollection(info.SymbolSpecifications); - NamingStyles = new ObservableCollection(info.NamingStyles.Select(n => new MutableNamingStyle(n))); + Specifications = [.. info.SymbolSpecifications]; + NamingStyles = [.. info.NamingStyles.Select(n => new MutableNamingStyle(n))]; SetMoveArrowStatuses(); } @@ -98,9 +98,9 @@ internal void UpdateSpecificationList(ManageSymbolSpecificationsDialogViewModel var symbolSpecifications = viewModel.Items.Cast().Select(n => new SymbolSpecification( n.ID, n.ItemName, - n.SymbolKindList.Where(s => s.IsChecked).Select(k => k.CreateSymbolOrTypeOrMethodKind()).ToImmutableArray(), - n.AccessibilityList.Where(s => s.IsChecked).Select(a => a._accessibility).ToImmutableArray(), - n.ModifierList.Where(s => s.IsChecked).Select(m => new SymbolSpecification.ModifierKind(m._modifier)).ToImmutableArray())); + [.. n.SymbolKindList.Where(s => s.IsChecked).Select(k => k.CreateSymbolOrTypeOrMethodKind())], + [.. n.AccessibilityList.Where(s => s.IsChecked).Select(a => a._accessibility)], + [.. n.ModifierList.Where(s => s.IsChecked).Select(m => new SymbolSpecification.ModifierKind(m._modifier))])); Specifications.Clear(); foreach (var specification in symbolSpecifications) diff --git a/src/VisualStudio/Core/Impl/Options/Style/NamingPreferences/NamingStyles/ManageNamingStylesDialogViewModel.cs b/src/VisualStudio/Core/Impl/Options/Style/NamingPreferences/NamingStyles/ManageNamingStylesDialogViewModel.cs index 4906ec16bcda8..47936d79bd57b 100644 --- a/src/VisualStudio/Core/Impl/Options/Style/NamingPreferences/NamingStyles/ManageNamingStylesDialogViewModel.cs +++ b/src/VisualStudio/Core/Impl/Options/Style/NamingPreferences/NamingStyles/ManageNamingStylesDialogViewModel.cs @@ -28,10 +28,10 @@ public ManageNamingStylesDialogViewModel( { _notificationService = notificationService; - Items = new ObservableCollection(namingStyles.Select(style => new NamingStyleViewModel( + Items = [.. namingStyles.Select(style => new NamingStyleViewModel( style.Clone(), !namingRules.Any(rule => rule.SelectedStyle?.ID == style.ID), - notificationService))); + notificationService))]; } internal void RemoveNamingStyle(NamingStyleViewModel namingStyle) diff --git a/src/VisualStudio/Core/Impl/Options/Style/NamingPreferences/NamingStyles/NamingStyleDialog.xaml.cs b/src/VisualStudio/Core/Impl/Options/Style/NamingPreferences/NamingStyles/NamingStyleDialog.xaml.cs index aff18bc03599f..cba2dac1a98f5 100644 --- a/src/VisualStudio/Core/Impl/Options/Style/NamingPreferences/NamingStyles/NamingStyleDialog.xaml.cs +++ b/src/VisualStudio/Core/Impl/Options/Style/NamingPreferences/NamingStyles/NamingStyleDialog.xaml.cs @@ -5,6 +5,7 @@ #nullable disable using System.Windows; +using Microsoft.CodeAnalysis; using Microsoft.VisualStudio.PlatformUI; namespace Microsoft.VisualStudio.LanguageServices.Implementation.Options.Style.NamingPreferences @@ -24,7 +25,7 @@ internal partial class NamingStyleDialog : DialogWindow public string CapitalizationLabelText => ServicesVSResources.Capitalization_colon; public string SampleIdentifierLabelText => ServicesVSResources.Sample_Identifier_colon; public string OK => ServicesVSResources.OK; - public string Cancel => ServicesVSResources.Cancel; + public string Cancel => EditorFeaturesResources.Cancel; internal NamingStyleDialog(NamingStyleViewModel viewModel) { diff --git a/src/VisualStudio/Core/Impl/Options/Style/NamingPreferences/SymbolSpecification/ManageSymbolSpecificationsDialogViewModel.cs b/src/VisualStudio/Core/Impl/Options/Style/NamingPreferences/SymbolSpecification/ManageSymbolSpecificationsDialogViewModel.cs index cb32574514375..35ef6128ab371 100644 --- a/src/VisualStudio/Core/Impl/Options/Style/NamingPreferences/SymbolSpecification/ManageSymbolSpecificationsDialogViewModel.cs +++ b/src/VisualStudio/Core/Impl/Options/Style/NamingPreferences/SymbolSpecification/ManageSymbolSpecificationsDialogViewModel.cs @@ -31,11 +31,11 @@ public ManageSymbolSpecificationsDialogViewModel( LanguageName = languageName; _notificationService = notificationService; - Items = new ObservableCollection(specifications.Select(specification => new SymbolSpecificationViewModel( + Items = [.. specifications.Select(specification => new SymbolSpecificationViewModel( languageName, specification, !namingRules.Any(rule => rule.SelectedSpecification?.ID == specification.ID), - notificationService))); + notificationService))]; } internal void AddSymbolSpecification(INamingStylesInfoDialogViewModel _) diff --git a/src/VisualStudio/Core/Impl/Options/Style/NamingPreferences/SymbolSpecification/SymbolSpecificationDialog.xaml.cs b/src/VisualStudio/Core/Impl/Options/Style/NamingPreferences/SymbolSpecification/SymbolSpecificationDialog.xaml.cs index d53c3a8257cee..b18e474780e67 100644 --- a/src/VisualStudio/Core/Impl/Options/Style/NamingPreferences/SymbolSpecification/SymbolSpecificationDialog.xaml.cs +++ b/src/VisualStudio/Core/Impl/Options/Style/NamingPreferences/SymbolSpecification/SymbolSpecificationDialog.xaml.cs @@ -10,6 +10,7 @@ using System.Windows.Controls; using System.Windows.Data; using System.Windows.Input; +using Microsoft.CodeAnalysis; using Microsoft.VisualStudio.LanguageServices.Implementation.Utilities; using Microsoft.VisualStudio.PlatformUI; @@ -27,7 +28,7 @@ internal partial class SymbolSpecificationDialog : DialogWindow public string SelectAllButtonText => ServicesVSResources.Select_All; public string DeselectAllButtonText => ServicesVSResources.Deselect_All; public string OK => ServicesVSResources.OK; - public string Cancel => ServicesVSResources.Cancel; + public string Cancel => EditorFeaturesResources.Cancel; private readonly AutomationDelegatingListView symbolKindsListView; private readonly AutomationDelegatingListView accessibilitiesListView; diff --git a/src/VisualStudio/Core/Impl/Options/Style/NamingPreferences/SymbolSpecification/SymbolSpecificationViewModel.cs b/src/VisualStudio/Core/Impl/Options/Style/NamingPreferences/SymbolSpecification/SymbolSpecificationViewModel.cs index 4bca1cdb1d3e1..31f4331490dc8 100644 --- a/src/VisualStudio/Core/Impl/Options/Style/NamingPreferences/SymbolSpecification/SymbolSpecificationViewModel.cs +++ b/src/VisualStudio/Core/Impl/Options/Style/NamingPreferences/SymbolSpecification/SymbolSpecificationViewModel.cs @@ -145,9 +145,9 @@ internal SymbolSpecification GetSymbolSpecification() return new SymbolSpecification( ID, ItemName, - SymbolKindList.Where(s => s.IsChecked).Select(s => s.CreateSymbolOrTypeOrMethodKind()).ToImmutableArray(), - AccessibilityList.Where(a => a.IsChecked).Select(a => a._accessibility).ToImmutableArray(), - ModifierList.Where(m => m.IsChecked).Select(m => new ModifierKind(m._modifier)).ToImmutableArray()); + [.. SymbolKindList.Where(s => s.IsChecked).Select(s => s.CreateSymbolOrTypeOrMethodKind())], + [.. AccessibilityList.Where(a => a.IsChecked).Select(a => a._accessibility)], + [.. ModifierList.Where(m => m.IsChecked).Select(m => new ModifierKind(m._modifier))]); } internal bool TrySubmit() diff --git a/src/VisualStudio/Core/Impl/ProjectSystem/CPS/CPSProjectFactory.cs b/src/VisualStudio/Core/Impl/ProjectSystem/CPS/CPSProjectFactory.cs index 278ad1bff12f9..9dd9945d9b718 100644 --- a/src/VisualStudio/Core/Impl/ProjectSystem/CPS/CPSProjectFactory.cs +++ b/src/VisualStudio/Core/Impl/ProjectSystem/CPS/CPSProjectFactory.cs @@ -33,7 +33,7 @@ internal partial class CPSProjectFactory : IWorkspaceProjectContextFactory /// Solutions containing projects that use older compiler toolset that does not provide a checksum algorithm. /// Used only for EnC issue diagnostics. /// - private ImmutableHashSet _solutionsWithMissingChecksumAlgorithm = ImmutableHashSet.Empty; + private ImmutableHashSet _solutionsWithMissingChecksumAlgorithm = []; [ImportingConstructor] [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] @@ -104,7 +104,7 @@ public override string GetPropertyValue(string name) public override ImmutableArray GetItemValues(string name) => name switch { - BuildPropertyNames.IntermediateAssembly => ImmutableArray.Create(OutputAssembly), + BuildPropertyNames.IntermediateAssembly => [OutputAssembly], _ => throw ExceptionUtilities.UnexpectedValue(name) }; } diff --git a/src/VisualStudio/Core/Impl/ProjectSystem/CPS/CPSProject_IWorkspaceProjectContext.cs b/src/VisualStudio/Core/Impl/ProjectSystem/CPS/CPSProject_IWorkspaceProjectContext.cs index a2a3a64ef3950..f69673ff87597 100644 --- a/src/VisualStudio/Core/Impl/ProjectSystem/CPS/CPSProject_IWorkspaceProjectContext.cs +++ b/src/VisualStudio/Core/Impl/ProjectSystem/CPS/CPSProject_IWorkspaceProjectContext.cs @@ -238,7 +238,7 @@ public void AddAdditionalFile(string filePath, bool isInCurrentContext = true) => _projectSystemProject.AddAdditionalFile(filePath); public void AddAdditionalFile(string filePath, IEnumerable folderNames, bool isInCurrentContext = true) - => _projectSystemProject.AddAdditionalFile(filePath, folders: folderNames.ToImmutableArray()); + => _projectSystemProject.AddAdditionalFile(filePath, folders: [.. folderNames]); public void Dispose() { diff --git a/src/VisualStudio/Core/Impl/RoslynVisualStudioWorkspace.cs b/src/VisualStudio/Core/Impl/RoslynVisualStudioWorkspace.cs index 8fb122de116e0..95f8dbe01b48f 100644 --- a/src/VisualStudio/Core/Impl/RoslynVisualStudioWorkspace.cs +++ b/src/VisualStudio/Core/Impl/RoslynVisualStudioWorkspace.cs @@ -122,13 +122,12 @@ public override void DisplayReferencedSymbols(Solution solution, IEnumerable GetBrowseObjectAsync( + SymbolListItem symbolListItem, CancellationToken cancellationToken) { - var compilation = symbolListItem.GetCompilation(this); + var compilation = await symbolListItem.GetCompilationAsync(this, cancellationToken).ConfigureAwait(true); if (compilation == null) - { return null; - } var symbol = symbolListItem.ResolveSymbol(compilation); var sourceLocation = symbol.Locations.Where(l => l.IsInSource).FirstOrDefault(); @@ -167,7 +166,7 @@ public override void DisplayReferencedSymbols(Solution solution, IEnumerable(vsFileCodeModel); if (fileCodeModel != null) { - var syntaxNode = tree.GetRoot().FindNode(sourceLocation.SourceSpan); + var syntaxNode = tree.GetRoot(cancellationToken).FindNode(sourceLocation.SourceSpan); while (syntaxNode != null) { if (!codeModelService.TryGetNodeKey(syntaxNode).IsEmpty) diff --git a/src/VisualStudio/Core/Impl/SolutionExplorer/AnalyzerItem/AnalyzerItemSource.cs b/src/VisualStudio/Core/Impl/SolutionExplorer/AnalyzerItem/AnalyzerItemSource.cs index 1451dca714dc9..7db53244947e0 100644 --- a/src/VisualStudio/Core/Impl/SolutionExplorer/AnalyzerItem/AnalyzerItemSource.cs +++ b/src/VisualStudio/Core/Impl/SolutionExplorer/AnalyzerItem/AnalyzerItemSource.cs @@ -145,7 +145,7 @@ async Task> GetAnalyzerReferencesWithAnalyzers // If we can't make a remote call. Fall back to processing in the VS host. if (client is null) - return project.AnalyzerReferences.Where(r => r is not AnalyzerFileReference || r.HasAnalyzersOrSourceGenerators(project.Language)).ToImmutableArray(); + return [.. project.AnalyzerReferences.Where(r => r is not AnalyzerFileReference || r.HasAnalyzersOrSourceGenerators(project.Language))]; using var connection = client.CreateConnection(callbackTarget: null); diff --git a/src/VisualStudio/Core/Impl/SolutionExplorer/AnalyzerItemTracker.cs b/src/VisualStudio/Core/Impl/SolutionExplorer/AnalyzerItemTracker.cs index bd5c9e9a2ac0b..bd18f54329276 100644 --- a/src/VisualStudio/Core/Impl/SolutionExplorer/AnalyzerItemTracker.cs +++ b/src/VisualStudio/Core/Impl/SolutionExplorer/AnalyzerItemTracker.cs @@ -47,8 +47,8 @@ public void Unregister() public IVsHierarchy? SelectedHierarchy { get; private set; } public uint SelectedItemId { get; private set; } = VSConstants.VSITEMID_NIL; public AnalyzersFolderItem? SelectedFolder { get; private set; } - public ImmutableArray SelectedAnalyzerItems { get; private set; } = ImmutableArray.Empty; - public ImmutableArray SelectedDiagnosticItems { get; private set; } = ImmutableArray.Empty; + public ImmutableArray SelectedAnalyzerItems { get; private set; } = []; + public ImmutableArray SelectedDiagnosticItems { get; private set; } = []; int IVsSelectionEvents.OnCmdUIContextChanged(uint dwCmdUICookie, int fActive) { @@ -78,20 +78,18 @@ int IVsSelectionEvents.OnSelectionChanged( var selectedObjects = GetSelectedObjects(pSCNew); - this.SelectedAnalyzerItems = selectedObjects + this.SelectedAnalyzerItems = [.. selectedObjects .OfType() - .Select(b => b.AnalyzerItem) - .ToImmutableArray(); + .Select(b => b.AnalyzerItem)]; this.SelectedFolder = selectedObjects .OfType() .Select(b => b.Folder) .FirstOrDefault(); - this.SelectedDiagnosticItems = selectedObjects + this.SelectedDiagnosticItems = [.. selectedObjects .OfType() - .Select(b => b.DiagnosticItem) - .ToImmutableArray(); + .Select(b => b.DiagnosticItem)]; if (!object.ReferenceEquals(oldSelectedHierarchy, this.SelectedHierarchy) || oldSelectedItemId != this.SelectedItemId) diff --git a/src/VisualStudio/Core/Impl/SolutionExplorer/AnalyzersFolderItem/AnalyzersFolderItemSourceProvider.cs b/src/VisualStudio/Core/Impl/SolutionExplorer/AnalyzersFolderItem/AnalyzersFolderItemSourceProvider.cs index 2b66c8a56c5a9..3fba3a9380bde 100644 --- a/src/VisualStudio/Core/Impl/SolutionExplorer/AnalyzersFolderItem/AnalyzersFolderItemSourceProvider.cs +++ b/src/VisualStudio/Core/Impl/SolutionExplorer/AnalyzersFolderItem/AnalyzersFolderItemSourceProvider.cs @@ -69,7 +69,7 @@ private static ImmutableArray GetProjectTreeCapabilities(IVsHierarchy hi } else { - return ImmutableArray.Empty; + return []; } } diff --git a/src/VisualStudio/Core/Test.Next/Options/VisualStudioOptionStorageTests.cs b/src/VisualStudio/Core/Test.Next/Options/VisualStudioOptionStorageTests.cs index 6b095dba38db1..847248bbcd1b4 100644 --- a/src/VisualStudio/Core/Test.Next/Options/VisualStudioOptionStorageTests.cs +++ b/src/VisualStudio/Core/Test.Next/Options/VisualStudioOptionStorageTests.cs @@ -239,6 +239,7 @@ public void OptionHasStorageIfNecessary(string configName) "dotnet_lsp_using_devkit", // VSCode internal only option. Does not need any UI. "dotnet_enable_references_code_lens", // VSCode only option. Does not apply to VS. "dotnet_enable_tests_code_lens", // VSCode only option. Does not apply to VS. + "dotnet_enable_auto_insert", // VSCode only option. Does not apply to VS. "end_of_line", // persisted by the editor "ExtensionManagerOptions_DisableCrashingExtensions", // TODO: remove? https://github.com/dotnet/roslyn/issues/66063 "FeatureOnOffOptions_RefactoringVerification", // TODO: remove? https://github.com/dotnet/roslyn/issues/66063 diff --git a/src/VisualStudio/Core/Test.Next/Remote/SerializationValidator.cs b/src/VisualStudio/Core/Test.Next/Remote/SerializationValidator.cs index f197b7ef48307..27803abdc44c7 100644 --- a/src/VisualStudio/Core/Test.Next/Remote/SerializationValidator.cs +++ b/src/VisualStudio/Core/Test.Next/Remote/SerializationValidator.cs @@ -60,7 +60,7 @@ public ChecksumObjectCollection(SerializationValidator validator, WellKnownSynch // using .Result here since we don't want to convert all calls to this to async. // and none of ChecksumWithChildren actually use async - Children = ImmutableArray.CreateRange(collection.Select(c => validator.GetValueAsync(c).Result)); + Children = [.. collection.Select(c => validator.GetValueAsync(c).Result)]; } public int Count => Children.Length; diff --git a/src/VisualStudio/Core/Test.Next/Roslyn.VisualStudio.Next.UnitTests.csproj b/src/VisualStudio/Core/Test.Next/Roslyn.VisualStudio.Next.UnitTests.csproj index 0da9a5230befa..ffd478efc1217 100644 --- a/src/VisualStudio/Core/Test.Next/Roslyn.VisualStudio.Next.UnitTests.csproj +++ b/src/VisualStudio/Core/Test.Next/Roslyn.VisualStudio.Next.UnitTests.csproj @@ -66,5 +66,13 @@ + + + + + + + + \ No newline at end of file diff --git a/src/VisualStudio/Core/Test.Next/Services/AssetProviderTests.cs b/src/VisualStudio/Core/Test.Next/Services/AssetProviderTests.cs index dedc0e4e8c2a1..06f61fddcb5f2 100644 --- a/src/VisualStudio/Core/Test.Next/Services/AssetProviderTests.cs +++ b/src/VisualStudio/Core/Test.Next/Services/AssetProviderTests.cs @@ -172,7 +172,7 @@ public async Task TestAssetArrayOrdering() var stateChecksums = await project.State.GetStateChecksumsAsync(CancellationToken.None); var textChecksums = stateChecksums.Documents.TextChecksums; - var textChecksumsReversed = new ChecksumCollection(textChecksums.Children.Reverse().ToImmutableArray()); + var textChecksumsReversed = new ChecksumCollection([.. textChecksums.Children.Reverse()]); var documents = await service.GetAssetsArrayAsync( AssetPath.FullLookupForTesting, textChecksums, CancellationToken.None); diff --git a/src/VisualStudio/Core/Test.Next/Services/ServiceHubServicesTests.cs b/src/VisualStudio/Core/Test.Next/Services/ServiceHubServicesTests.cs index fd9622f9ae376..2626d6f12bbf8 100644 --- a/src/VisualStudio/Core/Test.Next/Services/ServiceHubServicesTests.cs +++ b/src/VisualStudio/Core/Test.Next/Services/ServiceHubServicesTests.cs @@ -381,7 +381,7 @@ void DoPermute(int start, int end) { // We have one of our possible n! solutions, // add it to the list. - result.Add(values.ToImmutableArray()); + result.Add([.. values]); } else { @@ -523,8 +523,8 @@ public async Task InProcAndRemoteWorkspaceAgree2() { var sourceText = CreateText(Guid.NewGuid().ToString()); await TestInProcAndRemoteWorkspace( - ImmutableArray.Create(("SG.cs", sourceText)), - ImmutableArray.Create(("SG.cs", sourceText))); + [("SG.cs", sourceText)], + [("SG.cs", sourceText)]); } [Fact] @@ -532,24 +532,24 @@ public async Task InProcAndRemoteWorkspaceAgree3() { var sourceText = Guid.NewGuid().ToString(); await TestInProcAndRemoteWorkspace( - ImmutableArray.Create(("SG.cs", CreateText(sourceText))), - ImmutableArray.Create(("SG.cs", CreateText(sourceText)))); + [("SG.cs", CreateText(sourceText))], + [("SG.cs", CreateText(sourceText))]); } [Fact] public async Task InProcAndRemoteWorkspaceAgree4() { await TestInProcAndRemoteWorkspace( - ImmutableArray.Create(("SG.cs", CreateText(Guid.NewGuid().ToString()))), - ImmutableArray.Create(("SG.cs", CreateText(Guid.NewGuid().ToString())))); + [("SG.cs", CreateText(Guid.NewGuid().ToString()))], + [("SG.cs", CreateText(Guid.NewGuid().ToString()))]); } [Fact] public async Task InProcAndRemoteWorkspaceAgree5() { await TestInProcAndRemoteWorkspace( - ImmutableArray.Create(("SG.cs", CreateText(Guid.NewGuid().ToString()))), - ImmutableArray.Create(("NewName.cs", CreateText(Guid.NewGuid().ToString())))); + [("SG.cs", CreateText(Guid.NewGuid().ToString()))], + [("NewName.cs", CreateText(Guid.NewGuid().ToString()))]); } [Fact] @@ -557,8 +557,8 @@ public async Task InProcAndRemoteWorkspaceAgree6() { var sourceText = CreateText(Guid.NewGuid().ToString()); await TestInProcAndRemoteWorkspace( - ImmutableArray.Create(("SG.cs", sourceText)), - ImmutableArray.Create(("NewName.cs", sourceText))); + [("SG.cs", sourceText)], + [("NewName.cs", sourceText)]); } [Fact] @@ -566,48 +566,48 @@ public async Task InProcAndRemoteWorkspaceAgree7() { var sourceText = Guid.NewGuid().ToString(); await TestInProcAndRemoteWorkspace( - ImmutableArray.Create(("SG.cs", CreateText(sourceText))), - ImmutableArray.Create(("NewName.cs", CreateText(sourceText)))); + [("SG.cs", CreateText(sourceText))], + [("NewName.cs", CreateText(sourceText))]); } [Fact] public async Task InProcAndRemoteWorkspaceAgree8() { await TestInProcAndRemoteWorkspace( - ImmutableArray.Create(("SG.cs", CreateText(Guid.NewGuid().ToString()))), - ImmutableArray.Create(("NewName.cs", CreateText(Guid.NewGuid().ToString())))); + [("SG.cs", CreateText(Guid.NewGuid().ToString()))], + [("NewName.cs", CreateText(Guid.NewGuid().ToString()))]); } [Fact] public async Task InProcAndRemoteWorkspaceAgree9() { await TestInProcAndRemoteWorkspace( - ImmutableArray.Create(("SG.cs", CreateText("X", Encoding.ASCII))), - ImmutableArray.Create(("SG.cs", CreateText("X", Encoding.UTF8)))); + [("SG.cs", CreateText("X", Encoding.ASCII))], + [("SG.cs", CreateText("X", Encoding.UTF8))]); } [Fact] public async Task InProcAndRemoteWorkspaceAgree10() { await TestInProcAndRemoteWorkspace( - ImmutableArray.Create(("SG.cs", CreateText("X", Encoding.UTF8, checksumAlgorithm: SourceHashAlgorithm.Sha1))), - ImmutableArray.Create(("SG.cs", CreateText("X", Encoding.UTF8, checksumAlgorithm: SourceHashAlgorithm.Sha256)))); + [("SG.cs", CreateText("X", Encoding.UTF8, checksumAlgorithm: SourceHashAlgorithm.Sha1))], + [("SG.cs", CreateText("X", Encoding.UTF8, checksumAlgorithm: SourceHashAlgorithm.Sha256))]); } [Fact] public async Task InProcAndRemoteWorkspaceAgree11() { await TestInProcAndRemoteWorkspace( - ImmutableArray.Create(("SG.cs", CreateText(Guid.NewGuid().ToString()))), - ImmutableArray<(string, SourceText)>.Empty); + [("SG.cs", CreateText(Guid.NewGuid().ToString()))], + []); } [Fact] public async Task InProcAndRemoteWorkspaceAgree12() { await TestInProcAndRemoteWorkspace( - ImmutableArray<(string, SourceText)>.Empty, - ImmutableArray.Create(("SG.cs", CreateText(Guid.NewGuid().ToString())))); + [], + [("SG.cs", CreateText(Guid.NewGuid().ToString()))]); } [Fact] @@ -615,8 +615,8 @@ public async Task InProcAndRemoteWorkspaceAgree13() { var contents = Guid.NewGuid().ToString(); await TestInProcAndRemoteWorkspace( - ImmutableArray.Create(("SG.cs", CreateText(contents))), - ImmutableArray.Create(("SG.cs", CreateText(contents)), ("SG1.cs", CreateText(contents)))); + [("SG.cs", CreateText(contents))], + [("SG.cs", CreateText(contents)), ("SG1.cs", CreateText(contents))]); } [Fact] @@ -624,8 +624,8 @@ public async Task InProcAndRemoteWorkspaceAgree14() { var contents = Guid.NewGuid().ToString(); await TestInProcAndRemoteWorkspace( - ImmutableArray.Create(("SG.cs", CreateText(contents))), - ImmutableArray.Create(("SG.cs", CreateText(contents)), ("SG1.cs", CreateText("Other")))); + [("SG.cs", CreateText(contents))], + [("SG.cs", CreateText(contents)), ("SG1.cs", CreateText("Other"))]); } [Fact] @@ -633,8 +633,8 @@ public async Task InProcAndRemoteWorkspaceAgree15() { var contents = Guid.NewGuid().ToString(); await TestInProcAndRemoteWorkspace( - ImmutableArray.Create(("SG.cs", CreateText(contents))), - ImmutableArray.Create(("SG1.cs", CreateText(contents)), ("SG.cs", CreateText("Other")))); + [("SG.cs", CreateText(contents))], + [("SG1.cs", CreateText(contents)), ("SG.cs", CreateText("Other"))]); } [Fact] @@ -642,8 +642,8 @@ public async Task InProcAndRemoteWorkspaceAgree16() { var contents = Guid.NewGuid().ToString(); await TestInProcAndRemoteWorkspace( - ImmutableArray.Create(("SG.cs", CreateText(contents))), - ImmutableArray.Create(("SG1.cs", CreateText("Other")), ("SG.cs", CreateText(contents)))); + [("SG.cs", CreateText(contents))], + [("SG1.cs", CreateText("Other")), ("SG.cs", CreateText(contents))]); } [Fact] @@ -651,9 +651,9 @@ public async Task InProcAndRemoteWorkspaceAgree17() { var contents = Guid.NewGuid().ToString(); await TestInProcAndRemoteWorkspace( - ImmutableArray.Create(("SG.cs", CreateText(contents))), - ImmutableArray.Create(("SG1.cs", CreateText("Other")), ("SG.cs", CreateText(contents))), - ImmutableArray<(string, SourceText)>.Empty); + [("SG.cs", CreateText(contents))], + [("SG1.cs", CreateText("Other")), ("SG.cs", CreateText(contents))], + []); } [Fact] @@ -669,8 +669,8 @@ public async Task InProcAndRemoteWorkspaceAgree19() { var contents = CreateText(Guid.NewGuid().ToString()); await TestInProcAndRemoteWorkspace( - ImmutableArray.Create(("SG1.cs", contents), ("SG2.cs", contents)), - ImmutableArray.Create(("SG2.cs", contents), ("SG1.cs", contents))); + [("SG1.cs", contents), ("SG2.cs", contents)], + [("SG2.cs", contents), ("SG1.cs", contents)]); } [Fact] @@ -678,8 +678,8 @@ public async Task InProcAndRemoteWorkspaceAgree20() { var contents = Guid.NewGuid().ToString(); await TestInProcAndRemoteWorkspace( - ImmutableArray.Create(("SG1.cs", CreateText(contents)), ("SG2.cs", CreateText(contents))), - ImmutableArray.Create(("SG2.cs", CreateText(contents)), ("SG1.cs", CreateText(contents)))); + [("SG1.cs", CreateText(contents)), ("SG2.cs", CreateText(contents))], + [("SG2.cs", CreateText(contents)), ("SG1.cs", CreateText(contents))]); } [Theory, CombinatorialData] @@ -688,8 +688,8 @@ public async Task InProcAndRemoteWorkspaceAgree21( { var contents = Guid.NewGuid().ToString(); await TestInProcAndRemoteWorkspace( - ImmutableArray.Create(("SG.cs", CreateStreamText(contents, useBOM: useBOM1, useMemoryStream: useMemoryStream1))), - ImmutableArray.Create(("SG.cs", CreateStreamText(contents, useBOM: useBOM2, useMemoryStream: useMemoryStream2)))); + [("SG.cs", CreateStreamText(contents, useBOM: useBOM1, useMemoryStream: useMemoryStream1))], + [("SG.cs", CreateStreamText(contents, useBOM: useBOM2, useMemoryStream: useMemoryStream2))]); } [PartNotDiscoverable] diff --git a/src/VisualStudio/Core/Test.Next/Services/SolutionServiceTests.cs b/src/VisualStudio/Core/Test.Next/Services/SolutionServiceTests.cs index e74b1d5764919..80ffa6718ef66 100644 --- a/src/VisualStudio/Core/Test.Next/Services/SolutionServiceTests.cs +++ b/src/VisualStudio/Core/Test.Next/Services/SolutionServiceTests.cs @@ -369,7 +369,7 @@ public async Task TestAnalyzerConfigDocument() await VerifySolutionUpdate(workspace, s => { - return s.AddAnalyzerConfigDocuments(ImmutableArray.Create(analyzerConfigDocumentInfo)); + return s.AddAnalyzerConfigDocuments([analyzerConfigDocumentInfo]); }); workspace.OnAnalyzerConfigDocumentAdded(analyzerConfigDocumentInfo); diff --git a/src/VisualStudio/Core/Test.Next/Services/VisualStudioDiagnosticAnalyzerExecutorTests.cs b/src/VisualStudio/Core/Test.Next/Services/VisualStudioDiagnosticAnalyzerExecutorTests.cs index e916795d62c0e..b5c05e9dfb7c7 100644 --- a/src/VisualStudio/Core/Test.Next/Services/VisualStudioDiagnosticAnalyzerExecutorTests.cs +++ b/src/VisualStudio/Core/Test.Next/Services/VisualStudioDiagnosticAnalyzerExecutorTests.cs @@ -162,7 +162,7 @@ void Method() var compilationWithAnalyzers = new CompilationWithAnalyzersPair( projectCompilationWithAnalyzers: null, (await project.GetCompilationAsync()).WithAnalyzers( - analyzerReference.GetAnalyzers(project.Language).Where(a => a.GetType() == analyzerType).ToImmutableArray(), + [.. analyzerReference.GetAnalyzers(project.Language).Where(a => a.GetType() == analyzerType)], project.AnalyzerOptions)); var result = await runner.AnalyzeProjectAsync(project, compilationWithAnalyzers, logPerformanceInfo: false, getTelemetryInfo: false, cancellationToken: CancellationToken.None); @@ -233,7 +233,7 @@ private static async Task AnalyzeAsync(TestWorkspace w } var compilationWithAnalyzers = (await project.GetCompilationAsync()).WithAnalyzers( - analyzerReference.GetAnalyzers(project.Language).Where(a => a.GetType() == analyzerType).ToImmutableArray(), + [.. analyzerReference.GetAnalyzers(project.Language).Where(a => a.GetType() == analyzerType)], project.AnalyzerOptions); var analyzerDriver = isHostAnalyzer ? new CompilationWithAnalyzersPair(projectCompilationWithAnalyzers: null, compilationWithAnalyzers) @@ -263,7 +263,7 @@ private static TestWorkspace CreateWorkspace(string language, string code, Parse private class MyAnalyzer : DiagnosticAnalyzer { private readonly ImmutableArray _supportedDiagnostics = - ImmutableArray.Create(new DiagnosticDescriptor("test", "test", "test", "test", DiagnosticSeverity.Error, isEnabledByDefault: true)); + [new DiagnosticDescriptor("test", "test", "test", "test", DiagnosticSeverity.Error, isEnabledByDefault: true)]; public override ImmutableArray SupportedDiagnostics => _supportedDiagnostics; @@ -283,7 +283,7 @@ public override void Initialize(AnalysisContext context) private class DuplicateAnalyzer : DiagnosticAnalyzer { private readonly ImmutableArray _supportedDiagnostics = - ImmutableArray.Create(new DiagnosticDescriptor("test", "test", "test", "test", DiagnosticSeverity.Error, isEnabledByDefault: true)); + [new DiagnosticDescriptor("test", "test", "test", "test", DiagnosticSeverity.Error, isEnabledByDefault: true)]; public override ImmutableArray SupportedDiagnostics => _supportedDiagnostics; diff --git a/src/VisualStudio/Core/Test.Next/UnifiedSettings/TestModel/AlternativeDefault.cs b/src/VisualStudio/Core/Test.Next/UnifiedSettings/TestModel/AlternativeDefault.cs new file mode 100644 index 0000000000000..dc5de0685dd5d --- /dev/null +++ b/src/VisualStudio/Core/Test.Next/UnifiedSettings/TestModel/AlternativeDefault.cs @@ -0,0 +1,34 @@ +// 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.Text.Json.Serialization; +using Microsoft.CodeAnalysis.Options; +using Xunit; +using static Microsoft.VisualStudio.LanguageServices.Options.VisualStudioOptionStorage; + +namespace Roslyn.VisualStudio.Next.UnitTests.UnifiedSettings.TestModel; + +internal record AlternativeDefault +{ + [JsonPropertyName("flagName")] + public string FlagName { get; init; } + + [JsonPropertyName("default")] + public T Default { get; init; } + + [JsonConstructor] + public AlternativeDefault(string flagName, T @default) + { + FlagName = flagName; + Default = @default; + } + + public AlternativeDefault(IOption2 featureFlagOption, T defaultValue) + { + var optionStorage = Storages[featureFlagOption.Definition.ConfigName]; + Assert.IsType(optionStorage); + FlagName = ((FeatureFlagStorage)optionStorage).FlagName; + Default = defaultValue; + } +} diff --git a/src/VisualStudio/Core/Test.Next/UnifiedSettings/TestModel/Category.cs b/src/VisualStudio/Core/Test.Next/UnifiedSettings/TestModel/Category.cs new file mode 100644 index 0000000000000..7a95b5ccdf052 --- /dev/null +++ b/src/VisualStudio/Core/Test.Next/UnifiedSettings/TestModel/Category.cs @@ -0,0 +1,17 @@ +// 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.Text.Json.Serialization; + +namespace Roslyn.VisualStudio.Next.UnitTests.UnifiedSettings.TestModel; + +internal record Category +{ + [JsonPropertyName("title")] + [JsonConverter(typeof(ResourceStringConverter))] + public required string Title { get; init; } + + [JsonPropertyName("legacyOptionPageId")] + public string? LegacyOptionPageId { get; init; } +} diff --git a/src/VisualStudio/Core/Test.Next/UnifiedSettings/TestModel/EnumIntegerToString.cs b/src/VisualStudio/Core/Test.Next/UnifiedSettings/TestModel/EnumIntegerToString.cs new file mode 100644 index 0000000000000..f9a91a8ed2c35 --- /dev/null +++ b/src/VisualStudio/Core/Test.Next/UnifiedSettings/TestModel/EnumIntegerToString.cs @@ -0,0 +1,34 @@ +// 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.Linq; +using System.Text.Json.Serialization; +using Roslyn.Utilities; + +namespace Roslyn.VisualStudio.Next.UnitTests.UnifiedSettings.TestModel; + +internal record EnumIntegerToString +{ + [JsonPropertyName("input")] + public required Input Input { get; init; } + + [JsonPropertyName("map")] + public required Map[] Map { get; init; } + + public virtual bool Equals(EnumIntegerToString? other) + { + if (other is null) + return false; + + if (ReferenceEquals(this, other)) + return true; + + return Input.Equals(other.Input) && Map.SequenceEqual(other.Map); + } + + public override int GetHashCode() + { + return Hash.Combine(Input.GetHashCode(), Hash.CombineValues(Map)); + } +} diff --git a/src/VisualStudio/Core/Test.Next/UnifiedSettings/TestModel/Input.cs b/src/VisualStudio/Core/Test.Next/UnifiedSettings/TestModel/Input.cs new file mode 100644 index 0000000000000..fd4cb12b0bb53 --- /dev/null +++ b/src/VisualStudio/Core/Test.Next/UnifiedSettings/TestModel/Input.cs @@ -0,0 +1,64 @@ +// 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.Text.Json.Serialization; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Options; +using Roslyn.Utilities; +using Xunit; +using static Microsoft.VisualStudio.LanguageServices.Options.VisualStudioOptionStorage; + +namespace Roslyn.VisualStudio.Next.UnitTests.UnifiedSettings.TestModel; + +internal record Input +{ + [JsonPropertyName("store")] + public string Store { get; init; } + + [JsonPropertyName("path")] + public string Path { get; init; } + + [JsonConstructor] + public Input(string store, string path) + { + Store = store; + Path = path; + } + + public Input(IOption2 option, string? languageName = null) + { + Assert.False(option is IPerLanguageValuedOption && languageName is null); + Store = GetStore(option); + Path = GetPath(option, languageName); + } + + private static string GetStore(IOption2 option) + { + var optionStorage = Storages[option.Definition.ConfigName]; + return optionStorage switch + { + RoamingProfileStorage => "SettingsManager", + LocalUserProfileStorage => "VsUserSettingsRegistry", + _ => throw ExceptionUtilities.Unreachable() + }; + } + + private static string GetPath(IOption2 option, string? languageName) + { + var languageId = languageName switch + { + LanguageNames.CSharp => "CSharp", + LanguageNames.VisualBasic => "VisualBasic", + _ => string.Empty, + }; + + var optionStorage = Storages[option.Definition.ConfigName]; + return optionStorage switch + { + RoamingProfileStorage roamingProfile => roamingProfile.Key.Replace("%LANGUAGE%", languageId), + LocalUserProfileStorage userProfileStorage => $"{userProfileStorage.Path}\\{userProfileStorage.Key}", + _ => throw ExceptionUtilities.UnexpectedValue(option) + }; + } +} diff --git a/src/VisualStudio/Core/Test.Next/UnifiedSettings/TestModel/Map.cs b/src/VisualStudio/Core/Test.Next/UnifiedSettings/TestModel/Map.cs new file mode 100644 index 0000000000000..a6af5630d81ad --- /dev/null +++ b/src/VisualStudio/Core/Test.Next/UnifiedSettings/TestModel/Map.cs @@ -0,0 +1,16 @@ +// 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.Text.Json.Serialization; + +namespace Roslyn.VisualStudio.Next.UnitTests.UnifiedSettings.TestModel; + +internal record Map +{ + [JsonPropertyName("result")] + public required string Result { get; init; } + + [JsonPropertyName("match")] + public required int Match { get; init; } +} diff --git a/src/VisualStudio/Core/Test.Next/UnifiedSettings/TestModel/Message.cs b/src/VisualStudio/Core/Test.Next/UnifiedSettings/TestModel/Message.cs new file mode 100644 index 0000000000000..2f593b9f5fd08 --- /dev/null +++ b/src/VisualStudio/Core/Test.Next/UnifiedSettings/TestModel/Message.cs @@ -0,0 +1,14 @@ +// 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.Text.Json.Serialization; + +namespace Roslyn.VisualStudio.Next.UnitTests.UnifiedSettings.TestModel; + +internal record Message +{ + [JsonPropertyName("text")] + [JsonConverter(typeof(ResourceStringConverter))] + public required string Text { get; init; } +} diff --git a/src/VisualStudio/Core/Test.Next/UnifiedSettings/TestModel/Migration.cs b/src/VisualStudio/Core/Test.Next/UnifiedSettings/TestModel/Migration.cs new file mode 100644 index 0000000000000..4ec36efb078ec --- /dev/null +++ b/src/VisualStudio/Core/Test.Next/UnifiedSettings/TestModel/Migration.cs @@ -0,0 +1,17 @@ +// 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.Text.Json.Serialization; + +namespace Roslyn.VisualStudio.Next.UnitTests.UnifiedSettings.TestModel; + +internal record Migration +{ + [JsonPropertyName("pass")] + public Pass? Pass { get; init; } + + [JsonPropertyName("enumIntegerToString")] + public EnumIntegerToString? EnumIntegerToString { get; init; } +} + diff --git a/src/VisualStudio/Core/Test.Next/UnifiedSettings/TestModel/Pass.cs b/src/VisualStudio/Core/Test.Next/UnifiedSettings/TestModel/Pass.cs new file mode 100644 index 0000000000000..a5681b04da612 --- /dev/null +++ b/src/VisualStudio/Core/Test.Next/UnifiedSettings/TestModel/Pass.cs @@ -0,0 +1,13 @@ +// 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.Text.Json.Serialization; + +namespace Roslyn.VisualStudio.Next.UnitTests.UnifiedSettings.TestModel; + +internal record Pass +{ + [JsonPropertyName("input")] + public required Input Input { get; init; } +} diff --git a/src/VisualStudio/Core/Test.Next/UnifiedSettings/TestModel/ResourceStringArrayConverter.cs b/src/VisualStudio/Core/Test.Next/UnifiedSettings/TestModel/ResourceStringArrayConverter.cs new file mode 100644 index 0000000000000..49121b16e7931 --- /dev/null +++ b/src/VisualStudio/Core/Test.Next/UnifiedSettings/TestModel/ResourceStringArrayConverter.cs @@ -0,0 +1,43 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Text.Json; +using System.Text.Json.Serialization; +using Microsoft.CodeAnalysis.PooledObjects; + +namespace Roslyn.VisualStudio.Next.UnitTests.UnifiedSettings.TestModel; + +internal class ResourceStringArrayConverter : JsonConverter +{ + public override string[] Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + if (reader.TokenType != JsonTokenType.StartArray) + throw new JsonException("Expected StartArray token"); + + using var _ = ArrayBuilder.GetInstance(out var builder); + while (reader.Read()) + { + if (reader.TokenType == JsonTokenType.EndArray) + break; + + if (reader.TokenType == JsonTokenType.String) + { + var value = reader.GetString()!; + builder.Add(Utilities.EvalResource(value)!); + } + else + { + throw new JsonException("Token should be string"); + } + } + + return builder.ToArray(); + } + + public override void Write(Utf8JsonWriter writer, string[] value, JsonSerializerOptions options) + { + throw new NotImplementedException(); + } +} diff --git a/src/VisualStudio/Core/Test.Next/UnifiedSettings/TestModel/ResourceStringConverter.cs b/src/VisualStudio/Core/Test.Next/UnifiedSettings/TestModel/ResourceStringConverter.cs new file mode 100644 index 0000000000000..403f6904347db --- /dev/null +++ b/src/VisualStudio/Core/Test.Next/UnifiedSettings/TestModel/ResourceStringConverter.cs @@ -0,0 +1,27 @@ +// 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.Text.Json; +using System.Text.Json.Serialization; + +namespace Roslyn.VisualStudio.Next.UnitTests.UnifiedSettings.TestModel; +internal class ResourceStringConverter : JsonConverter +{ + public override string? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + if (reader.TokenType == JsonTokenType.String) + { + var locReference = reader.GetString()!; + return Utilities.EvalResource(locReference); + } + + throw new NotImplementedException(); + } + + public override void Write(Utf8JsonWriter writer, string value, JsonSerializerOptions options) + { + throw new NotImplementedException(); + } +} diff --git a/src/VisualStudio/Core/Test.Next/UnifiedSettings/TestModel/UnifiedSettingBase.cs b/src/VisualStudio/Core/Test.Next/UnifiedSettings/TestModel/UnifiedSettingBase.cs new file mode 100644 index 0000000000000..9528726891695 --- /dev/null +++ b/src/VisualStudio/Core/Test.Next/UnifiedSettings/TestModel/UnifiedSettingBase.cs @@ -0,0 +1,63 @@ +// 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.Linq; +using System.Text.Json.Serialization; +using Roslyn.Utilities; + +namespace Roslyn.VisualStudio.Next.UnitTests.UnifiedSettings.TestModel; + +internal abstract record UnifiedSettingBase +{ + [JsonPropertyName("title")] + [JsonConverter(typeof(ResourceStringConverter))] + public required string Title { get; init; } + + [JsonPropertyName("type")] + public required string Type { get; init; } + + [JsonPropertyName("order")] + public required int Order { get; init; } + + [JsonPropertyName("enableWhen")] + public string? EnableWhen { get; init; } + + [JsonPropertyName("migration")] + public required Migration Migration { get; init; } + + [JsonPropertyName("messages")] + public Message[]? Messages { get; init; } + + public virtual bool Equals(UnifiedSettingBase? other) + { + if (other is null) + { + return false; + } + + if (ReferenceEquals(this, other)) + { + return true; + } + + if (Title != other.Title + || Type != other.Type + || Order != other.Order + || EnableWhen != other.EnableWhen + || !Migration.Equals(other.Migration)) + { + return false; + } + + if (Messages is not null && other.Messages is not null) + { + return Messages.SequenceEqual(other.Messages); + } + + return true; + } + + public override int GetHashCode() + => Hash.Combine(Hash.Combine(Hash.Combine(Hash.Combine(Hash.Combine(Title.GetHashCode(), Type.GetHashCode()), Order.GetHashCode()), EnableWhen?.GetHashCode() ?? 0), Migration.GetHashCode()), Messages is null ? 0 : Hash.CombineValues(Messages)); +} diff --git a/src/VisualStudio/Core/Test.Next/UnifiedSettings/TestModel/UnifiedSettingsEnumOption.cs b/src/VisualStudio/Core/Test.Next/UnifiedSettings/TestModel/UnifiedSettingsEnumOption.cs new file mode 100644 index 0000000000000..7f6a904166f36 --- /dev/null +++ b/src/VisualStudio/Core/Test.Next/UnifiedSettings/TestModel/UnifiedSettingsEnumOption.cs @@ -0,0 +1,35 @@ +// 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.Linq; +using System.Text.Json.Serialization; +using Roslyn.Utilities; + +namespace Roslyn.VisualStudio.Next.UnitTests.UnifiedSettings.TestModel; + +internal record UnifiedSettingsEnumOption : UnifiedSettingsOption +{ + [JsonPropertyName("enum")] + public required string[] @Enum { get; init; } + + [JsonPropertyName("enumItemLabels")] + [JsonConverter(typeof(ResourceStringArrayConverter))] + public required string[] EnumItemLabels { get; init; } + + public virtual bool Equals(UnifiedSettingsEnumOption? other) + { + if (other is null) + return false; + + if (ReferenceEquals(this, other)) + return true; + + return base.Equals(other) && @Enum.SequenceEqual(other.@Enum) && EnumItemLabels.SequenceEqual(other.EnumItemLabels); + } + + public override int GetHashCode() + { + return Hash.Combine(Hash.Combine(base.GetHashCode(), Hash.CombineValues(@Enum)), Hash.CombineValues(EnumItemLabels)); + } +} diff --git a/src/VisualStudio/Core/Test.Next/UnifiedSettings/TestModel/UnifiedSettingsOption.cs b/src/VisualStudio/Core/Test.Next/UnifiedSettings/TestModel/UnifiedSettingsOption.cs new file mode 100644 index 0000000000000..78b7d80ba7752 --- /dev/null +++ b/src/VisualStudio/Core/Test.Next/UnifiedSettings/TestModel/UnifiedSettingsOption.cs @@ -0,0 +1,16 @@ +// 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.Text.Json.Serialization; + +namespace Roslyn.VisualStudio.Next.UnitTests.UnifiedSettings.TestModel; + +internal record UnifiedSettingsOption : UnifiedSettingBase +{ + [JsonPropertyName("default")] + public required T Default { get; init; } + + [JsonPropertyName("alternateDefault")] + public AlternativeDefault? AlternateDefault { get; init; } +} diff --git a/src/VisualStudio/Core/Test.Next/UnifiedSettings/TestModel/Utilities.cs b/src/VisualStudio/Core/Test.Next/UnifiedSettings/TestModel/Utilities.cs new file mode 100644 index 0000000000000..01a816265e1c2 --- /dev/null +++ b/src/VisualStudio/Core/Test.Next/UnifiedSettings/TestModel/Utilities.cs @@ -0,0 +1,54 @@ +// 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.Globalization; +using Microsoft.VisualStudio.LanguageServices; +using Microsoft.VisualStudio.LanguageServices.CSharp; +using Roslyn.Utilities; +using CSharpPackage = Microsoft.VisualStudio.LanguageServices.CSharp.VSPackage; +using VisualBasicPackage = Microsoft.VisualStudio.LanguageServices.VisualBasic.VSPackage; + +namespace Roslyn.VisualStudio.Next.UnitTests.UnifiedSettings.TestModel; + +internal static class Utilities +{ + private const string CSharpLanguageServiceDllName = "Microsoft.VisualStudio.LanguageServices.CSharp.dll"; + + private const string VisualBasicLanguageServiceDllName = "Microsoft.VisualStudio.LanguageServices.VisualBasic.dll"; + + private const string LanguageServiceDllName = "Microsoft.VisualStudio.LanguageServices.dll"; + + public static string? EvalResource(string resourceReference) + { + // Start with 1 because to skip @ at the beginning, like @Show_completion_item_filters + var resourcesIdentifier = resourceReference.Substring(1, resourceReference.IndexOf(";") - 1); + var resources = resourceReference[(resourceReference.IndexOf(";") + 1)..]; + var culture = new CultureInfo("en"); + if (Guid.TryParse(resources, out var packageGuid)) + { + if (packageGuid.Equals(Guids.CSharpPackageId)) + { + return CSharpPackage.ResourceManager.GetString(resourcesIdentifier, culture); + } + else if (packageGuid.Equals(Guids.VisualBasicPackageId)) + { + return VisualBasicPackage.ResourceManager.GetString(resourcesIdentifier, culture); + } + else + { + throw ExceptionUtilities.Unreachable(); + } + } + + var resourceDll = resourceReference[(resourceReference.IndexOf("\\") + 1)..]; + return resourceDll switch + { + CSharpLanguageServiceDllName => CSharpVSResources.ResourceManager.GetString(resourcesIdentifier, culture), + VisualBasicLanguageServiceDllName => VisualBasicPackage.ResourceManager.GetString(resourcesIdentifier, culture), + LanguageServiceDllName => ServicesVSResources.ResourceManager.GetString(resourcesIdentifier, culture), + _ => throw ExceptionUtilities.UnexpectedValue(resourceDll) + }; + } +} diff --git a/src/VisualStudio/Core/Test.Next/UnifiedSettings/UnifiedSettingsTests.cs b/src/VisualStudio/Core/Test.Next/UnifiedSettings/UnifiedSettingsTests.cs new file mode 100644 index 0000000000000..37eeb37486dd6 --- /dev/null +++ b/src/VisualStudio/Core/Test.Next/UnifiedSettings/UnifiedSettingsTests.cs @@ -0,0 +1,411 @@ +// 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.IO; +using System.IO.Hashing; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Text.Json; +using System.Text.Json.Nodes; +using System.Text.RegularExpressions; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Completion; +using Microsoft.CodeAnalysis.Editor.CSharp.CompleteStatement; +using Microsoft.CodeAnalysis.Options; +using Microsoft.VisualStudio.LanguageServices; +using Roslyn.Utilities; +using Roslyn.VisualStudio.Next.UnitTests.UnifiedSettings.TestModel; +using Xunit; + +namespace Roslyn.VisualStudio.Next.UnitTests.UnifiedSettings; + +public class UnifiedSettingsTests +{ + #region CSharpTest + /// + /// Dictionary containing the option to unified setting path for C#. + /// + private static readonly ImmutableDictionary s_csharpUnifiedSettingsStorage = ImmutableDictionary.Empty. + Add(CompletionOptionsStorage.TriggerOnTypingLetters, "textEditor.csharp.intellisense.triggerCompletionOnTypingLetters"). + Add(CompletionOptionsStorage.TriggerOnDeletion, "textEditor.csharp.intellisense.triggerCompletionOnDeletion"). + Add(CompletionOptionsStorage.TriggerInArgumentLists, "textEditor.csharp.intellisense.triggerCompletionInArgumentLists"). + Add(CompletionViewOptionsStorage.HighlightMatchingPortionsOfCompletionListItems, "textEditor.csharp.intellisense.highlightMatchingPortionsOfCompletionListItems"). + Add(CompletionViewOptionsStorage.ShowCompletionItemFilters, "textEditor.csharp.intellisense.showCompletionItemFilters"). + Add(CompleteStatementOptionsStorage.AutomaticallyCompleteStatementOnSemicolon, "textEditor.csharp.intellisense.completeStatementOnSemicolon"). + Add(CompletionOptionsStorage.SnippetsBehavior, "textEditor.csharp.intellisense.snippetsBehavior"). + Add(CompletionOptionsStorage.EnterKeyBehavior, "textEditor.csharp.intellisense.returnKeyCompletionBehavior"). + Add(CompletionOptionsStorage.ShowNameSuggestions, "textEditor.csharp.intellisense.showNameCompletionSuggestions"). + Add(CompletionOptionsStorage.ShowItemsFromUnimportedNamespaces, "textEditor.csharp.intellisense.showCompletionItemsFromUnimportedNamespaces"). + Add(CompletionViewOptionsStorage.EnableArgumentCompletionSnippets, "textEditor.csharp.intellisense.enableArgumentCompletionSnippets"). + Add(CompletionOptionsStorage.ShowNewSnippetExperienceUserOption, "textEditor.csharp.intellisense.showNewSnippetExperience"); + + /// + /// Array containing the option to expected unified settings for C# intellisense page. + /// + private static readonly ImmutableArray<(IOption2, UnifiedSettingBase)> s_csharpIntellisenseExpectedSettings = + [ + (CompletionOptionsStorage.TriggerOnTypingLetters, CreateBooleanOption( + CompletionOptionsStorage.TriggerOnTypingLetters, + title: "Show completion list after a character is typed", + order: 0, + languageName: LanguageNames.CSharp)), + (CompletionOptionsStorage.TriggerOnDeletion, CreateBooleanOption( + CompletionOptionsStorage.TriggerOnDeletion, + title: "Show completion list after a character is deleted", + order: 1, + customDefaultValue: false, + enableWhenOptionAndValue: (enableWhenOption: CompletionOptionsStorage.TriggerOnTypingLetters, whenValue: true), + languageName: LanguageNames.CSharp)), + (CompletionOptionsStorage.TriggerInArgumentLists, CreateBooleanOption( + CompletionOptionsStorage.TriggerInArgumentLists, + title: "Automatically show completion list in argument lists", + order: 10, + languageName: LanguageNames.CSharp)), + (CompletionViewOptionsStorage.HighlightMatchingPortionsOfCompletionListItems, CreateBooleanOption( + CompletionViewOptionsStorage.HighlightMatchingPortionsOfCompletionListItems, + "Highlight matching portions of completion list items", + order: 20, + languageName: LanguageNames.CSharp)), + (CompletionViewOptionsStorage.ShowCompletionItemFilters, CreateBooleanOption( + CompletionViewOptionsStorage.ShowCompletionItemFilters, + title: "Show completion item filters", + order: 30, + languageName: LanguageNames.CSharp)), + (CompleteStatementOptionsStorage.AutomaticallyCompleteStatementOnSemicolon, CreateBooleanOption( + CompleteStatementOptionsStorage.AutomaticallyCompleteStatementOnSemicolon, + title: "Automatically complete statement on semicolon", + order: 40, + languageName: LanguageNames.CSharp)), + (CompletionOptionsStorage.SnippetsBehavior, CreateEnumOption( + CompletionOptionsStorage.SnippetsBehavior, + "Snippets behavior", + order: 50, + customDefaultValue: SnippetsRule.AlwaysInclude, + enumLabels: ["Never include snippets", "Always include snippets", "Include snippets when ?-Tab is typed after an identifier"], + enumValues: [SnippetsRule.NeverInclude, SnippetsRule.AlwaysInclude, SnippetsRule.IncludeAfterTypingIdentifierQuestionTab], + customMaps: [new Map { Result = "neverInclude", Match = 1 }, new Map { Result = "alwaysInclude", Match = 2 }, new Map { Result = "alwaysInclude", Match = 0 }, new Map { Result = "includeAfterTypingIdentifierQuestionTab", Match = 3 }], + languageName: LanguageNames.CSharp)), + (CompletionOptionsStorage.EnterKeyBehavior, CreateEnumOption( + CompletionOptionsStorage.EnterKeyBehavior, + "Enter key behavior", + order: 60, + customDefaultValue: EnterKeyRule.Never, + enumLabels: ["Never add new line on enter", "Only add new line on enter after end of fully typed word", "Always add new line on enter"], + enumValues: [EnterKeyRule.Never, EnterKeyRule.AfterFullyTypedWord, EnterKeyRule.Always], + customMaps: [new Map { Result = "never", Match = 1 }, new Map { Result = "never", Match = 0 }, new Map { Result = "always", Match = 2}, new Map { Result = "afterFullyTypedWord", Match = 3 }], + languageName: LanguageNames.CSharp)), + (CompletionOptionsStorage.ShowNameSuggestions, CreateBooleanOption( + CompletionOptionsStorage.ShowNameSuggestions, + title: "Show name suggestions", + order: 70, + languageName: LanguageNames.CSharp)), + (CompletionOptionsStorage.ShowItemsFromUnimportedNamespaces, CreateBooleanOption( + CompletionOptionsStorage.ShowItemsFromUnimportedNamespaces, + title: "Show items from unimported namespaces", + order: 80, + languageName: LanguageNames.CSharp)), + (CompletionViewOptionsStorage.EnableArgumentCompletionSnippets, CreateBooleanOption( + CompletionViewOptionsStorage.EnableArgumentCompletionSnippets, + title: "Tab twice to insert arguments", + customDefaultValue: false, + order: 90, + languageName: LanguageNames.CSharp, + message: "Experimental feature")), + (CompletionOptionsStorage.ShowNewSnippetExperienceUserOption, CreateBooleanOption( + CompletionOptionsStorage.ShowNewSnippetExperienceUserOption, + title: "Show new snippet experience", + customDefaultValue: false, + order: 100, + languageName: LanguageNames.CSharp, + featureFlagAndExperimentValue: (CompletionOptionsStorage.ShowNewSnippetExperienceFeatureFlag, true), + message: "Experimental feature")), + ]; + + [Fact] + public async Task CSharpCategoriesTest() + { + using var registrationFileStream = typeof(UnifiedSettingsTests).GetTypeInfo().Assembly.GetManifestResourceStream("Roslyn.VisualStudio.Next.UnitTests.csharpSettings.registration.json"); + var jsonDocument = await JsonNode.ParseAsync(registrationFileStream!, documentOptions: new JsonDocumentOptions { CommentHandling = JsonCommentHandling.Skip }); + var categories = jsonDocument!.Root["categories"]!.AsObject(); + var propertyToCategory = categories.ToDictionary(kvp => kvp.Key, kvp => kvp.Value.Deserialize()); + Assert.Equal(2, propertyToCategory.Count); + Assert.Equal("C#", propertyToCategory["textEditor.csharp"]!.Title); + Assert.Equal("IntelliSense", propertyToCategory["textEditor.csharp.intellisense"]!.Title); + Assert.Equal(Guids.CSharpOptionPageIntelliSenseIdString, propertyToCategory["textEditor.csharp.intellisense"]!.LegacyOptionPageId); + await VerifyTagAsync(jsonDocument.ToString(), "Roslyn.VisualStudio.Next.UnitTests.csharpPackageRegistration.pkgdef"); + } + + [Fact] + public async Task CSharpIntellisenseTest() + { + using var registrationFileStream = typeof(UnifiedSettingsTests).GetTypeInfo().Assembly.GetManifestResourceStream("Roslyn.VisualStudio.Next.UnitTests.csharpSettings.registration.json"); + var jsonDocument = await JsonNode.ParseAsync(registrationFileStream!, documentOptions: new JsonDocumentOptions { CommentHandling = JsonCommentHandling.Skip }); + foreach (var (option, _) in s_csharpIntellisenseExpectedSettings) + { + Assert.True(s_csharpUnifiedSettingsStorage.ContainsKey(option)); + } + + VerifyProperties(jsonDocument!, "textEditor.csharp.intellisense", s_csharpIntellisenseExpectedSettings); + await VerifyTagAsync(jsonDocument!.ToString(), "Roslyn.VisualStudio.Next.UnitTests.csharpPackageRegistration.pkgdef"); + } + + #endregion + + #region VisualBasicTest + /// + /// Dictionary containing the option to unified setting path for VB. + /// + private static readonly ImmutableDictionary s_visualBasicUnifiedSettingsStorage = ImmutableDictionary.Empty. + Add(CompletionOptionsStorage.TriggerOnTypingLetters, "textEditor.basic.intellisense.triggerCompletionOnTypingLetters"). + Add(CompletionOptionsStorage.TriggerOnDeletion, "textEditor.basic.intellisense.triggerCompletionOnDeletion"). + Add(CompletionViewOptionsStorage.HighlightMatchingPortionsOfCompletionListItems, "textEditor.basic.intellisense.highlightMatchingPortionsOfCompletionListItems"). + Add(CompletionViewOptionsStorage.ShowCompletionItemFilters, "textEditor.basic.intellisense.showCompletionItemFilters"). + Add(CompletionOptionsStorage.SnippetsBehavior, "textEditor.basic.intellisense.snippetsBehavior"). + Add(CompletionOptionsStorage.EnterKeyBehavior, "textEditor.basic.intellisense.returnKeyCompletionBehavior"). + Add(CompletionOptionsStorage.ShowItemsFromUnimportedNamespaces, "textEditor.basic.intellisense.showCompletionItemsFromUnimportedNamespaces"). + Add(CompletionViewOptionsStorage.EnableArgumentCompletionSnippets, "textEditor.basic.intellisense.enableArgumentCompletionSnippets"); + + /// + /// Array containing the option to expected unified settings for VB intellisense page. + /// + private static readonly ImmutableArray<(IOption2, UnifiedSettingBase)> s_visualBasicIntellisenseExpectedSettings = + [ + (CompletionOptionsStorage.TriggerOnTypingLetters, CreateBooleanOption( + CompletionOptionsStorage.TriggerOnTypingLetters, + title: "Show completion list after a character is typed", + order: 0, + languageName: LanguageNames.VisualBasic)), + (CompletionOptionsStorage.TriggerOnDeletion, CreateBooleanOption( + CompletionOptionsStorage.TriggerOnDeletion, + title: "Show completion list after a character is deleted", + order: 1, + customDefaultValue: true, + languageName: LanguageNames.VisualBasic)), + (CompletionViewOptionsStorage.HighlightMatchingPortionsOfCompletionListItems, CreateBooleanOption( + CompletionViewOptionsStorage.HighlightMatchingPortionsOfCompletionListItems, + "Highlight matching portions of completion list items", + order: 10, + languageName: LanguageNames.VisualBasic)), + (CompletionViewOptionsStorage.ShowCompletionItemFilters, CreateBooleanOption( + CompletionViewOptionsStorage.ShowCompletionItemFilters, + title: "Show completion item filters", + order: 20, + languageName: LanguageNames.VisualBasic)), + (CompletionOptionsStorage.SnippetsBehavior, CreateEnumOption( + CompletionOptionsStorage.SnippetsBehavior, + "Snippets behavior", + order: 30, + customDefaultValue: SnippetsRule.IncludeAfterTypingIdentifierQuestionTab, + enumLabels: ["Never include snippets", "Always include snippets", "Include snippets when ?-Tab is typed after an identifier"], + enumValues: [SnippetsRule.NeverInclude, SnippetsRule.AlwaysInclude, SnippetsRule.IncludeAfterTypingIdentifierQuestionTab], + customMaps: [new Map { Result = "neverInclude", Match = 1 }, new Map { Result = "alwaysInclude", Match = 2 }, new Map { Result = "includeAfterTypingIdentifierQuestionTab", Match = 3 }, new Map { Result = "includeAfterTypingIdentifierQuestionTab", Match = 0 }], + languageName: LanguageNames.VisualBasic)), + (CompletionOptionsStorage.EnterKeyBehavior, CreateEnumOption( + CompletionOptionsStorage.EnterKeyBehavior, + "Enter key behavior", + order: 40, + customDefaultValue: EnterKeyRule.Always, + enumLabels: ["Never add new line on enter", "Only add new line on enter after end of fully typed word", "Always add new line on enter"], + enumValues: [EnterKeyRule.Never, EnterKeyRule.AfterFullyTypedWord, EnterKeyRule.Always], + customMaps: [new Map { Result = "never", Match = 1}, new Map { Result = "always", Match = 2}, new Map { Result = "always", Match = 0}, new Map { Result = "afterFullyTypedWord", Match = 3 }], + languageName: LanguageNames.VisualBasic)), + (CompletionOptionsStorage.ShowItemsFromUnimportedNamespaces, CreateBooleanOption( + CompletionOptionsStorage.ShowItemsFromUnimportedNamespaces, + title: "Show items from unimported namespaces", + order: 50, + languageName: LanguageNames.VisualBasic)), + (CompletionViewOptionsStorage.EnableArgumentCompletionSnippets, CreateBooleanOption( + CompletionViewOptionsStorage.EnableArgumentCompletionSnippets, + title: "Tab twice to insert arguments", + customDefaultValue: false, + order: 60, + languageName: LanguageNames.VisualBasic, + message: "Experimental feature")), + ]; + + [Fact] + public async Task VisualBasicCategoriesTest() + { + using var registrationFileStream = typeof(UnifiedSettingsTests).GetTypeInfo().Assembly.GetManifestResourceStream("Roslyn.VisualStudio.Next.UnitTests.visualBasicSettings.registration.json"); + var jsonDocument = await JsonNode.ParseAsync(registrationFileStream!, documentOptions: new JsonDocumentOptions { CommentHandling = JsonCommentHandling.Skip }); + var categories = jsonDocument!.Root["categories"]!.AsObject(); + var propertyToCategory = categories.ToDictionary(kvp => kvp.Key, kvp => kvp.Value.Deserialize()); + Assert.Equal(2, propertyToCategory.Count); + Assert.Equal("Visual Basic", propertyToCategory["textEditor.basic"]!.Title); + Assert.Equal("IntelliSense", propertyToCategory["textEditor.basic.intellisense"]!.Title); + Assert.Equal(Guids.VisualBasicOptionPageIntelliSenseIdString, propertyToCategory["textEditor.basic.intellisense"]!.LegacyOptionPageId); + await VerifyTagAsync(jsonDocument.ToString(), "Roslyn.VisualStudio.Next.UnitTests.visualBasicPackageRegistration.pkgdef"); + } + + [Fact] + public async Task VisualBasicIntellisenseTest() + { + using var registrationFileStream = typeof(UnifiedSettingsTests).GetTypeInfo().Assembly.GetManifestResourceStream("Roslyn.VisualStudio.Next.UnitTests.visualBasicSettings.registration.json"); + var jsonDocument = await JsonNode.ParseAsync(registrationFileStream!, documentOptions: new JsonDocumentOptions { CommentHandling = JsonCommentHandling.Skip }); + foreach (var (option, _) in s_visualBasicIntellisenseExpectedSettings) + { + Assert.True(s_visualBasicUnifiedSettingsStorage.ContainsKey(option)); + } + + VerifyProperties(jsonDocument!, "textEditor.basic.intellisense", s_visualBasicIntellisenseExpectedSettings); + await VerifyTagAsync(jsonDocument!.ToString(), "Roslyn.VisualStudio.Next.UnitTests.visualBasicPackageRegistration.pkgdef"); + } + + private static void VerifyProperties(JsonNode jsonDocument, string prefix, ImmutableArray<(IOption2, UnifiedSettingBase)> expectedOptionToSettings) + { + var properties = jsonDocument!.Root["properties"]!.AsObject() + .Where(jsonObject => jsonObject.Key.StartsWith(prefix)) + .SelectAsArray(jsonObject => jsonObject.Value); + Assert.Equal(expectedOptionToSettings.Length, properties.Length); + foreach (var (actualJson, (expectedOption, expectedSetting)) in properties.Zip(expectedOptionToSettings, (actual, expected) => (actual, expected))) + { + // We only have bool and enum option now. + UnifiedSettingBase actualSetting = expectedOption.Definition.Type.IsEnum + ? actualJson.Deserialize()! + : actualJson.Deserialize>()!; + Assert.Equal(expectedSetting, actualSetting); + } + } + + #endregion + + #region Helpers + + private static async Task VerifyTagAsync(string registrationFile, string pkgdefFileName) + { + using var pkgDefFileStream = typeof(UnifiedSettingsTests).GetTypeInfo().Assembly.GetManifestResourceStream(pkgdefFileName); + using var streamReader = new StreamReader(pkgDefFileStream!); + var pkgdefFile = await streamReader.ReadToEndAsync(); + + var fileBytes = Encoding.ASCII.GetBytes(registrationFile); + var expectedTags = BitConverter.ToInt64([.. XxHash128.Hash(fileBytes).Take(8)], 0).ToString("X16"); + var regex = new Regex(""" + "CacheTag"=qword:\w{16} + """); + var match = regex.Match(pkgdefFile, 0).Value; + var actualTag = match[^16..]; + // Please change the CacheTag value in pkddefFile when you modify the registration file. + Assert.Equal(expectedTags, actualTag); + } + + private static UnifiedSettingsOption CreateBooleanOption( + IOption2 onboardedOption, + string title, + int order, + string languageName, + bool? customDefaultValue = null, + (IOption2 featureFlagOption, bool value)? featureFlagAndExperimentValue = null, + (IOption2 enableWhenOption, object whenValue)? enableWhenOptionAndValue = null, + string? message = null) + { + var migration = new Migration { Pass = new Pass { Input = new Input(onboardedOption, languageName) } }; + var type = onboardedOption.Definition.Type; + // If the option's type is nullable type, like bool?, we use bool in the registration file. + var underlyingType = Nullable.GetUnderlyingType(type); + var nonNullableType = underlyingType ?? type; + + var alternativeDefault = featureFlagAndExperimentValue is not null + ? new AlternativeDefault(featureFlagAndExperimentValue.Value.featureFlagOption, featureFlagAndExperimentValue.Value.value) + : null; + + var enableWhen = enableWhenOptionAndValue is not null + ? $"${{config:{GetUnifiedSettingsOptionValue(enableWhenOptionAndValue.Value.enableWhenOption, languageName)}}}=='{enableWhenOptionAndValue.Value.whenValue.ToString().ToCamelCase()}'" + : null; + + var expectedDefault = customDefaultValue ?? onboardedOption.Definition.DefaultValue; + // If the option default value is null, it means the option is in experiment mode and is hidden by a feature flag. + // In Unified Settings it is not allowed and should be replaced by using the alternative default. + // Like: + // "textEditor.csharp.intellisense.showNewSnippetExperience": { + // "type": "boolean", + // "default": false, + // "alternateDefault": { + // "flagName": "Roslyn.SnippetCompletion", + // "default": true + // } + // } + // so please specify a non-null default value. + Assert.NotNull(expectedDefault); + + return new UnifiedSettingsOption + { + Title = title, + Type = nonNullableType.Name.ToCamelCase(), + Order = order, + EnableWhen = enableWhen, + Migration = migration, + AlternateDefault = alternativeDefault, + Default = (bool)expectedDefault, + Messages = message is null ? null : [new Message { Text = message }], + }; + } + + private static UnifiedSettingsEnumOption CreateEnumOption( + IOption2 onboardedOption, + string title, + int order, + string[] enumLabels, + string languageName, + T? customDefaultValue = default, + T[]? enumValues = null, + Map[]? customMaps = null, + (IOption2 featureFlagOption, T value)? featureFlagAndExperimentValue = null, + (IOption2 enableWhenOption, object whenValue)? enableWhenOptionAndValue = null) where T : Enum + { + var type = onboardedOption.Definition.Type; + // If the option's type is nullable type, we use the original type in the registration file. + var nonNullableType = Nullable.GetUnderlyingType(type) ?? type; + Assert.Equal(typeof(T), nonNullableType); + + var expectedEnumValues = enumValues ?? [.. Enum.GetValues(nonNullableType).Cast()]; + var migration = new Migration + { + EnumIntegerToString = new EnumIntegerToString + { + Input = new Input(onboardedOption, languageName), + Map = customMaps ?? [.. expectedEnumValues.Select(value => new Map { Result = value.ToString().ToCamelCase(), Match = Convert.ToInt32(value) })] + } + }; + + var alternativeDefault = featureFlagAndExperimentValue is not null + ? new AlternativeDefault(featureFlagAndExperimentValue.Value.featureFlagOption, featureFlagAndExperimentValue.Value.value.ToString().ToCamelCase()) + : null; + + var enableWhen = enableWhenOptionAndValue is not null + ? $"${{config:{GetUnifiedSettingsOptionValue(enableWhenOptionAndValue.Value.enableWhenOption, languageName)}}}=='{enableWhenOptionAndValue.Value.whenValue.ToString().ToCamelCase()}'" + : null; + + var expectedDefault = customDefaultValue ?? onboardedOption.Definition.DefaultValue; + Assert.NotNull(expectedDefault); + + return new UnifiedSettingsEnumOption + { + Title = title, + Type = "string", + Enum = [.. expectedEnumValues.Select(value => value.ToString().ToCamelCase())], + EnumItemLabels = enumLabels, + Order = order, + EnableWhen = enableWhen, + Migration = migration, + AlternateDefault = alternativeDefault, + Default = expectedDefault.ToString().ToCamelCase(), + }; + } + + private static string GetUnifiedSettingsOptionValue(IOption2 option, string languageName) + { + return languageName switch + { + LanguageNames.CSharp => s_csharpUnifiedSettingsStorage[option], + LanguageNames.VisualBasic => s_visualBasicUnifiedSettingsStorage[option], + _ => throw ExceptionUtilities.UnexpectedValue(languageName) + }; + } + + #endregion +} diff --git a/src/VisualStudio/Core/Test/AbstractTextViewFilterTests.vb b/src/VisualStudio/Core/Test/AbstractTextViewFilterTests.vb index d6d1c5846579b..228503029028f 100644 --- a/src/VisualStudio/Core/Test/AbstractTextViewFilterTests.vb +++ b/src/VisualStudio/Core/Test/AbstractTextViewFilterTests.vb @@ -16,7 +16,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests <[UseExportProvider]> Public Class AbstractTextViewFilterTests - Public Sub MapPointsInProjectionCSharp() + Public Async Function MapPointsInProjectionCSharp() As Task Dim workspaceXml = CommonReferences="true"> @@ -45,13 +45,13 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests ]]>.Value.Replace(vbLf, vbCrLf), {doc}) Dim matchingSpan = projected.SelectedSpans.Single() - TestSpan(workspace, projected, projected.CursorPosition.Value, matchingSpan.End) - TestSpan(workspace, projected, matchingSpan.End, projected.CursorPosition.Value) + Await TestSpan(workspace, projected, projected.CursorPosition.Value, matchingSpan.End) + Await TestSpan(workspace, projected, matchingSpan.End, projected.CursorPosition.Value) End Using - End Sub + End Function - Public Sub GotoBraceNavigatesToOuterPositionOfMatchingBraceCSharp() + Public Async Function GotoBraceNavigatesToOuterPositionOfMatchingBraceCSharp() As Task Dim workspaceXml = CommonReferences="true"> @@ -75,13 +75,13 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests Using workspace = EditorTestWorkspace.Create(workspaceXml, composition:=VisualStudioTestCompositions.LanguageServices) Dim doc = workspace.Documents.Single() Dim span = doc.SelectedSpans.Single() - TestSpan(workspace, doc, doc.CursorPosition.Value, span.End, commandId:=CUInt(VSConstants.VSStd2KCmdID.GOTOBRACE)) - TestSpan(workspace, doc, span.End, doc.CursorPosition.Value, commandId:=CUInt(VSConstants.VSStd2KCmdID.GOTOBRACE)) + Await TestSpan(workspace, doc, doc.CursorPosition.Value, span.End, commandId:=CUInt(VSConstants.VSStd2KCmdID.GOTOBRACE)) + Await TestSpan(workspace, doc, span.End, doc.CursorPosition.Value, commandId:=CUInt(VSConstants.VSStd2KCmdID.GOTOBRACE)) End Using - End Sub + End Function - Public Sub GotoBraceFromLeftAndRightOfOpenAndCloseBracesCSharp() + Public Async Function GotoBraceFromLeftAndRightOfOpenAndCloseBracesCSharp() As Task Dim workspaceXml = CommonReferences="true"> @@ -105,15 +105,15 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests Using workspace = EditorTestWorkspace.Create(workspaceXml, composition:=VisualStudioTestCompositions.LanguageServices) Dim doc = workspace.Documents.Single() Dim span = doc.SelectedSpans.Single() - TestSpan(workspace, doc, span.Start, span.End, commandId:=CUInt(VSConstants.VSStd2KCmdID.GOTOBRACE)) - TestSpan(workspace, doc, span.End, span.Start, commandId:=CUInt(VSConstants.VSStd2KCmdID.GOTOBRACE)) - TestSpan(workspace, doc, span.Start + 1, span.End, commandId:=CUInt(VSConstants.VSStd2KCmdID.GOTOBRACE)) - TestSpan(workspace, doc, span.End - 1, span.Start, commandId:=CUInt(VSConstants.VSStd2KCmdID.GOTOBRACE)) + Await TestSpan(workspace, doc, span.Start, span.End, commandId:=CUInt(VSConstants.VSStd2KCmdID.GOTOBRACE)) + Await TestSpan(workspace, doc, span.End, span.Start, commandId:=CUInt(VSConstants.VSStd2KCmdID.GOTOBRACE)) + Await TestSpan(workspace, doc, span.Start + 1, span.End, commandId:=CUInt(VSConstants.VSStd2KCmdID.GOTOBRACE)) + Await TestSpan(workspace, doc, span.End - 1, span.Start, commandId:=CUInt(VSConstants.VSStd2KCmdID.GOTOBRACE)) End Using - End Sub + End Function - Public Sub GotoBraceExtFindsTheInnerPositionOfCloseBraceAndOuterPositionOfOpenBraceCSharp() + Public Async Function GotoBraceExtFindsTheInnerPositionOfCloseBraceAndOuterPositionOfOpenBraceCSharp() As Task Dim workspaceXml = CommonReferences="true"> @@ -137,13 +137,13 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests Using workspace = EditorTestWorkspace.Create(workspaceXml, composition:=VisualStudioTestCompositions.LanguageServices) Dim doc = workspace.Documents.Single() Dim span = doc.SelectedSpans.Single() - TestSpan(workspace, doc, caretPosition:=span.Start, startPosition:=span.Start, endPosition:=span.End, commandId:=CUInt(VSConstants.VSStd2KCmdID.GOTOBRACE_EXT)) - TestSpan(workspace, doc, caretPosition:=doc.CursorPosition.Value, startPosition:=span.End, endPosition:=span.Start, commandId:=CUInt(VSConstants.VSStd2KCmdID.GOTOBRACE_EXT)) + Await TestSpan(workspace, doc, caretPosition:=span.Start, startPosition:=span.Start, endPosition:=span.End, commandId:=CUInt(VSConstants.VSStd2KCmdID.GOTOBRACE_EXT)) + Await TestSpan(workspace, doc, caretPosition:=doc.CursorPosition.Value, startPosition:=span.End, endPosition:=span.Start, commandId:=CUInt(VSConstants.VSStd2KCmdID.GOTOBRACE_EXT)) End Using - End Sub + End Function - Public Sub GotoBraceExtFromLeftAndRightOfOpenAndCloseBracesCSharp() + Public Async Function GotoBraceExtFromLeftAndRightOfOpenAndCloseBracesCSharp() As Task Dim workspaceXml = CommonReferences="true"> @@ -169,17 +169,17 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests Dim span = doc.SelectedSpans.Single() ' Test from left and right of Open parenthesis - TestSpan(workspace, doc, caretPosition:=span.Start, startPosition:=span.Start, endPosition:=span.End - 1, commandId:=CUInt(VSConstants.VSStd2KCmdID.GOTOBRACE_EXT)) - TestSpan(workspace, doc, caretPosition:=span.Start + 1, startPosition:=span.Start, endPosition:=span.End - 1, commandId:=CUInt(VSConstants.VSStd2KCmdID.GOTOBRACE_EXT)) + Await TestSpan(workspace, doc, caretPosition:=span.Start, startPosition:=span.Start, endPosition:=span.End - 1, commandId:=CUInt(VSConstants.VSStd2KCmdID.GOTOBRACE_EXT)) + Await TestSpan(workspace, doc, caretPosition:=span.Start + 1, startPosition:=span.Start, endPosition:=span.End - 1, commandId:=CUInt(VSConstants.VSStd2KCmdID.GOTOBRACE_EXT)) ' Test from left and right of Close parenthesis - TestSpan(workspace, doc, caretPosition:=span.End, startPosition:=span.End - 1, endPosition:=span.Start, commandId:=CUInt(VSConstants.VSStd2KCmdID.GOTOBRACE_EXT)) - TestSpan(workspace, doc, caretPosition:=span.End - 1, startPosition:=span.End - 1, endPosition:=span.Start, commandId:=CUInt(VSConstants.VSStd2KCmdID.GOTOBRACE_EXT)) + Await TestSpan(workspace, doc, caretPosition:=span.End, startPosition:=span.End - 1, endPosition:=span.Start, commandId:=CUInt(VSConstants.VSStd2KCmdID.GOTOBRACE_EXT)) + Await TestSpan(workspace, doc, caretPosition:=span.End - 1, startPosition:=span.End - 1, endPosition:=span.Start, commandId:=CUInt(VSConstants.VSStd2KCmdID.GOTOBRACE_EXT)) End Using - End Sub + End Function - Public Sub GotoBraceFromLeftAndRightOfOpenAndCloseBracesBasic() + Public Async Function GotoBraceFromLeftAndRightOfOpenAndCloseBracesBasic() As Task Dim workspaceXml = CommonReferences="true"> @@ -202,15 +202,15 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests Using workspace = EditorTestWorkspace.Create(workspaceXml, composition:=VisualStudioTestCompositions.LanguageServices) Dim doc = workspace.Documents.Single() Dim span = doc.SelectedSpans.Single() - TestSpan(workspace, doc, span.Start, span.End, commandId:=CUInt(VSConstants.VSStd2KCmdID.GOTOBRACE)) - TestSpan(workspace, doc, span.End, span.Start, commandId:=CUInt(VSConstants.VSStd2KCmdID.GOTOBRACE)) - TestSpan(workspace, doc, span.Start + 1, span.End, commandId:=CUInt(VSConstants.VSStd2KCmdID.GOTOBRACE)) - TestSpan(workspace, doc, span.End - 1, span.Start, commandId:=CUInt(VSConstants.VSStd2KCmdID.GOTOBRACE)) + Await TestSpan(workspace, doc, span.Start, span.End, commandId:=CUInt(VSConstants.VSStd2KCmdID.GOTOBRACE)) + Await TestSpan(workspace, doc, span.End, span.Start, commandId:=CUInt(VSConstants.VSStd2KCmdID.GOTOBRACE)) + Await TestSpan(workspace, doc, span.Start + 1, span.End, commandId:=CUInt(VSConstants.VSStd2KCmdID.GOTOBRACE)) + Await TestSpan(workspace, doc, span.End - 1, span.Start, commandId:=CUInt(VSConstants.VSStd2KCmdID.GOTOBRACE)) End Using - End Sub + End Function - Public Sub GotoBraceExtFromLeftAndRightOfOpenAndCloseBracesBasic() + Public Async Function GotoBraceExtFromLeftAndRightOfOpenAndCloseBracesBasic() As Task Dim workspaceXml = CommonReferences="true"> @@ -235,58 +235,58 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests Dim span = doc.SelectedSpans.Single() ' Test from left and right of Open parenthesis - TestSpan(workspace, doc, caretPosition:=span.Start, startPosition:=span.Start, endPosition:=span.End - 1, commandId:=CUInt(VSConstants.VSStd2KCmdID.GOTOBRACE_EXT)) - TestSpan(workspace, doc, caretPosition:=span.Start + 1, startPosition:=span.Start, endPosition:=span.End - 1, commandId:=CUInt(VSConstants.VSStd2KCmdID.GOTOBRACE_EXT)) + Await TestSpan(workspace, doc, caretPosition:=span.Start, startPosition:=span.Start, endPosition:=span.End - 1, commandId:=CUInt(VSConstants.VSStd2KCmdID.GOTOBRACE_EXT)) + Await TestSpan(workspace, doc, caretPosition:=span.Start + 1, startPosition:=span.Start, endPosition:=span.End - 1, commandId:=CUInt(VSConstants.VSStd2KCmdID.GOTOBRACE_EXT)) ' Test from left and right of Close parenthesis - TestSpan(workspace, doc, caretPosition:=span.End, startPosition:=span.End - 1, endPosition:=span.Start, commandId:=CUInt(VSConstants.VSStd2KCmdID.GOTOBRACE_EXT)) - TestSpan(workspace, doc, caretPosition:=span.End - 1, startPosition:=span.End - 1, endPosition:=span.Start, commandId:=CUInt(VSConstants.VSStd2KCmdID.GOTOBRACE_EXT)) + Await TestSpan(workspace, doc, caretPosition:=span.End, startPosition:=span.End - 1, endPosition:=span.Start, commandId:=CUInt(VSConstants.VSStd2KCmdID.GOTOBRACE_EXT)) + Await TestSpan(workspace, doc, caretPosition:=span.End - 1, startPosition:=span.End - 1, endPosition:=span.Start, commandId:=CUInt(VSConstants.VSStd2KCmdID.GOTOBRACE_EXT)) End Using - End Sub + End Function - Private Shared Sub TestSpan(workspace As EditorTestWorkspace, document As EditorTestHostDocument, startPosition As Integer, endPosition As Integer, Optional commandId As UInteger = Nothing) + Private Shared Async Function TestSpan(workspace As EditorTestWorkspace, document As EditorTestHostDocument, startPosition As Integer, endPosition As Integer, Optional commandId As UInteger = Nothing) As Task Dim braceMatcher = workspace.ExportProvider.GetExportedValue(Of IBraceMatchingService)() Dim initialLine = document.InitialTextSnapshot.GetLineFromPosition(startPosition) Dim initialLineNumber = initialLine.LineNumber Dim initialIndex = startPosition - initialLine.Start.Position Dim spans() = {New VsTextSpan()} - Assert.Equal(0, AbstractVsTextViewFilter.GetPairExtentsWorker( - document.GetTextView(), - braceMatcher, - workspace.GlobalOptions, - initialLineNumber, - initialIndex, - spans, - commandId = CUInt(VSConstants.VSStd2KCmdID.GOTOBRACE_EXT), - CancellationToken.None)) + Assert.Equal(0, Await AbstractVsTextViewFilter.GetPairExtentsAsync( + document.GetTextView(), + braceMatcher, + workspace.GlobalOptions, + initialLineNumber, + initialIndex, + spans, + commandId = CUInt(VSConstants.VSStd2KCmdID.GOTOBRACE_EXT), + CancellationToken.None)) ' Note - we only set either the start OR the end to the result, the other gets set to the source. Dim resultLine = document.InitialTextSnapshot.GetLineFromPosition(endPosition) Dim resultIndex = endPosition - resultLine.Start.Position AssertSpansMatch(startPosition, endPosition, initialLineNumber, initialIndex, spans, resultLine, resultIndex) - End Sub + End Function - Private Shared Sub TestSpan(workspace As EditorTestWorkspace, document As EditorTestHostDocument, caretPosition As Integer, startPosition As Integer, endPosition As Integer, Optional commandId As UInteger = Nothing) + Private Shared Async Function TestSpan(workspace As EditorTestWorkspace, document As EditorTestHostDocument, caretPosition As Integer, startPosition As Integer, endPosition As Integer, Optional commandId As UInteger = Nothing) As Task Dim braceMatcher = workspace.ExportProvider.GetExportedValue(Of IBraceMatchingService)() Dim initialLine = document.InitialTextSnapshot.GetLineFromPosition(caretPosition) Dim initialLineNumber = initialLine.LineNumber Dim initialIndex = caretPosition - initialLine.Start.Position Dim spans() = {New VsTextSpan()} - Assert.Equal(0, AbstractVsTextViewFilter.GetPairExtentsWorker( - document.GetTextView(), - braceMatcher, - workspace.GlobalOptions, - initialLineNumber, - initialIndex, - spans, - commandId = CUInt(VSConstants.VSStd2KCmdID.GOTOBRACE_EXT), - CancellationToken.None)) + Assert.Equal(0, Await AbstractVsTextViewFilter.GetPairExtentsAsync( + document.GetTextView(), + braceMatcher, + workspace.GlobalOptions, + initialLineNumber, + initialIndex, + spans, + commandId = CUInt(VSConstants.VSStd2KCmdID.GOTOBRACE_EXT), + CancellationToken.None)) 'In extending selection (GotoBraceExt) scenarios we set both start AND end to the result. Dim startIndex = startPosition - initialLine.Start.Position Dim resultLine = document.InitialTextSnapshot.GetLineFromPosition(endPosition) Dim resultIndex = endPosition - resultLine.Start.Position AssertSpansMatch(startPosition, endPosition, initialLineNumber, startIndex, spans, resultLine, resultIndex) - End Sub + End Function Private Shared Sub AssertSpansMatch(startPosition As Integer, endPosition As Integer, initialLineNumber As Integer, startIndex As Integer, spans() As VsTextSpan, resultLine As Text.ITextSnapshotLine, resultIndex As Integer) If endPosition > startPosition Then diff --git a/src/VisualStudio/Core/Test/ChangeSignature/AddParameterViewModelTests.vb b/src/VisualStudio/Core/Test/ChangeSignature/AddParameterViewModelTests.vb index b167207e190d1..3b032143c930d 100644 --- a/src/VisualStudio/Core/Test/ChangeSignature/AddParameterViewModelTests.vb +++ b/src/VisualStudio/Core/Test/ChangeSignature/AddParameterViewModelTests.vb @@ -2,10 +2,10 @@ ' The .NET Foundation licenses this file to you under the MIT license. ' See the LICENSE file in the project root for more information. +Imports System.Threading Imports System.Windows Imports Microsoft.CodeAnalysis Imports Microsoft.CodeAnalysis.Editor.UnitTests.Extensions -Imports Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces Imports Microsoft.CodeAnalysis.Test.Utilities Imports Microsoft.VisualStudio.LanguageServices.Implementation.ChangeSignature Imports Roslyn.Test.Utilities @@ -15,14 +15,14 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.ChangeSignature Public Class AddParameterViewModelTests - Public Sub AddParameter_SubmittingRequiresTypeAndNameAndCallsiteValue() + Public Async Function AddParameter_SubmittingRequiresTypeAndNameAndCallsiteValue() As Task Dim markup = - Dim viewModelTestState = GetViewModelTestStateAsync(markup, LanguageNames.CSharp) + Dim viewModelTestState = Await GetViewModelTestStateAsync(markup, LanguageNames.CSharp) Dim viewModel = viewModelTestState.ViewModel VerifyOpeningState(viewModel) @@ -43,17 +43,17 @@ class MyClass viewModel.CallSiteValue = "7" Assert.True(viewModel.TrySubmit()) - End Sub + End Function - Public Sub AddParameter_TypeNameTextBoxInteractions() + Public Async Function AddParameter_TypeNameTextBoxInteractions() As Task Dim markup = { public void M($$) { } }"]]> - Dim viewModelTestState = GetViewModelTestStateAsync(markup, LanguageNames.CSharp) + Dim viewModelTestState = Await GetViewModelTestStateAsync(markup, LanguageNames.CSharp) Dim viewModel = viewModelTestState.ViewModel VerifyOpeningState(viewModel) @@ -127,13 +127,13 @@ class MyClass monitor.Detach() AssertTypeBindingIconAndTextIs(viewModel, NameOf(viewModel.TypeIsEmptyImage), ServicesVSResources.Please_enter_a_type_name) - End Sub + End Function - Public Sub AddParameter_NoExistingParameters_TypeBinds(typeName As String) + Public Async Function AddParameter_NoExistingParameters_TypeBinds(typeName As String) As Task Dim markup = - Dim viewModelTestState = GetViewModelTestStateAsync(markup, LanguageNames.CSharp) + Dim viewModelTestState = Await GetViewModelTestStateAsync(markup, LanguageNames.CSharp) Dim viewModel = viewModelTestState.ViewModel VerifyOpeningState(viewModel) @@ -174,17 +174,17 @@ class MyClass viewModel.CallSiteValue = "0" Assert.True(viewModel.TrySubmit()) - End Sub + End Function - Public Sub AddParameter_CannotBeBothRequiredAndOmit() + Public Async Function AddParameter_CannotBeBothRequiredAndOmit() As Task Dim markup = { public void M($$) { } }"]]> - Dim viewModelTestState = GetViewModelTestStateAsync(markup, LanguageNames.CSharp) + Dim viewModelTestState = Await GetViewModelTestStateAsync(markup, LanguageNames.CSharp) Dim viewModel = viewModelTestState.ViewModel VerifyOpeningState(viewModel) @@ -204,13 +204,13 @@ class MyClass Assert.True(viewModel.IsCallsiteRegularValue) Assert.False(viewModel.IsCallsiteOmitted) - End Sub + End Function - Public Sub AddParameter_ExistingParameters_TypeBinds(typeName As String) + Public Async Function AddParameter_ExistingParameters_TypeBinds(typeName As String) As Task Dim markup = - Dim viewModelTestState = GetViewModelTestStateAsync(markup, LanguageNames.CSharp) + Dim viewModelTestState = Await GetViewModelTestStateAsync(markup, LanguageNames.CSharp) Dim viewModel = viewModelTestState.ViewModel VerifyOpeningState(viewModel) @@ -251,7 +251,7 @@ class MyClass viewModel.CallSiteValue = "0" Assert.True(viewModel.TrySubmit()) - End Sub + End Function Private Shared Sub AssertTypeBindingIconAndTextIs(viewModel As AddParameterDialogViewModel, currentIcon As String, expectedMessage As String) Assert.True(viewModel.TypeIsEmptyImage = If(NameOf(viewModel.TypeIsEmptyImage) = currentIcon, Visibility.Visible, Visibility.Collapsed)) @@ -285,9 +285,9 @@ class MyClass Assert.Equal(ServicesVSResources.A_type_and_name_must_be_provided, message) End Sub - Private Shared Function GetViewModelTestStateAsync( + Private Shared Async Function GetViewModelTestStateAsync( markup As XElement, - languageName As String) As AddParameterViewModelTestState + languageName As String) As Task(Of AddParameterViewModelTestState) Dim workspaceXml = @@ -303,20 +303,21 @@ class MyClass Assert.True(False, "Missing caret location in document.") End If - Dim viewModel = New AddParameterDialogViewModel(workspaceDoc, doc.CursorPosition.Value) + Dim document = Await SemanticDocument.CreateAsync(workspaceDoc, CancellationToken.None) + Dim viewModel = New AddParameterDialogViewModel(document, doc.CursorPosition.Value) Return New AddParameterViewModelTestState(viewModel) End Using End Function - Public Sub AddParameter_SubmittingTypeWithModifiersIsInvalid() + Public Async Function AddParameter_SubmittingTypeWithModifiersIsInvalid() As Task Dim markup = - Dim viewModelTestState = GetViewModelTestStateAsync(markup, LanguageNames.CSharp) + Dim viewModelTestState = Await GetViewModelTestStateAsync(markup, LanguageNames.CSharp) Dim viewModel = viewModelTestState.ViewModel VerifyOpeningState(viewModel) @@ -346,17 +347,17 @@ class MyClass viewModel.VerbatimTypeName = "params int[]" Assert.False(viewModel.CanSubmit(message)) Assert.Equal(ServicesVSResources.Parameter_type_contains_invalid_characters, message) - End Sub + End Function - Public Sub AddParameter_CannotSubmitVoidParameterType() + Public Async Function AddParameter_CannotSubmitVoidParameterType() As Task Dim markup = - Dim viewModelTestState = GetViewModelTestStateAsync(markup, LanguageNames.CSharp) + Dim viewModelTestState = Await GetViewModelTestStateAsync(markup, LanguageNames.CSharp) Dim viewModel = viewModelTestState.ViewModel VerifyOpeningState(viewModel) @@ -371,6 +372,6 @@ class MyClass viewModel.VerbatimTypeName = "System.Void" Assert.False(viewModel.CanSubmit(message)) Assert.Equal(ServicesVSResources.SystemVoid_is_not_a_valid_type_for_a_parameter, message) - End Sub + End Function End Class End Namespace diff --git a/src/VisualStudio/Core/Test/ChangeSignature/ChangeSignatureViewModelTests.vb b/src/VisualStudio/Core/Test/ChangeSignature/ChangeSignatureViewModelTests.vb index 65c6ce325defc..43952266f976b 100644 --- a/src/VisualStudio/Core/Test/ChangeSignature/ChangeSignatureViewModelTests.vb +++ b/src/VisualStudio/Core/Test/ChangeSignature/ChangeSignatureViewModelTests.vb @@ -467,10 +467,11 @@ class Goo Dim token = Await tree.GetTouchingWordAsync(doc.CursorPosition.Value, workspaceDoc.Project.Services.GetService(Of ISyntaxFactsService)(), CancellationToken.None) Dim symbol = (Await workspaceDoc.GetSemanticModelAsync()).GetDeclaredSymbol(token.Parent) + Dim document = Await SemanticDocument.CreateAsync(workspaceDoc, CancellationToken.None) Dim viewModel = New ChangeSignatureDialogViewModel( + document, ParameterConfiguration.Create(symbol.GetParameters().Select(Function(p) DirectCast(New ExistingParameter(p), Parameter)).ToImmutableArray(), symbol.IsExtensionMethod(), selectedIndex:=0), symbol, - workspaceDoc, positionForTypeBinding:=0, workspace.ExportProvider.GetExportedValue(Of IClassificationFormatMapService)().GetClassificationFormatMap("text"), workspace.ExportProvider.GetExportedValue(Of ClassificationTypeMap)()) diff --git a/src/VisualStudio/Core/Test/GoToDefinition/GoToDefinitionApiTests.vb b/src/VisualStudio/Core/Test/GoToDefinition/GoToDefinitionApiTests.vb index 058f6f3686833..112cf546c6e05 100644 --- a/src/VisualStudio/Core/Test/GoToDefinition/GoToDefinitionApiTests.vb +++ b/src/VisualStudio/Core/Test/GoToDefinition/GoToDefinitionApiTests.vb @@ -6,7 +6,6 @@ Imports System.Threading Imports Microsoft.CodeAnalysis Imports Microsoft.CodeAnalysis.Editor.Shared.Utilities Imports Microsoft.CodeAnalysis.Editor.UnitTests.Utilities.GoToHelpers -Imports Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces Imports Microsoft.CodeAnalysis.GoToDefinition Imports Microsoft.CodeAnalysis.Navigation Imports Microsoft.CodeAnalysis.Test.Utilities diff --git a/src/VisualStudio/Core/Test/Microsoft.VisualStudio.LanguageServices.UnitTests.vbproj b/src/VisualStudio/Core/Test/Microsoft.VisualStudio.LanguageServices.UnitTests.vbproj index 982fa6235b259..ff7653acf0a89 100644 --- a/src/VisualStudio/Core/Test/Microsoft.VisualStudio.LanguageServices.UnitTests.vbproj +++ b/src/VisualStudio/Core/Test/Microsoft.VisualStudio.LanguageServices.UnitTests.vbproj @@ -62,8 +62,4 @@ - - - - \ No newline at end of file diff --git a/src/VisualStudio/Core/Test/MoveStaticMembers/MoveStaticMembersViewModelTest.vb b/src/VisualStudio/Core/Test/MoveStaticMembers/MoveStaticMembersViewModelTest.vb index 9aee840ed010d..65f171ebd2ba8 100644 --- a/src/VisualStudio/Core/Test/MoveStaticMembers/MoveStaticMembersViewModelTest.vb +++ b/src/VisualStudio/Core/Test/MoveStaticMembers/MoveStaticMembersViewModelTest.vb @@ -15,6 +15,7 @@ Imports Microsoft.VisualStudio.LanguageServices.Implementation.MoveStaticMembers Imports Microsoft.VisualStudio.LanguageServices.Implementation.PullMemberUp Imports Microsoft.VisualStudio.LanguageServices.Implementation.Utilities Imports Microsoft.VisualStudio.Utilities +Imports Roslyn.Test.Utilities Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.MoveStaticMembers @@ -94,10 +95,10 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.MoveStaticMembers ' We can call the method, but we need the document still to test submission Dim viewModel = Await GetViewModelAsync(markUp).ConfigureAwait(False) - Assert.Equal("TestClassHelpers", viewModel.DestinationName.TypeName) + Assert.Equal("TestNs.TestClassHelpers", viewModel.DestinationName.FullyQualifiedTypeName) SetSearchText(viewModel, "ExtraNs.TestClassHelpers") - Assert.Equal("TestNs.ExtraNs.TestClassHelpers", viewModel.DestinationName.TypeName) - Assert.Equal("TestNs.", viewModel.PrependedNamespace) + Assert.Equal("TestNs.ExtraNs.TestClassHelpers", viewModel.DestinationName.FullyQualifiedTypeName) + Assert.Equal("TestNs.ExtraNs.", viewModel.TypeName_NamespaceOnly) Assert.True(viewModel.CanSubmit) Dim cancelledOptions = VisualStudioMoveStaticMembersOptionsService.GenerateOptions(LanguageNames.CSharp, viewModel, False) @@ -178,8 +179,8 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.MoveStaticMembers ]]> Dim viewModel = Await GetViewModelAsync(markUp) - Assert.Equal(viewModel.DestinationName.TypeName, "TestClassHelpers") - Assert.Equal("TestNs.", viewModel.PrependedNamespace) + Assert.Equal(viewModel.DestinationName.FullyQualifiedTypeName, "TestNs.TestClassHelpers") + Assert.Equal("TestNs.", viewModel.TypeName_NamespaceOnly) Assert.True(viewModel.ShowMessage) Assert.Equal(ServicesVSResources.New_Type_Name_colon, viewModel.Message) @@ -405,15 +406,15 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.MoveStaticMembers Assert.Equal(2, viewModel.AvailableTypes.Length) Assert.Equal(1, viewModel.MemberSelectionViewModel.CheckedMembers.Length) - viewModel.SearchText = viewModel.AvailableTypes.ElementAt(1).TypeName - Assert.Equal("TestNs.ExtraNs.ConflictingNsClassName", viewModel.DestinationName.TypeName) + viewModel.SearchText = viewModel.AvailableTypes.ElementAt(1).FullyQualifiedTypeName + Assert.Equal("TestNs.ExtraNs.ConflictingNsClassName", viewModel.DestinationName.FullyQualifiedTypeName) Assert.NotNull(viewModel.DestinationName.NamedType) Assert.False(viewModel.DestinationName.IsNew) Assert.False(viewModel.ShowMessage) Assert.True(viewModel.CanSubmit) - viewModel.SearchText = viewModel.AvailableTypes.ElementAt(0).TypeName - Assert.Equal("TestNs.ConflictingClassName", viewModel.DestinationName.TypeName) + viewModel.SearchText = viewModel.AvailableTypes.ElementAt(0).FullyQualifiedTypeName + Assert.Equal("TestNs.ConflictingClassName", viewModel.DestinationName.FullyQualifiedTypeName) Assert.NotNull(viewModel.DestinationName.NamedType) Assert.False(viewModel.DestinationName.IsNew) Assert.False(viewModel.ShowMessage) @@ -426,6 +427,95 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.MoveStaticMembers Assert.Equal("TestNs.ConflictingClassName", options.Destination.ToDisplayString()) Assert.Equal("TestFile.cs", options.FileName) End Function + + + Public Async Function CSTestTypeSelection2() As Task + Dim markUp = + + + namespace TestNs + { + public class FromClass + { + public static int Bar$$bar() + { + return 12345; + } + } + + public struct TestStruct + { + } + + public interface ITestInterface + { + } + } + + +]]> + Dim viewModel = Await GetViewModelAsync(markUp) + + ' Should Not have the interface in the list as we started from a class. Should still have the struct through. + Assert.Equal(1, viewModel.AvailableTypes.Length) + Assert.Equal(1, viewModel.MemberSelectionViewModel.CheckedMembers.Length) + + viewModel.SearchText = viewModel.AvailableTypes.ElementAt(0).FullyQualifiedTypeName + Assert.Equal("TestNs.TestStruct", viewModel.DestinationName.FullyQualifiedTypeName) + Assert.NotNull(viewModel.DestinationName.NamedType) + Assert.False(viewModel.DestinationName.IsNew) + Assert.False(viewModel.ShowMessage) + Assert.True(viewModel.CanSubmit) + End Function + + + Public Async Function CSTestTypeSelection3() As Task + Dim markUp = + + + namespace TestNs + { + public interface FromInterface + { + public static int Bar$$bar() + { + return 12345; + } + } + + public struct TestStruct + { + } + + public interface ITestInterface + { + } + } + + +]]> + Dim viewModel = Await GetViewModelAsync(markUp) + + Assert.Equal(2, viewModel.AvailableTypes.Length) + Assert.Equal(1, viewModel.MemberSelectionViewModel.CheckedMembers.Length) + + ' Should have the interface and the struct in the list as we started from an interface. + viewModel.SearchText = "TestNs.TestStruct" + Assert.Equal("TestNs.TestStruct", viewModel.DestinationName.FullyQualifiedTypeName) + Assert.NotNull(viewModel.DestinationName.NamedType) + Assert.False(viewModel.DestinationName.IsNew) + Assert.False(viewModel.ShowMessage) + Assert.True(viewModel.CanSubmit) + + viewModel.SearchText = "TestNs.ITestInterface" + Assert.Equal("TestNs.ITestInterface", viewModel.DestinationName.FullyQualifiedTypeName) + Assert.NotNull(viewModel.DestinationName.NamedType) + Assert.False(viewModel.DestinationName.IsNew) + Assert.False(viewModel.ShowMessage) + Assert.True(viewModel.CanSubmit) + End Function #End Region #Region "VB" @@ -449,10 +539,10 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.MoveStaticMembers ' We can call the method, but we need the document still to test submission Dim viewModel = Await GetViewModelAsync(markUp).ConfigureAwait(False) - Assert.Equal("TestClassHelpers", viewModel.DestinationName.TypeName) + Assert.Equal("TestNs.TestClassHelpers", viewModel.DestinationName.FullyQualifiedTypeName) SetSearchText(viewModel, "ExtraNs.TestClassHelpers") - Assert.Equal("TestNs.ExtraNs.TestClassHelpers", viewModel.DestinationName.TypeName) - Assert.Equal("TestNs.", viewModel.PrependedNamespace) + Assert.Equal("TestNs.ExtraNs.TestClassHelpers", viewModel.DestinationName.FullyQualifiedTypeName) + Assert.Equal("TestNs.ExtraNs.", viewModel.TypeName_NamespaceOnly) Assert.True(viewModel.CanSubmit) Dim cancelledOptions = VisualStudioMoveStaticMembersOptionsService.GenerateOptions(LanguageNames.VisualBasic, viewModel, False) @@ -519,8 +609,8 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.MoveStaticMembers ]]> Dim viewModel = Await GetViewModelAsync(markUp) - Assert.Equal(viewModel.DestinationName.TypeName, "TestClassHelpers") - Assert.Equal("TestNs.", viewModel.PrependedNamespace) + Assert.Equal(viewModel.DestinationName.FullyQualifiedTypeName, "TestNs.TestClassHelpers") + Assert.Equal("TestNs.", viewModel.TypeName_NamespaceOnly) Assert.True(viewModel.ShowMessage) Assert.Equal(ServicesVSResources.New_Type_Name_colon, viewModel.Message) @@ -591,8 +681,8 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.MoveStaticMembers Dim viewModel = Await GetViewModelAsync(markUp) - Assert.Equal(viewModel.DestinationName.TypeName, "TestClassHelpers") - Assert.Equal("RootNs.TestNs.", viewModel.PrependedNamespace) + Assert.Equal(viewModel.DestinationName.FullyQualifiedTypeName, "RootNs.TestNs.TestClassHelpers") + Assert.Equal("RootNs.TestNs.", viewModel.TypeName_NamespaceOnly) Assert.True(viewModel.ShowMessage) Assert.Equal(ServicesVSResources.New_Type_Name_colon, viewModel.Message) @@ -756,15 +846,15 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.MoveStaticMembers Assert.Equal(2, viewModel.AvailableTypes.Length) Assert.Equal(1, viewModel.MemberSelectionViewModel.CheckedMembers.Length) - viewModel.SearchText = viewModel.AvailableTypes.ElementAt(1).TypeName - Assert.Equal("TestNs.ExtraNs.ConflictingNsClassName", viewModel.DestinationName.TypeName) + viewModel.SearchText = viewModel.AvailableTypes.ElementAt(1).FullyQualifiedTypeName + Assert.Equal("TestNs.ExtraNs.ConflictingNsClassName", viewModel.DestinationName.FullyQualifiedTypeName) Assert.NotNull(viewModel.DestinationName.NamedType) Assert.False(viewModel.DestinationName.IsNew) Assert.False(viewModel.ShowMessage) Assert.True(viewModel.CanSubmit) - viewModel.SearchText = viewModel.AvailableTypes.ElementAt(0).TypeName - Assert.Equal("TestNs.ConflictingClassName", viewModel.DestinationName.TypeName) + viewModel.SearchText = viewModel.AvailableTypes.ElementAt(0).FullyQualifiedTypeName + Assert.Equal("TestNs.ConflictingClassName", viewModel.DestinationName.FullyQualifiedTypeName) Assert.NotNull(viewModel.DestinationName.NamedType) Assert.False(viewModel.DestinationName.IsNew) Assert.False(viewModel.ShowMessage) diff --git a/src/VisualStudio/Core/Test/ObjectBrowser/CSharp/ObjectBrowerTests.vb b/src/VisualStudio/Core/Test/ObjectBrowser/CSharp/ObjectBrowerTests.vb index 196598bd03704..2c18867314fda 100644 --- a/src/VisualStudio/Core/Test/ObjectBrowser/CSharp/ObjectBrowerTests.vb +++ b/src/VisualStudio/Core/Test/ObjectBrowser/CSharp/ObjectBrowerTests.vb @@ -1192,10 +1192,10 @@ class C vbTab & "where TResult : class" & vbCrLf & $" {String.Format(ServicesVSResources.Member_of_0, "C")}" & vbCrLf & "" & vbCrLf & -ServicesVSResources.Summary_colon & vbCrLf & +FeaturesResources.Summary_colon & vbCrLf & "The M method." & vbCrLf & "" & vbCrLf & -ServicesVSResources.Returns_colon & vbCrLf & +FeaturesResources.Returns_colon & vbCrLf & "Returns a TResult.") End Using End Sub @@ -1229,10 +1229,10 @@ class C "public int M()" & vbCrLf & $" {String.Format(ServicesVSResources.Member_of_0, "C")}" & vbCrLf & "" & vbCrLf & -ServicesVSResources.Summary_colon & vbCrLf & +FeaturesResources.Summary_colon & vbCrLf & "Describes the method." & vbCrLf & "" & vbCrLf & -ServicesVSResources.Returns_colon & vbCrLf & +FeaturesResources.Returns_colon & vbCrLf & "Returns a value.") End Using End Sub @@ -1263,10 +1263,10 @@ class C "public int M { get; }" & vbCrLf & $" {String.Format(ServicesVSResources.Member_of_0, "C")}" & vbCrLf & "" & vbCrLf & -ServicesVSResources.Summary_colon & vbCrLf & +FeaturesResources.Summary_colon & vbCrLf & "Gets a value." & vbCrLf & "" & vbCrLf & -ServicesVSResources.Returns_colon & vbCrLf & +FeaturesResources.Returns_colon & vbCrLf & "Returns a value.") End Using End Sub @@ -1297,10 +1297,10 @@ class C "public int M { get; }" & vbCrLf & $" {String.Format(ServicesVSResources.Member_of_0, "C")}" & vbCrLf & "" & vbCrLf & -ServicesVSResources.Summary_colon & vbCrLf & +FeaturesResources.Summary_colon & vbCrLf & "Gets a value." & vbCrLf & "" & vbCrLf & -ServicesVSResources.Value_colon & vbCrLf & +FeaturesResources.Value_colon & vbCrLf & "An integer value.") End Using End Sub diff --git a/src/VisualStudio/Core/Test/ObjectBrowser/VisualBasic/ObjectBrowerTests.vb b/src/VisualStudio/Core/Test/ObjectBrowser/VisualBasic/ObjectBrowerTests.vb index 033fe1aec30a8..2374283e683af 100644 --- a/src/VisualStudio/Core/Test/ObjectBrowser/VisualBasic/ObjectBrowerTests.vb +++ b/src/VisualStudio/Core/Test/ObjectBrowser/VisualBasic/ObjectBrowerTests.vb @@ -2165,17 +2165,17 @@ End Class "Public Sub M(Of T)(i As Integer, s As String)" & vbCrLf & $" {String.Format(ServicesVSResources.Member_of_0, "C")}" & vbCrLf & "" & vbCrLf & -ServicesVSResources.Summary_colon & vbCrLf & +FeaturesResources.Summary_colon & vbCrLf & "The is my summary!" & vbCrLf & "" & vbCrLf & ServicesVSResources.Type_Parameters_colon & vbCrLf & "T: Hello from a type parameter" & vbCrLf & "" & vbCrLf & -ServicesVSResources.Parameters_colon1 & vbCrLf & +FeaturesResources.Parameters_colon & vbCrLf & "i: The parameter i" & vbCrLf & "s: The parameter t" & vbCrLf & "" & vbCrLf & -ServicesVSResources.Remarks_colon & vbCrLf & +FeaturesResources.Remarks_colon & vbCrLf & "Takes i and s.") End Using End Sub @@ -2207,10 +2207,10 @@ End Class "Public Function M() As Integer" & vbCrLf & $" {String.Format(ServicesVSResources.Member_of_0, "C")}" & vbCrLf & "" & vbCrLf & -ServicesVSResources.Summary_colon & vbCrLf & +FeaturesResources.Summary_colon & vbCrLf & "Describes the method." & vbCrLf & "" & vbCrLf & -ServicesVSResources.Returns_colon & vbCrLf & +FeaturesResources.Returns_colon & vbCrLf & "Returns a value.") End Using End Sub @@ -2240,10 +2240,10 @@ End Class "Public ReadOnly Property M As Integer" & vbCrLf & $" {String.Format(ServicesVSResources.Member_of_0, "C")}" & vbCrLf & "" & vbCrLf & -ServicesVSResources.Summary_colon & vbCrLf & +FeaturesResources.Summary_colon & vbCrLf & "Gets a value." & vbCrLf & "" & vbCrLf & -ServicesVSResources.Returns_colon & vbCrLf & +FeaturesResources.Returns_colon & vbCrLf & "Returns a value.") End Using End Sub @@ -2273,10 +2273,10 @@ End Class "Public ReadOnly Property M As Integer" & vbCrLf & $" {String.Format(ServicesVSResources.Member_of_0, "C")}" & vbCrLf & "" & vbCrLf & -ServicesVSResources.Summary_colon & vbCrLf & +FeaturesResources.Summary_colon & vbCrLf & "Gets a value." & vbCrLf & "" & vbCrLf & -ServicesVSResources.Value_colon & vbCrLf & +FeaturesResources.Value_colon & vbCrLf & "An integer value.") End Using End Sub diff --git a/src/VisualStudio/Core/Test/Snippets/CSharpSnippetExpansionClientTests.vb b/src/VisualStudio/Core/Test/Snippets/CSharpSnippetExpansionClientTests.vb index 40116e888fd13..e271d20b5cd15 100644 --- a/src/VisualStudio/Core/Test/Snippets/CSharpSnippetExpansionClientTests.vb +++ b/src/VisualStudio/Core/Test/Snippets/CSharpSnippetExpansionClientTests.vb @@ -386,7 +386,7 @@ using G= H.I; Dim formattingOptions = CSharpSyntaxFormattingOptions.Default - Dim updatedDocument = expansionClient.GetTestAccessor().LanguageHelper.AddImports( + Dim updatedDocument = Await expansionClient.GetTestAccessor().LanguageHelper.AddImportsAsync( document, addImportOptions, formattingOptions, diff --git a/src/VisualStudio/Core/Test/Snippets/SnippetTestState.vb b/src/VisualStudio/Core/Test/Snippets/SnippetTestState.vb index dc52a84921156..61926ba77da2c 100644 --- a/src/VisualStudio/Core/Test/Snippets/SnippetTestState.vb +++ b/src/VisualStudio/Core/Test/Snippets/SnippetTestState.vb @@ -159,8 +159,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.Snippets End Sub End Class - - <[Shared]> + Friend Class MockSnippetExpansionClientFactory Inherits SnippetExpansionClientFactory @@ -211,36 +210,35 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.Snippets End Function End Class - - <[Shared]> + Friend NotInheritable Class MockCSharpSnippetLanguageHelper Inherits MockSnippetLanguageHelper - Public Sub New() - MyBase.New(Guids.CSharpLanguageServiceId) + Public Sub New(threadingContext As IThreadingContext) + MyBase.New(threadingContext, Guids.CSharpLanguageServiceId) End Sub End Class - - <[Shared]> + Friend NotInheritable Class MockVisualBasicSnippetLanguageHelper Inherits MockSnippetLanguageHelper - Public Sub New() - MyBase.New(Guids.VisualBasicDebuggerLanguageId) + Public Sub New(threadingContext As IThreadingContext) + MyBase.New(threadingContext, Guids.VisualBasicDebuggerLanguageId) End Sub End Class Friend MustInherit Class MockSnippetLanguageHelper Inherits AbstractSnippetExpansionLanguageHelper - Protected Sub New(languageServiceGuid As Guid) + Protected Sub New(threadingContext As IThreadingContext, languageServiceGuid As Guid) + MyBase.New(threadingContext) Me.LanguageServiceGuid = languageServiceGuid End Sub @@ -252,8 +250,8 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.Snippets End Get End Property - Public Overrides Function AddImports(document As Document, addImportOptions As AddImportPlacementOptions, formattingOptions As SyntaxFormattingOptions, position As Integer, snippetNode As XElement, cancellationToken As CancellationToken) As Document - Return document + Public Overrides Function AddImportsAsync(document As Document, addImportOptions As AddImportPlacementOptions, formattingOptions As SyntaxFormattingOptions, position As Integer, snippetNode As XElement, cancellationToken As CancellationToken) As Task(Of Document) + Return Task.FromResult(document) End Function Public Overrides Function InsertEmptyCommentAndGetEndPositionTrackingSpan(expansionSession As IVsExpansionSession, textView As ITextView, subjectBuffer As ITextBuffer) As ITrackingSpan diff --git a/src/VisualStudio/Core/Test/Snippets/VisualBasicSnippetExpansionClientTests.vb b/src/VisualStudio/Core/Test/Snippets/VisualBasicSnippetExpansionClientTests.vb index 752282bc42a08..287179692a5e6 100644 --- a/src/VisualStudio/Core/Test/Snippets/VisualBasicSnippetExpansionClientTests.vb +++ b/src/VisualStudio/Core/Test/Snippets/VisualBasicSnippetExpansionClientTests.vb @@ -408,7 +408,7 @@ End Class Dim formattingOptions = VisualBasicSyntaxFormattingOptions.Default - Dim updatedDocument = expansionClient.GetTestAccessor().LanguageHelper.AddImports( + Dim updatedDocument = Await expansionClient.GetTestAccessor().LanguageHelper.AddImportsAsync( document, addImportOptions, formattingOptions, diff --git a/src/VisualStudio/Core/Test/SymbolSearch/SymbolSearchUpdateEngineTests.vb b/src/VisualStudio/Core/Test/SymbolSearch/SymbolSearchUpdateEngineTests.vb index 53261ed0ab99d..644a16c07e9f9 100644 --- a/src/VisualStudio/Core/Test/SymbolSearch/SymbolSearchUpdateEngineTests.vb +++ b/src/VisualStudio/Core/Test/SymbolSearch/SymbolSearchUpdateEngineTests.vb @@ -258,7 +258,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.SymbolSearch Dim factoryMock = New Mock(Of IDatabaseFactoryService)(MockBehavior.Strict) ' Simulate Elfie throwing when trying to make a database from the contents of that response - factoryMock.Setup(Function(f) f.CreateDatabaseFromBytes(It.IsAny(Of Byte()))). + factoryMock.Setup(Function(f) f.CreateDatabaseFromBytes(It.IsAny(Of Byte()), It.IsAny(Of Boolean))). Throws(New NotImplementedException()) ' Because the parsing failed we will expect to call into the 'UpdateFailedDelay' to @@ -303,7 +303,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.SymbolSearch ' Successfully create a database from that response. Dim factoryMock = New Mock(Of IDatabaseFactoryService)(MockBehavior.Strict) - factoryMock.Setup(Function(f) f.CreateDatabaseFromBytes(It.IsAny(Of Byte()))). + factoryMock.Setup(Function(f) f.CreateDatabaseFromBytes(It.IsAny(Of Byte()), It.IsAny(Of Boolean))). Returns(New AddReferenceDatabase()) ' Expect that we'll write the database to disk successfully. @@ -352,13 +352,13 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.SymbolSearch ' Create a database from the client response. Dim factoryMock = New Mock(Of IDatabaseFactoryService)(MockBehavior.Strict) - factoryMock.Setup(Function(f) f.CreateDatabaseFromBytes(It.IsAny(Of Byte()))). + factoryMock.Setup(Function(f) f.CreateDatabaseFromBytes(It.IsAny(Of Byte()), It.IsAny(Of Boolean))). Returns(New AddReferenceDatabase()) Dim delayMock = New Mock(Of IDelayService)(MockBehavior.Strict) ' Write the temp file out to disk. - ioMock.Setup(Sub(s) s.WriteAndFlushAllBytes(It.IsAny(Of String), It.IsAny(Of Byte()))) + ioMock.Setup(Sub(s) s.WriteAndFlushAllBytes(It.IsAny(Of String), It.IsAny(Of ArraySegment(Of Byte)))) ' Simulate a failure doing the first 'replace' of the database file. ioMock.Setup(Sub(s) s.Replace(It.IsAny(Of String), It.IsAny(Of String), It.IsAny(Of String), It.IsAny(Of Boolean))). @@ -405,7 +405,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.SymbolSearch ' We'll successfully read in the local database. Dim databaseFactoryMock = New Mock(Of IDatabaseFactoryService)(MockBehavior.Strict) - databaseFactoryMock.Setup(Function(f) f.CreateDatabaseFromBytes(It.IsAny(Of Byte()))). + databaseFactoryMock.Setup(Function(f) f.CreateDatabaseFromBytes(It.IsAny(Of Byte()), It.IsAny(Of Boolean))). Returns(New AddReferenceDatabase()) ' Create a client that will return a patch that says things are up to date. @@ -450,7 +450,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.SymbolSearch ' We'll successfully read in the local database. Dim databaseFactoryMock = New Mock(Of IDatabaseFactoryService)(MockBehavior.Strict) - databaseFactoryMock.Setup(Function(f) f.CreateDatabaseFromBytes(It.IsAny(Of Byte()))). + databaseFactoryMock.Setup(Function(f) f.CreateDatabaseFromBytes(It.IsAny(Of Byte()), It.IsAny(Of Boolean))). Returns(New AddReferenceDatabase()) ' Create a client that will return a patch that says things are too old. @@ -504,7 +504,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.SymbolSearch ' We'll successfully read in the local database. Dim databaseFactoryMock = New Mock(Of IDatabaseFactoryService)(MockBehavior.Strict) - databaseFactoryMock.Setup(Function(f) f.CreateDatabaseFromBytes(It.IsAny(Of Byte()))). + databaseFactoryMock.Setup(Function(f) f.CreateDatabaseFromBytes(It.IsAny(Of Byte()), It.IsAny(Of Boolean))). Returns(New AddReferenceDatabase()) ' Create a client that will return a patch with contents. @@ -564,7 +564,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.SymbolSearch ' We'll successfully read in the local database. Dim databaseFactoryMock = New Mock(Of IDatabaseFactoryService)(MockBehavior.Strict) - databaseFactoryMock.Setup(Function(f) f.CreateDatabaseFromBytes(It.IsAny(Of Byte()))). + databaseFactoryMock.Setup(Function(f) f.CreateDatabaseFromBytes(It.IsAny(Of Byte()), It.IsAny(Of Boolean))). Returns(New AddReferenceDatabase()) ' Create a client that will return a patch with contents. @@ -606,10 +606,10 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.SymbolSearch Private Shared Sub SetupWritesDatabaseSuccessfullyToDisk(ioMock As Mock(Of IIOService)) ' Expect that we'll write out the temp file. - ioMock.Setup(Sub(s) s.WriteAndFlushAllBytes(It.IsRegex(".*tmp"), It.IsAny(Of Byte()))) + ioMock.Setup(Sub(s) s.WriteAndFlushAllBytes(It.IsRegex(".*tmp"), It.IsAny(Of ArraySegment(Of Byte)))) ' Expect that we'll replace the existing file with the temp file. - ioMock.Setup(Sub(s) s.Replace(It.IsRegex(".*tmp"), It.IsRegex(".*txt"), Nothing, It.IsAny(Of Boolean))) + ioMock.Setup(Sub(s) s.Replace(It.IsRegex(".*tmp"), It.IsRegex(".*(txt|bin)"), Nothing, It.IsAny(Of Boolean))) End Sub Private Shared Function CreatefileDownloaderFactoryMock( diff --git a/src/VisualStudio/Core/Test/UnifiedSettings/VisualBasicUnifiedSettingsTests.vb b/src/VisualStudio/Core/Test/UnifiedSettings/VisualBasicUnifiedSettingsTests.vb deleted file mode 100644 index 7f42c3704baf2..0000000000000 --- a/src/VisualStudio/Core/Test/UnifiedSettings/VisualBasicUnifiedSettingsTests.vb +++ /dev/null @@ -1,97 +0,0 @@ -' Licensed to the .NET Foundation under one or more agreements. -' The .NET Foundation licenses this file to you under the MIT license. -' See the LICENSE file in the project root for more information. - -Imports System.Collections.Immutable -Imports System.IO -Imports System.Reflection -Imports Microsoft.CodeAnalysis -Imports Microsoft.CodeAnalysis.Completion -Imports Microsoft.CodeAnalysis.Options -Imports Microsoft.VisualStudio.LanguageServices -Imports Microsoft.VisualStudio.LanguageServices.UnitTests.UnifiedSettings -Imports Newtonsoft.Json.Linq - -Namespace Roslyn.VisualStudio.VisualBasic.UnitTests.UnifiedSettings - Public Class VisualBasicUnifiedSettingsTests - Inherits UnifiedSettingsTests - - Friend Overrides ReadOnly Property OnboardedOptions As ImmutableArray(Of IOption2) - Get - Return ImmutableArray.Create(Of IOption2)( - CompletionOptionsStorage.TriggerOnTypingLetters, - CompletionOptionsStorage.TriggerOnDeletion, - CompletionViewOptionsStorage.HighlightMatchingPortionsOfCompletionListItems, - CompletionViewOptionsStorage.ShowCompletionItemFilters, - CompletionOptionsStorage.SnippetsBehavior, - CompletionOptionsStorage.EnterKeyBehavior, - CompletionOptionsStorage.ShowItemsFromUnimportedNamespaces, - CompletionViewOptionsStorage.EnableArgumentCompletionSnippets - ) - End Get - End Property - - Friend Overrides Function GetEnumOptionValues([option] As IOption2) As Object() - Dim allValues = [Enum].GetValues([option].Type).Cast(Of Object) - If [option].Equals(CompletionOptionsStorage.SnippetsBehavior) Then - 'SnippetsRule.Default is used as a stub value, overridden per language at runtime. - ' It is not shown in the option page - Return allValues.Where(Function(value) Not value.Equals(SnippetsRule.Default)).ToArray() - ElseIf [option].Equals(CompletionOptionsStorage.EnterKeyBehavior) Then - ' EnterKeyRule.Default is used as a stub value, overridden per language at runtime. - ' It Is Not shown in the option page - Return allValues.Where(Function(value) Not value.Equals(EnterKeyRule.Default)).ToArray() - End If - - Return MyBase.GetEnumOptionValues([option]) - End Function - - Friend Overrides Function GetOptionsDefaultValue([option] As IOption2) As Object - ' The default values of some options are set at runtime. option.defaultValue is just a dummy value in this case. - ' However, in unified settings we always set the correct value in registration.json. - If [option].Equals(CompletionOptionsStorage.SnippetsBehavior) Then - ' CompletionOptionsStorage.SnippetsBehavior's default value is SnippetsRule.Default. - ' It's overridden differently per-language at runtime. - Return SnippetsRule.IncludeAfterTypingIdentifierQuestionTab - ElseIf [option].Equals(CompletionOptionsStorage.EnterKeyBehavior) Then - ' CompletionOptionsStorage.EnterKeyBehavior's default value is EnterKeyBehavior.Default. - ' It's overridden differently per-language at runtime. - Return EnterKeyRule.Always - ElseIf [option].Equals(CompletionOptionsStorage.TriggerOnDeletion) Then - ' CompletionOptionsStorage.TriggerOnDeletion's default value is null. - ' It's enabled by default for Visual Basic - Return True - ElseIf [option].Equals(CompletionOptionsStorage.ShowItemsFromUnimportedNamespaces) Then - ' CompletionOptionsStorage.ShowItemsFromUnimportedNamespaces's default value is null - ' It's enabled by default for Visual Basic - Return True - ElseIf [option].Equals(CompletionViewOptionsStorage.EnableArgumentCompletionSnippets) Then - ' CompletionViewOptionsStorage.EnableArgumentCompletionSnippets' default value is null - ' It's disabled by default for Visual Basic - Return False - End If - - Return MyBase.GetOptionsDefaultValue([option]) - End Function - - - Public Async Function IntelliSensePageTests() As Task - Using registrationFileStream = GetType(VisualBasicUnifiedSettingsTests).GetTypeInfo().Assembly.GetManifestResourceStream("visualBasicSettings.registration.json") - Using pkgDefFileStream = GetType(VisualBasicUnifiedSettingsTests).GetTypeInfo().Assembly.GetManifestResourceStream("PackageRegistration.pkgdef") - Using pkgDefFileReader = New StreamReader(pkgDefFileStream) - Using reader = New StreamReader(registrationFileStream) - Dim registrationFile = Await reader.ReadToEndAsync().ConfigureAwait(False) - Dim pkgDefFile = Await pkgDefFileReader.ReadToEndAsync().ConfigureAwait(False) - Dim registrationJsonObject = JObject.Parse(registrationFile, New JsonLoadSettings()) - Dim categoriesTitle = registrationJsonObject.SelectToken("$.categories['textEditor.basic'].title") - Assert.Equal("Visual Basic", categoriesTitle) - Dim optionPageId = registrationJsonObject.SelectToken("$.categories['textEditor.basic.intellisense'].legacyOptionPageId") - Assert.Equal(Guids.VisualBasicOptionPageIntelliSenseIdString, optionPageId.ToString()) - TestUnifiedSettingsCategory(registrationJsonObject, categoryBasePath:="textEditor.basic.intellisense", languageName:=LanguageNames.VisualBasic, pkgDefFile) - End Using - End Using - End Using - End Using - End Function - End Class -End Namespace diff --git a/src/VisualStudio/ExternalAccess/FSharp/Editor/Implementation/Debugging/FSharpDebugDataTipInfo.cs b/src/VisualStudio/ExternalAccess/FSharp/Editor/Implementation/Debugging/FSharpDebugDataTipInfo.cs index 441dd55735257..c02e99b3b2f16 100644 --- a/src/VisualStudio/ExternalAccess/FSharp/Editor/Implementation/Debugging/FSharpDebugDataTipInfo.cs +++ b/src/VisualStudio/ExternalAccess/FSharp/Editor/Implementation/Debugging/FSharpDebugDataTipInfo.cs @@ -5,17 +5,13 @@ using Microsoft.CodeAnalysis.Debugging; using Microsoft.CodeAnalysis.Text; -namespace Microsoft.CodeAnalysis.ExternalAccess.FSharp.Editor.Implementation.Debugging -{ - internal readonly struct FSharpDebugDataTipInfo - { - internal readonly DebugDataTipInfo UnderlyingObject; +namespace Microsoft.CodeAnalysis.ExternalAccess.FSharp.Editor.Implementation.Debugging; - public FSharpDebugDataTipInfo(TextSpan span, string text) - => UnderlyingObject = new DebugDataTipInfo(span, text); +internal readonly struct FSharpDebugDataTipInfo(TextSpan span, string text) +{ + internal readonly DebugDataTipInfo UnderlyingObject = new(span, text); - public readonly TextSpan Span => UnderlyingObject.Span; - public readonly string Text => UnderlyingObject.Text; - public bool IsDefault => UnderlyingObject.IsDefault; - } + public readonly TextSpan Span => UnderlyingObject.Span; + public readonly string Text => UnderlyingObject.Text!; + public bool IsDefault => UnderlyingObject.IsDefault; } diff --git a/src/VisualStudio/ExternalAccess/FSharp/Internal/Diagnostics/FSharpSimplifyNameDiagnosticAnalyzer.cs b/src/VisualStudio/ExternalAccess/FSharp/Internal/Diagnostics/FSharpSimplifyNameDiagnosticAnalyzer.cs index 304de16a63025..5de0fc5b156ca 100644 --- a/src/VisualStudio/ExternalAccess/FSharp/Internal/Diagnostics/FSharpSimplifyNameDiagnosticAnalyzer.cs +++ b/src/VisualStudio/ExternalAccess/FSharp/Internal/Diagnostics/FSharpSimplifyNameDiagnosticAnalyzer.cs @@ -48,7 +48,7 @@ internal class FSharpSimplifyNameDiagnosticAnalyzer : DocumentDiagnosticAnalyzer ExternalAccessFSharpResources.NameCanBeSimplified, DiagnosticCategory.Style, DiagnosticSeverity.Hidden, isEnabledByDefault: true, customTags: FSharpDiagnosticCustomTags.Unnecessary); - public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create(_descriptor); + public override ImmutableArray SupportedDiagnostics => [_descriptor]; public bool IsHighPriority => false; diff --git a/src/VisualStudio/ExternalAccess/FSharp/Internal/Diagnostics/FSharpUnusedDeclarationsAnalyzer.cs b/src/VisualStudio/ExternalAccess/FSharp/Internal/Diagnostics/FSharpUnusedDeclarationsAnalyzer.cs index da8d8d16180cd..37a35d397f322 100644 --- a/src/VisualStudio/ExternalAccess/FSharp/Internal/Diagnostics/FSharpUnusedDeclarationsAnalyzer.cs +++ b/src/VisualStudio/ExternalAccess/FSharp/Internal/Diagnostics/FSharpUnusedDeclarationsAnalyzer.cs @@ -50,7 +50,7 @@ internal class FSharpUnusedDeclarationsDiagnosticAnalyzer : DocumentDiagnosticAn ExternalAccessFSharpResources.TheValueIsUnused, DiagnosticCategory.Style, DiagnosticSeverity.Hidden, isEnabledByDefault: true, customTags: FSharpDiagnosticCustomTags.Unnecessary); - public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create(_descriptor); + public override ImmutableArray SupportedDiagnostics => [_descriptor]; public bool IsHighPriority => false; diff --git a/src/VisualStudio/ExternalAccess/FSharp/Internal/Diagnostics/FSharpUnusedOpensDiagnosticAnalyzer.cs b/src/VisualStudio/ExternalAccess/FSharp/Internal/Diagnostics/FSharpUnusedOpensDiagnosticAnalyzer.cs index 172cb58bf324f..8e6c29622535c 100644 --- a/src/VisualStudio/ExternalAccess/FSharp/Internal/Diagnostics/FSharpUnusedOpensDiagnosticAnalyzer.cs +++ b/src/VisualStudio/ExternalAccess/FSharp/Internal/Diagnostics/FSharpUnusedOpensDiagnosticAnalyzer.cs @@ -45,7 +45,7 @@ internal class FSharpUnusedOpensDeclarationsDiagnosticAnalyzer : DocumentDiagnos ExternalAccessFSharpResources.UnusedOpens, DiagnosticCategory.Style, DiagnosticSeverity.Hidden, isEnabledByDefault: true, customTags: FSharpDiagnosticCustomTags.Unnecessary); - public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create(_descriptor); + public override ImmutableArray SupportedDiagnostics => [_descriptor]; public override int Priority => 90; // Default = 50 diff --git a/src/VisualStudio/ExternalAccess/FSharp/Internal/Editor/FSharpEditorFormattingService.cs b/src/VisualStudio/ExternalAccess/FSharp/Internal/Editor/FSharpEditorFormattingService.cs index 367b812c8282a..c76f097940cee 100644 --- a/src/VisualStudio/ExternalAccess/FSharp/Internal/Editor/FSharpEditorFormattingService.cs +++ b/src/VisualStudio/ExternalAccess/FSharp/Internal/Editor/FSharpEditorFormattingService.cs @@ -79,25 +79,25 @@ public bool SupportsFormattingOnTypedCharacter(Document document, char ch) async Task> IFormattingInteractionService.GetFormattingChangesAsync(Document document, ITextBuffer textBuffer, TextSpan? textSpan, CancellationToken cancellationToken) { var changes = await GetFormattingChangesAsync(document, textSpan, cancellationToken).ConfigureAwait(false); - return changes?.ToImmutableArray() ?? ImmutableArray.Empty; + return changes?.ToImmutableArray() ?? []; } async Task> IFormattingInteractionService.GetFormattingChangesAsync(Document document, ITextBuffer textBuffer, char typedChar, int position, CancellationToken cancellationToken) { var changes = await GetFormattingChangesAsync(document, typedChar, position, cancellationToken).ConfigureAwait(false); - return changes?.ToImmutableArray() ?? ImmutableArray.Empty; + return changes?.ToImmutableArray() ?? []; } async Task> IFormattingInteractionService.GetFormattingChangesOnPasteAsync(Document document, ITextBuffer textBuffer, TextSpan textSpan, CancellationToken cancellationToken) { var changes = await GetFormattingChangesOnPasteAsync(document, textSpan, cancellationToken).ConfigureAwait(false); - return changes?.ToImmutableArray() ?? ImmutableArray.Empty; + return changes?.ToImmutableArray() ?? []; } async Task> IFormattingInteractionService.GetFormattingChangesOnReturnAsync(Document document, int position, CancellationToken cancellationToken) { var changes = await GetFormattingChangesOnReturnAsync(document, position, cancellationToken).ConfigureAwait(false); - return changes?.ToImmutableArray() ?? ImmutableArray.Empty; + return changes?.ToImmutableArray() ?? []; } } } diff --git a/src/VisualStudio/ExternalAccess/FSharp/Internal/Editor/FSharpNavigationBarItemService.cs b/src/VisualStudio/ExternalAccess/FSharp/Internal/Editor/FSharpNavigationBarItemService.cs index 8cbee65073e5d..9d71c9d48eb00 100644 --- a/src/VisualStudio/ExternalAccess/FSharp/Internal/Editor/FSharpNavigationBarItemService.cs +++ b/src/VisualStudio/ExternalAccess/FSharp/Internal/Editor/FSharpNavigationBarItemService.cs @@ -53,7 +53,7 @@ async Task> INavigationBarItemService.GetItems { var items = await _service.GetItemsAsync(document, cancellationToken).ConfigureAwait(false); return items == null - ? ImmutableArray.Empty + ? [] : ConvertItems(items, textVersion); } diff --git a/src/VisualStudio/ExternalAccess/FSharp/Internal/Editor/Implementation/Debugging/FSharpLanguageDebugInfoService.cs b/src/VisualStudio/ExternalAccess/FSharp/Internal/Editor/Implementation/Debugging/FSharpLanguageDebugInfoService.cs index ffeb91a5f55d5..b8fe584ea5eda 100644 --- a/src/VisualStudio/ExternalAccess/FSharp/Internal/Editor/Implementation/Debugging/FSharpLanguageDebugInfoService.cs +++ b/src/VisualStudio/ExternalAccess/FSharp/Internal/Editor/Implementation/Debugging/FSharpLanguageDebugInfoService.cs @@ -14,20 +14,14 @@ namespace Microsoft.CodeAnalysis.ExternalAccess.FSharp.Internal.Editor.Implementation.Debugging { - [Shared] - [ExportLanguageService(typeof(ILanguageDebugInfoService), LanguageNames.FSharp)] - internal class FSharpLanguageDebugInfoService : ILanguageDebugInfoService + [ExportLanguageService(typeof(ILanguageDebugInfoService), LanguageNames.FSharp), Shared] + [method: ImportingConstructor] + [method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] + internal class FSharpLanguageDebugInfoService(IFSharpLanguageDebugInfoService service) : ILanguageDebugInfoService { - private readonly IFSharpLanguageDebugInfoService _service; + private readonly IFSharpLanguageDebugInfoService _service = service; - [ImportingConstructor] - [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - public FSharpLanguageDebugInfoService(IFSharpLanguageDebugInfoService service) - { - _service = service; - } - - public async Task GetDataTipInfoAsync(Document document, int position, CancellationToken cancellationToken) + public async Task GetDataTipInfoAsync(Document document, int position, bool includeKind, CancellationToken cancellationToken) => (await _service.GetDataTipInfoAsync(document, position, cancellationToken).ConfigureAwait(false)).UnderlyingObject; public async Task GetLocationInfoAsync(Document document, int position, CancellationToken cancellationToken) diff --git a/src/VisualStudio/ExternalAccess/FSharp/Internal/InlineHints/FSharpInlineHintsService.cs b/src/VisualStudio/ExternalAccess/FSharp/Internal/InlineHints/FSharpInlineHintsService.cs index e96db44666b25..356226a39ca84 100644 --- a/src/VisualStudio/ExternalAccess/FSharp/Internal/InlineHints/FSharpInlineHintsService.cs +++ b/src/VisualStudio/ExternalAccess/FSharp/Internal/InlineHints/FSharpInlineHintsService.cs @@ -31,7 +31,7 @@ public async Task> GetInlineHintsAsync( Document document, TextSpan textSpan, InlineHintsOptions options, bool displayAllOverride, CancellationToken cancellationToken) { if (_service == null) - return ImmutableArray.Empty; + return []; var hints = await _service.GetInlineHintsAsync(document, textSpan, cancellationToken).ConfigureAwait(false); return hints.SelectAsArray(h => new InlineHint(h.Span, h.DisplayParts, (d, c) => h.GetDescriptionAsync(d, c))); diff --git a/src/VisualStudio/ExternalAccess/FSharp/Internal/NavigateTo/InternalFSharpNavigateToSearchResult.cs b/src/VisualStudio/ExternalAccess/FSharp/Internal/NavigateTo/InternalFSharpNavigateToSearchResult.cs index 4737fafc0afdd..74a4a1623cf6d 100644 --- a/src/VisualStudio/ExternalAccess/FSharp/Internal/NavigateTo/InternalFSharpNavigateToSearchResult.cs +++ b/src/VisualStudio/ExternalAccess/FSharp/Internal/NavigateTo/InternalFSharpNavigateToSearchResult.cs @@ -33,7 +33,7 @@ public InternalFSharpNavigateToSearchResult(FSharpNavigateToSearchResult result) public bool IsCaseSensitive => false; - public ImmutableArray NameMatchSpans => ImmutableArray.Empty; + public ImmutableArray NameMatchSpans => []; public string SecondarySort => null; diff --git a/src/VisualStudio/ExternalAccess/FSharp/Internal/Navigation/InternalFSharpNavigableItem.cs b/src/VisualStudio/ExternalAccess/FSharp/Internal/Navigation/InternalFSharpNavigableItem.cs index 48cadf77ebc2e..f2ae319723ab8 100644 --- a/src/VisualStudio/ExternalAccess/FSharp/Internal/Navigation/InternalFSharpNavigableItem.cs +++ b/src/VisualStudio/ExternalAccess/FSharp/Internal/Navigation/InternalFSharpNavigableItem.cs @@ -41,6 +41,6 @@ public InternalFSharpNavigableItem(FSharpNavigableItem item) public bool IsStale => false; - public ImmutableArray ChildItems => ImmutableArray.Empty; + public ImmutableArray ChildItems => []; } } diff --git a/src/VisualStudio/ExternalAccess/FSharp/TaskList/FSharpTaskListService.cs b/src/VisualStudio/ExternalAccess/FSharp/TaskList/FSharpTaskListService.cs index 2d16c1d708fe3..9fbe5e1c26d78 100644 --- a/src/VisualStudio/ExternalAccess/FSharp/TaskList/FSharpTaskListService.cs +++ b/src/VisualStudio/ExternalAccess/FSharp/TaskList/FSharpTaskListService.cs @@ -29,7 +29,7 @@ public FSharpTaskListService([Import(AllowDefault = true)] IFSharpTaskListServic public async Task> GetTaskListItemsAsync(Document document, ImmutableArray descriptors, CancellationToken cancellationToken) { if (_impl == null) - return ImmutableArray.Empty; + return []; var result = await _impl.GetTaskListItemsAsync( document, @@ -37,7 +37,7 @@ public async Task> GetTaskListItemsAsync(Document d cancellationToken).ConfigureAwait(false); if (result.Length == 0) - return ImmutableArray.Empty; + return []; var text = await document.GetValueTextAsync(cancellationToken).ConfigureAwait(false); diff --git a/src/VisualStudio/ExternalAccess/FSharp/VS/IFSharpWorkspaceProjectContextFactory.cs b/src/VisualStudio/ExternalAccess/FSharp/VS/IFSharpWorkspaceProjectContextFactory.cs index 31638ec5db697..055095ea608c5 100644 --- a/src/VisualStudio/ExternalAccess/FSharp/VS/IFSharpWorkspaceProjectContextFactory.cs +++ b/src/VisualStudio/ExternalAccess/FSharp/VS/IFSharpWorkspaceProjectContextFactory.cs @@ -91,7 +91,7 @@ public override string GetPropertyValue(string name) }; public override ImmutableArray GetItemValues(string name) - => ImmutableArray.Empty; + => []; } } diff --git a/src/VisualStudio/IntegrationTest/New.IntegrationTests/CSharp/CSharpIntelliSense.cs b/src/VisualStudio/IntegrationTest/New.IntegrationTests/CSharp/CSharpIntelliSense.cs index 64a44d7713c2d..42c0b6d5561f7 100644 --- a/src/VisualStudio/IntegrationTest/New.IntegrationTests/CSharp/CSharpIntelliSense.cs +++ b/src/VisualStudio/IntegrationTest/New.IntegrationTests/CSharp/CSharpIntelliSense.cs @@ -168,7 +168,7 @@ public async Task CtrlAltSpace(bool showCompletionInArgumentLists) await TestServices.EditorVerifier.CurrentLineTextAsync(" System.Console.WriteLine();$$", assertCaretPosition: true, HangMitigatingCancellationToken); await TestServices.Input.SendAsync([VirtualKeyCode.HOME, (VirtualKeyCode.END, VirtualKeyCode.SHIFT), VirtualKeyCode.DELETE], HangMitigatingCancellationToken); - await TestServices.Input.SendAsync(new InputKey(VirtualKeyCode.SPACE, ImmutableArray.Create(VirtualKeyCode.CONTROL, VirtualKeyCode.MENU)), HangMitigatingCancellationToken); + await TestServices.Input.SendAsync(new InputKey(VirtualKeyCode.SPACE, [VirtualKeyCode.CONTROL, VirtualKeyCode.MENU]), HangMitigatingCancellationToken); await TestServices.Input.SendAsync("System.Console.", HangMitigatingCancellationToken); Assert.True(await TestServices.Editor.IsCompletionActiveAsync(HangMitigatingCancellationToken)); diff --git a/src/VisualStudio/IntegrationTest/New.IntegrationTests/CSharp/CSharpKeywordHighlighting.cs b/src/VisualStudio/IntegrationTest/New.IntegrationTests/CSharp/CSharpKeywordHighlighting.cs index fec1066da488f..25abb259cb4c1 100644 --- a/src/VisualStudio/IntegrationTest/New.IntegrationTests/CSharp/CSharpKeywordHighlighting.cs +++ b/src/VisualStudio/IntegrationTest/New.IntegrationTests/CSharp/CSharpKeywordHighlighting.cs @@ -47,7 +47,7 @@ void M() await VerifyAsync("foreach", spans, HangMitigatingCancellationToken); await VerifyAsync("break", spans, HangMitigatingCancellationToken); await VerifyAsync("continue", spans, HangMitigatingCancellationToken); - await VerifyAsync("in", ImmutableArray.Create(), HangMitigatingCancellationToken); + await VerifyAsync("in", [], HangMitigatingCancellationToken); } [IdeFact] diff --git a/src/VisualStudio/IntegrationTest/New.IntegrationTests/CSharp/CSharpRename.cs b/src/VisualStudio/IntegrationTest/New.IntegrationTests/CSharp/CSharpRename.cs index a21f24aa2f944..080b2c5a3da4c 100644 --- a/src/VisualStudio/IntegrationTest/New.IntegrationTests/CSharp/CSharpRename.cs +++ b/src/VisualStudio/IntegrationTest/New.IntegrationTests/CSharp/CSharpRename.cs @@ -738,7 +738,7 @@ public class Class2 var selectedSpan = spans["selection"].Single(); await TestServices.Editor.SetSelectionAsync(selectedSpan, HangMitigatingCancellationToken); await TestServices.Input.SendWithoutActivateAsync( - new InputKey(VirtualKeyCode.BACK, ImmutableArray.Empty), HangMitigatingCancellationToken); + new InputKey(VirtualKeyCode.BACK, []), HangMitigatingCancellationToken); await TestServices.Input.SendWithoutActivateAsync(["Other", "Stuff"], HangMitigatingCancellationToken); await TestServices.EditorVerifier.TextEqualsAsync( """ diff --git a/src/VisualStudio/IntegrationTest/New.IntegrationTests/CSharp/CSharpWinForms.cs b/src/VisualStudio/IntegrationTest/New.IntegrationTests/CSharp/CSharpWinForms.cs index 3675c407613eb..0229383641503 100644 --- a/src/VisualStudio/IntegrationTest/New.IntegrationTests/CSharp/CSharpWinForms.cs +++ b/src/VisualStudio/IntegrationTest/New.IntegrationTests/CSharp/CSharpWinForms.cs @@ -8,6 +8,7 @@ using Microsoft.CodeAnalysis.Test.Utilities; using Microsoft.VisualStudio.IntegrationTest.Utilities; using Roslyn.VisualStudio.IntegrationTests; +using Roslyn.Test.Utilities; using Xunit; namespace Roslyn.VisualStudio.NewIntegrationTests.CSharp; @@ -94,7 +95,7 @@ public async Task AddClickHandler() Assert.Contains(@"this.SomeButton.Click += new System.EventHandler(this.ExecuteWhenButtonClicked);", designerActualText); await TestServices.SolutionExplorer.OpenFileAsync(project, "Form1.cs", HangMitigatingCancellationToken); var codeFileActualText = await TestServices.Editor.GetTextAsync(HangMitigatingCancellationToken); - Assert.Contains(@" public partial class Form1 : Form + Assert.Contains(@" public partial class Form1: Form { public Form1() { @@ -204,32 +205,34 @@ await TestServices.Workspace.WaitForAllAsyncOperationsAsync( var actualText = await TestServices.Editor.GetTextAsync(HangMitigatingCancellationToken); Assert.Contains(@"public System.Windows.Forms.Button SomeButton;", actualText); } - [IdeFact] public async Task DeleteControl() { - var project = ProjectName; - await TestServices.SolutionExplorer.OpenFileWithDesignerAsync(project, "Form1.cs", HangMitigatingCancellationToken); - await TestServices.Editor.AddWinFormButtonAsync("SomeButton", HangMitigatingCancellationToken); - await TestServices.SolutionExplorer.SaveFileAsync(project, "Form1.cs", HangMitigatingCancellationToken); - await TestServices.SolutionExplorer.SaveFileAsync(project, "Form1.resx", HangMitigatingCancellationToken); - await TestServices.Editor.DeleteWinFormButtonAsync("SomeButton", HangMitigatingCancellationToken); - - await TestServices.Workspace.WaitForAllAsyncOperationsAsync( - [ - FeatureAttribute.Workspace, - FeatureAttribute.SolutionCrawlerLegacy, - FeatureAttribute.DiagnosticService, - FeatureAttribute.EditAndContinue, - FeatureAttribute.ErrorSquiggles, - FeatureAttribute.ErrorList, - ], - HangMitigatingCancellationToken); - - Assert.Empty(await TestServices.ErrorList.GetBuildErrorsAsync(HangMitigatingCancellationToken)); - await TestServices.SolutionExplorer.OpenFileAsync(project, "Form1.Designer.cs", HangMitigatingCancellationToken); - var actualText = await TestServices.Editor.GetTextAsync(HangMitigatingCancellationToken); - Assert.DoesNotContain(@"VisualStudio.Editor.SomeButton.Name = ""SomeButton"";", actualText); - Assert.DoesNotContain(@"private System.Windows.Forms.Button SomeButton;", actualText); + if (ExecutionConditionUtil.IsBitness64) + { + var project = ProjectName; + await TestServices.SolutionExplorer.OpenFileWithDesignerAsync(project, "Form1.cs", HangMitigatingCancellationToken); + await TestServices.Editor.AddWinFormButtonAsync("SomeButton", HangMitigatingCancellationToken); + await TestServices.SolutionExplorer.SaveFileAsync(project, "Form1.cs", HangMitigatingCancellationToken); + await TestServices.SolutionExplorer.SaveFileAsync(project, "Form1.resx", HangMitigatingCancellationToken); + await TestServices.Editor.DeleteWinFormButtonAsync("SomeButton", HangMitigatingCancellationToken); + + await TestServices.Workspace.WaitForAllAsyncOperationsAsync( + [ + FeatureAttribute.Workspace, + FeatureAttribute.SolutionCrawlerLegacy, + FeatureAttribute.DiagnosticService, + FeatureAttribute.EditAndContinue, + FeatureAttribute.ErrorSquiggles, + FeatureAttribute.ErrorList, + ], + HangMitigatingCancellationToken); + + Assert.Empty(await TestServices.ErrorList.GetBuildErrorsAsync(HangMitigatingCancellationToken)); + await TestServices.SolutionExplorer.OpenFileAsync(project, "Form1.Designer.cs", HangMitigatingCancellationToken); + var actualText = await TestServices.Editor.GetTextAsync(HangMitigatingCancellationToken); + Assert.DoesNotContain(@"VisualStudio.Editor.SomeButton.Name = ""SomeButton"";", actualText); + Assert.DoesNotContain(@"private System.Windows.Forms.Button SomeButton;", actualText); + } } } diff --git a/src/VisualStudio/IntegrationTest/New.IntegrationTests/InProcess/AutomationElementHelper.cs b/src/VisualStudio/IntegrationTest/New.IntegrationTests/InProcess/AutomationElementHelper.cs index 79893d1f91e40..e00ced80c3da6 100644 --- a/src/VisualStudio/IntegrationTest/New.IntegrationTests/InProcess/AutomationElementHelper.cs +++ b/src/VisualStudio/IntegrationTest/New.IntegrationTests/InProcess/AutomationElementHelper.cs @@ -11,7 +11,7 @@ namespace Microsoft.VisualStudio.IntegrationTest.Utilities; -public class AutomationElementHelper +public static class AutomationElementHelper { /// /// Finds the automation element by and clicks on it asynchronously. diff --git a/src/VisualStudio/IntegrationTest/New.IntegrationTests/InProcess/EditorInProcess.cs b/src/VisualStudio/IntegrationTest/New.IntegrationTests/InProcess/EditorInProcess.cs index f684eed46e2b4..e622d282327ee 100644 --- a/src/VisualStudio/IntegrationTest/New.IntegrationTests/InProcess/EditorInProcess.cs +++ b/src/VisualStudio/IntegrationTest/New.IntegrationTests/InProcess/EditorInProcess.cs @@ -334,7 +334,7 @@ public async Task GetCurrentClassificationsAsync(CancellationToken can var classifierAggregatorService = await TestServices.Shell.GetComponentModelServiceAsync(cancellationToken); classifier = classifierAggregatorService.GetClassifier(textView); var classifiedSpans = classifier.GetClassificationSpans(selectionSpan); - return classifiedSpans.Select(x => x.ClassificationType.Classification).ToArray(); + return [.. classifiedSpans.Select(x => x.ClassificationType.Classification)]; } finally { @@ -745,7 +745,7 @@ public async Task GetLightBulbActionsAsync(CancellationToken cancellat var view = await GetActiveTextViewAsync(cancellationToken); var broker = await GetComponentModelServiceAsync(cancellationToken); - return (await GetLightBulbActionsAsync(broker, view, cancellationToken)).Select(a => a.DisplayText).ToArray(); + return [.. (await GetLightBulbActionsAsync(broker, view, cancellationToken)).Select(a => a.DisplayText)]; } public async Task ApplyLightBulbActionAsync(string actionName, FixAllScope? fixAllScope, bool blockUntilComplete, CancellationToken cancellationToken) diff --git a/src/VisualStudio/IntegrationTest/New.IntegrationTests/InProcess/ErrorListInProcess.cs b/src/VisualStudio/IntegrationTest/New.IntegrationTests/InProcess/ErrorListInProcess.cs index 351e4349b4de2..2273947cbfc85 100644 --- a/src/VisualStudio/IntegrationTest/New.IntegrationTests/InProcess/ErrorListInProcess.cs +++ b/src/VisualStudio/IntegrationTest/New.IntegrationTests/InProcess/ErrorListInProcess.cs @@ -52,10 +52,9 @@ public async Task> GetErrorsAsync(ErrorSource errorSource var errorItems = await GetErrorItemsAsync(errorSource, minimumSeverity, cancellationToken); var list = errorItems.Select(GetMessage).ToList(); - return list + return [.. list .OrderBy(x => x, StringComparer.OrdinalIgnoreCase) - .ThenBy(x => x, StringComparer.Ordinal) - .ToImmutableArray(); + .ThenBy(x => x, StringComparer.Ordinal)]; } public async Task NavigateToErrorListItemAsync(int item, bool isPreview, bool shouldActivate, CancellationToken cancellationToken) @@ -87,7 +86,7 @@ private async Task> GetErrorItemsAsync(ErrorSo var errorList = await GetRequiredGlobalServiceAsync(cancellationToken); var args = await errorList.TableControl.ForceUpdateAsync().WithCancellation(cancellationToken); - return args.AllEntries + return [.. args.AllEntries .Where(item => { if (item.GetCategory() > minimumSeverity) @@ -102,8 +101,7 @@ private async Task> GetErrorItemsAsync(ErrorSo } return true; - }) - .ToImmutableArray(); + })]; } private static string GetMessage(ITableEntryHandle item) diff --git a/src/VisualStudio/IntegrationTest/New.IntegrationTests/InProcess/FindReferencesWindowInProcess.cs b/src/VisualStudio/IntegrationTest/New.IntegrationTests/InProcess/FindReferencesWindowInProcess.cs index 334dfb6e44e3d..504735e831152 100644 --- a/src/VisualStudio/IntegrationTest/New.IntegrationTests/InProcess/FindReferencesWindowInProcess.cs +++ b/src/VisualStudio/IntegrationTest/New.IntegrationTests/InProcess/FindReferencesWindowInProcess.cs @@ -56,7 +56,7 @@ public async Task> GetContentsAsync(Cancellat var forcedUpdateResult = await tableControl.ForceUpdateAsync().WithCancellation(cancellationToken); // Extract the basic text of the results. - return forcedUpdateResult.AllEntries.Cast().ToImmutableArray(); + return [.. forcedUpdateResult.AllEntries.Cast()]; } public async Task NavigateToAsync(ITableEntryHandle2 referenceInGeneratedFile, bool isPreview, bool shouldActivate, CancellationToken cancellationToken) diff --git a/src/VisualStudio/IntegrationTest/New.IntegrationTests/InProcess/ITextViewWindowInProcessExtensions.cs b/src/VisualStudio/IntegrationTest/New.IntegrationTests/InProcess/ITextViewWindowInProcessExtensions.cs index a76d02adeff9e..0b6041150e045 100644 --- a/src/VisualStudio/IntegrationTest/New.IntegrationTests/InProcess/ITextViewWindowInProcessExtensions.cs +++ b/src/VisualStudio/IntegrationTest/New.IntegrationTests/InProcess/ITextViewWindowInProcessExtensions.cs @@ -91,7 +91,7 @@ public static async Task> GetCompletionItemsAsync(thi var view = await textViewWindow.GetActiveTextViewAsync(cancellationToken); if (view is null) - return ImmutableArray.Empty; + return []; var broker = await textViewWindow.TestServices.Shell.GetComponentModelServiceAsync(cancellationToken); var sessions = broker.GetSessions(view); @@ -101,7 +101,7 @@ public static async Task> GetCompletionItemsAsync(thi } var selectedCompletionSet = sessions[0].SelectedCompletionSet; - return selectedCompletionSet.Completions.ToImmutableArray(); + return [.. selectedCompletionSet.Completions]; } public static async Task InvokeCodeActionListAsync(this ITextViewWindowInProcess textViewWindow, CancellationToken cancellationToken) diff --git a/src/VisualStudio/IntegrationTest/New.IntegrationTests/InProcess/InputKey.cs b/src/VisualStudio/IntegrationTest/New.IntegrationTests/InProcess/InputKey.cs index ef8d9219ec191..a9a7559cd89c7 100644 --- a/src/VisualStudio/IntegrationTest/New.IntegrationTests/InProcess/InputKey.cs +++ b/src/VisualStudio/IntegrationTest/New.IntegrationTests/InProcess/InputKey.cs @@ -25,7 +25,7 @@ public InputKey(VirtualKeyCode virtualKeyCode, ImmutableArray mo public InputKey(char character) { - Modifiers = ImmutableArray.Empty; + Modifiers = []; VirtualKeyCode = 0; Character = character; Text = null; @@ -33,7 +33,7 @@ public InputKey(char character) public InputKey(string text) { - Modifiers = ImmutableArray.Empty; + Modifiers = []; VirtualKeyCode = 0; Character = null; Text = text; @@ -46,10 +46,10 @@ public static implicit operator InputKey(string text) => new(text); public static implicit operator InputKey(VirtualKeyCode virtualKeyCode) - => new(virtualKeyCode, ImmutableArray.Empty); + => new(virtualKeyCode, []); public static implicit operator InputKey((VirtualKeyCode virtualKeyCode, VirtualKeyCode modifier) modifiedKey) - => new(modifiedKey.virtualKeyCode, ImmutableArray.Create(modifiedKey.modifier)); + => new(modifiedKey.virtualKeyCode, [modifiedKey.modifier]); public void Apply(IInputSimulator simulator) { diff --git a/src/VisualStudio/IntegrationTest/New.IntegrationTests/InProcess/LightBulbHelper.cs b/src/VisualStudio/IntegrationTest/New.IntegrationTests/InProcess/LightBulbHelper.cs index 56f17a3b6705e..394c9ddf4640a 100644 --- a/src/VisualStudio/IntegrationTest/New.IntegrationTests/InProcess/LightBulbHelper.cs +++ b/src/VisualStudio/IntegrationTest/New.IntegrationTests/InProcess/LightBulbHelper.cs @@ -60,7 +60,7 @@ public static async Task> WaitForItemsAsync(Test return; if (e.Status == QuerySuggestedActionCompletionStatus.Completed) - tcs.SetResult(e.ActionSets.ToList()); + tcs.SetResult([.. e.ActionSets]); else if (e.Status == QuerySuggestedActionCompletionStatus.CompletedWithoutData) tcs.SetResult([]); else if (e.Status == QuerySuggestedActionCompletionStatus.Canceled) diff --git a/src/VisualStudio/IntegrationTest/New.IntegrationTests/InProcess/MessageBoxInProcess.cs b/src/VisualStudio/IntegrationTest/New.IntegrationTests/InProcess/MessageBoxInProcess.cs index 8c46764d27b3f..03febc6b4323a 100644 --- a/src/VisualStudio/IntegrationTest/New.IntegrationTests/InProcess/MessageBoxInProcess.cs +++ b/src/VisualStudio/IntegrationTest/New.IntegrationTests/InProcess/MessageBoxInProcess.cs @@ -26,8 +26,8 @@ internal partial class MessageBoxInProcess private static uint s_hotReloadUIServiceCookie; #pragma warning restore IDE0052 // Remove unread private members - private static ImmutableList s_handlers = ImmutableList.Empty; - private static ImmutableList s_hotReloadHandlers = ImmutableList.Empty; + private static ImmutableList s_handlers = []; + private static ImmutableList s_hotReloadHandlers = []; protected override async Task InitializeCoreAsync() { diff --git a/src/VisualStudio/IntegrationTest/New.IntegrationTests/InProcess/StateResetInProcess.cs b/src/VisualStudio/IntegrationTest/New.IntegrationTests/InProcess/StateResetInProcess.cs index 9eac00fa11aa0..dd8c87a51c050 100644 --- a/src/VisualStudio/IntegrationTest/New.IntegrationTests/InProcess/StateResetInProcess.cs +++ b/src/VisualStudio/IntegrationTest/New.IntegrationTests/InProcess/StateResetInProcess.cs @@ -39,11 +39,13 @@ internal partial class StateResetInProcess /// Contains the persistence slots of tool windows to close between tests. /// /// - private static readonly ImmutableHashSet s_windowsToClose = ImmutableHashSet.Create( + private static readonly ImmutableHashSet s_windowsToClose = + [ FindReferencesWindowInProcess.FindReferencesWindowGuid, new Guid(EnvDTE.Constants.vsWindowKindObjectBrowser), new Guid(ToolWindowGuids80.CodedefinitionWindow), - VSConstants.StandardToolWindows.Immediate); + VSConstants.StandardToolWindows.Immediate, + ]; public async Task ResetGlobalOptionsAsync(CancellationToken cancellationToken) { diff --git a/src/VisualStudio/IntegrationTest/New.IntegrationTests/TestUtilities.cs b/src/VisualStudio/IntegrationTest/New.IntegrationTests/TestUtilities.cs index 1988f049975b3..04eb6faa91fc2 100644 --- a/src/VisualStudio/IntegrationTest/New.IntegrationTests/TestUtilities.cs +++ b/src/VisualStudio/IntegrationTest/New.IntegrationTests/TestUtilities.cs @@ -9,7 +9,7 @@ namespace Microsoft.VisualStudio.IntegrationTest.Utilities; -public class TestUtilities +public static class TestUtilities { public static void ThrowIfExpectedItemNotFound(IEnumerable actual, IEnumerable expected) where TCollection : IEquatable diff --git a/src/VisualStudio/IntegrationTest/New.IntegrationTests/VisualBasic/BasicGenerateConstructorDialog.cs b/src/VisualStudio/IntegrationTest/New.IntegrationTests/VisualBasic/BasicGenerateConstructorDialog.cs index 1ba09ff58186a..08ccf502eb8e5 100644 --- a/src/VisualStudio/IntegrationTest/New.IntegrationTests/VisualBasic/BasicGenerateConstructorDialog.cs +++ b/src/VisualStudio/IntegrationTest/New.IntegrationTests/VisualBasic/BasicGenerateConstructorDialog.cs @@ -37,7 +37,7 @@ Dim k as Boolean End Class", HangMitigatingCancellationToken); await TestServices.Editor.InvokeCodeActionListAsync(HangMitigatingCancellationToken); - await TestServices.EditorVerifier.CodeActionAsync("Generate constructor...", applyFix: true, blockUntilComplete: false, cancellationToken: HangMitigatingCancellationToken); + await TestServices.EditorVerifier.CodeActionAsync("Generate constructor from members...", applyFix: true, blockUntilComplete: false, cancellationToken: HangMitigatingCancellationToken); await TestServices.PickMembersDialog.VerifyOpenAsync(HangMitigatingCancellationToken); await TestServices.PickMembersDialog.ClickCancelAsync(HangMitigatingCancellationToken); var actualText = await TestServices.Editor.GetTextAsync(HangMitigatingCancellationToken); @@ -66,7 +66,7 @@ Dim k as Boolean End Class", HangMitigatingCancellationToken); await TestServices.Editor.InvokeCodeActionListAsync(HangMitigatingCancellationToken); - await TestServices.EditorVerifier.CodeActionAsync("Generate constructor...", applyFix: true, blockUntilComplete: false, cancellationToken: HangMitigatingCancellationToken); + await TestServices.EditorVerifier.CodeActionAsync("Generate constructor from members...", applyFix: true, blockUntilComplete: false, cancellationToken: HangMitigatingCancellationToken); await TestServices.PickMembersDialog.VerifyOpenAsync(HangMitigatingCancellationToken); await TestServices.PickMembersDialog.ClickOKAsync(HangMitigatingCancellationToken); await TestServices.Workspace.WaitForAsyncOperationsAsync(FeatureAttribute.LightBulb, HangMitigatingCancellationToken); @@ -100,7 +100,7 @@ Dim k as Boolean End Class", HangMitigatingCancellationToken); await TestServices.Editor.InvokeCodeActionListAsync(HangMitigatingCancellationToken); - await TestServices.EditorVerifier.CodeActionAsync("Generate constructor...", applyFix: true, blockUntilComplete: false, cancellationToken: HangMitigatingCancellationToken); + await TestServices.EditorVerifier.CodeActionAsync("Generate constructor from members...", applyFix: true, blockUntilComplete: false, cancellationToken: HangMitigatingCancellationToken); await TestServices.PickMembersDialog.VerifyOpenAsync(HangMitigatingCancellationToken); await TestServices.Input.SendWithoutActivateAsync(VirtualKeyCode.TAB, HangMitigatingCancellationToken); await TestServices.Input.SendWithoutActivateAsync(VirtualKeyCode.TAB, HangMitigatingCancellationToken); @@ -137,7 +137,7 @@ Dim k as Boolean End Class", HangMitigatingCancellationToken); await TestServices.Editor.InvokeCodeActionListAsync(HangMitigatingCancellationToken); - await TestServices.EditorVerifier.CodeActionAsync("Generate constructor...", applyFix: true, blockUntilComplete: false, cancellationToken: HangMitigatingCancellationToken); + await TestServices.EditorVerifier.CodeActionAsync("Generate constructor from members...", applyFix: true, blockUntilComplete: false, cancellationToken: HangMitigatingCancellationToken); await TestServices.PickMembersDialog.VerifyOpenAsync(HangMitigatingCancellationToken); await TestServices.Input.SendWithoutActivateAsync(VirtualKeyCode.TAB, HangMitigatingCancellationToken); await TestServices.Input.SendWithoutActivateAsync(VirtualKeyCode.TAB, HangMitigatingCancellationToken); diff --git a/src/VisualStudio/IntegrationTest/New.IntegrationTests/VisualBasic/BasicIntelliSense.cs b/src/VisualStudio/IntegrationTest/New.IntegrationTests/VisualBasic/BasicIntelliSense.cs index 89b52cdba4c60..342d230c979da 100644 --- a/src/VisualStudio/IntegrationTest/New.IntegrationTests/VisualBasic/BasicIntelliSense.cs +++ b/src/VisualStudio/IntegrationTest/New.IntegrationTests/VisualBasic/BasicIntelliSense.cs @@ -301,7 +301,7 @@ public async Task CtrlAltSpace() await ClearEditorAsync(HangMitigatingCancellationToken); - await TestServices.Input.SendAsync(new InputKey(VirtualKeyCode.SPACE, ImmutableArray.Create(VirtualKeyCode.CONTROL, VirtualKeyCode.MENU)), HangMitigatingCancellationToken); + await TestServices.Input.SendAsync(new InputKey(VirtualKeyCode.SPACE, [VirtualKeyCode.CONTROL, VirtualKeyCode.MENU]), HangMitigatingCancellationToken); await TestServices.Input.SendAsync("Nam Foo", HangMitigatingCancellationToken); await TestServices.EditorVerifier.CurrentLineTextAsync("Nam Foo$$", assertCaretPosition: true, HangMitigatingCancellationToken); diff --git a/src/VisualStudio/IntegrationTest/New.IntegrationTests/VisualBasic/BasicNavigationBar.cs b/src/VisualStudio/IntegrationTest/New.IntegrationTests/VisualBasic/BasicNavigationBar.cs index 7f308cea4dda7..8a1547bdf6b23 100644 --- a/src/VisualStudio/IntegrationTest/New.IntegrationTests/VisualBasic/BasicNavigationBar.cs +++ b/src/VisualStudio/IntegrationTest/New.IntegrationTests/VisualBasic/BasicNavigationBar.cs @@ -70,11 +70,11 @@ public async Task VerifyNavBar() Assert.Equal("A", await TestServices.Editor.GetNavigationBarSelectionAsync(NavigationBarDropdownKind.Member, HangMitigatingCancellationToken)); await TestServices.Editor.ExpandNavigationBarAsync(NavigationBarDropdownKind.Member, HangMitigatingCancellationToken); - expectedItems = new[] - { + expectedItems = + [ "A", "B", - }; + ]; Assert.Equal(expectedItems, await TestServices.Editor.GetNavigationBarItemsAsync(NavigationBarDropdownKind.Member, HangMitigatingCancellationToken)); await TestServices.Editor.SelectNavigationBarItemAsync(NavigationBarDropdownKind.Member, "B", HangMitigatingCancellationToken); diff --git a/src/VisualStudio/LiveShare/Impl/Client/Projects/RoslynRemoteProjectInfoProvider.cs b/src/VisualStudio/LiveShare/Impl/Client/Projects/RoslynRemoteProjectInfoProvider.cs index f5983f261fd6b..1e8bab887d7c8 100644 --- a/src/VisualStudio/LiveShare/Impl/Client/Projects/RoslynRemoteProjectInfoProvider.cs +++ b/src/VisualStudio/LiveShare/Impl/Client/Projects/RoslynRemoteProjectInfoProvider.cs @@ -40,13 +40,13 @@ public async Task> GetRemoteProjectInfosAsync(Cancel { if (!_remoteLanguageServiceWorkspace.IsRemoteSession) { - return ImmutableArray.Empty; + return []; } var lspClient = _roslynLspClientServiceFactory.ActiveLanguageServerClient; if (lspClient == null) { - return ImmutableArray.Empty; + return []; } CustomProtocol.Project[] projects; @@ -62,7 +62,7 @@ public async Task> GetRemoteProjectInfosAsync(Cancel if (projects == null) { - return ImmutableArray.Empty; + return []; } var projectInfos = ImmutableArray.CreateBuilder(); @@ -77,7 +77,7 @@ public async Task> GetRemoteProjectInfosAsync(Cancel .Where(f => !_secondaryBufferFileExtensions.Any(ext => f.LocalPath.EndsWith(ext))) .Select(f => lspClient.ProtocolConverter.FromProtocolUriAsync(f, false, cancellationToken)); var files = await Task.WhenAll(filesTasks).ConfigureAwait(false); - var projectInfo = CreateProjectInfo(project.Name, project.Language, files.Select(f => f.LocalPath).ToImmutableArray(), _remoteLanguageServiceWorkspace.Services.SolutionServices); + var projectInfo = CreateProjectInfo(project.Name, project.Language, [.. files.Select(f => f.LocalPath)], _remoteLanguageServiceWorkspace.Services.SolutionServices); projectInfos.Add(projectInfo); } diff --git a/src/VisualStudio/LiveShare/Impl/Client/RemoteLanguageServiceWorkspace.cs b/src/VisualStudio/LiveShare/Impl/Client/RemoteLanguageServiceWorkspace.cs index 39ade75d22b3b..93b7878aa2496 100644 --- a/src/VisualStudio/LiveShare/Impl/Client/RemoteLanguageServiceWorkspace.cs +++ b/src/VisualStudio/LiveShare/Impl/Client/RemoteLanguageServiceWorkspace.cs @@ -92,8 +92,8 @@ public RemoteLanguageServiceWorkspace( _threadingContext = threadingContext; _vsFolderWorkspaceService = vsFolderWorkspaceService; - _remoteWorkspaceRootPaths = ImmutableHashSet.Empty; - _registeredExternalPaths = ImmutableHashSet.Empty; + _remoteWorkspaceRootPaths = []; + _registeredExternalPaths = []; } void IOpenTextBufferEventListener.OnOpenDocument(string moniker, ITextBuffer textBuffer, IVsHierarchy? hierarchy) => NotifyOnDocumentOpened(moniker, textBuffer); @@ -196,8 +196,8 @@ public void EndSession() // Clear the remote paths on end of session. Live share handles closing all the files. using (s_RemotePathsGate.DisposableWait()) { - _remoteWorkspaceRootPaths = ImmutableHashSet.Empty; - _registeredExternalPaths = ImmutableHashSet.Empty; + _remoteWorkspaceRootPaths = []; + _registeredExternalPaths = []; } } diff --git a/src/VisualStudio/LiveShare/Impl/ProjectsHandler.cs b/src/VisualStudio/LiveShare/Impl/ProjectsHandler.cs index 39413cf743dfc..6682d5de11c0c 100644 --- a/src/VisualStudio/LiveShare/Impl/ProjectsHandler.cs +++ b/src/VisualStudio/LiveShare/Impl/ProjectsHandler.cs @@ -43,7 +43,7 @@ public async Task HandleAsync(object param, RequestContext r var lspProject = new CustomProtocol.Project { Name = project.Name, - SourceFiles = project.Documents.Select(d => requestContext.ProtocolConverter.ToProtocolUri(new Uri(d.FilePath))).ToArray(), + SourceFiles = [.. project.Documents.Select(d => requestContext.ProtocolConverter.ToProtocolUri(new Uri(d.FilePath)))], Language = project.Language }; diff --git a/src/VisualStudio/LiveShare/Test/ProjectsHandlerTests.cs b/src/VisualStudio/LiveShare/Test/ProjectsHandlerTests.cs index 1c05c41931776..bf830d1fd3bae 100644 --- a/src/VisualStudio/LiveShare/Test/ProjectsHandlerTests.cs +++ b/src/VisualStudio/LiveShare/Test/ProjectsHandlerTests.cs @@ -35,7 +35,7 @@ private static CustomProtocol.Project CreateLspProject(Project project) { Language = project.Language, Name = project.Name, - SourceFiles = project.Documents.Select(document => document.GetURI()).ToArray() + SourceFiles = [.. project.Documents.Select(document => document.GetURI())] }; } } diff --git a/src/VisualStudio/TestUtilities2/CodeModel/Mocks/MockVisualStudioWorkspace.vb b/src/VisualStudio/TestUtilities2/CodeModel/Mocks/MockVisualStudioWorkspace.vb index 7c0243c92fd22..f535cc16a6710 100644 --- a/src/VisualStudio/TestUtilities2/CodeModel/Mocks/MockVisualStudioWorkspace.vb +++ b/src/VisualStudio/TestUtilities2/CodeModel/Mocks/MockVisualStudioWorkspace.vb @@ -81,7 +81,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.CodeModel.Mocks Throw New NotImplementedException() End Sub - Friend Overrides Function GetBrowseObject(symbolListItem As SymbolListItem) As Object + Friend Overrides Function GetBrowseObjectAsync(symbolListItem As SymbolListItem, cancellationToken As CancellationToken) As Task(Of Object) Throw New NotImplementedException() End Function diff --git a/src/VisualStudio/TestUtilities2/Microsoft.VisualStudio.LanguageServices.Test.Utilities2.vbproj b/src/VisualStudio/TestUtilities2/Microsoft.VisualStudio.LanguageServices.Test.Utilities2.vbproj index fe756c77e4fdb..6ca1ded5756a1 100644 --- a/src/VisualStudio/TestUtilities2/Microsoft.VisualStudio.LanguageServices.Test.Utilities2.vbproj +++ b/src/VisualStudio/TestUtilities2/Microsoft.VisualStudio.LanguageServices.Test.Utilities2.vbproj @@ -43,7 +43,7 @@ - + @@ -52,7 +52,7 @@ - + diff --git a/src/VisualStudio/TestUtilities2/ProjectSystemShim/Framework/TestEnvironment.vb b/src/VisualStudio/TestUtilities2/ProjectSystemShim/Framework/TestEnvironment.vb index c0261ecc1802c..bde25c3691429 100644 --- a/src/VisualStudio/TestUtilities2/ProjectSystemShim/Framework/TestEnvironment.vb +++ b/src/VisualStudio/TestUtilities2/ProjectSystemShim/Framework/TestEnvironment.vb @@ -123,7 +123,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.ProjectSystemShim.Fr Throw New NotImplementedException() End Function - Friend Overrides Function GetBrowseObject(symbolListItem As SymbolListItem) As Object + Friend Overrides Function GetBrowseObjectAsync(symbolListItem As SymbolListItem, cancellationToken As CancellationToken) As Task(Of Object) Throw New NotImplementedException() End Function End Class diff --git a/src/VisualStudio/TestUtilities2/UnifiedSettings/UnifiedSettingsTests.vb b/src/VisualStudio/TestUtilities2/UnifiedSettings/UnifiedSettingsTests.vb deleted file mode 100644 index ecf8ba700f9bf..0000000000000 --- a/src/VisualStudio/TestUtilities2/UnifiedSettings/UnifiedSettingsTests.vb +++ /dev/null @@ -1,228 +0,0 @@ -' Licensed to the .NET Foundation under one or more agreements. -' The .NET Foundation licenses this file to you under the MIT license. -' See the LICENSE file in the project root for more information. - -Imports System.Collections.Immutable -Imports System.IO.Hashing -Imports System.Text -Imports System.Text.RegularExpressions -Imports Microsoft.CodeAnalysis -Imports Microsoft.CodeAnalysis.Options -Imports Microsoft.VisualStudio.LanguageServices.Options -Imports Microsoft.VisualStudio.LanguageServices.Options.VisualStudioOptionStorage -Imports Newtonsoft.Json.Linq -Imports Roslyn.Test.Utilities -Imports Roslyn.Utilities - -Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.UnifiedSettings - Partial Public MustInherit Class UnifiedSettingsTests - ' Onboarded options in Unified Settings registration file - Friend MustOverride ReadOnly Property OnboardedOptions As ImmutableArray(Of IOption2) - - ' Override this method to if the option use different default value. - Friend Overridable Function GetOptionsDefaultValue([option] As IOption2) As Object - Return [option].DefaultValue - End Function - - ' Override this method to specify all possible enum values in option page. - Friend Overridable Function GetEnumOptionValues([option] As IOption2) As Object() - Dim type = [option].Definition.Type - Assert.True(type.IsEnum) - Return [Enum].GetValues(type).Cast(Of Object).AsArray() - End Function - - Protected Sub TestUnifiedSettingsCategory(registrationJsonObject As JObject, categoryBasePath As String, languageName As String, pkdDefFile As String) - Dim actualAllSettings = registrationJsonObject.SelectToken($"$.properties").Children.OfType(Of JProperty). - Where(Function(setting) setting.Name.StartsWith(categoryBasePath)). - Select(Function(setting) setting.Name). - OrderBy(Function(name) name). - ToArray() - - Dim expectedAllSettings = OnboardedOptions.Select(Function(onboardedOption) s_unifiedSettingsStorage(onboardedOption.Definition.ConfigName).GetUnifiedSettingsPath(languageName)). - OrderBy(Function(name) name). - ToArray() - Assert.Equal(expectedAllSettings, actualAllSettings) - - For Each onboardedOption In OnboardedOptions - Dim optionName = onboardedOption.Definition.ConfigName - Dim settingStorage As UnifiedSettingsStorage = Nothing - If s_unifiedSettingsStorage.TryGetValue(optionName, settingStorage) Then - Dim unifiedSettingsPath = settingStorage.GetUnifiedSettingsPath(languageName) - VerifyType(registrationJsonObject, unifiedSettingsPath, onboardedOption) - - Dim expectedDefaultValue = GetOptionsDefaultValue(onboardedOption) - Dim actualDefaultValue = registrationJsonObject.SelectToken($"$.properties('{unifiedSettingsPath}').default") - Assert.Equal(expectedDefaultValue.ToString().ToCamelCase(), actualDefaultValue.ToString().ToCamelCase()) - - If onboardedOption.Type.IsEnum Then - ' Enum settings contains special setup. - VerifyEnum(registrationJsonObject, unifiedSettingsPath, onboardedOption, languageName) - Else - VerifySettings(registrationJsonObject, unifiedSettingsPath, onboardedOption, languageName) - End If - Else - ' Can't find the option in the storage dictionary - Throw ExceptionUtilities.UnexpectedValue(optionName) - End If - Next - - Dim registrationFileBytes = ASCIIEncoding.ASCII.GetBytes(registrationJsonObject.ToString()) - Dim hash = XxHash128.Hash(registrationFileBytes) - Dim tagBytes = hash.Take(8).ToArray() - Dim expectedCacheTagValue = BitConverter.ToInt64(tagBytes, 0).ToString("X16") - - Dim regexExp = New Regex("""CacheTag""=qword:\w{16}") - Dim match = regexExp.Match(pkdDefFile, 0).Value - Dim actual = match.Substring(match.Length - 16) - ' Please change the CacheTag value in pkddef if you modify the unified settings regirstration file - Assert.Equal(expectedCacheTagValue, actual) - End Sub - - Private Shared Sub VerifySettings(registrationJsonObject As JObject, unifiedSettingPath As String, [option] As IOption2, languageName As String) - VerifyMigration(registrationJsonObject, unifiedSettingPath, [option], languageName) - End Sub - - Private Sub VerifyEnum(registrationJsonObject As JObject, unifiedSettingPath As String, [option] As IOption2, languageName As String) - Dim actualEnumValues = registrationJsonObject.SelectToken($"$.properties('{unifiedSettingPath}').enum").Select(Function(token) token.ToString()).OrderBy(Function(value) value) - Dim expectedEnumValues = GetEnumOptionValues([option]).Select(Function(value) value.ToString().ToCamelCase()).OrderBy(Function(value) value) - AssertEx.Equal(expectedEnumValues, actualEnumValues) - VerifyEnumMigration(registrationJsonObject, unifiedSettingPath, [option], languageName) - End Sub - - Private Shared Sub VerifyType(registrationJsonObject As JObject, unifiedSettingPath As String, [option] As IOption2) - Dim actualType = registrationJsonObject.SelectToken($"$.properties['{unifiedSettingPath}'].type") - Dim expectedType = [option].Definition.Type - If expectedType.IsEnum Then - ' Enum is string in json - Assert.Equal("string", actualType.ToString()) - Else - Dim expectedTypeName = ConvertTypeNameToJsonType([option].Definition.Type) - Assert.Equal(expectedTypeName, actualType.ToString()) - End If - End Sub - - Private Shared Function ConvertTypeNameToJsonType(optionType As Type) As String - Dim underlyingType = Nullable.GetUnderlyingType(optionType) - ' If the type is Nullable type, its mapping type in unified setting page would be the normal type - ' These options would need to change to non-nullable form - ' See https://github.com/dotnet/roslyn/issues/69367 - If underlyingType Is Nothing Then - Return optionType.Name.ToCamelCase() - Else - Return underlyingType.Name.ToCamelCase() - End If - End Function - - Private Sub VerifyEnumMigration(registrationJsonObject As JObject, unifiedSettingPath As String, [option] As IOption2, languageName As String) - Dim actualMigration = registrationJsonObject.SelectToken($"$.properties('{unifiedSettingPath}').migration") - Dim migrationProperty = DirectCast(actualMigration.Children().Single(), JProperty) - Dim migrationType = migrationProperty.Name - Assert.Equal("enumIntegerToString", migrationType) - - ' Verify input node and map node - Dim input = registrationJsonObject.SelectToken($"$.properties('{unifiedSettingPath}').migration.enumIntegerToString.input") - VerifyInput(input, [option], languageName) - VerifyEnumToIntegerMappings(registrationJsonObject, unifiedSettingPath, [option]) - End Sub - - Private Shared Sub VerifyMigration(registrationJsonObject As JObject, unifiedSettingPath As String, [option] As IOption2, languageName As String) - Dim actualMigration = registrationJsonObject.SelectToken($"$.properties('{unifiedSettingPath}').migration") - ' Get the single property under migration - Dim migrationProperty = DirectCast(actualMigration.Children().Single(), JProperty) - Dim migrationType = migrationProperty.Name - If migrationType = "pass" Then - ' Verify input node - Dim input = registrationJsonObject.SelectToken($"$.properties('{unifiedSettingPath}').migration.pass.input") - VerifyInput(input, [option], languageName) - Else - ' Need adding more migration types if new type is added - Throw ExceptionUtilities.UnexpectedValue(migrationType) - End If - End Sub - - ' Verify input property under migration - Private Shared Sub VerifyInput(input As JToken, [option] As IOption2, languageName As String) - Dim store = input.SelectToken("store").ToString() - Dim path = input.SelectToken("path").ToString() - Dim configName = [option].Definition.ConfigName - Dim visualStudioStorage = Storages(configName) - If TypeOf visualStudioStorage Is VisualStudioOptionStorage.RoamingProfileStorage Then - Dim roamingProfileStorage = DirectCast(visualStudioStorage, VisualStudioOptionStorage.RoamingProfileStorage) - Assert.Equal("SettingsManager", store) - Assert.Equal(roamingProfileStorage.Key.Replace("%LANGUAGE%", GetSubstituteLanguage(languageName)), path) - Else - ' Not supported yet - Throw ExceptionUtilities.Unreachable - End If - End Sub - - Private Shared Function GetSubstituteLanguage(languageName As String) As String - Select Case languageName - Case LanguageNames.CSharp - Return "CSharp" - Case LanguageNames.VisualBasic - Return "VisualBasic" - Case Else - Return languageName - End Select - End Function - - Private Sub VerifyEnumToIntegerMappings(registrationJsonObject As JObject, unifiedSettingPath As String, [option] As IOption2) - ' Here we are going to verify a structure like this: - ' "map": [ - ' { - ' "result": "neverInclude", - ' "match": 1 - ' }, - ' // '0' matches to SnippetsRule.Default. Means the behavior is decided by language. - ' // '2' matches to SnippetsRule.AlwaysInclude. It's the default behavior for C# - ' // Put both mapping here, so it's possible for unified setting to load '0' from the storage. - ' // Put '2' in front, so unified settings would persist '2' to storage when 'alwaysInclude' is selected. - ' { - ' "result": "alwaysInclude", - ' "match": 2 - ' }, - ' { - ' "result": "alwaysInclude", - ' "match": 0 - ' }, - ' { - ' "result": "includeAfterTypingIdentifierQuestionTab", - ' "match": 3 - ' } - ' ] - Dim actualMappings = CType(registrationJsonObject.SelectToken(String.Format("$.properties['{0}'].migration.enumIntegerToString.map", unifiedSettingPath)), JArray).Select(Function(mapping) (mapping("result").ToString(), Integer.Parse(mapping("match").ToString()))).ToArray() - - Dim enumValues = [option].Type.GetEnumValues().Cast(Of Object).ToDictionary( - keySelector:=Function(enumValue) enumValue.ToString().ToCamelCase(), - elementSelector:=Function(enumValue) - Dim actualDefaultValue = GetOptionsDefaultValue([option]) - If actualDefaultValue.Equals(enumValue) Then - ' This value is the real default value at runtime. - ' So map it to both default value and its own value. - ' Like 'alwaysInclude' in the above example, it would map to both 0 and 2. - Return New Integer() {CInt(enumValue), CInt([option].DefaultValue)} - End If - - Return New Integer() {CInt(enumValue)} - End Function - ) - - For Each tuple In actualMappings - Dim result = tuple.Item1 - Dim match = tuple.Item2 - Dim acceptableValues = enumValues(result) - Assert.Contains(match, acceptableValues) - Next - - ' If the default value of the enum is a stub value, verify the real value mapping is put in font of the default value mapping. - ' It makes sure the default value would be converted to the real value by unified settings engine. - Dim realDefaultValue = GetOptionsDefaultValue([option]) - Dim indexOfTheRealDefaultMapping = Array.IndexOf(actualMappings, (realDefaultValue.ToString().ToCamelCase(), CInt(realDefaultValue))) - Assert.NotEqual(-1, indexOfTheRealDefaultMapping) - Dim indexOfTheDefaultMapping = Array.IndexOf(actualMappings, (realDefaultValue.ToString().ToCamelCase(), CInt([option].DefaultValue))) - Assert.NotEqual(-1, indexOfTheDefaultMapping) - Assert.True(indexOfTheRealDefaultMapping < indexOfTheDefaultMapping) - End Sub - End Class -End Namespace diff --git a/src/VisualStudio/TestUtilities2/UnifiedSettings/UnifiedSettingsTests_UnifiedSettingsStorage.vb b/src/VisualStudio/TestUtilities2/UnifiedSettings/UnifiedSettingsTests_UnifiedSettingsStorage.vb deleted file mode 100644 index b253bc0db5914..0000000000000 --- a/src/VisualStudio/TestUtilities2/UnifiedSettings/UnifiedSettingsTests_UnifiedSettingsStorage.vb +++ /dev/null @@ -1,58 +0,0 @@ -' Licensed to the .NET Foundation under one or more agreements. -' The .NET Foundation licenses this file to you under the MIT license. -' See the LICENSE file in the project root for more information. - -Imports Microsoft.CodeAnalysis - -Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.UnifiedSettings - Partial Public Class UnifiedSettingsTests - - ' Mapping from the config name to its path in Unified Settings registration file - Private Shared ReadOnly s_unifiedSettingsStorage As New Dictionary(Of String, UnifiedSettingsStorage)() From { - {"dotnet_trigger_completion_on_typing_letters", New UnifiedSettingsStorage("textEditor.%LANGUAGE%.intellisense.triggerCompletionOnTypingLetters")}, - {"dotnet_trigger_completion_on_deletion", New UnifiedSettingsStorage("textEditor.%LANGUAGE%.intellisense.triggerCompletionOnDeletion")}, - {"dotnet_trigger_completion_in_argument_lists", New UnifiedSettingsStorage("textEditor.%LANGUAGE%.intellisense.triggerCompletionInArgumentLists")}, - {"dotnet_highlight_matching_portions_of_completion_list_items", New UnifiedSettingsStorage("textEditor.%LANGUAGE%.intellisense.highlightMatchingPortionsOfCompletionListItems")}, - {"dotnet_show_completion_item_filters", New UnifiedSettingsStorage("textEditor.%LANGUAGE%.intellisense.showCompletionItemFilters")}, - {"csharp_complete_statement_on_semicolon", New UnifiedSettingsStorage("textEditor.csharp.intellisense.completeStatementOnSemicolon")}, - {"dotnet_snippets_behavior", New UnifiedSettingsStorage("textEditor.%LANGUAGE%.intellisense.snippetsBehavior")}, - {"dotnet_return_key_completion_behavior", New UnifiedSettingsStorage("textEditor.%LANGUAGE%.intellisense.returnKeyCompletionBehavior")}, - {"dotnet_show_name_completion_suggestions", New UnifiedSettingsStorage("textEditor.%LANGUAGE%.intellisense.showNameCompletionSuggestions")}, - {"dotnet_show_completion_items_from_unimported_namespaces", New UnifiedSettingsStorage("textEditor.%LANGUAGE%.intellisense.showCompletionItemsFromUnimportedNamespaces")}, - {"dotnet_enable_argument_completion_snippets", New UnifiedSettingsStorage("textEditor.%LANGUAGE%.intellisense.enableArgumentCompletionSnippets")}, - {"dotnet_show_new_snippet_experience", New UnifiedSettingsStorage("textEditor.%LANGUAGE%.intellisense.showNewSnippetExperience")} - } - - Friend NotInheritable Class UnifiedSettingsStorage - Private Const LanguagePlaceholder As String = "%LANGUAGE%" - - ' C# name used in Unified Settings path. - Private Const csharpKey As String = "csharp" - - ' Visual Basic name used in Unified Settings path. - Private Const visualBasicKey As String = "basic" - - ' Unified settings base path, might contains %LANGAUGE% if it maps to two per-language different setting. - Public Property UnifiedSettingsBasePath As String - - Public Sub New(unifiedSettingsPath As String) - UnifiedSettingsBasePath = unifiedSettingsPath - End Sub - - Public Function GetUnifiedSettingsPath(language As String) As String - If Not UnifiedSettingsBasePath.Contains(LanguagePlaceholder) Then - Return UnifiedSettingsBasePath - End If - - Select Case language - Case LanguageNames.CSharp - Return UnifiedSettingsBasePath.Replace(LanguagePlaceholder, csharpKey) - Case LanguageNames.VisualBasic - Return UnifiedSettingsBasePath.Replace(LanguagePlaceholder, visualBasicKey) - Case Else - Throw New Exception("Unexpected language value") - End Select - End Function - End Class - End Class -End Namespace diff --git a/src/VisualStudio/VisualBasic/Impl/BasicVSResources.resx b/src/VisualStudio/VisualBasic/Impl/BasicVSResources.resx index b0aabb98df28e..4c5b223bcf5fe 100644 --- a/src/VisualStudio/VisualBasic/Impl/BasicVSResources.resx +++ b/src/VisualStudio/VisualBasic/Impl/BasicVSResources.resx @@ -120,73 +120,28 @@ Microsoft Visual Basic - - Insert Snippet - - - IntelliSense - Automatic _insertion of Interface and MustOverride members - - _Show procedure line separators - _Don't put ByRef on custom structure - - Editor Help - A_utomatic insertion of end constructs - - Highlight related _keywords under cursor - - - _Highlight references to symbol under cursor - _Pretty listing (reformatting) of code _Enter outlining mode when files open - - Extract Method - _Generate XML documentation comments for ''' {Locked="'''"} "'''" is a VB keyword and should not be localized. - - Highlighting - - - Optimize for solution size - - - Large - - - Regular - - - Small - - - Performance - - - Show preview for rename _tracking - _Navigate to Object Browser for symbols defined in metadata - - Go to Definition - Import Directives @@ -223,36 +178,9 @@ Predefined type preferences: - - _Highlight matching portions of completion list items - - - Show completion item _filters - Completion Lists - - Enter key behavior: - - - _Only add new line on enter after end of fully typed word - - - _Always add new line on enter - - - _Never add new line on enter - - - Snippets behavior - - - Show completion list after a character is _deleted - - - _Show completion list after a character is typed - 'nothing' checking: @@ -277,18 +205,6 @@ In relational operators: = <> < > <= >= Like Is - - Never - - - Unused local - - - Show items from unimported namespaces - - - Show remarks in Quick Info - Prefer 'IsNot' expression @@ -302,10 +218,6 @@ Add missing imports on paste 'import' is a Visual Basic keyword and should not be localized - - Remove unnecessary imports - {Locked="Import"} 'import' is a Visual Basic keyword and should not be localized - Prefer simplified object creation diff --git a/src/VisualStudio/VisualBasic/Impl/CodeModel/MethodXML/MethodXmlBuilder.vb b/src/VisualStudio/VisualBasic/Impl/CodeModel/MethodXML/MethodXmlBuilder.vb index 61d95267fbe21..25ec13b0538f5 100644 --- a/src/VisualStudio/VisualBasic/Impl/CodeModel/MethodXML/MethodXmlBuilder.vb +++ b/src/VisualStudio/VisualBasic/Impl/CodeModel/MethodXML/MethodXmlBuilder.vb @@ -531,7 +531,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.CodeModel.MethodXm Return False End If - If Not TypeOf constantValue.Value Is Integer Then + If TypeOf constantValue.Value IsNot Integer Then Return False End If @@ -547,7 +547,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.CodeModel.MethodXm End Function Private Function TryGenerateSimpleArrayBound(argument As ArgumentSyntax) As Boolean - If Not TypeOf argument Is SimpleArgumentSyntax Then + If TypeOf argument IsNot SimpleArgumentSyntax Then Return False End If @@ -555,7 +555,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.CodeModel.MethodXm End Function Private Function TryGenerateRangeArrayBound(argument As ArgumentSyntax) As Boolean - If Not TypeOf argument Is RangeArgumentSyntax Then + If TypeOf argument IsNot RangeArgumentSyntax Then Return False End If diff --git a/src/VisualStudio/VisualBasic/Impl/CodeModel/VisualBasicCodeModelService.CodeModelEventCollector.vb b/src/VisualStudio/VisualBasic/Impl/CodeModel/VisualBasicCodeModelService.CodeModelEventCollector.vb index 1eeec30edab43..e97cd9da76dfd 100644 --- a/src/VisualStudio/VisualBasic/Impl/CodeModel/VisualBasicCodeModelService.CodeModelEventCollector.vb +++ b/src/VisualStudio/VisualBasic/Impl/CodeModel/VisualBasicCodeModelService.CodeModelEventCollector.vb @@ -70,7 +70,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.CodeModel Private Shared Function GetImportsClauses(importsStatements As SyntaxList(Of ImportsStatementSyntax)) As IReadOnlyList(Of ImportsClauseSyntax) Return importsStatements _ .SelectMany(Function(i) i.ImportsClauses) _ - .Where(Function(i) Not TypeOf i Is XmlNamespaceImportsClauseSyntax) _ + .Where(Function(i) TypeOf i IsNot XmlNamespaceImportsClauseSyntax) _ .ToArray() End Function diff --git a/src/VisualStudio/VisualBasic/Impl/CodeModel/VisualBasicCodeModelService.vb b/src/VisualStudio/VisualBasic/Impl/CodeModel/VisualBasicCodeModelService.vb index 42f2a2a2cba67..4804603202332 100644 --- a/src/VisualStudio/VisualBasic/Impl/CodeModel/VisualBasicCodeModelService.vb +++ b/src/VisualStudio/VisualBasic/Impl/CodeModel/VisualBasicCodeModelService.vb @@ -227,7 +227,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.CodeModel End If Case SyntaxKind.EventStatement - If Not TypeOf node.Parent Is EventBlockSyntax Then + If TypeOf node.Parent IsNot EventBlockSyntax Then If scope = EnvDTE.vsCMElement.vsCMElementEvent Then Return True End If @@ -239,7 +239,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.CodeModel End If Case SyntaxKind.PropertyStatement - If Not TypeOf node.Parent Is PropertyBlockSyntax Then + If TypeOf node.Parent IsNot PropertyBlockSyntax Then If scope = EnvDTE.vsCMElement.vsCMElementProperty Then Return True End If @@ -1528,7 +1528,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.CodeModel If TypeOf member Is TypeBlockSyntax OrElse TypeOf member Is EnumBlockSyntax Then - If Not TypeOf member.Parent Is TypeBlockSyntax AndAlso + If TypeOf member.Parent IsNot TypeBlockSyntax AndAlso (newAccess = EnvDTE.vsCMAccess.vsCMAccessPrivate OrElse newAccess = EnvDTE.vsCMAccess.vsCMAccessProtected OrElse newAccess = EnvDTE.vsCMAccess.vsCMAccessProjectOrProtected) Then @@ -2084,7 +2084,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.CodeModel Public Overrides Function ValidateFunctionKind(containerNode As SyntaxNode, kind As EnvDTE.vsCMFunction, name As String) As EnvDTE.vsCMFunction If kind = EnvDTE.vsCMFunction.vsCMFunctionSub Then - Return If(name = "New" AndAlso Not TypeOf containerNode Is InterfaceBlockSyntax, + Return If(name = "New" AndAlso TypeOf containerNode IsNot InterfaceBlockSyntax, EnvDTE.vsCMFunction.vsCMFunctionConstructor, kind) End If @@ -4163,9 +4163,9 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.CodeModel End Function Public Overrides Function GetFunctionExtender(name As String, node As SyntaxNode, symbol As ISymbol) As Object - If Not TypeOf node Is MethodBlockBaseSyntax AndAlso - Not TypeOf node Is MethodStatementSyntax AndAlso - Not TypeOf symbol Is IMethodSymbol Then + If TypeOf node IsNot MethodBlockBaseSyntax AndAlso + TypeOf node IsNot MethodStatementSyntax AndAlso + TypeOf symbol IsNot IMethodSymbol Then Throw Exceptions.ThrowEUnexpected() End If @@ -4188,16 +4188,16 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.CodeModel End Function Public Overrides Function GetPropertyExtender(name As String, node As SyntaxNode, symbol As ISymbol) As Object - If Not TypeOf node Is PropertyBlockSyntax AndAlso - Not TypeOf node Is PropertyStatementSyntax AndAlso - Not TypeOf symbol Is IPropertySymbol Then + If TypeOf node IsNot PropertyBlockSyntax AndAlso + TypeOf node IsNot PropertyStatementSyntax AndAlso + TypeOf symbol IsNot IPropertySymbol Then Throw Exceptions.ThrowEUnexpected() End If If StringComparer.OrdinalIgnoreCase.Equals(name, ExtenderNames.VBAutoPropertyExtender) Then Dim isAutoImplemented = TypeOf node Is PropertyStatementSyntax AndAlso - Not TypeOf node.Parent Is InterfaceBlockSyntax + TypeOf node.Parent IsNot InterfaceBlockSyntax Return AutoPropertyExtender.Create(isAutoImplemented) End If diff --git a/src/VisualStudio/VisualBasic/Impl/Help/VisualBasicHelpContextService.Visitor.vb b/src/VisualStudio/VisualBasic/Impl/Help/VisualBasicHelpContextService.Visitor.vb index c964dda4fc328..b2cadac5605b4 100644 --- a/src/VisualStudio/VisualBasic/Impl/Help/VisualBasicHelpContextService.Visitor.vb +++ b/src/VisualStudio/VisualBasic/Impl/Help/VisualBasicHelpContextService.Visitor.vb @@ -431,7 +431,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.Help End Select If _isNotMetadata Then - If Not TypeOf node.Parent Is InheritsOrImplementsStatementSyntax Then + If TypeOf node.Parent IsNot InheritsOrImplementsStatementSyntax Then If TypeOf node.Parent Is DeclarationStatementSyntax OrElse TypeOf node.Parent Is FieldDeclarationSyntax Then Return End If diff --git a/src/VisualStudio/VisualBasic/Impl/LanguageService/VisualBasicPackage.IVbEntryPointProvider.vb b/src/VisualStudio/VisualBasic/Impl/LanguageService/VisualBasicPackage.IVbEntryPointProvider.vb index e6b682f8bb16e..9a46944c9c449 100644 --- a/src/VisualStudio/VisualBasic/Impl/LanguageService/VisualBasicPackage.IVbEntryPointProvider.vb +++ b/src/VisualStudio/VisualBasic/Impl/LanguageService/VisualBasicPackage.IVbEntryPointProvider.vb @@ -12,10 +12,11 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic Partial Friend Class VisualBasicPackage Implements IVBEntryPointProvider - Public Function GetFormEntryPointsList(<[In]> pHierarchy As Object, - cItems As Integer, - bstrList() As String, - ByVal pcActualItems As IntPtr) As Integer Implements IVBEntryPointProvider.GetFormEntryPointsList + Public Function GetFormEntryPointsList( + pHierarchy As Object, + cItems As Integer, + bstrList() As String, + pcActualItems As IntPtr) As Integer Implements IVBEntryPointProvider.GetFormEntryPointsList Dim workspace = ComponentModel.GetService(Of VisualStudioWorkspace)() Dim hierarchy = CType(pHierarchy, IVsHierarchy) diff --git a/src/VisualStudio/VisualBasic/Impl/Microsoft.VisualStudio.LanguageServices.VisualBasic.vbproj b/src/VisualStudio/VisualBasic/Impl/Microsoft.VisualStudio.LanguageServices.VisualBasic.vbproj index b94764b606b87..491f2a1e80c77 100644 --- a/src/VisualStudio/VisualBasic/Impl/Microsoft.VisualStudio.LanguageServices.VisualBasic.vbproj +++ b/src/VisualStudio/VisualBasic/Impl/Microsoft.VisualStudio.LanguageServices.VisualBasic.vbproj @@ -47,6 +47,7 @@ + @@ -55,7 +56,7 @@ - + true VSPackage Designer diff --git a/src/VisualStudio/VisualBasic/Impl/ObjectBrowser/DescriptionBuilder.vb b/src/VisualStudio/VisualBasic/Impl/ObjectBrowser/DescriptionBuilder.vb index bc464b0bf38c6..33ca08992143d 100644 --- a/src/VisualStudio/VisualBasic/Impl/ObjectBrowser/DescriptionBuilder.vb +++ b/src/VisualStudio/VisualBasic/Impl/ObjectBrowser/DescriptionBuilder.vb @@ -6,17 +6,17 @@ Imports System.Collections.Immutable Imports Microsoft.CodeAnalysis Imports Microsoft.VisualStudio.Shell.Interop Imports Microsoft.VisualStudio.LanguageServices.Implementation.Library.ObjectBrowser +Imports System.Threading Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.ObjectBrowser - Friend Class DescriptionBuilder + Friend NotInheritable Class DescriptionBuilder Inherits AbstractDescriptionBuilder Public Sub New( description As IVsObjectBrowserDescription3, libraryManager As ObjectBrowserLibraryManager, listItem As ObjectListItem, - project As Project - ) + project As Project) MyBase.New(description, libraryManager, listItem, project) End Sub @@ -26,7 +26,10 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.ObjectBrowser AddName(namespaceSymbol.ToDisplayString()) End Sub - Protected Overrides Sub BuildDelegateDeclaration(typeSymbol As INamedTypeSymbol, options As _VSOBJDESCOPTIONS) + Protected Overrides Async Function BuildDelegateDeclarationAsync( + typeSymbol As INamedTypeSymbol, + options As _VSOBJDESCOPTIONS, + cancellationToken As CancellationToken) As Task Debug.Assert(typeSymbol.TypeKind = TypeKind.Delegate) BuildTypeModifiers(typeSymbol) @@ -47,21 +50,24 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.ObjectBrowser If typeSymbol.TypeParameters.Length > 0 Then AddText("(Of ") - BuildTypeParameterList(typeSymbol.TypeParameters) + Await BuildTypeParameterListAsync(typeSymbol.TypeParameters, cancellationToken).ConfigureAwait(True) AddText(")") End If AddText("(") - BuildParameterList(delegateInvokeMethod.Parameters) + Await BuildParameterListAsync(delegateInvokeMethod.Parameters, cancellationToken).ConfigureAwait(True) AddText(")") If Not delegateInvokeMethod.ReturnsVoid Then AddText(" As ") - AddTypeLink(delegateInvokeMethod.ReturnType, LinkFlags.None) + Await AddTypeLinkAsync(delegateInvokeMethod.ReturnType, LinkFlags.None, cancellationToken).ConfigureAwait(True) End If - End Sub + End Function - Protected Overrides Sub BuildTypeDeclaration(typeSymbol As INamedTypeSymbol, options As _VSOBJDESCOPTIONS) + Protected Overrides Async Function BuildTypeDeclarationAsync( + typeSymbol As INamedTypeSymbol, + options As _VSOBJDESCOPTIONS, + cancellationToken As CancellationToken) As Task BuildTypeModifiers(typeSymbol) Select Case typeSymbol.TypeKind @@ -87,7 +93,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.ObjectBrowser If typeSymbol.TypeParameters.Length > 0 Then AddText("(Of ") - BuildTypeParameterList(typeSymbol.TypeParameters) + Await BuildTypeParameterListAsync(typeSymbol.TypeParameters, cancellationToken).ConfigureAwait(True) AddText(")") End If @@ -98,7 +104,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.ObjectBrowser AddIndent() AddIndent() AddText("Inherits ") - AddTypeLink(baseType, LinkFlags.None) + Await AddTypeLinkAsync(baseType, LinkFlags.None, cancellationToken).ConfigureAwait(True) End If End If @@ -106,23 +112,28 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.ObjectBrowser Dim underlyingType = typeSymbol.EnumUnderlyingType If underlyingType IsNot Nothing AndAlso underlyingType.SpecialType <> SpecialType.System_Int32 Then AddText(" As ") - AddTypeLink(underlyingType, LinkFlags.None) + Await AddTypeLinkAsync(underlyingType, LinkFlags.None, cancellationToken).ConfigureAwait(True) End If End If - End Sub + End Function - Protected Overrides Sub BuildMethodDeclaration(methodSymbol As IMethodSymbol, options As _VSOBJDESCOPTIONS) + Protected Overrides Async Function BuildMethodDeclarationAsync( + methodSymbol As IMethodSymbol, + options As _VSOBJDESCOPTIONS, + cancellationToken As CancellationToken) As Task Select Case methodSymbol.MethodKind Case MethodKind.Conversion, MethodKind.UserDefinedOperator - BuildOperatorDeclaration(methodSymbol) + Await BuildOperatorDeclarationAsync(methodSymbol, cancellationToken).ConfigureAwait(True) Case MethodKind.DeclareMethod - BuildDeclareMethodDeclaration(methodSymbol) + Await BuildDeclareMethodDeclarationAsync(methodSymbol, cancellationToken).ConfigureAwait(True) Case Else - BuildRegularMethodDeclaration(methodSymbol) + Await BuildRegularMethodDeclarationAsync(methodSymbol, cancellationToken).ConfigureAwait(True) End Select - End Sub + End Function - Private Sub BuildOperatorDeclaration(methodSymbol As IMethodSymbol) + Private Async Function BuildOperatorDeclarationAsync( + methodSymbol As IMethodSymbol, + cancellationToken As CancellationToken) As Task BuildMemberModifiers(methodSymbol) Select Case methodSymbol.Name @@ -138,16 +149,18 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.ObjectBrowser AddName(methodSymbol.ToDisplayString(methodNameFormat)) AddText("(") - BuildParameterList(methodSymbol.Parameters) + Await BuildParameterListAsync(methodSymbol.Parameters, cancellationToken).ConfigureAwait(True) AddText(")") If Not methodSymbol.ReturnsVoid Then AddText(" As ") - AddTypeLink(methodSymbol.ReturnType, LinkFlags.None) + Await AddTypeLinkAsync(methodSymbol.ReturnType, LinkFlags.None, cancellationToken).ConfigureAwait(True) End If - End Sub + End Function - Private Sub BuildDeclareMethodDeclaration(methodSymbol As IMethodSymbol) + Private Async Function BuildDeclareMethodDeclarationAsync( + methodSymbol As IMethodSymbol, + cancellationToken As CancellationToken) As Task BuildMemberModifiers(methodSymbol) AddText("Declare ") @@ -185,16 +198,18 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.ObjectBrowser End If AddText("(") - BuildParameterList(methodSymbol.Parameters) + Await BuildParameterListAsync(methodSymbol.Parameters, cancellationToken).ConfigureAwait(True) AddText(")") If Not methodSymbol.ReturnsVoid Then AddText(" As ") - AddTypeLink(methodSymbol.ReturnType, LinkFlags.None) + Await AddTypeLinkAsync(methodSymbol.ReturnType, LinkFlags.None, cancellationToken).ConfigureAwait(True) End If - End Sub + End Function - Private Sub BuildRegularMethodDeclaration(methodSymbol As IMethodSymbol) + Private Async Function BuildRegularMethodDeclarationAsync( + methodSymbol As IMethodSymbol, + cancellationToken As CancellationToken) As Task BuildMemberModifiers(methodSymbol) If methodSymbol.ReturnsVoid Then @@ -208,27 +223,30 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.ObjectBrowser If methodSymbol.TypeParameters.Length > 0 Then AddText("(Of ") - BuildTypeParameterList(methodSymbol.TypeParameters) + Await BuildTypeParameterListAsync(methodSymbol.TypeParameters, cancellationToken).ConfigureAwait(True) AddText(")") End If AddText("(") - BuildParameterList(methodSymbol.Parameters) + Await BuildParameterListAsync(methodSymbol.Parameters, cancellationToken).ConfigureAwait(True) AddText(")") If Not methodSymbol.ReturnsVoid Then AddText(" As ") - AddTypeLink(methodSymbol.ReturnType, LinkFlags.None) + Await AddTypeLinkAsync(methodSymbol.ReturnType, LinkFlags.None, cancellationToken).ConfigureAwait(True) End If - End Sub + End Function - Protected Overrides Sub BuildFieldDeclaration(fieldSymbol As IFieldSymbol, options As _VSOBJDESCOPTIONS) + Protected Overrides Async Function BuildFieldDeclarationAsync( + fieldSymbol As IFieldSymbol, + options As _VSOBJDESCOPTIONS, + cancellationToken As CancellationToken) As Task BuildMemberModifiers(fieldSymbol) AddText(fieldSymbol.Name) AddText(" As ") - AddTypeLink(fieldSymbol.Type, LinkFlags.None) + Await AddTypeLinkAsync(fieldSymbol.Type, LinkFlags.None, cancellationToken).ConfigureAwait(True) If fieldSymbol.HasConstantValue Then AddText(" = ") @@ -239,9 +257,12 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.ObjectBrowser AddText(fieldSymbol.ConstantValue.ToString()) End If End If - End Sub + End Function - Protected Overrides Sub BuildPropertyDeclaration(propertySymbol As IPropertySymbol, options As _VSOBJDESCOPTIONS) + Protected Overrides Async Function BuildPropertyDeclarationAsync( + propertySymbol As IPropertySymbol, + options As _VSOBJDESCOPTIONS, + cancellationToken As CancellationToken) As Task BuildMemberModifiers(propertySymbol) If propertySymbol.GetMethod IsNot Nothing Then @@ -258,15 +279,18 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.ObjectBrowser If propertySymbol.Parameters.Length > 0 Then AddText("(") - BuildParameterList(propertySymbol.Parameters) + Await BuildParameterListAsync(propertySymbol.Parameters, cancellationToken).ConfigureAwait(True) AddText(")") End If AddText(" As ") - AddTypeLink(propertySymbol.Type, LinkFlags.None) - End Sub + Await AddTypeLinkAsync(propertySymbol.Type, LinkFlags.None, cancellationToken).ConfigureAwait(True) + End Function - Protected Overrides Sub BuildEventDeclaration(eventSymbol As IEventSymbol, options As _VSOBJDESCOPTIONS) + Protected Overrides Async Function BuildEventDeclarationAsync( + eventSymbol As IEventSymbol, + options As _VSOBJDESCOPTIONS, + cancellationToken As CancellationToken) As Task BuildMemberModifiers(eventSymbol) AddText("Event ") @@ -279,12 +303,12 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.ObjectBrowser If eventType IsNot Nothing AndAlso eventType.TypeKind = TypeKind.Delegate Then Dim delegateInvokeMethod = CType(eventType, INamedTypeSymbol).DelegateInvokeMethod If delegateInvokeMethod IsNot Nothing Then - BuildParameterList(delegateInvokeMethod.Parameters) + Await BuildParameterListAsync(delegateInvokeMethod.Parameters, cancellationToken).ConfigureAwait(True) End If End If AddText(")") - End Sub + End Function Private Sub BuildAccessibility(symbol As ISymbol) Select Case symbol.DeclaredAccessibility @@ -369,7 +393,9 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.ObjectBrowser End If End Sub - Private Sub BuildParameterList(parameters As ImmutableArray(Of IParameterSymbol)) + Private Async Function BuildParameterListAsync( + parameters As ImmutableArray(Of IParameterSymbol), + cancellationToken As CancellationToken) As Task Dim count = parameters.Length If count = 0 Then Return @@ -399,7 +425,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.ObjectBrowser AddParam(current.Name) AddText(" As ") - AddTypeLink(current.Type, LinkFlags.None) + Await AddTypeLinkAsync(current.Type, LinkFlags.None, cancellationToken).ConfigureAwait(True) If current.HasExplicitDefaultValue Then AddText(" = ") @@ -410,9 +436,11 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.ObjectBrowser End If End If Next - End Sub + End Function - Private Sub BuildTypeParameterList(typeParameters As ImmutableArray(Of ITypeParameterSymbol)) + Private Async Function BuildTypeParameterListAsync( + typeParameters As ImmutableArray(Of ITypeParameterSymbol), + cancellationToken As CancellationToken) As Task Dim count = typeParameters.Length If count = 0 Then Return @@ -426,24 +454,28 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.ObjectBrowser Dim current = typeParameters(i) AddName(current.Name) - AddConstraints(current) + Await AddConstraintsAsync(current, cancellationToken).ConfigureAwait(True) Next - End Sub + End Function - Private Sub AddConstraints(typeParameter As ITypeParameterSymbol) + Private Async Function AddConstraintsAsync( + typeParameter As ITypeParameterSymbol, + cancellationToken As CancellationToken) As Task Dim count = CountConstraints(typeParameter) If count = 0 Then Return End If If count = 1 Then - AddSingleConstraint(typeParameter) + Await AddSingleConstraintAsync(typeParameter, cancellationToken).ConfigureAwait(True) Else - AddMultipleConstraints(typeParameter) + Await AddMultipleConstraintsAsync(typeParameter, cancellationToken).ConfigureAwait(True) End If - End Sub + End Function - Private Sub AddSingleConstraint(typeParameter As ITypeParameterSymbol) + Private Async Function AddSingleConstraintAsync( + typeParameter As ITypeParameterSymbol, + cancellationToken As CancellationToken) As Task AddName(" As ") If typeParameter.HasReferenceTypeConstraint Then @@ -454,11 +486,13 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.ObjectBrowser AddName("New") Else Debug.Assert(typeParameter.ConstraintTypes.Length = 1) - AddTypeLink(typeParameter.ConstraintTypes(0), LinkFlags.None) + Await AddTypeLinkAsync(typeParameter.ConstraintTypes(0), LinkFlags.None, cancellationToken).ConfigureAwait(True) End If - End Sub + End Function - Private Sub AddMultipleConstraints(typeParameter As ITypeParameterSymbol) + Private Async Function AddMultipleConstraintsAsync( + typeParameter As ITypeParameterSymbol, + cancellationToken As CancellationToken) As Task AddName(" As {") Dim constraintAdded = False @@ -492,13 +526,13 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.ObjectBrowser AddName(", ") End If - AddTypeLink(constraintType, LinkFlags.None) + Await AddTypeLinkAsync(constraintType, LinkFlags.None, cancellationToken).ConfigureAwait(True) constraintAdded = True Next End If AddName("}") - End Sub + End Function Private Shared Function CountConstraints(typeParameter As ITypeParameterSymbol) As Integer Dim result = typeParameter.ConstraintTypes.Length diff --git a/src/VisualStudio/VisualBasic/Impl/ObjectBrowser/ObjectBrowserLibraryManager.vb b/src/VisualStudio/VisualBasic/Impl/ObjectBrowser/ObjectBrowserLibraryManager.vb index 7ef52cd3126ee..4137850141568 100644 --- a/src/VisualStudio/VisualBasic/Impl/ObjectBrowser/ObjectBrowserLibraryManager.vb +++ b/src/VisualStudio/VisualBasic/Impl/ObjectBrowser/ObjectBrowserLibraryManager.vb @@ -8,7 +8,7 @@ Imports Microsoft.VisualStudio.LanguageServices.Implementation.Library.ObjectBro Imports Microsoft.VisualStudio.ComponentModelHost Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.ObjectBrowser - Friend Class ObjectBrowserLibraryManager + Friend NotInheritable Class ObjectBrowserLibraryManager Inherits AbstractObjectBrowserLibraryManager Public Sub New(serviceProvider As IServiceProvider, componentModel As IComponentModel, workspace As VisualStudioWorkspace) diff --git a/src/VisualStudio/VisualBasic/Impl/Options/AdvancedOptionPage.vb b/src/VisualStudio/VisualBasic/Impl/Options/AdvancedOptionPage.vb index 91107a5e24345..52d1bc4a74e53 100644 --- a/src/VisualStudio/VisualBasic/Impl/Options/AdvancedOptionPage.vb +++ b/src/VisualStudio/VisualBasic/Impl/Options/AdvancedOptionPage.vb @@ -3,7 +3,6 @@ ' See the LICENSE file in the project root for more information. Imports System.Runtime.InteropServices -Imports Microsoft.VisualStudio.ComponentModelHost Imports Microsoft.VisualStudio.LanguageServices.Implementation.Options Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.Options @@ -12,8 +11,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.Options Inherits AbstractOptionPage Protected Overrides Function CreateOptionPage(serviceProvider As IServiceProvider, optionStore As OptionStore) As AbstractOptionPageControl - Dim componentModel = DirectCast(Me.Site.GetService(GetType(SComponentModel)), IComponentModel) - Return New AdvancedOptionPageControl(optionStore, componentModel) + Return New AdvancedOptionPageControl(optionStore) End Function End Class End Namespace diff --git a/src/VisualStudio/VisualBasic/Impl/Options/AdvancedOptionPageControl.xaml b/src/VisualStudio/VisualBasic/Impl/Options/AdvancedOptionPageControl.xaml index 7d5ad3e381d22..6daae1a3a70a5 100644 --- a/src/VisualStudio/VisualBasic/Impl/Options/AdvancedOptionPageControl.xaml +++ b/src/VisualStudio/VisualBasic/Impl/Options/AdvancedOptionPageControl.xaml @@ -62,8 +62,8 @@ Content="{x:Static local:AdvancedOptionPageStrings.Option_Automatically_reload_updated_analyzers_and_generators}" /> - + @@ -96,14 +96,6 @@ - - - - - - @@ -189,6 +181,8 @@ + @@ -277,14 +271,6 @@ - - diff --git a/src/VisualStudio/VisualBasic/Impl/Options/AdvancedOptionPageControl.xaml.vb b/src/VisualStudio/VisualBasic/Impl/Options/AdvancedOptionPageControl.xaml.vb index f57ecd19f709b..c989627195069 100644 --- a/src/VisualStudio/VisualBasic/Impl/Options/AdvancedOptionPageControl.xaml.vb +++ b/src/VisualStudio/VisualBasic/Impl/Options/AdvancedOptionPageControl.xaml.vb @@ -41,22 +41,15 @@ Imports Microsoft.CodeAnalysis.Structure Imports Microsoft.CodeAnalysis.SymbolSearch Imports Microsoft.CodeAnalysis.ValidateFormatString Imports Microsoft.CodeAnalysis.VisualBasic.AutomaticInsertionOfAbstractOrInterfaceMembers -Imports Microsoft.VisualStudio.ComponentModelHost Imports Microsoft.VisualStudio.LanguageServices.DocumentOutline Imports Microsoft.VisualStudio.LanguageServices.Implementation Imports Microsoft.VisualStudio.LanguageServices.Implementation.Options Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.Options Friend Class AdvancedOptionPageControl - Private ReadOnly _threadingContext As IThreadingContext - Private ReadOnly _colorSchemeApplier As ColorSchemeApplier - - Public Sub New(optionStore As OptionStore, componentModel As IComponentModel) + Public Sub New(optionStore As OptionStore) MyBase.New(optionStore) - _threadingContext = componentModel.GetService(Of IThreadingContext)() - _colorSchemeApplier = componentModel.GetService(Of ColorSchemeApplier)() - InitializeComponent() ' Keep this code in sync with the actual order options appear in Tools | Options @@ -79,10 +72,9 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.Options BindToOption(Enable_file_logging_for_diagnostics, VisualStudioLoggingOptionsStorage.EnableFileLoggingForDiagnostics) BindToOption(Skip_analyzers_for_implicitly_triggered_builds, FeatureOnOffOptions.SkipAnalyzersForImplicitlyTriggeredBuilds) - BindToOption(Show_Remove_Unused_References_command_in_Solution_Explorer_experimental, FeatureOnOffOptions.OfferRemoveUnusedReferences, + BindToOption(Show_Remove_Unused_References_command_in_Solution_Explorer, FeatureOnOffOptions.OfferRemoveUnusedReferences, Function() - ' If the option has not been set by the user, check if the option is enabled from experimentation. - Return optionStore.GetOption(FeatureOnOffOptions.OfferRemoveUnusedReferencesFeatureFlag) + Return True End Function) ' Source Generators @@ -137,6 +129,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.Options ' Fading BindToOption(Fade_out_unused_imports, FadingOptions.FadeOutUnusedImports, LanguageNames.VisualBasic) + BindToOption(Fade_out_unused_members, FadingOptions.FadeOutUnusedMembers, LanguageNames.VisualBasic) ' Block structure guides BindToOption(Show_guides_for_declaration_level_constructs, BlockStructureOptionsStorage.ShowBlockStructureGuidesForDeclarationLevelConstructs, LanguageNames.VisualBasic) @@ -210,19 +203,6 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.Options ' Since this dialog is constructed once for the lifetime of the application and VS Theme can be changed after the application has started, ' we need to update the visibility of our combobox and warnings based on the current VS theme before being rendered. Friend Overrides Sub OnLoad() - Dim cancellationToken = _threadingContext.DisposalToken - Dim values = _threadingContext.JoinableTaskFactory.Run( - Async Function() - Return (isSupportedTheme:=Await _colorSchemeApplier.IsSupportedThemeAsync(cancellationToken).ConfigureAwait(False), - isCustomized:=Await _colorSchemeApplier.IsThemeCustomizedAsync(cancellationToken).ConfigureAwait(False)) - End Function) - - Dim isSupportedTheme = values.isSupportedTheme - Dim isCustomized = values.isCustomized - Editor_color_scheme.IsEnabled = isSupportedTheme - Customized_Theme_Warning.Visibility = If(isSupportedTheme AndAlso isCustomized, Visibility.Visible, Visibility.Collapsed) - Custom_VS_Theme_Warning.Visibility = If(isSupportedTheme, Visibility.Collapsed, Visibility.Visible) - UpdateInlineHintsOptions() MyBase.OnLoad() diff --git a/src/VisualStudio/VisualBasic/Impl/Options/AdvancedOptionPageStrings.vb b/src/VisualStudio/VisualBasic/Impl/Options/AdvancedOptionPageStrings.vb index 12ee11a2dec73..c9b1279055b99 100644 --- a/src/VisualStudio/VisualBasic/Impl/Options/AdvancedOptionPageStrings.vb +++ b/src/VisualStudio/VisualBasic/Impl/Options/AdvancedOptionPageStrings.vb @@ -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. +Imports Microsoft.CodeAnalysis Imports Microsoft.CodeAnalysis.ColorSchemes Imports Microsoft.CodeAnalysis.SolutionCrawler @@ -23,7 +24,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.Options ServicesVSResources.Analyze_source_generated_files Public ReadOnly Property Option_Background_Analysis_Scope_None As String = - ServicesVSResources.None + WorkspacesResources.None Public ReadOnly Property Option_Background_Analysis_Scope_Active_File As String = ServicesVSResources.Current_document @@ -50,7 +51,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.Options ServicesVSResources.Show_compiler_errors_and_warnings_for_colon Public ReadOnly Property Option_Compiler_Diagnostics_Scope_None As String = - ServicesVSResources.None + WorkspacesResources.None Public ReadOnly Property Option_Compiler_Diagnostics_Scope_Visible_Files As String = ServicesVSResources.Current_document ' We show "Current document" to users for consistency with term used elsewhere. @@ -77,7 +78,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.Options ServicesVSResources.Run_code_analysis_in_separate_process_requires_restart Public ReadOnly Property Option_DisplayLineSeparators As String = - BasicVSResources.Show_procedure_line_separators + ServicesVSResources.Show_procedure_line_separators Public ReadOnly Property Option_Underline_reassigned_variables As String = ServicesVSResources.Underline_reassigned_variables @@ -92,7 +93,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.Options ServicesVSResources.Color_hints Public ReadOnly Property Option_Inline_Hints As String = - ServicesVSResources.Inline_Hints + EditorFeaturesResources.Inline_Hints Public ReadOnly Property Option_Display_inline_parameter_name_hints As String = ServicesVSResources.Display_inline_parameter_name_hints @@ -131,16 +132,16 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.Options BasicVSResources.Don_t_put_ByRef_on_custom_structure Public ReadOnly Property Option_EditorHelp As String = - BasicVSResources.Editor_Help + ServicesVSResources.Editor_Help Public ReadOnly Property Option_EnableEndConstruct As String = BasicVSResources.A_utomatic_insertion_of_end_constructs Public ReadOnly Property Option_EnableHighlightKeywords As String = - BasicVSResources.Highlight_related_keywords_under_cursor + ServicesVSResources.Highlight_related_keywords_under_cursor Public ReadOnly Property Option_EnableHighlightReferences As String = - BasicVSResources.Highlight_references_to_symbol_under_cursor + ServicesVSResources.Highlight_references_to_symbol_under_cursor Public ReadOnly Property Option_EnableLineCommit As String = BasicVSResources.Pretty_listing_reformatting_of_code @@ -164,7 +165,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.Options ServicesVSResources.Collapse_metadata_signature_files_on_open Public ReadOnly Property Option_ExtractMethod As String = - BasicVSResources.Extract_Method + EditorFeaturesResources.Extract_Method Public ReadOnly Property Option_Implement_Interface_or_Abstract_Class As String = ServicesVSResources.Implement_Interface_or_Abstract_Class @@ -193,46 +194,31 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.Options Public ReadOnly Property Option_InsertApostropheAtTheStartOfNewLinesWhenWritingApostropheComments As String = BasicVSResources.Insert_apostrophe_at_the_start_of_new_lines_when_writing_apostrophe_comments - Public ReadOnly Property Option_ShowRemarksInQuickInfo As String - Get - Return BasicVSResources.Show_remarks_in_Quick_Info - End Get - End Property + Public ReadOnly Property Option_ShowRemarksInQuickInfo As String = + ServicesVSResources.Show_remarks_in_Quick_Info - Public ReadOnly Property Option_GoToDefinition As String - Get - Return BasicVSResources.Go_to_Definition - End Get - End Property + Public ReadOnly Property Option_GoToDefinition As String = + EditorFeaturesResources.Go_to_Definition - Public ReadOnly Property Option_Highlighting As String - Get - Return BasicVSResources.Highlighting - End Get - End Property + Public ReadOnly Property Option_Highlighting As String = + ServicesVSResources.Highlighting - Public ReadOnly Property Option_NavigateToObjectBrowser As String - Get - Return BasicVSResources.Navigate_to_Object_Browser_for_symbols_defined_in_metadata - End Get - End Property + Public ReadOnly Property Option_NavigateToObjectBrowser As String = + BasicVSResources.Navigate_to_Object_Browser_for_symbols_defined_in_metadata - Public ReadOnly Property Option_OptimizeForSolutionSize As String - Get - Return BasicVSResources.Optimize_for_solution_size - End Get - End Property + Public ReadOnly Property Option_OptimizeForSolutionSize As String = + ServicesVSResources.Optimize_for_solution_size Public ReadOnly Property Option_OptimizeForSolutionSize_Small As String = - BasicVSResources.Small + ServicesVSResources.Small Public ReadOnly Property Option_OptimizeForSolutionSize_Regular As String = - BasicVSResources.Regular + ServicesVSResources.Regular Public ReadOnly Property Option_OptimizeForSolutionSize_Large As String = - BasicVSResources.Large + ServicesVSResources.Large - Public ReadOnly Property Option_Outlining As String = ServicesVSResources.Outlining + Public ReadOnly Property Option_Outlining As String = EditorFeaturesResources.Outlining Public ReadOnly Property Option_Show_outlining_for_declaration_level_constructs As String = ServicesVSResources.Show_outlining_for_declaration_level_constructs @@ -267,14 +253,17 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.Options Public ReadOnly Property Option_Fade_out_unused_imports As String = BasicVSResources.Fade_out_unused_imports + Public ReadOnly Property Option_Fade_out_unused_members As String = + ServicesVSResources.Fade_out_unused_members + Public ReadOnly Property Option_Performance As String = - BasicVSResources.Performance + ServicesVSResources.Performance Public ReadOnly Property Option_Report_invalid_placeholders_in_string_dot_format_calls As String = BasicVSResources.Report_invalid_placeholders_in_string_dot_format_calls Public ReadOnly Property Option_RenameTrackingPreview As String = - BasicVSResources.Show_preview_for_rename_tracking + ServicesVSResources.Show_preview_for_rename_tracking Public ReadOnly Property Option_Import_Directives As String = BasicVSResources.Import_Directives @@ -321,12 +310,6 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.Options Public ReadOnly Property Option_Editor_Color_Scheme As String = ServicesVSResources.Editor_Color_Scheme - Public ReadOnly Property Editor_color_scheme_options_are_only_available_when_using_a_color_theme_bundled_with_Visual_Studio_The_color_theme_can_be_configured_from_the_Environment_General_options_page As String = - ServicesVSResources.Editor_color_scheme_options_are_only_available_when_using_a_color_theme_bundled_with_Visual_Studio_The_color_theme_can_be_configured_from_the_Environment_General_options_page - - Public ReadOnly Property Some_color_scheme_colors_are_being_overridden_by_changes_made_in_the_Environment_Fonts_and_Colors_options_page_Choose_Use_Defaults_in_the_Fonts_and_Colors_page_to_revert_all_customizations As String = - ServicesVSResources.Some_color_scheme_colors_are_being_overridden_by_changes_made_in_the_Environment_Fonts_and_Colors_options_page_Choose_Use_Defaults_in_the_Fonts_and_Colors_page_to_revert_all_customizations - Public ReadOnly Property Option_Color_Scheme_VisualStudio2019 As String = ServicesVSResources.Visual_Studio_2019 @@ -339,8 +322,8 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.Options Public ReadOnly Property Color_Scheme_VisualStudio2017_Tag As ColorSchemeName = ColorSchemeName.VisualStudio2017 - Public ReadOnly Property Option_Show_Remove_Unused_References_command_in_Solution_Explorer_experimental As String = - ServicesVSResources.Show_Remove_Unused_References_command_in_Solution_Explorer_experimental + Public ReadOnly Property Option_Show_Remove_Unused_References_command_in_Solution_Explorer As String = + ServicesVSResources.Show_Remove_Unused_References_command_in_Solution_Explorer Public ReadOnly Property Option_Enable_file_logging_for_diagnostics As String = ServicesVSResources.Enable_file_logging_for_diagnostics @@ -363,11 +346,8 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.Options Public ReadOnly Property Option_Go_To_Definition As String = ServicesVSResources.Go_To_Definition - Public ReadOnly Property Option_Navigate_asynchronously_exerimental As String = - ServicesVSResources.Navigate_asynchronously_exerimental - Public ReadOnly Property Option_Rename As String = - ServicesVSResources.Rename + EditorFeaturesResources.Rename Public ReadOnly Property Option_Rename_asynchronously_experimental As String = ServicesVSResources.Rename_asynchronously_experimental diff --git a/src/VisualStudio/VisualBasic/Impl/Options/AutomationObject/AutomationObject.Fading.vb b/src/VisualStudio/VisualBasic/Impl/Options/AutomationObject/AutomationObject.Fading.vb index 7e7c76af9158d..d0e2e0d61a433 100644 --- a/src/VisualStudio/VisualBasic/Impl/Options/AutomationObject/AutomationObject.Fading.vb +++ b/src/VisualStudio/VisualBasic/Impl/Options/AutomationObject/AutomationObject.Fading.vb @@ -23,5 +23,14 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.Options SetBooleanOption(FadingOptions.FadeOutUnusedImports, value) End Set End Property + + Public Property Fading_FadeOutUnusedMembers As Boolean + Get + Return GetBooleanOption(FadingOptions.FadeOutUnusedMembers) + End Get + Set(value As Boolean) + SetBooleanOption(FadingOptions.FadeOutUnusedMembers, value) + End Set + End Property End Class End Namespace diff --git a/src/VisualStudio/VisualBasic/Impl/Options/AutomationObject/AutomationObject.vb b/src/VisualStudio/VisualBasic/Impl/Options/AutomationObject/AutomationObject.vb index 9707be51d9ce8..77ae151d38dbb 100644 --- a/src/VisualStudio/VisualBasic/Impl/Options/AutomationObject/AutomationObject.vb +++ b/src/VisualStudio/VisualBasic/Impl/Options/AutomationObject/AutomationObject.vb @@ -9,7 +9,7 @@ Imports Microsoft.VisualStudio.LanguageServices.Implementation.Options Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.Options - Partial Public Class AutomationObject + Partial Public NotInheritable Class AutomationObject Inherits AbstractAutomationObject Friend Sub New(legacyGlobalOptions As ILegacyGlobalOptionService) diff --git a/src/VisualStudio/VisualBasic/Impl/Options/IntelliSenseOptionPageControl.xaml b/src/VisualStudio/VisualBasic/Impl/Options/IntelliSenseOptionPageControl.xaml index fe4bfff186c95..cdc81d010c0b7 100644 --- a/src/VisualStudio/VisualBasic/Impl/Options/IntelliSenseOptionPageControl.xaml +++ b/src/VisualStudio/VisualBasic/Impl/Options/IntelliSenseOptionPageControl.xaml @@ -63,7 +63,7 @@ + Content="{x:Static local:IntelliSenseOptionPageStrings.Option_Tab_twice_to_insert_arguments_experimental}" /> diff --git a/src/VisualStudio/VisualBasic/Impl/Options/IntelliSenseOptionPageStrings.vb b/src/VisualStudio/VisualBasic/Impl/Options/IntelliSenseOptionPageStrings.vb index 39b3bf040f610..67a8b73d86133 100644 --- a/src/VisualStudio/VisualBasic/Impl/Options/IntelliSenseOptionPageStrings.vb +++ b/src/VisualStudio/VisualBasic/Impl/Options/IntelliSenseOptionPageStrings.vb @@ -8,31 +8,31 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.Options BasicVSResources.Completion_Lists Public ReadOnly Property Option_Show_completion_list_after_a_character_is_typed As String = - BasicVSResources.Show_completion_list_after_a_character_is_typed + ServicesVSResources._Show_completion_list_after_a_character_is_typed Public ReadOnly Property Option_Show_completion_list_after_a_character_is_deleted As String = - BasicVSResources.Show_completion_list_after_a_character_is_deleted + ServicesVSResources.Show_completion_list_after_a_character_is__deleted Public ReadOnly Property Option_Highlight_matching_portions_of_completion_list_items As String = - BasicVSResources.Highlight_matching_portions_of_completion_list_items + ServicesVSResources._Highlight_matching_portions_of_completion_list_items Public ReadOnly Property Option_Show_completion_item_filters As String = - BasicVSResources.Show_completion_item_filters + ServicesVSResources.Show_completion_item__filters Public ReadOnly Property Option_Only_add_new_line_on_enter_with_whole_word As String = - BasicVSResources.Only_add_new_line_on_enter_after_end_of_fully_typed_word + ServicesVSResources.Only_add_new_line_on_enter_after_end_of_fully_typed_word Public ReadOnly Property Option_Always_add_new_line_on_enter As String = - BasicVSResources.Always_add_new_line_on_enter + ServicesVSResources.Always_add_new_line_on_enter Public ReadOnly Property Option_Never_add_new_line_on_enter As String = - BasicVSResources.Never_add_new_line_on_enter + ServicesVSResources.Never_add_new_line_on_enter Public ReadOnly Property Enter_key_behavior_Title As String = - BasicVSResources.Enter_key_behavior_colon + ServicesVSResources.Enter_key_behavior_colon Public ReadOnly Property Snippets_behavior As String = - BasicVSResources.Snippets_behavior + ServicesVSResources.Snippets_behavior Public ReadOnly Property Option_Never_include_snippets As String = VSPackage.Never_include_snippets @@ -44,10 +44,9 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.Options VSPackage.Include_snippets_when_Tab_is_typed_after_an_identifier Public ReadOnly Property Option_Show_items_from_unimported_namespaces As String = - BasicVSResources.Show_items_from_unimported_namespaces - - Public ReadOnly Property Option_Tab_twice_to_insert_arguments As String = - ServicesVSResources.Tab_twice_to_insert_arguments + ServicesVSResources.Show_items_from_unimported_namespaces + Public ReadOnly Property Option_Tab_twice_to_insert_arguments_experimental As String = + ServicesVSResources.Tab_twice_to_insert_arguments_experimental End Module End Namespace diff --git a/src/VisualStudio/VisualBasic/Impl/Options/StyleViewModel.vb b/src/VisualStudio/VisualBasic/Impl/Options/StyleViewModel.vb index 786b75791274a..97aee74630bba 100644 --- a/src/VisualStudio/VisualBasic/Impl/Options/StyleViewModel.vb +++ b/src/VisualStudio/VisualBasic/Impl/Options/StyleViewModel.vb @@ -892,7 +892,7 @@ End Class Private Sub AddUnusedValueOptions(optionStore As OptionStore, expressionPreferencesGroupTitle As String) Dim unusedValuePreferences = New List(Of CodeStylePreference) From { - New CodeStylePreference(BasicVSResources.Unused_local, isChecked:=True) + New CodeStylePreference(ServicesVSResources.Unused_local, isChecked:=True) } Dim enumValues = diff --git a/src/VisualStudio/VisualBasic/Impl/PackageRegistration.pkgdef b/src/VisualStudio/VisualBasic/Impl/PackageRegistration.pkgdef index 088ecdbfeb727..04cf35e3f6e42 100644 --- a/src/VisualStudio/VisualBasic/Impl/PackageRegistration.pkgdef +++ b/src/VisualStudio/VisualBasic/Impl/PackageRegistration.pkgdef @@ -191,8 +191,8 @@ "DisplayLineSeparators"=dword:00000001 // CacheTag value should be changed when registration file changes -// See https://devdiv.visualstudio.com/DevDiv/_wiki/wikis/DevDiv.wiki/39345/Manifest-Build-Deployment-and-Setup-Authoring-In-Depth?anchor=example-pkgdef-key for more infomation +// See https://devdiv.visualstudio.com/DevDiv/_wiki/wikis/DevDiv.wiki/39345/Manifest-Build-Deployment-and-Setup-Authoring-In-Depth?anchor=example-pkgdef-key for more information [$RootKey$\SettingsManifests\{574fc912-f74f-4b4e-92c3-f695c208a2bb}] @="Microsoft.VisualStudio.LanguageServices.VisualBasic.VisualBasicPackage" "ManifestPath"="$PackageFolder$\UnifiedSettings\visualBasicSettings.registration.json" -"CacheTag"=qword:5DE8496A8900B809 +"CacheTag"=qword:A051BA2C3046E62E diff --git a/src/VisualStudio/VisualBasic/Impl/Snippets/SnippetCommandHandler.vb b/src/VisualStudio/VisualBasic/Impl/Snippets/SnippetCommandHandler.vb index 57f71b1a2c1c4..1bd28bccb8114 100644 --- a/src/VisualStudio/VisualBasic/Impl/Snippets/SnippetCommandHandler.vb +++ b/src/VisualStudio/VisualBasic/Impl/Snippets/SnippetCommandHandler.vb @@ -76,7 +76,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.Snippets bstrKinds:=Nothing, iCountKinds:=0, fIncludeNULLKind:=1, - bstrPrefixText:=BasicVSResources.Insert_Snippet, + bstrPrefixText:=ServicesVSResources.Insert_Snippet, bstrCompletionChar:=">"c) Return True diff --git a/src/VisualStudio/VisualBasic/Impl/Snippets/VisualBasicSnippetExpansionLanguageHelper.vb b/src/VisualStudio/VisualBasic/Impl/Snippets/VisualBasicSnippetExpansionLanguageHelper.vb index 01edd5338e9f2..7e18a757f01d2 100644 --- a/src/VisualStudio/VisualBasic/Impl/Snippets/VisualBasicSnippetExpansionLanguageHelper.vb +++ b/src/VisualStudio/VisualBasic/Impl/Snippets/VisualBasicSnippetExpansionLanguageHelper.vb @@ -7,6 +7,7 @@ Imports System.Threading Imports Microsoft.CodeAnalysis Imports Microsoft.CodeAnalysis.AddImport Imports Microsoft.CodeAnalysis.Editor.Shared.Extensions +Imports Microsoft.CodeAnalysis.Editor.[Shared].Utilities Imports Microsoft.CodeAnalysis.Formatting Imports Microsoft.CodeAnalysis.Host.Mef Imports Microsoft.CodeAnalysis.Shared.Extensions @@ -20,36 +21,35 @@ Imports Microsoft.VisualStudio.TextManager.Interop Imports VsTextSpan = Microsoft.VisualStudio.TextManager.Interop.TextSpan Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.Snippets - - <[Shared]> + Friend NotInheritable Class VisualBasicSnippetExpansionLanguageHelper Inherits AbstractSnippetExpansionLanguageHelper - Public Sub New() + Public Sub New(threadingContext As IThreadingContext) + MyBase.New(threadingContext) End Sub - Public Overrides ReadOnly Property LanguageServiceGuid As Guid - Get - Return Guids.VisualBasicDebuggerLanguageId - End Get - End Property + Public Overrides ReadOnly Property LanguageServiceGuid As Guid = Guids.VisualBasicDebuggerLanguageId - Public Overrides ReadOnly Property FallbackDefaultLiteral As String - Get - Return "Nothing" - End Get - End Property + Public Overrides ReadOnly Property FallbackDefaultLiteral As String = "Nothing" - Public Overrides Function AddImports(document As Document, addImportOptions As AddImportPlacementOptions, formattingOptions As SyntaxFormattingOptions, position As Integer, snippetNode As XElement, cancellationToken As CancellationToken) As Document + Public Overrides Async Function AddImportsAsync( + document As Document, + addImportOptions As AddImportPlacementOptions, + formattingOptions As SyntaxFormattingOptions, + position As Integer, + snippetNode As XElement, + cancellationToken As CancellationToken) As Task(Of Document) Dim importsNode = snippetNode.Element(XName.Get("Imports", snippetNode.Name.NamespaceName)) If importsNode Is Nothing OrElse Not importsNode.HasElements() Then Return document End If - Dim newImportsStatements = GetImportsStatementsToAdd(document, snippetNode, importsNode, cancellationToken) + Dim newImportsStatements = Await GetImportsStatementsToAddAsync( + document, snippetNode, importsNode, cancellationToken).ConfigureAwait(True) If Not newImportsStatements.Any() Then Return document End If @@ -67,8 +67,8 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.Snippets Dim newRoot = CType(root, CompilationUnitSyntax).AddImportsStatements(newImportsStatements, addImportOptions.PlaceSystemNamespaceFirst) Dim newDocument = document.WithSyntaxRoot(newRoot) - Dim formattedDocument = Formatter.FormatAsync(newDocument, Formatter.Annotation, formattingOptions, cancellationToken).WaitAndGetResult(cancellationToken) - document.Project.Solution.Workspace.ApplyDocumentChanges(formattedDocument, cancellationToken) + Dim formattedDocument = Await Formatter.FormatAsync(newDocument, Formatter.Annotation, formattingOptions, cancellationToken).ConfigureAwait(True) + Await document.Project.Solution.Workspace.ApplyDocumentChangesAsync(Me.ThreadingContext, formattedDocument, cancellationToken).configureawait(True) Return formattedDocument End Function @@ -98,10 +98,10 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.Snippets Return Nothing End Function - Private Shared Function GetImportsStatementsToAdd(document As Document, snippetNode As XElement, importsNode As XElement, cancellationToken As CancellationToken) As IList(Of ImportsStatementSyntax) + Private Shared Async Function GetImportsStatementsToAddAsync(document As Document, snippetNode As XElement, importsNode As XElement, cancellationToken As CancellationToken) As Task(Of IList(Of ImportsStatementSyntax)) Dim root = document.GetSyntaxRootSynchronously(cancellationToken) Dim localImportsClauses = CType(root, CompilationUnitSyntax).Imports.SelectMany(Function(x) x.ImportsClauses) - Dim compilation = document.Project.GetCompilationAsync(cancellationToken).WaitAndGetResult(cancellationToken) + Dim compilation = Await document.Project.GetCompilationAsync(cancellationToken).ConfigureAwait(True) Dim options = CType(compilation.Options, VisualBasicCompilationOptions) Dim globalImportsClauses = options.GlobalImports.Select(Function(g) g.Clause) diff --git a/src/VisualStudio/VisualBasic/Impl/UnifiedSettings/visualBasicSettings.registration.json b/src/VisualStudio/VisualBasic/Impl/UnifiedSettings/visualBasicSettings.registration.json index c744cc9dc0357..8751cfb2f0791 100644 --- a/src/VisualStudio/VisualBasic/Impl/UnifiedSettings/visualBasicSettings.registration.json +++ b/src/VisualStudio/VisualBasic/Impl/UnifiedSettings/visualBasicSettings.registration.json @@ -6,7 +6,7 @@ "properties": { // CompletionOptionsStorage.TriggerOnTypingLetters "textEditor.basic.intellisense.triggerCompletionOnTypingLetters": { - "title": "@Show_completion_list_after_a_character_is_typed;..\\Microsoft.VisualStudio.LanguageServices.VisualBasic.dll", + "title": "@Show_completion_list_after_a_character_is_typed;..\\Microsoft.VisualStudio.LanguageServices.dll", "type": "boolean", "default": true, "order": 0, @@ -21,7 +21,7 @@ }, // CompletionOptionsStorage.TriggerOnDeletion "textEditor.basic.intellisense.triggerCompletionOnDeletion": { - "title": "@Show_completion_list_after_a_character_is_deleted;..\\Microsoft.VisualStudio.LanguageServices.VisualBasic.dll", + "title": "@Show_completion_list_after_a_character_is_deleted;..\\Microsoft.VisualStudio.LanguageServices.dll", "type": "boolean", "default": true, "order": 1, @@ -36,7 +36,7 @@ }, // CompletionViewOptionsStorage.HighlightMatchingPortionsOfCompletionListItems "textEditor.basic.intellisense.highlightMatchingPortionsOfCompletionListItems": { - "title": "@Highlight_matching_portions_of_completion_list_items;..\\Microsoft.VisualStudio.LanguageServices.VisualBasic.dll", + "title": "@Highlight_matching_portions_of_completion_list_items;..\\Microsoft.VisualStudio.LanguageServices.dll", "type": "boolean", "default": true, "order": 10, @@ -51,7 +51,7 @@ }, // CompletionViewOptionsStorage.ShowCompletionItemFilters "textEditor.basic.intellisense.showCompletionItemFilters": { - "title": "@Show_completion_item_filters;..\\Microsoft.VisualStudio.LanguageServices.VisualBasic.dll", + "title": "@Show_completion_item_filters;..\\Microsoft.VisualStudio.LanguageServices.dll", "type": "boolean", "default": true, "order": 20, @@ -66,7 +66,7 @@ }, // CompletionOptionsStorage.SnippetsBehavior "textEditor.basic.intellisense.snippetsBehavior": { - "title": "@Snippets_behavior;..\\Microsoft.VisualStudio.LanguageServices.VisualBasic.dll", + "title": "@Snippets_behavior;..\\Microsoft.VisualStudio.LanguageServices.dll", "type": "string", "enum": [ "neverInclude", "alwaysInclude", "includeAfterTypingIdentifierQuestionTab" ], "enumItemLabels": [ "@Never_include_snippets;{574fc912-f74f-4b4e-92c3-f695c208a2bb}", "@Always_include_snippets;{574fc912-f74f-4b4e-92c3-f695c208a2bb}", "@Include_snippets_when_Tab_is_typed_after_an_identifier;{574fc912-f74f-4b4e-92c3-f695c208a2bb}" ], @@ -105,7 +105,7 @@ }, // CompletionOptionsStorage.EnterKeyBehavior "textEditor.basic.intellisense.returnKeyCompletionBehavior": { - "title": "@Enter_key_behavior_colon;..\\Microsoft.VisualStudio.LanguageServices.VisualBasic.dll", + "title": "@Enter_key_behavior;..\\Microsoft.VisualStudio.LanguageServices.dll", "type": "string", "enum": [ "never", "afterFullyTypedWord", "always" ], "enumItemLabels": [ "@Never_add_new_line_on_enter;{574fc912-f74f-4b4e-92c3-f695c208a2bb}", "@Only_add_new_line_on_enter_after_end_of_fully_typed_word;{574fc912-f74f-4b4e-92c3-f695c208a2bb}", "@Always_add_new_line_on_enter;{574fc912-f74f-4b4e-92c3-f695c208a2bb}" ], @@ -144,7 +144,7 @@ }, // CompletionOptionsStorage.ShowItemsFromUnimportedNamespaces "textEditor.basic.intellisense.showCompletionItemsFromUnimportedNamespaces": { - "title": "@Show_items_from_unimported_namespaces;..\\Microsoft.VisualStudio.LanguageServices.VisualBasic.dll", + "title": "@Show_items_from_unimported_namespaces;..\\Microsoft.VisualStudio.LanguageServices.dll", "type": "boolean", "default": true, "order": 50, @@ -163,6 +163,11 @@ "type": "boolean", "default": false, "order": 60, + "messages": [ + { + "text": "@Experimental_feature;..\\Microsoft.VisualStudio.LanguageServices.dll" + } + ], "migration": { "pass": { "input": { @@ -175,7 +180,7 @@ }, "categories": { "textEditor.basic":{ - "title": "Visual Basic" + "title": "@101;{574fc912-f74f-4b4e-92c3-f695c208a2bb}" }, "textEditor.basic.intellisense": { "title": "@112;{574fc912-f74f-4b4e-92c3-f695c208a2bb}", diff --git a/src/VisualStudio/VisualBasic/Impl/Venus/VisualBasicContainedLanguage.vb b/src/VisualStudio/VisualBasic/Impl/Venus/VisualBasicContainedLanguage.vb index 69dd87973d03b..6a03ab41c021e 100644 --- a/src/VisualStudio/VisualBasic/Impl/Venus/VisualBasicContainedLanguage.vb +++ b/src/VisualStudio/VisualBasic/Impl/Venus/VisualBasicContainedLanguage.vb @@ -59,7 +59,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.Venus pszObjectName As String, pszNameOfEvent As String) As Integer Implements IVsContainedLanguageStaticEventBinding.AddStaticEventBinding Me.ComponentModel.GetService(Of IUIThreadOperationExecutor)().Execute( - BasicVSResources.IntelliSense, + EditorFeaturesResources.IntelliSense, defaultDescription:="", allowCancellation:=False, showProgress:=False, @@ -116,7 +116,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.Venus ppbstrMemberIDs As IntPtr) As Integer Implements IVsContainedLanguageStaticEventBinding.GetStaticEventBindingsForObject Dim members As Integer Me.ComponentModel.GetService(Of IUIThreadOperationExecutor)().Execute( - BasicVSResources.IntelliSense, + EditorFeaturesResources.IntelliSense, defaultDescription:="", allowCancellation:=False, showProgress:=Nothing, @@ -139,7 +139,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.Venus pszNameOfEvent As String) As Integer Implements IVsContainedLanguageStaticEventBinding.RemoveStaticEventBinding Me.ComponentModel.GetService(Of IUIThreadOperationExecutor)().Execute( - BasicVSResources.IntelliSense, + EditorFeaturesResources.IntelliSense, defaultDescription:="", allowCancellation:=False, showProgress:=Nothing, diff --git a/src/VisualStudio/VisualBasic/Impl/xlf/BasicVSResources.cs.xlf b/src/VisualStudio/VisualBasic/Impl/xlf/BasicVSResources.cs.xlf index a095b351cce37..d7075d31aa373 100644 --- a/src/VisualStudio/VisualBasic/Impl/xlf/BasicVSResources.cs.xlf +++ b/src/VisualStudio/VisualBasic/Impl/xlf/BasicVSResources.cs.xlf @@ -27,26 +27,11 @@ Microsoft Visual Basic - - Insert Snippet - Vložit fragment - - - - IntelliSense - IntelliSense - - Automatic _insertion of Interface and MustOverride members Automatické _vkládání členů Interface a MustOverride - - Never - Nikdy - - Prefer 'IsNot' expression Upřednostňovat výraz IsNot @@ -62,51 +47,21 @@ Upřednostňovat zjednodušené vytváření objektů - - Remove unnecessary imports - Odebrat nepotřebné importy - {Locked="Import"} 'import' is a Visual Basic keyword and should not be localized - Show hints for 'New' expressions Zobrazit nápovědy pro výrazy New - - Show items from unimported namespaces - Zobrazit položky z neimportovaných oborů názvů - - - - _Show procedure line separators - Zob_razit oddělovače řádků procedur - - _Don't put ByRef on custom structure _Nevkládat ByRef do vlastní struktury - - Editor Help - Nápověda k editoru - - A_utomatic insertion of end constructs A_utomatické vkládání koncových konstruktorů - - Highlight related _keywords under cursor - Zvýrazňovat související _klíčová slova pod kurzorem - - - - _Highlight references to symbol under cursor - Z_výrazňovat odkazy na symbol pod kurzorem - - _Pretty listing (reformatting) of code _Přehledný výpis (přeformátování) kódu @@ -117,66 +72,16 @@ P_o otevření souborů přejít do režimu osnovy - - Extract Method - Extrahovat metodu - - _Generate XML documentation comments for ''' _Generovat komentáře dokumentace XML pro ''' {Locked="'''"} "'''" is a VB keyword and should not be localized. - - Highlighting - Zvýraznění - - - - Optimize for solution size - Optimalizovat pro velikost řešení - - - - Large - Velké - - - - Regular - Normální - - - - Show remarks in Quick Info - Zobrazit poznámky v Rychlých informacích - - - - Small - Malé - - - - Performance - Výkon - - - - Show preview for rename _tracking - Zobrazit náhled pro sledování _rename - - _Navigate to Object Browser for symbols defined in metadata _Přejít do Prohlížeče objektů pro symboly definované v metadatech - - Go to Definition - Přejít k definici - - Import Directives Importovat direktivy @@ -237,61 +142,11 @@ Předdefinované předvolby typů: - - _Highlight matching portions of completion list items - _Zvýraznit odpovídající části položek seznamu dokončení - - - - Show completion item _filters - Zobrazit _filtry položek dokončení - - Completion Lists Seznamy dokončení - - Enter key behavior: - Chování klávesy Enter: - - - - _Only add new line on enter after end of fully typed word - _Při stisku Enter přidat nový řádek jenom po dopsání celého slova - - - - _Always add new line on enter - _Při stisku Enter vždy přidat nový řádek - - - - _Never add new line on enter - _Při stisku Enter nikdy nepřidávat nový řádek - - - - Snippets behavior - Chování fragmentů - - - - Show completion list after a character is _deleted - _Zobrazit seznam dokončení po odstranění znaku - - - - _Show completion list after a character is typed - _Zobrazovat seznam dokončení po zadání znaku - - - - Unused local - Nepoužitá místní - - 'nothing' checking: 'Kontrola hodnot nothing: diff --git a/src/VisualStudio/VisualBasic/Impl/xlf/BasicVSResources.de.xlf b/src/VisualStudio/VisualBasic/Impl/xlf/BasicVSResources.de.xlf index 63b9d71ab0553..9d611be72263a 100644 --- a/src/VisualStudio/VisualBasic/Impl/xlf/BasicVSResources.de.xlf +++ b/src/VisualStudio/VisualBasic/Impl/xlf/BasicVSResources.de.xlf @@ -27,26 +27,11 @@ Microsoft Visual Basic - - Insert Snippet - Schnipsel einfügen - - - - IntelliSense - IntelliSense - - Automatic _insertion of Interface and MustOverride members Automatisches _Einfügen von Schnittstellen- und MustOverride-Membern - - Never - Nie - - Prefer 'IsNot' expression Ausdruck "IsNot" bevorzugen @@ -62,51 +47,21 @@ Vereinfachte Objekterstellung bevorzugen - - Remove unnecessary imports - Unnötige Import-Direktiven entfernen - {Locked="Import"} 'import' is a Visual Basic keyword and should not be localized - Show hints for 'New' expressions Hinweise für new-Ausdrücke anzeigen - - Show items from unimported namespaces - Elemente aus nicht importierten Namespaces anzeigen - - - - _Show procedure line separators - _Zeilentrennzeichen in Prozeduren anzeigen - - _Don't put ByRef on custom structure _ByRef nicht für benutzerdefinierte Struktur verwenden - - Editor Help - Editor-Hilfe - - A_utomatic insertion of end constructs end-Konstrukte _automatisch einfügen - - Highlight related _keywords under cursor - Verwandte _Schlüsselbegriffe unter Cursor anzeigen - - - - _Highlight references to symbol under cursor - _Verweise auf Symbol unter Cursor hervorheben - - _Pretty listing (reformatting) of code _Automatische Strukturierung und Einrückung des Programmcodes @@ -117,66 +72,16 @@ _Gliederungsmodus beim Öffnen von Dateien starten - - Extract Method - Methode extrahieren - - _Generate XML documentation comments for ''' _XML-Dokumentationskommentare generieren für ''' {Locked="'''"} "'''" is a VB keyword and should not be localized. - - Highlighting - Hervorheben - - - - Optimize for solution size - Für Lösungsgröße optimieren - - - - Large - Groß - - - - Regular - Regulär - - - - Show remarks in Quick Info - Hinweise in QuickInfo anzeigen - - - - Small - Klein - - - - Performance - Leistung - - - - Show preview for rename _tracking - Vorschau für Nachverfolgung beim _Umbenennen anzeigen - - _Navigate to Object Browser for symbols defined in metadata Für i_n Metadaten definierte Symbole zum Objektkatalog navigieren - - Go to Definition - Gehe zu Definition - - Import Directives Import-Direktiven @@ -237,61 +142,11 @@ Vordefinierte Typeinstellungen: - - _Highlight matching portions of completion list items - _Übereinstimmende Teile der Vervollständigungslistenelemente anzeigen - - - - Show completion item _filters - Vervollständigungselement_filter anzeigen - - Completion Lists Vervollständigungslisten - - Enter key behavior: - Verhalten der EINGABETASTE: - - - - _Only add new line on enter after end of fully typed word - Neue _Zeile beim Drücken der EINGABETASTE nur nach einem vollständig eingegebenen Wort einfügen - - - - _Always add new line on enter - _Immer neue Zeile beim Drücken der EINGABETASTE einfügen - - - - _Never add new line on enter - _Nie neue Zeile beim Drücken der EINGABETASTE einfügen - - - - Snippets behavior - Schnipselverhalten - - - - Show completion list after a character is _deleted - Vervollstän_digungsliste nach Löschen eines Zeichens anzeigen - - - - _Show completion list after a character is typed - _Vervoll­ständigungsliste nach Eingabe eines Zeichens anzeigen - - - - Unused local - Nicht verwendete lokale Variable - - 'nothing' checking: 'Überprüfung auf "nothing": diff --git a/src/VisualStudio/VisualBasic/Impl/xlf/BasicVSResources.es.xlf b/src/VisualStudio/VisualBasic/Impl/xlf/BasicVSResources.es.xlf index ecad7b68a9f27..4e6efec27dfb2 100644 --- a/src/VisualStudio/VisualBasic/Impl/xlf/BasicVSResources.es.xlf +++ b/src/VisualStudio/VisualBasic/Impl/xlf/BasicVSResources.es.xlf @@ -27,26 +27,11 @@ Microsoft Visual Basic - - Insert Snippet - Insertar fragmento de código - - - - IntelliSense - IntelliSense - - Automatic _insertion of Interface and MustOverride members I_nserción automática de miembros Interface y MustOverride - - Never - Nunca - - Prefer 'IsNot' expression Anteponer expresión "IsNot" @@ -62,51 +47,21 @@ Preferir la creación de objetos simplificados - - Remove unnecessary imports - Quitar importaciones innecesarias - {Locked="Import"} 'import' is a Visual Basic keyword and should not be localized - Show hints for 'New' expressions Mostrar sugerencias para las expresiones "new" - - Show items from unimported namespaces - Mostrar elementos de espacios de nombres no importados - - - - _Show procedure line separators - Mo_strar separadores de líneas de procedimientos - - _Don't put ByRef on custom structure _No poner ByRef en una estructura personalizada - - Editor Help - Ayuda de editor - - A_utomatic insertion of end constructs Inserción a_utomática de construcciones end - - Highlight related _keywords under cursor - Resaltar palabras cla_ve relacionadas bajo el cursor - - - - _Highlight references to symbol under cursor - _Resaltar referencias al símbolo bajo el cursor - - _Pretty listing (reformatting) of code _Lista descriptiva (nuevo formato) de código @@ -117,66 +72,16 @@ _Especificar el modo de esquematización al abrir los archivos - - Extract Method - Extraer método - - _Generate XML documentation comments for ''' _Generar comentarios de documentación XML con ''' {Locked="'''"} "'''" is a VB keyword and should not be localized. - - Highlighting - Resaltar - - - - Optimize for solution size - Optimizar para tamaño de la solución - - - - Large - Grande - - - - Regular - Normal - - - - Show remarks in Quick Info - Mostrar comentarios en Información rápida - - - - Small - Pequeño - - - - Performance - Rendimiento - - - - Show preview for rename _tracking - Mostrar vista previa para _seguimiento de cambio de nombre - - _Navigate to Object Browser for symbols defined in metadata _Vaya al Examinador de objetos para obtener los símbolos definidos en los metadatos - - Go to Definition - Ir a definición - - Import Directives Directivas de importación @@ -237,61 +142,11 @@ Preferencias de tipos predefinidos: - - _Highlight matching portions of completion list items - _Resaltar partes coincidentes de elementos de lista de finalización - - - - Show completion item _filters - Mostrar _filtros de elementos de finalización - - Completion Lists Listas de finalización - - Enter key behavior: - Comportamiento de la tecla Entrar: - - - - _Only add new line on enter after end of fully typed word - _Agregar solo una nueva línea con Entrar al final de palabras - - - - _Always add new line on enter - _Agregar siempre una nueva línea al presionar Entrar - - - - _Never add new line on enter - _No agregar nunca una nueva línea al presionar Entrar - - - - Snippets behavior - Comportamiento de los fragmentos de código - - - - Show completion list after a character is _deleted - Mostrar lista de finalización después de _eliminar un carácter - - - - _Show completion list after a character is typed - _Mostrar lista de finalización después de escribir un carácter - - - - Unused local - Local sin uso - - 'nothing' checking: 'Comprobación de "nothing": diff --git a/src/VisualStudio/VisualBasic/Impl/xlf/BasicVSResources.fr.xlf b/src/VisualStudio/VisualBasic/Impl/xlf/BasicVSResources.fr.xlf index 244dafeaadc9e..b10599f6d1b67 100644 --- a/src/VisualStudio/VisualBasic/Impl/xlf/BasicVSResources.fr.xlf +++ b/src/VisualStudio/VisualBasic/Impl/xlf/BasicVSResources.fr.xlf @@ -27,26 +27,11 @@ Microsoft Visual Basic - - Insert Snippet - Insérer un extrait - - - - IntelliSense - IntelliSense - - Automatic _insertion of Interface and MustOverride members _Insertion automatique des membres Interface et MustOverride - - Never - Jamais - - Prefer 'IsNot' expression Préférer l'expression 'IsNot' @@ -62,51 +47,21 @@ Préférer la création d’objets simplifiée - - Remove unnecessary imports - Supprimer les importations inutiles - {Locked="Import"} 'import' is a Visual Basic keyword and should not be localized - Show hints for 'New' expressions Afficher les indicateurs pour les expressions 'New' - - Show items from unimported namespaces - Afficher les éléments des espaces de noms qui ne sont pas importés - - - - _Show procedure line separators - _Afficher les séparateurs de ligne de procédure - - _Don't put ByRef on custom structure _Ne pas ajouter ByRef dans une structure personnalisée - - Editor Help - Aide de l'éditeur - - A_utomatic insertion of end constructs Insertion a_utomatique des constructions de fin - - Highlight related _keywords under cursor - Surligner les mots clés liés sous le _curseur - - - - _Highlight references to symbol under cursor - _Surligner les références jusqu'au symbole sous le curseur - - _Pretty listing (reformatting) of code _Listing en mode Pretty (nouvelle mise en forme) du code @@ -117,66 +72,16 @@ _Passer en mode Plan à l'ouverture des fichiers - - Extract Method - Extraire la méthode - - _Generate XML documentation comments for ''' _Générer des commentaires de documentation XML pour ''' {Locked="'''"} "'''" is a VB keyword and should not be localized. - - Highlighting - Mise en surbrillance - - - - Optimize for solution size - Optimiser pour la taille de la solution - - - - Large - Grande - - - - Regular - Normal - - - - Show remarks in Quick Info - Afficher les notes dans Info express - - - - Small - Petite - - - - Performance - Performances - - - - Show preview for rename _tracking - Affiche_r un aperçu pour le suivi des renommages - - _Navigate to Object Browser for symbols defined in metadata _Naviguer vers l'Explorateur d'objets pour les symboles définis dans les métadonnées - - Go to Definition - Atteindre la définition - - Import Directives Importer des directives @@ -237,61 +142,11 @@ Préférences de types prédéfinies : - - _Highlight matching portions of completion list items - _Mettre en surbrillance les parties correspondantes des éléments de liste de saisie semi-automatique - - - - Show completion item _filters - Afficher les _filtres d'éléments de saisie semi-automatique - - Completion Lists Listes de saisie semi-automatique - - Enter key behavior: - Comportement de la touche Entrée : - - - - _Only add new line on enter after end of fully typed word - Aj_outer uniquement une nouvelle ligne après Entrée à la fin d'un mot complet tapé - - - - _Always add new line on enter - Toujours _ajouter une nouvelle ligne après Entrée - - - - _Never add new line on enter - _Ne jamais ajouter de nouvelle ligne après Entrée - - - - Snippets behavior - Comportement des extraits de code - - - - Show completion list after a character is _deleted - Afficher la liste de saisie semi-automatique après la suppression d'un _caractère - - - - _Show completion list after a character is typed - _Afficher la liste de saisie semi-automatique après la saisie d'un caractère - - - - Unused local - Local inutilisé - - 'nothing' checking: 'Contrôle de 'nothing' : diff --git a/src/VisualStudio/VisualBasic/Impl/xlf/BasicVSResources.it.xlf b/src/VisualStudio/VisualBasic/Impl/xlf/BasicVSResources.it.xlf index b8cbfe8759d4c..28440ce4d4e69 100644 --- a/src/VisualStudio/VisualBasic/Impl/xlf/BasicVSResources.it.xlf +++ b/src/VisualStudio/VisualBasic/Impl/xlf/BasicVSResources.it.xlf @@ -27,26 +27,11 @@ Microsoft Visual Basic - - Insert Snippet - Inserisci frammento - - - - IntelliSense - IntelliSense - - Automatic _insertion of Interface and MustOverride members _Inserimento automatico di membri Interface e MustOverride - - Never - Mai - - Prefer 'IsNot' expression Preferisci l'espressione 'IsNot' @@ -62,51 +47,21 @@ Preferire la creazione semplificata degli oggetti - - Remove unnecessary imports - Rimuovere le importazioni non necessarie - {Locked="Import"} 'import' is a Visual Basic keyword and should not be localized - Show hints for 'New' expressions Mostra suggerimenti per le espressioni 'New' - - Show items from unimported namespaces - Mostra elementi da spazi dei nomi non importati - - - - _Show procedure line separators - _Mostra separatori di riga routine - - _Don't put ByRef on custom structure _Non inserire ByRef nella struttura personalizzata - - Editor Help - Guida Editor - - A_utomatic insertion of end constructs Inserimento a_utomatico di costrutti End - - Highlight related _keywords under cursor - Evidenzia _parole chiave correlate sotto il cursore - - - - _Highlight references to symbol under cursor - _Evidenzia riferimenti a simbolo sotto il cursore - - _Pretty listing (reformatting) of code _Riformattazione del codice @@ -117,66 +72,16 @@ Attiva m_odalità struttura all'apertura dei file - - Extract Method - Estrai metodo - - _Generate XML documentation comments for ''' _Genera commenti in formato documentazione XML per ''' {Locked="'''"} "'''" is a VB keyword and should not be localized. - - Highlighting - Evidenziazione - - - - Optimize for solution size - Ottimizza in base alle dimensioni della soluzione - - - - Large - Grande - - - - Regular - Normale - - - - Show remarks in Quick Info - Mostra i commenti in Informazioni rapide - - - - Small - Piccola - - - - Performance - Prestazioni - - - - Show preview for rename _tracking - Mostra anteprima per verifica _ridenominazione - - _Navigate to Object Browser for symbols defined in metadata _Passa a Visualizzatore oggetti per i simboli definiti nei metadati - - Go to Definition - Vai a definizione - - Import Directives Direttive import @@ -237,61 +142,11 @@ Preferenze per tipi predefiniti: - - _Highlight matching portions of completion list items - _Evidenzia le parti corrispondenti di voci dell'elenco di completamento - - - - Show completion item _filters - Mostra i _filtri per le voci di completamento - - Completion Lists Elenchi di completamento - - Enter key behavior: - Comportamento del tasto INVIO: - - - - _Only add new line on enter after end of fully typed word - Aggi_ungi una nuova riga dopo INVIO alla fine della parola digitata - - - - _Always add new line on enter - _Aggiungi sempre una nuova riga dopo INVIO - - - - _Never add new line on enter - _Non aggiungere mai una nuova riga dopo INVIO - - - - Snippets behavior - Comportamento dei frammenti - - - - Show completion list after a character is _deleted - Mostra _elenco di completamento dopo l'eliminazione di un carattere - - - - _Show completion list after a character is typed - Mo_stra elenco di completamento dopo la digitazione di un carattere - - - - Unused local - Variabile locale inutilizzata - - 'nothing' checking: 'Controllo 'nothing': diff --git a/src/VisualStudio/VisualBasic/Impl/xlf/BasicVSResources.ja.xlf b/src/VisualStudio/VisualBasic/Impl/xlf/BasicVSResources.ja.xlf index b12555f31c426..86348590967ef 100644 --- a/src/VisualStudio/VisualBasic/Impl/xlf/BasicVSResources.ja.xlf +++ b/src/VisualStudio/VisualBasic/Impl/xlf/BasicVSResources.ja.xlf @@ -27,26 +27,11 @@ Microsoft Visual Basic - - Insert Snippet - スニペットの挿入 - - - - IntelliSense - IntelliSense - - Automatic _insertion of Interface and MustOverride members インターフェイスと MustOverride メンバーの自動挿入(_I) - - Never - 行わない - - Prefer 'IsNot' expression 'IsNot' 式を優先する @@ -62,51 +47,21 @@ 簡素化されたオブジェクト作成を優先 - - Remove unnecessary imports - 不要なインポートの削除 - {Locked="Import"} 'import' is a Visual Basic keyword and should not be localized - Show hints for 'New' expressions 'New' 式のヒントを表示する - - Show items from unimported namespaces - インポートされていない名前空間の項目を表示する - - - - _Show procedure line separators - プロシージャ行の区切り記号を表示する(_S) - - _Don't put ByRef on custom structure カスタム構造に ByRef を置かない(_D) - - Editor Help - エディターのヘルプ - - A_utomatic insertion of end constructs 構造文の終端の自動挿入(_U) - - Highlight related _keywords under cursor - カーソルの下にあるキーワードの関連キーワードをハイライトする(_K) - - - - _Highlight references to symbol under cursor - カーソルの下にあるシンボルへの参照をハイライトする(_H) - - _Pretty listing (reformatting) of code コードの再フォーマット(_P) @@ -117,66 +72,16 @@ ファイルが開かれたときにアウトライン モードを実行する(_E) - - Extract Method - メソッドの抽出 - - _Generate XML documentation comments for ''' ''' が入力されたときに XML ドキュメント コメントを生成する(_G) {Locked="'''"} "'''" is a VB keyword and should not be localized. - - Highlighting - 強調表示 - - - - Optimize for solution size - ソリューションのサイズを最適化します - - - - Large - - - - - Regular - 標準 - - - - Show remarks in Quick Info - クイック ヒントに注釈を表示する - - - - Small - - - - - Performance - パフォーマンス - - - - Show preview for rename _tracking - 名前変更追跡のプレビューの表示(_T) - - _Navigate to Object Browser for symbols defined in metadata メタデータで定義されている記号のオブジェクト ブラウザーに移動する(_N) - - Go to Definition - 定義へ移動 - - Import Directives ディレクティブをインポートする @@ -237,61 +142,11 @@ 定義済みの型の設定: - - _Highlight matching portions of completion list items - 入力候補一覧の項目の一致している部分を強調表示する(_H) - - - - Show completion item _filters - 入力候補の項目フィルターを表示する(_F) - - Completion Lists 入力候補一覧 - - Enter key behavior: - Enter キー入力時動作: - - - - _Only add new line on enter after end of fully typed word - 単語を完全に入力した後 Enter キーで新しい行のみを追加する(_O) - - - - _Always add new line on enter - Enter キーで常に新しい行を追加する(_A) - - - - _Never add new line on enter - Enter キーで新しい行を追加しない(_N) - - - - Snippets behavior - スニペットの動作 - - - - Show completion list after a character is _deleted - 文字が削除された後に入力候補一覧を表示する(_D) - - - - _Show completion list after a character is typed - 文字が入力された後に入力候補一覧を表示する(_S) - - - - Unused local - 未使用のローカル - - 'nothing' checking: 'nothing' のチェック中: diff --git a/src/VisualStudio/VisualBasic/Impl/xlf/BasicVSResources.ko.xlf b/src/VisualStudio/VisualBasic/Impl/xlf/BasicVSResources.ko.xlf index 19878d608dcdf..8121f3af2059d 100644 --- a/src/VisualStudio/VisualBasic/Impl/xlf/BasicVSResources.ko.xlf +++ b/src/VisualStudio/VisualBasic/Impl/xlf/BasicVSResources.ko.xlf @@ -27,26 +27,11 @@ Microsoft Visual Basic - - Insert Snippet - 조각 삽입 - - - - IntelliSense - IntelliSense - - Automatic _insertion of Interface and MustOverride members Interface 및 MustOverride 멤버 자동 삽입(_I) - - Never - 안 함 - - Prefer 'IsNot' expression 'IsNot' 식 선호 @@ -62,51 +47,21 @@ 단순화된 개체 만들기 선호 - - Remove unnecessary imports - 불필요한 가져오기 제거 - {Locked="Import"} 'import' is a Visual Basic keyword and should not be localized - Show hints for 'New' expressions 'New' 식에 대한 힌트 표시 - - Show items from unimported namespaces - 가져오지 않은 네임스페이스의 항목 표시 - - - - _Show procedure line separators - 프로시저 줄 구분선 표시(_S) - - _Don't put ByRef on custom structure 사용자 지정 구조에 ByRef 추가 안 함(_D) - - Editor Help - 편집기 도움말 - - A_utomatic insertion of end constructs 맺음 구문 자동 삽입(_U) - - Highlight related _keywords under cursor - 커서 아래의 관련 키워드 강조(_K) - - - - _Highlight references to symbol under cursor - 커서 아래의 기호에 대한 참조 강조(_H) - - _Pretty listing (reformatting) of code 코드 자동 서식 지정(서식 다시 지정)(_P) @@ -117,66 +72,16 @@ 개요 모드로 파일 열기(_E) - - Extract Method - 메서드 추출 - - _Generate XML documentation comments for ''' '''에 대해 XML 문서 주석 생성(_G) {Locked="'''"} "'''" is a VB keyword and should not be localized. - - Highlighting - 강조 표시 - - - - Optimize for solution size - 솔루션 크기에 맞게 최적화 - - - - Large - 크게 - - - - Regular - 일반 - - - - Show remarks in Quick Info - 요약 정보에 설명 표시 - - - - Small - 작게 - - - - Performance - 성능 - - - - Show preview for rename _tracking - 이름 바꾸기 추적 미리 보기 표시(_T) - - _Navigate to Object Browser for symbols defined in metadata 메타데이터에 정의된 기호를 위해 개체 브라우저로 이동(_N) - - Go to Definition - 정의로 이동 - - Import Directives Import 지시문 @@ -237,61 +142,11 @@ 미리 정의된 형식 기본 설정: - - _Highlight matching portions of completion list items - 완성 목록 항목에서 일치하는 부분 강조 표시(_H) - - - - Show completion item _filters - 완성 항목 필터 표시(_F) - - Completion Lists 완성 목록 - - Enter key behavior: - <Enter> 키 기능: - - - - _Only add new line on enter after end of fully typed word - 단어를 모두 입력한 후 <Enter> 키를 누르면 새 줄 추가(_O) - - - - _Always add new line on enter - <Enter> 키를 누르면 항상 새 줄 추가(_A) - - - - _Never add new line on enter - <Enter> 키를 누르면 새 줄 추가 안 함(_N) - - - - Snippets behavior - 코드 조각 동작 - - - - Show completion list after a character is _deleted - 문자를 삭제하면 완성 목록 표시(_D) - - - - _Show completion list after a character is typed - 문자를 입력하면 완성 목록 표시(_S) - - - - Unused local - 사용하지 않는 로컬 - - 'nothing' checking: 'nothing' 검사: diff --git a/src/VisualStudio/VisualBasic/Impl/xlf/BasicVSResources.pl.xlf b/src/VisualStudio/VisualBasic/Impl/xlf/BasicVSResources.pl.xlf index 821817918bd48..684824a8291c7 100644 --- a/src/VisualStudio/VisualBasic/Impl/xlf/BasicVSResources.pl.xlf +++ b/src/VisualStudio/VisualBasic/Impl/xlf/BasicVSResources.pl.xlf @@ -27,26 +27,11 @@ Microsoft Visual Basic - - Insert Snippet - Wstaw fragment kodu - - - - IntelliSense - IntelliSense - - Automatic _insertion of Interface and MustOverride members Automatyczne _wstawianie składowych Interface i MustOverride - - Never - Nigdy - - Prefer 'IsNot' expression Preferuj wyrażenie „IsNot” @@ -62,51 +47,21 @@ Preferuj uproszczone tworzenie obiektów - - Remove unnecessary imports - Usuń niepotrzebne importy - {Locked="Import"} 'import' is a Visual Basic keyword and should not be localized - Show hints for 'New' expressions Pokaż wskazówki dla wyrażeń „New” - - Show items from unimported namespaces - Pokaż elementy z nieimportowanych przestrzeni nazw - - - - _Show procedure line separators - _Pokaż separatory wierszy procedury - - _Don't put ByRef on custom structure _Nie umieszczaj elementu ByRef w strukturze niestandardowej - - Editor Help - Pomoc edytora - - A_utomatic insertion of end constructs A_utomatyczne wstawianie konstrukcji końcowych - - Highlight related _keywords under cursor - Wyróżnij powiązane _słowa kluczowe pod kursorem - - - - _Highlight references to symbol under cursor - _Wyróżnij odwołania do symbolu pod kursorem - - _Pretty listing (reformatting) of code _Automatyczne formatowanie (ponowne formatowanie) kodu @@ -117,66 +72,16 @@ _Przejdź do trybu konspektu przy otwieraniu plików - - Extract Method - Wyodrębnianie metody - - _Generate XML documentation comments for ''' _Generuj komentarze dokumentacji XML dla ''' {Locked="'''"} "'''" is a VB keyword and should not be localized. - - Highlighting - Wyróżnianie - - - - Optimize for solution size - Optymalizuj pod kątem rozmiaru rozwiązania - - - - Large - Duży - - - - Regular - Standardowy - - - - Show remarks in Quick Info - Pokaż uwagi w szybkich podpowiedziach - - - - Small - Mały - - - - Performance - Wydajność - - - - Show preview for rename _tracking - Pokaż podgląd śledzenia _zmian nazw - - _Navigate to Object Browser for symbols defined in metadata _Przejdź do przeglądarki obiektów, aby uzyskać symbole zdefiniowane w metadanych - - Go to Definition - Przejdź do definicji - - Import Directives Dyrektywy import @@ -237,61 +142,11 @@ Preferencje wstępnie zdefiniowanego typu: - - _Highlight matching portions of completion list items - _Wyróżnij pasujące fragmenty elementów listy uzupełniania - - - - Show completion item _filters - Pokaż _filtry elementów uzupełniania - - Completion Lists Listy uzupełniania - - Enter key behavior: - Zachowanie klawisza Enter: - - - - _Only add new line on enter after end of fully typed word - _Dodaj nowy wiersz po naciśnięciu klawisza Enter tylko po zakończeniu pełnego wpisanego wyrazu - - - - _Always add new line on enter - _Zawsze dodawaj nowy wiersz po naciśnięciu klawisza Enter - - - - _Never add new line on enter - _Nigdy nie dodawaj nowego wiersza po naciśnięciu klawisza Enter - - - - Snippets behavior - Zachowanie fragmentów kodu - - - - Show completion list after a character is _deleted - Pokaż listę _uzupełniania po usunięciu znaku - - - - _Show completion list after a character is typed - _Pokaż listę uzupełniania po wpisaniu znaku - - - - Unused local - Nieużywane zmienne lokalne - - 'nothing' checking: 'Sprawdzanie „nothing”: diff --git a/src/VisualStudio/VisualBasic/Impl/xlf/BasicVSResources.pt-BR.xlf b/src/VisualStudio/VisualBasic/Impl/xlf/BasicVSResources.pt-BR.xlf index 71f7adbfcc571..b7791dfeac3d5 100644 --- a/src/VisualStudio/VisualBasic/Impl/xlf/BasicVSResources.pt-BR.xlf +++ b/src/VisualStudio/VisualBasic/Impl/xlf/BasicVSResources.pt-BR.xlf @@ -27,26 +27,11 @@ Microsoft Visual Basic - - Insert Snippet - Inserir Snippet - - - - IntelliSense - IntelliSense - - Automatic _insertion of Interface and MustOverride members _Inserção automática de membros Interface e MustOverride - - Never - Nunca - - Prefer 'IsNot' expression Preferir a expressão 'IsNot' @@ -62,51 +47,21 @@ Preferir a criação simplificada de objetos - - Remove unnecessary imports - Remover as Importações desnecessárias - {Locked="Import"} 'import' is a Visual Basic keyword and should not be localized - Show hints for 'New' expressions Mostrar as dicas para as expressões 'New' - - Show items from unimported namespaces - Mostrar os itens de namespaces não importados - - - - _Show procedure line separators - _Mostrar separadores de linha de procedimento - - _Don't put ByRef on custom structure _Não colocar ByRef na estrutura personalizada - - Editor Help - Ajuda do Editor - - A_utomatic insertion of end constructs Inserção a_utomática de constructos finais - - Highlight related _keywords under cursor - Realçar _palavras-chave relacionadas usando o cursor - - - - _Highlight references to symbol under cursor - _Realçar referências a símbolo sob o cursor - - _Pretty listing (reformatting) of code _Reformatação automática de código @@ -117,66 +72,16 @@ _Entrar no modo de estrutura de tópicos quando os arquivos abrirem - - Extract Method - Extrair Método - - _Generate XML documentation comments for ''' _Gerar comentário da documentação XML para ''' {Locked="'''"} "'''" is a VB keyword and should not be localized. - - Highlighting - Destaque - - - - Optimize for solution size - Otimizar para o tamanho de solução - - - - Large - Grande - - - - Regular - Normal - - - - Show remarks in Quick Info - Mostrar os comentários nas Informações Rápidas - - - - Small - Pequeno - - - - Performance - Desempenho - - - - Show preview for rename _tracking - Mostrar visualização para acompanhamento de _renomeação - - _Navigate to Object Browser for symbols defined in metadata _Navegue para o Pesquisador de Objetos para símbolos definido nos metadados - - Go to Definition - Ir para Definição - - Import Directives Importar Diretivas @@ -237,61 +142,11 @@ Preferências de tipo predefinidas: - - _Highlight matching portions of completion list items - _Realçar partes correspondentes dos itens da lista de conclusão - - - - Show completion item _filters - Mostrar _filtros de itens de conclusão - - Completion Lists Listas de Conclusão - - Enter key behavior: - Insira o comportamento da tecla: - - - - _Only add new line on enter after end of fully typed word - _Só adicionar nova linha ao inserir depois do final de uma palavra totalmente digitada - - - - _Always add new line on enter - _Sempre adicionar nova linha ao inserir - - - - _Never add new line on enter - _Nunca adicionar nova linha ao inserir - - - - Snippets behavior - Comportamento de snippets - - - - Show completion list after a character is _deleted - Mostrar lista de conclusão após um caractere ser _excluído - - - - _Show completion list after a character is typed - _Mostrar lista de conclusão depois que um caractere é digitado - - - - Unused local - Local não usado - - 'nothing' checking: 'verificação de 'nothing': diff --git a/src/VisualStudio/VisualBasic/Impl/xlf/BasicVSResources.ru.xlf b/src/VisualStudio/VisualBasic/Impl/xlf/BasicVSResources.ru.xlf index 2f19095174378..12288b8fd8aa3 100644 --- a/src/VisualStudio/VisualBasic/Impl/xlf/BasicVSResources.ru.xlf +++ b/src/VisualStudio/VisualBasic/Impl/xlf/BasicVSResources.ru.xlf @@ -27,26 +27,11 @@ Microsoft Visual Basic - - Insert Snippet - Вставить фрагмент - - - - IntelliSense - IntelliSense - - Automatic _insertion of Interface and MustOverride members Автоматическая в_ставка членов Interface и MustOverride - - Never - Никогда - - Prefer 'IsNot' expression Предпочтительно использовать выражение IsNot @@ -62,51 +47,21 @@ Предпочтение упрощенному созданию объектов - - Remove unnecessary imports - Удалить ненужные операции импорта - {Locked="Import"} 'import' is a Visual Basic keyword and should not be localized - Show hints for 'New' expressions Отображать подсказки для выражений "New" - - Show items from unimported namespaces - Отображать элементы из неимпортированных пространств имен - - - - _Show procedure line separators - _Показывать разделительные линии процедур - - _Don't put ByRef on custom structure _Не помещать ByRef в пользовательскую структуру - - Editor Help - Справка по редактору - - A_utomatic insertion of end constructs А_втоматическая вставка конечной конструкции - - Highlight related _keywords under cursor - Выделить связанные _ключевые слова под курсором - - - - _Highlight references to symbol under cursor - _Выделить ссылки на символ под курсором - - _Pretty listing (reformatting) of code Ав_томатическое форматирование кода @@ -117,66 +72,16 @@ _Включать режим создания структуры при открытии файлов - - Extract Method - Извлечение метода - - _Generate XML documentation comments for ''' _Создавать комментарии XML-документации для ''' {Locked="'''"} "'''" is a VB keyword and should not be localized. - - Highlighting - Выделение - - - - Optimize for solution size - Оптимизировать под размер решения - - - - Large - Большой - - - - Regular - обычный - - - - Show remarks in Quick Info - Показать заметки в кратких сведениях - - - - Small - Малый - - - - Performance - Производительность - - - - Show preview for rename _tracking - Показывать предпросмотр для _отслеживания переименований - - _Navigate to Object Browser for symbols defined in metadata _Перейти в обозреватель объектов для символов, определенных в метаданных - - Go to Definition - Перейти к определению - - Import Directives Директивы Import @@ -237,61 +142,11 @@ Предпочтения для предопределенных типов: - - _Highlight matching portions of completion list items - _Выделять совпадающие части элементов списка завершения - - - - Show completion item _filters - Показывать фильтр_ы элементов завершения - - Completion Lists Списки завершения - - Enter key behavior: - Поведение при нажатии клавиши ВВОД: - - - - _Only add new line on enter after end of fully typed word - До_бавлять новую строку при нажатии клавиши ВВОД только в конце полностью введенного слова - - - - _Always add new line on enter - _Всегда добавлять символ новой строки при нажатии клавиши ВВОД - - - - _Never add new line on enter - _Никогда не добавлять новую строку при нажатии клавиши ВВОД - - - - Snippets behavior - Поведение фрагментов кода - - - - Show completion list after a character is _deleted - Показывать список завершения после удалени_я знака - - - - _Show completion list after a character is typed - _Показывать список завершения после ввода знака - - - - Unused local - Не использовать локальный аргумент - - 'nothing' checking: 'Проверка значений "nothing": diff --git a/src/VisualStudio/VisualBasic/Impl/xlf/BasicVSResources.tr.xlf b/src/VisualStudio/VisualBasic/Impl/xlf/BasicVSResources.tr.xlf index fe333e73dae87..62d810cdf8339 100644 --- a/src/VisualStudio/VisualBasic/Impl/xlf/BasicVSResources.tr.xlf +++ b/src/VisualStudio/VisualBasic/Impl/xlf/BasicVSResources.tr.xlf @@ -27,26 +27,11 @@ Microsoft Visual Basic - - Insert Snippet - Kod Parçacığı Ekle - - - - IntelliSense - IntelliSense - - Automatic _insertion of Interface and MustOverride members Interface ve MustOverride üyelerini otomatik olarak _ekle - - Never - Hiçbir zaman - - Prefer 'IsNot' expression 'IsNot' ifadesini tercih edin @@ -62,51 +47,21 @@ Basitleştirilmiş nesne oluşturmayı tercih et - - Remove unnecessary imports - Gereksiz içeri aktarmaları kaldır - {Locked="Import"} 'import' is a Visual Basic keyword and should not be localized - Show hints for 'New' expressions 'New' ifadeleri için ipuçlarını göster - - Show items from unimported namespaces - İçeri aktarılmayan ad alanlarındaki öğeleri göster - - - - _Show procedure line separators - Yordam satır ayıraçlarını _göster - - _Don't put ByRef on custom structure Özel yapıya ByRef _yerleştirme - - Editor Help - Düzenleyici Yardımı - - A_utomatic insertion of end constructs Bitiş yapılarını o_tomatik ekle - - Highlight related _keywords under cursor - İmlecin altında ilgili ana_htar sözcükleri vurgula - - - - _Highlight references to symbol under cursor - İmlecin altındaki sembole başvuruları _vurgula - - _Pretty listing (reformatting) of code Kodu _düzgün listeleme (yeniden biçimlendirme) @@ -117,66 +72,16 @@ Dosyalar açılırken ana hat oluşturma moduna _gir - - Extract Method - Metodu Ayıkla - - _Generate XML documentation comments for ''' ''' için XML belge açıklamaları _oluştur {Locked="'''"} "'''" is a VB keyword and should not be localized. - - Highlighting - Vurgulama - - - - Optimize for solution size - Çözüm boyutunu iyileştir - - - - Large - Büyük - - - - Regular - Normal - - - - Show remarks in Quick Info - Hızlı Bilgi notlarını göster - - - - Small - Küçük - - - - Performance - Performans - - - - Show preview for rename _tracking - Yeniden adlandırma i_zlemesi için önizleme göster - - _Navigate to Object Browser for symbols defined in metadata Meta verilerde tanımlanan semboller için Nesne Tarayıcısı'na _git - - Go to Definition - Tanıma Git - - Import Directives İçeri Aktarma Yönergeleri @@ -237,61 +142,11 @@ Önceden tanımlanmış tür tercihleri: - - _Highlight matching portions of completion list items - Tamamlanma listesi öğelerinin eşleşen bölümlerini _vurgula - - - - Show completion item _filters - Tamamlanma öğesi _filtrelerini göster - - Completion Lists Tamamlama Listeleri - - Enter key behavior: - Enter tuşu davranışı: - - - - _Only add new line on enter after end of fully typed word - _Enter tuşuna basıldığında yalnızca tam bir kelime yazılmışsa sonuna yeni satır ekle - - - - _Always add new line on enter - _Enter tuşuna basıldığında her zaman yeni satır ekle - - - - _Never add new line on enter - Enter tuşuna basıldığında _hiçbir zaman yeni satır ekleme - - - - Snippets behavior - Kod parçacığı davranışı - - - - Show completion list after a character is _deleted - Bir karakter _silindikten sonra tamamlanma listesini göster - - - - _Show completion list after a character is typed - Bir karakter yazıldıktan sonra tamamlanma listesini _göster - - - - Unused local - Kullanılmayan yerel - - 'nothing' checking: 'nothing' denetimi: diff --git a/src/VisualStudio/VisualBasic/Impl/xlf/BasicVSResources.zh-Hans.xlf b/src/VisualStudio/VisualBasic/Impl/xlf/BasicVSResources.zh-Hans.xlf index cf119fa77ccf0..447a02cf17fcf 100644 --- a/src/VisualStudio/VisualBasic/Impl/xlf/BasicVSResources.zh-Hans.xlf +++ b/src/VisualStudio/VisualBasic/Impl/xlf/BasicVSResources.zh-Hans.xlf @@ -27,26 +27,11 @@ Microsoft Visual Basic - - Insert Snippet - 插入片段 - - - - IntelliSense - IntelliSense - - Automatic _insertion of Interface and MustOverride members 自动插入 Interface 和 MustOverride 成员(_I) - - Never - 从不 - - Prefer 'IsNot' expression 首选 "IsNot" 表达式 @@ -62,51 +47,21 @@ 更偏好简化的对象创建 - - Remove unnecessary imports - 移除不必要的导入 - {Locked="Import"} 'import' is a Visual Basic keyword and should not be localized - Show hints for 'New' expressions 显示 "New" 表达式的提示 - - Show items from unimported namespaces - 显示 unimported 命名空间中的项 - - - - _Show procedure line separators - 显示过程行分隔符(_S) - - _Don't put ByRef on custom structure 请勿将 ByRef 放在自定义结构中(_D) - - Editor Help - 编辑器帮助 - - A_utomatic insertion of end constructs 自动插入 end 构造(_U) - - Highlight related _keywords under cursor - 突出显示光标下相关的关键字(_K) - - - - _Highlight references to symbol under cursor - 突出显示对光标下符号的引用(_H) - - _Pretty listing (reformatting) of code 整齐排列代码(重新格式化)(_P) @@ -117,66 +72,16 @@ 打开文件时进入大纲模式(_E) - - Extract Method - 提取方法 - - _Generate XML documentation comments for ''' 为 ''' 生成 XML 文档注释(_G) {Locked="'''"} "'''" is a VB keyword and should not be localized. - - Highlighting - 突出显示 - - - - Optimize for solution size - 优化解决方案大小 - - - - Large - - - - - Regular - 常规 - - - - Show remarks in Quick Info - 在快速信息中显示备注 - - - - Small - - - - - Performance - 性能 - - - - Show preview for rename _tracking - 显示重命名跟踪的预览(_T) - - _Navigate to Object Browser for symbols defined in metadata 导航到对象浏览器以了解元数据中定义的符号(_N) - - Go to Definition - 转到定义 - - Import Directives Import 指令 @@ -237,61 +142,11 @@ 预定义类型首选项: - - _Highlight matching portions of completion list items - 突出显示完成列表项的匹配部分(_H) - - - - Show completion item _filters - 显示完成项筛选器(_F) - - Completion Lists 完成列表 - - Enter key behavior: - 输入关键行为: - - - - _Only add new line on enter after end of fully typed word - _只有在完整键入的单词结尾后按下回车键时才添加新行 - - - - _Always add new line on enter - 始终在按下 Enter 时添加新行(_A) - - - - _Never add new line on enter - 按下 Enter 时不添加新行(_N) - - - - Snippets behavior - 片段行为 - - - - Show completion list after a character is _deleted - 删除字符后显示完成列表(_D) - - - - _Show completion list after a character is typed - 键入字符后显示完成列表(_S) - - - - Unused local - 未使用的本地 - - 'nothing' checking: '"nothing" 检查: diff --git a/src/VisualStudio/VisualBasic/Impl/xlf/BasicVSResources.zh-Hant.xlf b/src/VisualStudio/VisualBasic/Impl/xlf/BasicVSResources.zh-Hant.xlf index b1a8e9c40547a..43e18a9a5324a 100644 --- a/src/VisualStudio/VisualBasic/Impl/xlf/BasicVSResources.zh-Hant.xlf +++ b/src/VisualStudio/VisualBasic/Impl/xlf/BasicVSResources.zh-Hant.xlf @@ -27,26 +27,11 @@ Microsoft Visual Basic - - Insert Snippet - 插入程式碼片段 - - - - IntelliSense - IntelliSense - - Automatic _insertion of Interface and MustOverride members 自動插入 Interface 及 MustOverride 成員(_I) - - Never - 永不 - - Prefer 'IsNot' expression 建議使用 'IsNot' 運算式 @@ -62,51 +47,21 @@ 偏好簡易物件建立 - - Remove unnecessary imports - 移除不必要的 Import - {Locked="Import"} 'import' is a Visual Basic keyword and should not be localized - Show hints for 'New' expressions 顯示 'New' 運算式的提示 - - Show items from unimported namespaces - 顯示來自未匯入命名空間的項目 - - - - _Show procedure line separators - 顯示程序行分隔符號(_S) - - _Don't put ByRef on custom structure 請勿將 ByRef 置於自訂結構(_D) - - Editor Help - 編輯器說明 - - A_utomatic insertion of end constructs 自動插入 End 建構(_U) - - Highlight related _keywords under cursor - 反白資料指標下的相關關鍵字(_K) - - - - _Highlight references to symbol under cursor - 反白顯示資料指標下符號的參考項目(_H) - - _Pretty listing (reformatting) of code 程式碼美化排列 (重新格式化)(_P) @@ -117,66 +72,16 @@ 開啟檔案時進入大綱模式(_E) - - Extract Method - 擷取方法 - - _Generate XML documentation comments for ''' 產生 ''' 的 XML 文件註解(_G) {Locked="'''"} "'''" is a VB keyword and should not be localized. - - Highlighting - 反白 - - - - Optimize for solution size - 最佳化方案大小 - - - - Large - - - - - Regular - 一般 - - - - Show remarks in Quick Info - 在快速諮詢中顯示備註 - - - - Small - - - - - Performance - 效能 - - - - Show preview for rename _tracking - 顯示預覽以追蹤重新命名(_T) - - _Navigate to Object Browser for symbols defined in metadata 巡覽至定義於中繼資料內符號的物件瀏覽器(_N) - - Go to Definition - 移至定義 - - Import Directives Import 指示詞 @@ -237,61 +142,11 @@ 預先定義的類型喜好設定: - - _Highlight matching portions of completion list items - 反白完成清單項目的相符部分(_H) - - - - Show completion item _filters - 顯示完成項目篩選(_F) - - Completion Lists 完成清單 - - Enter key behavior: - Enter 鍵行為: - - - - _Only add new line on enter after end of fully typed word - 僅在完整輸入的字結尾處按 Enter 鍵時加入新行(_O) - - - - _Always add new line on enter - 一律在按下 Enter 鍵時加入新行(_A) - - - - _Never add new line on enter - 永不在按下 Enter 鍵時加入新行(_N) - - - - Snippets behavior - 程式碼片段行為 - - - - Show completion list after a character is _deleted - 刪除一個字元後顯示完成清單(_D) - - - - _Show completion list after a character is typed - 輸入一個字元後顯示完成清單(_S) - - - - Unused local - 未使用的區域函式 - - 'nothing' checking: 'nothing' 檢查: diff --git a/src/VisualStudio/Xaml/Impl/Diagnostics/Analyzers/XamlDocumentDiagnosticAnalyzer.cs b/src/VisualStudio/Xaml/Impl/Diagnostics/Analyzers/XamlDocumentDiagnosticAnalyzer.cs index 5a9c33a1fa9c1..da09545525a0e 100644 --- a/src/VisualStudio/Xaml/Impl/Diagnostics/Analyzers/XamlDocumentDiagnosticAnalyzer.cs +++ b/src/VisualStudio/Xaml/Impl/Diagnostics/Analyzers/XamlDocumentDiagnosticAnalyzer.cs @@ -20,7 +20,7 @@ public override ImmutableArray SupportedDiagnostics { get { - return XamlProjectService.AnalyzerService?.SupportedDiagnostics ?? ImmutableArray.Empty; + return XamlProjectService.AnalyzerService?.SupportedDiagnostics ?? []; } } @@ -28,7 +28,7 @@ public override async Task> AnalyzeSyntaxAsync(Docume { if (XamlProjectService.AnalyzerService == null) { - return ImmutableArray.Empty; + return []; } return await XamlProjectService.AnalyzerService.AnalyzeSyntaxAsync(document, cancellationToken).ConfigureAwait(false); @@ -38,7 +38,7 @@ public override async Task> AnalyzeSemanticsAsync(Doc { if (XamlProjectService.AnalyzerService == null) { - return ImmutableArray.Empty; + return []; } return await XamlProjectService.AnalyzerService.AnalyzeSemanticsAsync(document, cancellationToken).ConfigureAwait(false); diff --git a/src/VisualStudio/Xaml/Impl/Features/Completion/XamlCommitCharacters.cs b/src/VisualStudio/Xaml/Impl/Features/Completion/XamlCommitCharacters.cs index e75ae9073c2ae..f8c06bf5a4107 100644 --- a/src/VisualStudio/Xaml/Impl/Features/Completion/XamlCommitCharacters.cs +++ b/src/VisualStudio/Xaml/Impl/Features/Completion/XamlCommitCharacters.cs @@ -28,7 +28,7 @@ public static XamlCommitCharacters Create(ImmutableArray characters, Immut => new(characters, nonInsertCharacters); public static XamlCommitCharacters Create(ImmutableArray characters, params char[] nonInsertCharacters) - => new(characters, nonInsertCharacters?.ToImmutableArray() ?? ImmutableArray.Empty); + => new(characters, nonInsertCharacters?.ToImmutableArray() ?? []); public static XamlCommitCharacters Create(char[] characters, params char[] nonInsertCharacters) => Create(characters.ToImmutableArray(), nonInsertCharacters); diff --git a/src/VisualStudio/Xaml/Impl/Features/InlineRename/XamlEditorInlineRenameService.cs b/src/VisualStudio/Xaml/Impl/Features/InlineRename/XamlEditorInlineRenameService.cs index 080c38a091408..7d649a1c81067 100644 --- a/src/VisualStudio/Xaml/Impl/Features/InlineRename/XamlEditorInlineRenameService.cs +++ b/src/VisualStudio/Xaml/Impl/Features/InlineRename/XamlEditorInlineRenameService.cs @@ -88,7 +88,7 @@ public async Task FindRenameLocationsAsync(SymbolRenam return new InlineRenameLocationSet( _renameInfo, _document.Project.Solution, - references.ToImmutableArray()); + [.. references]); } public TextSpan? GetConflictEditSpan(InlineRenameLocation location, string triggerText, string replacementText, CancellationToken cancellationToken) diff --git a/src/VisualStudio/Xaml/Impl/Implementation/LanguageClient/XamlCapabilities.cs b/src/VisualStudio/Xaml/Impl/Implementation/LanguageClient/XamlCapabilities.cs index 8db73690f66ea..250dcedcbb452 100644 --- a/src/VisualStudio/Xaml/Impl/Implementation/LanguageClient/XamlCapabilities.cs +++ b/src/VisualStudio/Xaml/Impl/Implementation/LanguageClient/XamlCapabilities.cs @@ -20,7 +20,7 @@ internal static class XamlCapabilities { ResolveProvider = true, TriggerCharacters = ["<", " ", ":", ".", "=", "\"", "'", "{", ",", "("], - AllCommitCharacters = RoslynCompletion.CompletionRules.Default.DefaultCommitCharacters.Select(c => c.ToString()).ToArray() + AllCommitCharacters = [.. RoslynCompletion.CompletionRules.Default.DefaultCommitCharacters.Select(c => c.ToString())] }, HoverProvider = true, FoldingRangeProvider = new FoldingRangeOptions { }, diff --git a/src/VisualStudio/Xaml/Impl/Implementation/LanguageClient/XamlInProcLanguageClient.cs b/src/VisualStudio/Xaml/Impl/Implementation/LanguageClient/XamlInProcLanguageClient.cs index d8286a40995d4..6abbd9a45669b 100644 --- a/src/VisualStudio/Xaml/Impl/Implementation/LanguageClient/XamlInProcLanguageClient.cs +++ b/src/VisualStudio/Xaml/Impl/Implementation/LanguageClient/XamlInProcLanguageClient.cs @@ -40,7 +40,7 @@ public XamlInProcLanguageClient( { } - protected override ImmutableArray SupportedLanguages => ImmutableArray.Create(StringConstants.XamlLanguageName); + protected override ImmutableArray SupportedLanguages => [StringConstants.XamlLanguageName]; public override ServerCapabilities GetCapabilities(ClientCapabilities clientCapabilities) { diff --git a/src/VisualStudio/Xaml/Impl/Implementation/LanguageClient/XamlInProcLanguageClientDisableUX.cs b/src/VisualStudio/Xaml/Impl/Implementation/LanguageClient/XamlInProcLanguageClientDisableUX.cs index ea0e953a8b15d..0f6323cf52c66 100644 --- a/src/VisualStudio/Xaml/Impl/Implementation/LanguageClient/XamlInProcLanguageClientDisableUX.cs +++ b/src/VisualStudio/Xaml/Impl/Implementation/LanguageClient/XamlInProcLanguageClientDisableUX.cs @@ -42,7 +42,7 @@ public XamlInProcLanguageClientDisableUX( { } - protected override ImmutableArray SupportedLanguages => ImmutableArray.Create(StringConstants.XamlLanguageName); + protected override ImmutableArray SupportedLanguages => [StringConstants.XamlLanguageName]; public override ServerCapabilities GetCapabilities(ClientCapabilities clientCapabilities) { diff --git a/src/VisualStudio/Xaml/Impl/Implementation/LanguageServer/Extensions/SymbolExtensions.cs b/src/VisualStudio/Xaml/Impl/Implementation/LanguageServer/Extensions/SymbolExtensions.cs index 048a9200df1fb..b589a28577e6c 100644 --- a/src/VisualStudio/Xaml/Impl/Implementation/LanguageServer/Extensions/SymbolExtensions.cs +++ b/src/VisualStudio/Xaml/Impl/Implementation/LanguageServer/Extensions/SymbolExtensions.cs @@ -22,33 +22,33 @@ public static async Task> GetDescriptionAsync(this ISymb { if (symbol == null) { - return Enumerable.Empty(); + return []; } var codeProject = document.GetCodeProject(); var formatter = codeProject.Services.GetService(); if (formatter == null) { - return Enumerable.Empty(); + return []; } var symbolDisplayService = codeProject.Services.GetService(); if (symbolDisplayService == null) { - return Enumerable.Empty(); + return []; } // Any code document will do var codeDocument = codeProject.Documents.FirstOrDefault(); if (codeDocument == null) { - return Enumerable.Empty(); + return []; } var semanticModel = await codeDocument.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); if (semanticModel == null) { - return Enumerable.Empty(); + return []; } var services = codeProject.Solution.Services; diff --git a/src/VisualStudio/Xaml/Impl/Implementation/LanguageServer/Handler/Completion/CompletionHandler.cs b/src/VisualStudio/Xaml/Impl/Implementation/LanguageServer/Handler/Completion/CompletionHandler.cs index bd452e515bae3..3bca4cbe6881d 100644 --- a/src/VisualStudio/Xaml/Impl/Implementation/LanguageServer/Handler/Completion/CompletionHandler.cs +++ b/src/VisualStudio/Xaml/Impl/Implementation/LanguageServer/Handler/Completion/CompletionHandler.cs @@ -74,7 +74,7 @@ public CompletionHandler() var commitCharactersCache = new Dictionary>(); return new VSInternalCompletionList { - Items = completionResult.Completions.Select(c => CreateCompletionItem(c, document.Id, text, request.Position, request.TextDocument, commitCharactersCache)).ToArray(), + Items = [.. completionResult.Completions.Select(c => CreateCompletionItem(c, document.Id, text, request.Position, request.TextDocument, commitCharactersCache))], SuggestionMode = false, }; } diff --git a/src/VisualStudio/Xaml/Impl/Implementation/LanguageServer/Handler/Diagnostics/AbstractPullDiagnosticHandler.cs b/src/VisualStudio/Xaml/Impl/Implementation/LanguageServer/Handler/Diagnostics/AbstractPullDiagnosticHandler.cs index 29d2279d9c4a6..4a26da672ecf0 100644 --- a/src/VisualStudio/Xaml/Impl/Implementation/LanguageServer/Handler/Diagnostics/AbstractPullDiagnosticHandler.cs +++ b/src/VisualStudio/Xaml/Impl/Implementation/LanguageServer/Handler/Diagnostics/AbstractPullDiagnosticHandler.cs @@ -125,7 +125,7 @@ protected AbstractPullDiagnosticHandler(IXamlPullDiagnosticService xamlDiagnosti } var project = document.Project; - return xamlDiagnostics.Value.Select(d => new VSDiagnostic() + return [.. xamlDiagnostics.Value.Select(d => new VSDiagnostic() { Code = d.Code, Message = d.Message ?? string.Empty, @@ -143,7 +143,7 @@ protected AbstractPullDiagnosticHandler(IXamlPullDiagnosticService xamlDiagnosti ProjectName = project.Name, }, ], - }).ToArray(); + })]; } private static LSP.DiagnosticSeverity ConvertDiagnosticSeverity(XamlDiagnosticSeverity severity) diff --git a/src/VisualStudio/Xaml/Impl/Implementation/LanguageServer/Handler/Diagnostics/DocumentPullDiagnosticHandler.cs b/src/VisualStudio/Xaml/Impl/Implementation/LanguageServer/Handler/Diagnostics/DocumentPullDiagnosticHandler.cs index 3767986c01e99..79d58a30ad7cd 100644 --- a/src/VisualStudio/Xaml/Impl/Implementation/LanguageServer/Handler/Diagnostics/DocumentPullDiagnosticHandler.cs +++ b/src/VisualStudio/Xaml/Impl/Implementation/LanguageServer/Handler/Diagnostics/DocumentPullDiagnosticHandler.cs @@ -39,7 +39,7 @@ protected override ImmutableArray GetDocuments(RequestContext context) // Note: context.Document may be null in the case where the client is asking about a document that we have // since removed from the workspace. In this case, we don't really have anything to process. // GetPreviousResults will be used to properly realize this and notify the client that the doc is gone. - return context.Document == null ? ImmutableArray.Empty : [context.Document]; + return context.Document == null ? [] : [context.Document]; } protected override VSInternalDiagnosticParams[]? GetPreviousResults(VSInternalDocumentDiagnosticsParams diagnosticsParams) diff --git a/src/VisualStudio/Xaml/Impl/Implementation/LanguageServer/Handler/Diagnostics/WorkspacePullDiagnosticHandler.cs b/src/VisualStudio/Xaml/Impl/Implementation/LanguageServer/Handler/Diagnostics/WorkspacePullDiagnosticHandler.cs index 2cac64e989511..3bf3f21307bda 100644 --- a/src/VisualStudio/Xaml/Impl/Implementation/LanguageServer/Handler/Diagnostics/WorkspacePullDiagnosticHandler.cs +++ b/src/VisualStudio/Xaml/Impl/Implementation/LanguageServer/Handler/Diagnostics/WorkspacePullDiagnosticHandler.cs @@ -48,7 +48,7 @@ protected override ImmutableArray GetDocuments(RequestContext context) result.AddRange(project.Documents); } - return result.Distinct().ToImmutableArray(); + return [.. result.Distinct()]; } protected override VSInternalDiagnosticParams[]? GetPreviousResults(VSInternalWorkspaceDiagnosticsParams diagnosticsParams) diff --git a/src/VisualStudio/Xaml/Impl/Implementation/LanguageServer/Handler/OnTypeRename/OnTypeRenameHandler.cs b/src/VisualStudio/Xaml/Impl/Implementation/LanguageServer/Handler/OnTypeRename/OnTypeRenameHandler.cs index 6dccebc29d394..f5b603d1d93d1 100644 --- a/src/VisualStudio/Xaml/Impl/Implementation/LanguageServer/Handler/OnTypeRename/OnTypeRenameHandler.cs +++ b/src/VisualStudio/Xaml/Impl/Implementation/LanguageServer/Handler/OnTypeRename/OnTypeRenameHandler.cs @@ -89,7 +89,7 @@ public OnTypeRenameHandler() return new LinkedEditingRanges { - Ranges = result.Ranges.Select(s => ProtocolConversions.TextSpanToRange(s, text)).ToArray(), + Ranges = [.. result.Ranges.Select(s => ProtocolConversions.TextSpanToRange(s, text))], WordPattern = result.WordPattern }; } diff --git a/src/Workspaces/CSharp/Portable/CSharpWorkspaceResources.resx b/src/Workspaces/CSharp/Portable/CSharpWorkspaceResources.resx index be41fd608ad01..96627de595696 100644 --- a/src/Workspaces/CSharp/Portable/CSharpWorkspaceResources.resx +++ b/src/Workspaces/CSharp/Portable/CSharpWorkspaceResources.resx @@ -123,15 +123,6 @@ Implement Interface - - Indentation preferences - - - Space preferences - - - Wrapping preferences - R&emove and Sort Usings diff --git a/src/Workspaces/CSharp/Portable/CodeGeneration/CSharpSyntaxGenerator.cs b/src/Workspaces/CSharp/Portable/CodeGeneration/CSharpSyntaxGenerator.cs index 781feb87fa332..cf2aa2ed0d0e9 100644 --- a/src/Workspaces/CSharp/Portable/CodeGeneration/CSharpSyntaxGenerator.cs +++ b/src/Workspaces/CSharp/Portable/CodeGeneration/CSharpSyntaxGenerator.cs @@ -191,14 +191,11 @@ public override SyntaxNode FieldDeclaration( private protected override SyntaxNode ParameterDeclaration( string name, SyntaxNode? type, SyntaxNode? initializer, RefKind refKind, bool isExtension, bool isParams, bool isScoped) { - var modifiers = CSharpSyntaxGeneratorInternal.GetParameterModifiers(isScoped, refKind); + var modifiers = CSharpSyntaxGeneratorInternal.GetParameterModifiers(isScoped, refKind, isParams); if (isExtension) modifiers = modifiers.Insert(0, ThisKeyword); - if (isParams) - modifiers = modifiers.Add(ParamsKeyword); - return SyntaxFactory.Parameter( default, modifiers, @@ -243,7 +240,9 @@ private protected override SyntaxNode MethodDeclaration( return SyntaxFactory.MethodDeclaration( attributeLists: default, - modifiers: AsModifierList(accessibility, modifiers, SyntaxKind.MethodDeclaration), + // Pass `withLeadingElasticMarker: true` to ensure method will space itself properly within the members it + // is added to. + modifiers: AsModifierList(accessibility, modifiers, SyntaxKind.MethodDeclaration, withLeadingElasticMarker: true), returnType: returnType != null ? (TypeSyntax)returnType : SyntaxFactory.PredefinedType(VoidKeyword), explicitInterfaceSpecifier: null, identifier: name.ToIdentifierToken(), @@ -1659,89 +1658,68 @@ private static SyntaxNode SetModifierTokens(SyntaxNode declaration, SyntaxTokenL _ => declaration, }; - private static SyntaxTokenList AsModifierList(Accessibility accessibility, DeclarationModifiers modifiers, SyntaxKind kind) - => AsModifierList(accessibility, GetAllowedModifiers(kind) & modifiers); + private static SyntaxTokenList AsModifierList( + Accessibility accessibility, + DeclarationModifiers modifiers, + SyntaxKind kind, + bool withLeadingElasticMarker = false) + => AsModifierList(accessibility, GetAllowedModifiers(kind) & modifiers, withLeadingElasticMarker); - private static SyntaxTokenList AsModifierList(Accessibility accessibility, DeclarationModifiers modifiers) + private static SyntaxTokenList AsModifierList( + Accessibility accessibility, + DeclarationModifiers modifiers, + bool withLeadingElasticMarker = false) { using var _ = ArrayBuilder.GetInstance(out var list); - switch (accessibility) + list.AddRange((IEnumerable)(accessibility switch { - case Accessibility.Internal: - list.Add(InternalKeyword); - break; - case Accessibility.Public: - list.Add(PublicKeyword); - break; - case Accessibility.Private: - list.Add(PrivateKeyword); - break; - case Accessibility.Protected: - list.Add(ProtectedKeyword); - break; - case Accessibility.ProtectedOrInternal: - list.Add(ProtectedKeyword); - list.Add(InternalKeyword); - break; - case Accessibility.ProtectedAndInternal: - list.Add(PrivateKeyword); - list.Add(ProtectedKeyword); - break; - case Accessibility.NotApplicable: - break; - } - - if (modifiers.IsFile) - list.Add(FileKeyword); - - if (modifiers.IsAbstract) - list.Add(AbstractKeyword); - - if (modifiers.IsNew) - list.Add(NewKeyword); - - if (modifiers.IsSealed) - list.Add(SealedKeyword); - - if (modifiers.IsOverride) - list.Add(OverrideKeyword); - - if (modifiers.IsVirtual) - list.Add(VirtualKeyword); - - if (modifiers.IsStatic) - list.Add(StaticKeyword); - - if (modifiers.IsAsync) - list.Add(AsyncKeyword); - - if (modifiers.IsConst) - list.Add(ConstKeyword); - - if (modifiers.IsReadOnly) - list.Add(ReadOnlyKeyword); - - if (modifiers.IsUnsafe) - list.Add(UnsafeKeyword); - - if (modifiers.IsVolatile) - list.Add(VolatileKeyword); - - if (modifiers.IsExtern) - list.Add(ExternKeyword); - - if (modifiers.IsRequired) - list.Add(RequiredKeyword); + Accessibility.Internal => [InternalKeyword], + Accessibility.Public => [PublicKeyword], + Accessibility.Private => [PrivateKeyword], + Accessibility.Protected => [ProtectedKeyword], + Accessibility.ProtectedOrInternal => [ProtectedKeyword, InternalKeyword], + Accessibility.ProtectedAndInternal => [PrivateKeyword, ProtectedKeyword], + _ => [], + })); + + AddIf(modifiers.IsFile, FileKeyword); + AddIf(modifiers.IsAbstract, AbstractKeyword); + AddIf(modifiers.IsNew, NewKeyword); + AddIf(modifiers.IsSealed, SealedKeyword); + AddIf(modifiers.IsOverride, OverrideKeyword); + AddIf(modifiers.IsVirtual, VirtualKeyword); + AddIf(modifiers.IsStatic, StaticKeyword); + AddIf(modifiers.IsAsync, AsyncKeyword); + AddIf(modifiers.IsConst, ConstKeyword); + AddIf(modifiers.IsReadOnly, ReadOnlyKeyword); + AddIf(modifiers.IsUnsafe, UnsafeKeyword); + AddIf(modifiers.IsVolatile, VolatileKeyword); + AddIf(modifiers.IsExtern, ExternKeyword); + AddIf(modifiers.IsRequired, RequiredKeyword); // partial and ref must be last - if (modifiers.IsRef) - list.Add(RefKeyword); + AddIf(modifiers.IsRef, RefKeyword); + AddIf(modifiers.IsPartial, PartialKeyword); - if (modifiers.IsPartial) - list.Add(PartialKeyword); + for (int i = 0, n = list.Count; i < n; i++) + { + // By default, do not place leading elastic trivia on modifiers we make. Just because something is + // adding/removing/modifying modifiers does not mean we want the parent construct to change its formatting + // respective to what's around it. + if (!withLeadingElasticMarker) + list[i] = list[i].WithoutLeadingTrivia(); + + list[i] = list[i].WithTrailingTrivia(SyntaxFactory.ElasticSpace); + } return [.. list]; + + void AddIf(bool test, SyntaxToken token) + { + if (test) + list.Add(token); + } } private protected override SyntaxNode TypeParameter(string name) @@ -3156,17 +3134,6 @@ private static StatementSyntax AsStatement(SyntaxNode node) public override SyntaxNode ExpressionStatement(SyntaxNode expression) => SyntaxFactory.ExpressionStatement((ExpressionSyntax)expression); - internal override SyntaxNode MemberAccessExpressionWorker(SyntaxNode? expression, SyntaxNode simpleName) - { - // can only be null in VB - Contract.ThrowIfNull(expression); - - return SyntaxFactory.MemberAccessExpression( - SyntaxKind.SimpleMemberAccessExpression, - ParenthesizeLeft((ExpressionSyntax)expression), - (SimpleNameSyntax)simpleName); - } - public override SyntaxNode ConditionalAccessExpression(SyntaxNode expression, SyntaxNode whenNotNull) => SyntaxGeneratorInternal.ConditionalAccessExpression(expression, whenNotNull); @@ -3177,27 +3144,6 @@ public override SyntaxNode ElementBindingExpression(IEnumerable argu => SyntaxFactory.ElementBindingExpression( SyntaxFactory.BracketedArgumentList([.. arguments.Cast()])); - /// - /// Parenthesize the left hand size of a member access, invocation or element access expression - /// - private static ExpressionSyntax ParenthesizeLeft(ExpressionSyntax expression) - { - if (expression is TypeSyntax || - expression.Kind() - is SyntaxKind.ThisExpression - or SyntaxKind.BaseExpression - or SyntaxKind.ParenthesizedExpression - or SyntaxKind.SimpleMemberAccessExpression - or SyntaxKind.InvocationExpression - or SyntaxKind.ElementAccessExpression - or SyntaxKind.MemberBindingExpression) - { - return expression; - } - - return (ExpressionSyntax)Parenthesize(expression); - } - private static SeparatedSyntaxList AsExpressionList(IEnumerable expressions) => [.. expressions.OfType()]; @@ -3234,52 +3180,14 @@ private static ArgumentSyntax AsArgument(SyntaxNode argOrExpression) => argOrExpression as ArgumentSyntax ?? SyntaxFactory.Argument((ExpressionSyntax)argOrExpression); public override SyntaxNode InvocationExpression(SyntaxNode expression, IEnumerable arguments) - => SyntaxFactory.InvocationExpression(ParenthesizeLeft((ExpressionSyntax)expression), CreateArgumentList(arguments)); + => SyntaxFactory.InvocationExpression(CSharpSyntaxGeneratorInternal.ParenthesizeLeft((ExpressionSyntax)expression), CreateArgumentList(arguments)); public override SyntaxNode ElementAccessExpression(SyntaxNode expression, IEnumerable arguments) - => SyntaxFactory.ElementAccessExpression(ParenthesizeLeft((ExpressionSyntax)expression), SyntaxFactory.BracketedArgumentList(CreateArguments(arguments))); + => SyntaxFactory.ElementAccessExpression(CSharpSyntaxGeneratorInternal.ParenthesizeLeft((ExpressionSyntax)expression), SyntaxFactory.BracketedArgumentList(CreateArguments(arguments))); internal override SyntaxToken NumericLiteralToken(string text, ulong value) => SyntaxFactory.Literal(text, value); - public override SyntaxNode DefaultExpression(SyntaxNode type) - => SyntaxFactory.DefaultExpression((TypeSyntax)type).WithAdditionalAnnotations(Simplifier.Annotation); - - public override SyntaxNode DefaultExpression(ITypeSymbol type) - { - // If it's just a reference type, then "null" is the default expression for it. Note: - // this counts for actual reference type, or a type parameter with a 'class' constraint. - // Also, if it's a nullable type, then we can use "null". - if (type.IsReferenceType || - type is IPointerTypeSymbol || - type.IsNullable()) - { - return SyntaxFactory.LiteralExpression(SyntaxKind.NullLiteralExpression); - } - - switch (type.SpecialType) - { - case SpecialType.System_Boolean: - return SyntaxFactory.LiteralExpression(SyntaxKind.FalseLiteralExpression); - case SpecialType.System_SByte: - case SpecialType.System_Byte: - case SpecialType.System_Int16: - case SpecialType.System_UInt16: - case SpecialType.System_Int32: - case SpecialType.System_UInt32: - case SpecialType.System_Int64: - case SpecialType.System_UInt64: - case SpecialType.System_Decimal: - case SpecialType.System_Single: - case SpecialType.System_Double: - return SyntaxFactory.LiteralExpression( - SyntaxKind.NumericLiteralExpression, SyntaxFactory.Literal("0", 0)); - } - - // Default to a "default()" expression. - return DefaultExpression(type.GenerateTypeSyntax()); - } - private static SyntaxNode Parenthesize(SyntaxNode expression, bool includeElasticTrivia = true, bool addSimplifierAnnotation = true) => CSharpSyntaxGeneratorInternal.Parenthesize(expression, includeElasticTrivia, addSimplifierAnnotation); @@ -3292,17 +3200,11 @@ public override SyntaxNode TypeOfExpression(SyntaxNode type) public override SyntaxNode TryCastExpression(SyntaxNode expression, SyntaxNode type) => SyntaxFactory.BinaryExpression(SyntaxKind.AsExpression, (ExpressionSyntax)Parenthesize(expression), (TypeSyntax)type); - public override SyntaxNode CastExpression(SyntaxNode type, SyntaxNode expression) - => SyntaxFactory.CastExpression((TypeSyntax)type, (ExpressionSyntax)Parenthesize(expression)).WithAdditionalAnnotations(Simplifier.Annotation); - - public override SyntaxNode ConvertExpression(SyntaxNode type, SyntaxNode expression) - => SyntaxFactory.CastExpression((TypeSyntax)type, (ExpressionSyntax)Parenthesize(expression)).WithAdditionalAnnotations(Simplifier.Annotation); - public override SyntaxNode AssignmentStatement(SyntaxNode left, SyntaxNode right) => SyntaxFactory.AssignmentExpression(SyntaxKind.SimpleAssignmentExpression, (ExpressionSyntax)left, (ExpressionSyntax)Parenthesize(right)); private static SyntaxNode CreateBinaryExpression(SyntaxKind syntaxKind, SyntaxNode left, SyntaxNode right) - => SyntaxFactory.BinaryExpression(syntaxKind, (ExpressionSyntax)Parenthesize(left), (ExpressionSyntax)Parenthesize(right)); + => CSharpSyntaxGeneratorInternal.CreateBinaryExpression(syntaxKind, left, right); public override SyntaxNode ValueEqualsExpression(SyntaxNode left, SyntaxNode right) => CreateBinaryExpression(SyntaxKind.EqualsExpression, left, right); @@ -3349,9 +3251,6 @@ public override SyntaxNode ModuloExpression(SyntaxNode left, SyntaxNode right) public override SyntaxNode BitwiseAndExpression(SyntaxNode left, SyntaxNode right) => CreateBinaryExpression(SyntaxKind.BitwiseAndExpression, left, right); - public override SyntaxNode BitwiseOrExpression(SyntaxNode left, SyntaxNode right) - => CreateBinaryExpression(SyntaxKind.BitwiseOrExpression, left, right); - public override SyntaxNode BitwiseNotExpression(SyntaxNode operand) => SyntaxFactory.PrefixUnaryExpression(SyntaxKind.BitwiseNotExpression, (ExpressionSyntax)Parenthesize(operand)); @@ -3377,13 +3276,10 @@ public override SyntaxNode BaseExpression() => SyntaxFactory.BaseExpression(); public override SyntaxNode TypedConstantExpression(TypedConstant value) - => ExpressionGenerator.GenerateExpression(this, value); + => ExpressionGenerator.GenerateExpression(value); private protected override SyntaxNode GenerateExpression(ITypeSymbol? type, object? value, bool canUseFieldReference) - => ExpressionGenerator.GenerateExpression(this, type, value, canUseFieldReference); - - public override SyntaxNode IdentifierName(string identifier) - => identifier.ToIdentifierName(); + => ExpressionGenerator.GenerateExpression(type, value, canUseFieldReference); public override SyntaxNode GenericName(string identifier, IEnumerable typeArguments) => GenericName(identifier.ToIdentifierToken(), typeArguments); @@ -3433,17 +3329,6 @@ internal override SyntaxNode GlobalAliasedName(SyntaxNode name) public override SyntaxNode NameExpression(INamespaceOrTypeSymbol namespaceOrTypeSymbol) => namespaceOrTypeSymbol.GenerateNameSyntax(); - private protected override SyntaxNode TypeExpression(ITypeSymbol typeSymbol, RefKind refKind) - { - var type = typeSymbol.GenerateTypeSyntax(); - return refKind switch - { - RefKind.Ref => SyntaxFactory.RefType(type), - RefKind.RefReadOnly => SyntaxFactory.RefType(RefKeyword, ReadOnlyKeyword, type), - _ => type, - }; - } - public override SyntaxNode TypeExpression(SpecialType specialType) => SyntaxFactory.PredefinedType(specialType switch { @@ -3668,7 +3553,7 @@ static IEnumerable> splitIntoLines(SyntaxTriviaList tr .Where(trivia => !trivia.Any(t => t.IsRegularOrDocComment())) .SelectMany(t => t); - return new SyntaxTriviaList(syntaxWithoutComments); + return [.. syntaxWithoutComments]; } internal override SyntaxNode ParseExpression(string stringToParse) diff --git a/src/Workspaces/CSharp/Portable/Formatting/CSharpSyntaxFormattingService.cs b/src/Workspaces/CSharp/Portable/Formatting/CSharpSyntaxFormattingService.cs index f3f3c44bea3cc..8e0238e4d88b8 100644 --- a/src/Workspaces/CSharp/Portable/Formatting/CSharpSyntaxFormattingService.cs +++ b/src/Workspaces/CSharp/Portable/Formatting/CSharpSyntaxFormattingService.cs @@ -116,7 +116,7 @@ public ImmutableArray GetFormattingChangesOnTypedCharacter( // if we're only doing smart indent, then ignore all edits to this token that occur before the span of the // token. They're irrelevant and may screw up other code the user doesn't want touched. var tokenEdits = FormatToken(document, indentationOptions, token, formattingRules, cancellationToken); - return tokenEdits.Where(t => t.Span.Start >= token.FullSpan.Start).ToImmutableArray(); + return [.. tokenEdits.Where(t => t.Span.Start >= token.FullSpan.Start)]; } // if formatting range fails, do format token one at least diff --git a/src/Workspaces/CSharp/Portable/LinkedFiles/CSharpLinkedFileMergeConflictCommentAdditionService.cs b/src/Workspaces/CSharp/Portable/LinkedFiles/CSharpLinkedFileMergeConflictCommentAdditionService.cs deleted file mode 100644 index f6f682aaa3f03..0000000000000 --- a/src/Workspaces/CSharp/Portable/LinkedFiles/CSharpLinkedFileMergeConflictCommentAdditionService.cs +++ /dev/null @@ -1,73 +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. - -#nullable disable - -using System; -using System.Composition; -using Microsoft.CodeAnalysis.Host.Mef; - -namespace Microsoft.CodeAnalysis.CSharp; - -[ExportLanguageService(typeof(ILinkedFileMergeConflictCommentAdditionService), LanguageNames.CSharp), Shared] -internal sealed class CSharpLinkedFileMergeConflictCommentAdditionService : AbstractLinkedFileMergeConflictCommentAdditionService -{ - [ImportingConstructor] - [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - public CSharpLinkedFileMergeConflictCommentAdditionService() - { - } - - internal override string GetConflictCommentText(string header, string beforeString, string afterString) - { - if (beforeString == null && afterString == null) - { - // Whitespace only - return null; - } - else if (beforeString == null) - { - // New code - return string.Format(@" -/* {0} -{1} -{2} -*/ -", - header, - WorkspacesResources.Added_colon, - afterString); - } - else if (afterString == null) - { - // Removed code - return string.Format(@" -/* {0} -{1} -{2} -*/ -", - header, - WorkspacesResources.Removed_colon, - beforeString); - } - else - { - // Changed code - return string.Format(@" -/* {0} -{1} -{2} -{3} -{4} -*/ -", - header, - WorkspacesResources.Before_colon, - beforeString, - WorkspacesResources.After_colon, - afterString); - } - } -} diff --git a/src/Workspaces/CSharp/Portable/OrganizeImports/CSharpOrganizeImportsService.Rewriter.cs b/src/Workspaces/CSharp/Portable/OrganizeImports/CSharpOrganizeImportsService.Rewriter.cs index 0dc5ee3dcf348..39aaa3c9a5283 100644 --- a/src/Workspaces/CSharp/Portable/OrganizeImports/CSharpOrganizeImportsService.Rewriter.cs +++ b/src/Workspaces/CSharp/Portable/OrganizeImports/CSharpOrganizeImportsService.Rewriter.cs @@ -15,28 +15,21 @@ namespace Microsoft.CodeAnalysis.CSharp.OrganizeImports; internal partial class CSharpOrganizeImportsService { - private sealed class Rewriter : CSharpSyntaxRewriter + private sealed class Rewriter(OrganizeImportsOptions options) : CSharpSyntaxRewriter { - private readonly bool _placeSystemNamespaceFirst; - private readonly bool _separateGroups; - private readonly SyntaxTrivia _newLineTrivia; + private readonly bool _placeSystemNamespaceFirst = options.PlaceSystemNamespaceFirst; + private readonly bool _separateGroups = options.SeparateImportDirectiveGroups; + private readonly SyntaxTrivia _fallbackTrivia = CSharpSyntaxGeneratorInternal.Instance.EndOfLine(options.NewLine); public readonly IList TextChanges = []; - public Rewriter(OrganizeImportsOptions options) - { - _placeSystemNamespaceFirst = options.PlaceSystemNamespaceFirst; - _separateGroups = options.SeparateImportDirectiveGroups; - _newLineTrivia = CSharpSyntaxGeneratorInternal.Instance.EndOfLine(options.NewLine); - } - public override SyntaxNode VisitCompilationUnit(CompilationUnitSyntax node) { node = (CompilationUnitSyntax)base.VisitCompilationUnit(node)!; UsingsAndExternAliasesOrganizer.Organize( node.Externs, node.Usings, _placeSystemNamespaceFirst, _separateGroups, - _newLineTrivia, + _fallbackTrivia, out var organizedExternAliasList, out var organizedUsingList); var result = node.WithExterns(organizedExternAliasList).WithUsings(organizedUsingList); @@ -61,7 +54,7 @@ private BaseNamespaceDeclarationSyntax VisitBaseNamespaceDeclaration(BaseNamespa UsingsAndExternAliasesOrganizer.Organize( node.Externs, node.Usings, _placeSystemNamespaceFirst, _separateGroups, - _newLineTrivia, + _fallbackTrivia, out var organizedExternAliasList, out var organizedUsingList); var result = node.WithExterns(organizedExternAliasList).WithUsings(organizedUsingList); diff --git a/src/Workspaces/CSharp/Portable/OrganizeImports/CSharpOrganizeImportsService.cs b/src/Workspaces/CSharp/Portable/OrganizeImports/CSharpOrganizeImportsService.cs index 66ad0bf91a843..ac311a2101232 100644 --- a/src/Workspaces/CSharp/Portable/OrganizeImports/CSharpOrganizeImportsService.cs +++ b/src/Workspaces/CSharp/Portable/OrganizeImports/CSharpOrganizeImportsService.cs @@ -2,32 +2,28 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System; using System.Composition; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.OrganizeImports; +using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CSharp.OrganizeImports; [ExportLanguageService(typeof(IOrganizeImportsService), LanguageNames.CSharp), Shared] -internal partial class CSharpOrganizeImportsService : IOrganizeImportsService +[method: ImportingConstructor] +[method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] +internal sealed partial class CSharpOrganizeImportsService() : IOrganizeImportsService { - [ImportingConstructor] - [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - public CSharpOrganizeImportsService() - { - } - public async Task OrganizeImportsAsync(Document document, OrganizeImportsOptions options, CancellationToken cancellationToken) { var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); var rewriter = new Rewriter(options); var newRoot = rewriter.Visit(root); + Contract.ThrowIfNull(newRoot); return document.WithSyntaxRoot(newRoot); } diff --git a/src/Workspaces/CSharp/Portable/Recommendations/CSharpRecommendationService.cs b/src/Workspaces/CSharp/Portable/Recommendations/CSharpRecommendationService.cs index 86ca4124a8c4e..21b595a69c135 100644 --- a/src/Workspaces/CSharp/Portable/Recommendations/CSharpRecommendationService.cs +++ b/src/Workspaces/CSharp/Portable/Recommendations/CSharpRecommendationService.cs @@ -13,14 +13,10 @@ namespace Microsoft.CodeAnalysis.CSharp.Recommendations; [ExportLanguageService(typeof(IRecommendationService), LanguageNames.CSharp), Shared] -internal partial class CSharpRecommendationService : AbstractRecommendationService +[method: ImportingConstructor] +[method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] +internal sealed partial class CSharpRecommendationService() : AbstractRecommendationService { - [ImportingConstructor] - [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - public CSharpRecommendationService() - { - } - protected override AbstractRecommendationServiceRunner CreateRunner(CSharpSyntaxContext context, bool filterOutOfScopeLocals, CancellationToken cancellationToken) => new CSharpRecommendationServiceRunner(context, filterOutOfScopeLocals, cancellationToken); } diff --git a/src/Workspaces/CSharp/Portable/Recommendations/CSharpRecommendationServiceRunner.cs b/src/Workspaces/CSharp/Portable/Recommendations/CSharpRecommendationServiceRunner.cs index 8a4a7fc4208ec..c4efc29de9721 100644 --- a/src/Workspaces/CSharp/Portable/Recommendations/CSharpRecommendationServiceRunner.cs +++ b/src/Workspaces/CSharp/Portable/Recommendations/CSharpRecommendationServiceRunner.cs @@ -5,11 +5,9 @@ using System; using System.Collections.Generic; using System.Collections.Immutable; -using System.ComponentModel; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Linq; -using System.Linq.Expressions; using System.Threading; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Extensions; @@ -26,14 +24,10 @@ namespace Microsoft.CodeAnalysis.CSharp.Recommendations; internal partial class CSharpRecommendationService { - private sealed partial class CSharpRecommendationServiceRunner : AbstractRecommendationServiceRunner + private sealed partial class CSharpRecommendationServiceRunner( + CSharpSyntaxContext context, bool filterOutOfScopeLocals, CancellationToken cancellationToken) + : AbstractRecommendationServiceRunner(context, filterOutOfScopeLocals, cancellationToken) { - public CSharpRecommendationServiceRunner( - CSharpSyntaxContext context, bool filterOutOfScopeLocals, CancellationToken cancellationToken) - : base(context, filterOutOfScopeLocals, cancellationToken) - { - } - protected override int GetLambdaParameterCount(AnonymousFunctionExpressionSyntax lambdaSyntax) => lambdaSyntax switch { @@ -330,6 +324,9 @@ private ImmutableArray GetSymbolsForTypeOrNamespaceContext() private ImmutableArray GetSymbolsForExpressionOrStatementContext() { + var contextNode = _context.LeftToken.GetRequiredParent(); + var semanticModel = _context.SemanticModel; + // Check if we're in an interesting situation like this: // // i // <-- here @@ -346,22 +343,40 @@ private ImmutableArray GetSymbolsForExpressionOrStatementContext() var filterOutOfScopeLocals = _filterOutOfScopeLocals; if (filterOutOfScopeLocals) { - var contextNode = _context.LeftToken.GetRequiredParent(); filterOutOfScopeLocals = !contextNode.IsFoundUnder(d => d.Declaration.Type) && !contextNode.IsFoundUnder(d => d.Type); } - var symbols = !_context.IsNameOfContext && _context.LeftToken.GetRequiredParent().IsInStaticContext() - ? _context.SemanticModel.LookupStaticMembers(_context.LeftToken.SpanStart) - : _context.SemanticModel.LookupSymbols(_context.LeftToken.SpanStart); + ImmutableArray symbols; + if (_context.IsNameOfContext) + { + symbols = semanticModel.LookupSymbols(_context.LeftToken.SpanStart); + + // We may be inside of a nameof() on a method. In that case, we want to include the parameters in + // the nameof if LookupSymbols didn't already return them. + var enclosingMethodOrLambdaNode = contextNode.AncestorsAndSelf().FirstOrDefault(n => n is AnonymousFunctionExpressionSyntax or BaseMethodDeclarationSyntax); + var enclosingMethodOrLambda = enclosingMethodOrLambdaNode is null + ? null + : semanticModel.GetSymbolInfo(enclosingMethodOrLambdaNode).GetAnySymbol() ?? semanticModel.GetDeclaredSymbol(enclosingMethodOrLambdaNode); + if (enclosingMethodOrLambda is IMethodSymbol method) + symbols = [.. symbols, .. method.Parameters]; + } + else + { + symbols = contextNode.IsInStaticContext() + ? semanticModel.LookupStaticMembers(_context.LeftToken.SpanStart) + : semanticModel.LookupSymbols(_context.LeftToken.SpanStart); + + symbols = FilterOutUncapturableParameters(symbols, contextNode); + } // Filter out any extension methods that might be imported by a using static directive. // But include extension methods declared in the context's type or it's parents var contextOuterTypes = ComputeOuterTypes(_context, _cancellationToken); - var contextEnclosingNamedType = _context.SemanticModel.GetEnclosingNamedType(_context.Position, _cancellationToken); + var contextEnclosingNamedType = semanticModel.GetEnclosingNamedType(_context.Position, _cancellationToken); - return symbols.WhereAsArray( + return symbols.Distinct().WhereAsArray( static (symbol, args) => !IsUndesirable(args._context, args.contextEnclosingNamedType, args.contextOuterTypes, args.filterOutOfScopeLocals, symbol, args._cancellationToken), (_context, contextOuterTypes, contextEnclosingNamedType, filterOutOfScopeLocals, _cancellationToken)); @@ -390,8 +405,24 @@ static bool IsUndesirable( if (filterOutOfScopeLocals && symbol.IsInaccessibleLocal(context.Position)) return true; - if (IsCapturedPrimaryConstructorParameter(context, enclosingNamedType, symbol, cancellationToken)) - return true; + // Outside of a nameof(...) we don't want to include a primary constructor parameter if it's not + // available. Inside of a nameof(...) we do want to include it as it's always legal and causes no + // warnings. + if (!context.IsNameOfContext && + symbol is IParameterSymbol parameterSymbol && + parameterSymbol.IsPrimaryConstructor(cancellationToken)) + { + // Primary constructor parameters are only available in instance members, so filter out if we're in + // a static context. + if (!context.IsInstanceContext) + return true; + + // If the parameter was already captured by a field, or by passing to a base-class constructor, then + // we don't want to offer it as the user will get a warning about double storage by capturing both + // into the field/base-type, and synthesized storage for the parameter. + if (IsCapturedPrimaryConstructorParameter(context, enclosingNamedType, parameterSymbol, cancellationToken)) + return true; + } return false; } @@ -399,18 +430,9 @@ static bool IsUndesirable( static bool IsCapturedPrimaryConstructorParameter( CSharpSyntaxContext context, INamedTypeSymbol? enclosingNamedType, - ISymbol symbol, + IParameterSymbol parameterSymbol, CancellationToken cancellationToken) { - if (enclosingNamedType is null) - return false; - - if (symbol is not IParameterSymbol parameterSymbol) - return false; - - if (!parameterSymbol.IsPrimaryConstructor(cancellationToken)) - return false; - // Fine to offer primary constructor parameters in field/property initializers var initializer = context.TargetToken.GetAncestors().FirstOrDefault(); if (initializer is @@ -425,49 +447,52 @@ static bool IsCapturedPrimaryConstructorParameter( // We're not in an initializer. Filter out this primary constructor parameter if it's already been // captured by an existing field or property initializer. - var parameterName = parameterSymbol.Name; - foreach (var reference in enclosingNamedType.DeclaringSyntaxReferences) + if (enclosingNamedType != null) { - if (reference.GetSyntax(cancellationToken) is not TypeDeclarationSyntax typeDeclaration) - continue; - - // See if the parameter was captured into a base-type constructor through the base list. - if (typeDeclaration.BaseList != null) + var parameterName = parameterSymbol.Name; + foreach (var reference in enclosingNamedType.DeclaringSyntaxReferences) { - foreach (var baseType in typeDeclaration.BaseList.Types) + if (reference.GetSyntax(cancellationToken) is not TypeDeclarationSyntax typeDeclaration) + continue; + + // See if the parameter was captured into a base-type constructor through the base list. + if (typeDeclaration.BaseList != null) { - if (baseType is PrimaryConstructorBaseTypeSyntax primaryConstructorBase) + foreach (var baseType in typeDeclaration.BaseList.Types) { - foreach (var argument in primaryConstructorBase.ArgumentList.Arguments) + if (baseType is PrimaryConstructorBaseTypeSyntax primaryConstructorBase) { - if (argument.Expression is IdentifierNameSyntax { Identifier: var argumentIdentifier } && - argumentIdentifier.ValueText == parameterName) + foreach (var argument in primaryConstructorBase.ArgumentList.Arguments) { - return true; + if (argument.Expression is IdentifierNameSyntax { Identifier.ValueText: var argumentIdentifier } && + argumentIdentifier == parameterName) + { + return true; + } } } } } - } - // Next, see if any field or property in the type captures the primary constructor parameter in its initializer. - foreach (var member in typeDeclaration.Members) - { - if (member is FieldDeclarationSyntax fieldDeclaration) + // Next, see if any field or property in the type captures the primary constructor parameter in its initializer. + foreach (var member in typeDeclaration.Members) { - foreach (var variableDeclarator in fieldDeclaration.Declaration.Variables) + if (member is FieldDeclarationSyntax fieldDeclaration) { - if (variableDeclarator.Initializer?.Value is IdentifierNameSyntax { Identifier: var fieldInitializerIdentifier } && - fieldInitializerIdentifier.ValueText == parameterName) + foreach (var variableDeclarator in fieldDeclaration.Declaration.Variables) { - return true; + if (variableDeclarator.Initializer?.Value is IdentifierNameSyntax { Identifier.ValueText: var fieldInitializerIdentifier } && + fieldInitializerIdentifier == parameterName) + { + return true; + } } } - } - else if (member is PropertyDeclarationSyntax { Initializer.Value: IdentifierNameSyntax { Identifier: var propertyInitializerIdentifier } } && - propertyInitializerIdentifier.ValueText == parameterName) - { - return true; + else if (member is PropertyDeclarationSyntax { Initializer.Value: IdentifierNameSyntax { Identifier.ValueText: var propertyInitializerIdentifier } } && + propertyInitializerIdentifier == parameterName) + { + return true; + } } } } @@ -476,6 +501,29 @@ static bool IsCapturedPrimaryConstructorParameter( } } + private static ImmutableArray FilterOutUncapturableParameters(ImmutableArray symbols, SyntaxNode contextNode) + { + // Can't capture parameters across a static lambda/local function + + var containingStaticFunction = contextNode.FirstAncestorOrSelf(a => a switch + { + AnonymousFunctionExpressionSyntax anonymousFunction => anonymousFunction.Modifiers.Any(SyntaxKind.StaticKeyword), + LocalFunctionStatementSyntax localFunction => localFunction.Modifiers.Any(SyntaxKind.StaticKeyword), + _ => false, + }); + + if (containingStaticFunction is null) + return symbols; + + return symbols.WhereAsArray(s => + { + if (s is not IParameterSymbol { DeclaringSyntaxReferences: [var parameterReference] }) + return true; + + return parameterReference.Span.Start >= containingStaticFunction.SpanStart; + }); + } + private RecommendedSymbols GetSymbolsOffOfName(NameSyntax name) { // Using an is pattern on an enum is a qualified name, but normal symbol processing works fine diff --git a/src/Workspaces/CSharp/Portable/Rename/CSharpRenameRewriterLanguageService.cs b/src/Workspaces/CSharp/Portable/Rename/CSharpRenameRewriterLanguageService.cs index d46119a5025c4..bd829b0af7481 100644 --- a/src/Workspaces/CSharp/Portable/Rename/CSharpRenameRewriterLanguageService.cs +++ b/src/Workspaces/CSharp/Portable/Rename/CSharpRenameRewriterLanguageService.cs @@ -241,8 +241,7 @@ public override SyntaxToken VisitToken(SyntaxToken token) if (tokenNeedsConflictCheck) { - newToken = RenameAndAnnotateAsync(token, newToken, isRenameLocation, isOldText).WaitAndGetResult_CanCallOnBackground(_cancellationToken); - + newToken = RenameAndAnnotate(token, newToken, isRenameLocation, isOldText); if (!_isProcessingComplexifiedSpans) { _invocationExpressionsNeedingConflictChecks.AddRange(token.GetAncestors()); @@ -322,7 +321,7 @@ private SyntaxNode Complexify(SyntaxNode originalNode, SyntaxNode newNode) return newNode; } - private async Task RenameAndAnnotateAsync(SyntaxToken token, SyntaxToken newToken, bool isRenameLocation, bool isOldText) + private SyntaxToken RenameAndAnnotate(SyntaxToken token, SyntaxToken newToken, bool isRenameLocation, bool isOldText) { try { @@ -362,7 +361,7 @@ private async Task RenameAndAnnotateAsync(SyntaxToken token, Syntax symbol = symbol.ContainingSymbol; } - var sourceDefinition = await SymbolFinder.FindSourceDefinitionAsync(symbol, _solution, _cancellationToken).ConfigureAwait(false); + var sourceDefinition = SymbolFinder.FindSourceDefinition(symbol, _solution, _cancellationToken); symbol = sourceDefinition ?? symbol; if (symbol is INamedTypeSymbol namedTypeSymbol) @@ -392,8 +391,8 @@ private async Task RenameAndAnnotateAsync(SyntaxToken token, Syntax AddModifiedSpan(oldSpan, newToken.Span); } - var renameDeclarationLocations = await - ConflictResolver.CreateDeclarationLocationAnnotationsAsync(_solution, symbols, _cancellationToken).ConfigureAwait(false); + var renameDeclarationLocations = ConflictResolver.CreateDeclarationLocationAnnotations( + _solution, symbols, _cancellationToken); var isNamespaceDeclarationReference = false; if (isRenameLocation && token.GetPreviousToken().IsKind(SyntaxKind.NamespaceKeyword)) @@ -478,23 +477,19 @@ private async Task RenameAndAnnotateAsync(SyntaxToken token, Syntax symbols = [symbolInfo.Symbol]; } - var renameDeclarationLocations = - ConflictResolver.CreateDeclarationLocationAnnotationsAsync( - _solution, - symbols, - _cancellationToken) - .WaitAndGetResult_CanCallOnBackground(_cancellationToken); + var renameDeclarationLocations = ConflictResolver.CreateDeclarationLocationAnnotations( + _solution, symbols, _cancellationToken); var renameAnnotation = new RenameActionAnnotation( - identifierToken.Span, - isRenameLocation: false, - prefix: null, - suffix: null, - renameDeclarationLocations: renameDeclarationLocations, - isOriginalTextLocation: false, - isNamespaceDeclarationReference: false, - isInvocationExpression: true, - isMemberGroupReference: false); + identifierToken.Span, + isRenameLocation: false, + prefix: null, + suffix: null, + renameDeclarationLocations: renameDeclarationLocations, + isOriginalTextLocation: false, + isNamespaceDeclarationReference: false, + isInvocationExpression: true, + isMemberGroupReference: false); return renameAnnotation; } @@ -945,7 +940,7 @@ renamedSymbol.ContainingSymbol is IMethodSymbol methodSymbol && if (symbol.IsOverride && symbol.GetOverriddenMember() != null) { - var originalSourceSymbol = await SymbolFinder.FindSourceDefinitionAsync(symbol.GetOverriddenMember(), solution, cancellationToken).ConfigureAwait(false); + var originalSourceSymbol = SymbolFinder.FindSourceDefinition(symbol.GetOverriddenMember(), solution, cancellationToken); if (originalSourceSymbol != null) { return await GetVBPropertyFromAccessorOrAnOverrideAsync(originalSourceSymbol, solution, cancellationToken).ConfigureAwait(false); diff --git a/src/Workspaces/CSharp/Portable/Simplification/Reducers/CSharpInferredMemberNameReducer.Rewriter.cs b/src/Workspaces/CSharp/Portable/Simplification/Reducers/CSharpInferredMemberNameReducer.Rewriter.cs index 07e65719ecc2a..c56a703e24214 100644 --- a/src/Workspaces/CSharp/Portable/Simplification/Reducers/CSharpInferredMemberNameReducer.Rewriter.cs +++ b/src/Workspaces/CSharp/Portable/Simplification/Reducers/CSharpInferredMemberNameReducer.Rewriter.cs @@ -40,7 +40,6 @@ private ArgumentSyntax SimplifyTupleName(ArgumentSyntax node, SemanticModel sema private static SyntaxNode SimplifyAnonymousTypeMemberName(AnonymousObjectMemberDeclaratorSyntax node, SemanticModel semanticModel, SimplifierOptions options, CancellationToken canellationToken) { - if (CanSimplifyAnonymousTypeMemberName(node)) { return node.WithNameEquals(null).WithTriviaFrom(node); diff --git a/src/Workspaces/CSharp/Portable/Simplification/Simplifiers/AbstractCSharpSimplifier.cs b/src/Workspaces/CSharp/Portable/Simplification/Simplifiers/AbstractCSharpSimplifier.cs index 3abe2311dac3e..74f55d6a39b1e 100644 --- a/src/Workspaces/CSharp/Portable/Simplification/Simplifiers/AbstractCSharpSimplifier.cs +++ b/src/Workspaces/CSharp/Portable/Simplification/Simplifiers/AbstractCSharpSimplifier.cs @@ -60,12 +60,8 @@ internal abstract class AbstractCSharpSimplifier if (kind != SyntaxKind.None) return SyntaxFactory.Token(kind); - if (specialType is SpecialType.System_IntPtr or SpecialType.System_UIntPtr && - semanticModel.SyntaxTree.Options.LanguageVersion() >= LanguageVersion.CSharp9 && - semanticModel.Compilation.SupportsRuntimeCapability(RuntimeCapability.NumericIntPtr)) - { + if (specialType is SpecialType.System_IntPtr or SpecialType.System_UIntPtr && semanticModel.UnifiesNativeIntegers()) return SyntaxFactory.Identifier(specialType == SpecialType.System_IntPtr ? "nint" : "nuint"); - } return null; } diff --git a/src/Workspaces/CSharp/Portable/xlf/CSharpWorkspaceResources.cs.xlf b/src/Workspaces/CSharp/Portable/xlf/CSharpWorkspaceResources.cs.xlf index 4d75217321cab..c57c7d358205a 100644 --- a/src/Workspaces/CSharp/Portable/xlf/CSharpWorkspaceResources.cs.xlf +++ b/src/Workspaces/CSharp/Portable/xlf/CSharpWorkspaceResources.cs.xlf @@ -12,11 +12,6 @@ Pravidla formátování jazyka C# - - Indentation preferences - Předvolby odsazení - - R&emove and Sort Usings Od&ebrat a seřadit direktivy Using @@ -27,11 +22,6 @@ &Seřadit direktivy using - - Space preferences - Předvolby mezer - - Only attributes, constructor initializers, expressions or statements can be made explicit Jako explicitní jde nastavit jenom atributy, inicializátory konstruktorů, výrazy nebo příkazy. @@ -42,11 +32,6 @@ Implementujte rozhraní. - - Wrapping preferences - Předvolby zalamování - - \ No newline at end of file diff --git a/src/Workspaces/CSharp/Portable/xlf/CSharpWorkspaceResources.de.xlf b/src/Workspaces/CSharp/Portable/xlf/CSharpWorkspaceResources.de.xlf index 3a21c621fe8ae..bf506d9defc67 100644 --- a/src/Workspaces/CSharp/Portable/xlf/CSharpWorkspaceResources.de.xlf +++ b/src/Workspaces/CSharp/Portable/xlf/CSharpWorkspaceResources.de.xlf @@ -12,11 +12,6 @@ C#-Formatierungsregeln - - Indentation preferences - Einstellungen für Einrückung - - R&emove and Sort Usings &Unnötige Using-Direktiven entfernen und sortieren @@ -27,11 +22,6 @@ Using-Anweisungen &sortieren - - Space preferences - Einstellungen für Abstände - - Only attributes, constructor initializers, expressions or statements can be made explicit Nur Attribute, Konstruktor-Initialisierungen, Ausdrücke oder Anweisungen können den Status ausdrücklich erhalten @@ -42,11 +32,6 @@ Schnittstelle implementieren - - Wrapping preferences - Umbrucheinstellungen - - \ No newline at end of file diff --git a/src/Workspaces/CSharp/Portable/xlf/CSharpWorkspaceResources.es.xlf b/src/Workspaces/CSharp/Portable/xlf/CSharpWorkspaceResources.es.xlf index 6030ff2225a20..e62149f0ac2a9 100644 --- a/src/Workspaces/CSharp/Portable/xlf/CSharpWorkspaceResources.es.xlf +++ b/src/Workspaces/CSharp/Portable/xlf/CSharpWorkspaceResources.es.xlf @@ -12,11 +12,6 @@ Reglas de formato de C# - - Indentation preferences - Preferencias de indentación - - R&emove and Sort Usings Q&uitar y ordenar usos @@ -27,11 +22,6 @@ &Ordenar instrucciones Using - - Space preferences - Preferencias de espacio - - Only attributes, constructor initializers, expressions or statements can be made explicit Solo los atributos, los inicializadores de constructor, las expresiones o las declaraciones se pueden hacer explícitos @@ -42,11 +32,6 @@ Implementar interfaz - - Wrapping preferences - Preferencias de encapsulado - - \ No newline at end of file diff --git a/src/Workspaces/CSharp/Portable/xlf/CSharpWorkspaceResources.fr.xlf b/src/Workspaces/CSharp/Portable/xlf/CSharpWorkspaceResources.fr.xlf index fcaff8d1afc09..c7aefe011ed76 100644 --- a/src/Workspaces/CSharp/Portable/xlf/CSharpWorkspaceResources.fr.xlf +++ b/src/Workspaces/CSharp/Portable/xlf/CSharpWorkspaceResources.fr.xlf @@ -12,11 +12,6 @@ Règles de formatage C# - - Indentation preferences - Préférences de mise en retrait - - R&emove and Sort Usings Supprim&er et trier les instructions using @@ -27,11 +22,6 @@ &Trier les using - - Space preferences - Préférences d'espace - - Only attributes, constructor initializers, expressions or statements can be made explicit Seuls des attributs, des initialiseurs de constructeur, des expressions ou des instructions peuvent être explicites @@ -42,11 +32,6 @@ Implémenter l'interface - - Wrapping preferences - Préférences d'enveloppement - - \ No newline at end of file diff --git a/src/Workspaces/CSharp/Portable/xlf/CSharpWorkspaceResources.it.xlf b/src/Workspaces/CSharp/Portable/xlf/CSharpWorkspaceResources.it.xlf index 583affc6fdbb8..00a8f47b2c708 100644 --- a/src/Workspaces/CSharp/Portable/xlf/CSharpWorkspaceResources.it.xlf +++ b/src/Workspaces/CSharp/Portable/xlf/CSharpWorkspaceResources.it.xlf @@ -12,11 +12,6 @@ Regole di formattazione C# - - Indentation preferences - Preferenze per rientro - - R&emove and Sort Usings Ri&muovi e ordina using @@ -27,11 +22,6 @@ Or&dina using - - Space preferences - Preferenze per spazi - - Only attributes, constructor initializers, expressions or statements can be made explicit È possibile rendere espliciti solo attributi, inizializzatori di costruttore, espressioni o istruzioni @@ -42,11 +32,6 @@ Implementa l'interfaccia - - Wrapping preferences - Preferenze per ritorno a capo - - \ No newline at end of file diff --git a/src/Workspaces/CSharp/Portable/xlf/CSharpWorkspaceResources.ja.xlf b/src/Workspaces/CSharp/Portable/xlf/CSharpWorkspaceResources.ja.xlf index f4350d6ef3c19..16105f18ed1a8 100644 --- a/src/Workspaces/CSharp/Portable/xlf/CSharpWorkspaceResources.ja.xlf +++ b/src/Workspaces/CSharp/Portable/xlf/CSharpWorkspaceResources.ja.xlf @@ -12,11 +12,6 @@ C# 書式ルール - - Indentation preferences - インデント設定 - - R&emove and Sort Usings Using の削除と並び替え(&E) @@ -27,11 +22,6 @@ using の並べ替え(&S) - - Space preferences - スペース設定 - - Only attributes, constructor initializers, expressions or statements can be made explicit 明示できるのは、属性、コンストラクターの初期化子、式、ステートメントだけです @@ -42,11 +32,6 @@ インターフェイスを実装します - - Wrapping preferences - 折り返しの設定 - - \ No newline at end of file diff --git a/src/Workspaces/CSharp/Portable/xlf/CSharpWorkspaceResources.ko.xlf b/src/Workspaces/CSharp/Portable/xlf/CSharpWorkspaceResources.ko.xlf index 2cf23f5c54afb..1af27670a5ef4 100644 --- a/src/Workspaces/CSharp/Portable/xlf/CSharpWorkspaceResources.ko.xlf +++ b/src/Workspaces/CSharp/Portable/xlf/CSharpWorkspaceResources.ko.xlf @@ -12,11 +12,6 @@ C# 서식 설정 규칙 - - Indentation preferences - 들여쓰기 기본 설정 - - R&emove and Sort Usings Using 제거 및 정렬(&E) @@ -27,11 +22,6 @@ Using 정렬(&S) - - Space preferences - 공간 기본 설정 - - Only attributes, constructor initializers, expressions or statements can be made explicit 특성, 생성자 이니셜라이저, 식 또는 문만 명시적일 수 있습니다. @@ -42,11 +32,6 @@ 인터페이스 구현 - - Wrapping preferences - 기본 설정 래핑 - - \ No newline at end of file diff --git a/src/Workspaces/CSharp/Portable/xlf/CSharpWorkspaceResources.pl.xlf b/src/Workspaces/CSharp/Portable/xlf/CSharpWorkspaceResources.pl.xlf index 95615c8552726..dffddae7341e9 100644 --- a/src/Workspaces/CSharp/Portable/xlf/CSharpWorkspaceResources.pl.xlf +++ b/src/Workspaces/CSharp/Portable/xlf/CSharpWorkspaceResources.pl.xlf @@ -12,11 +12,6 @@ Reguły formatowania kodu C# - - Indentation preferences - Preferencje wcięć - - R&emove and Sort Usings &Usuń i sortuj instrukcje Usings @@ -27,11 +22,6 @@ &Sortuj użycia - - Space preferences - Preferencje dotyczące odstępów - - Only attributes, constructor initializers, expressions or statements can be made explicit Jako jawne można ustawić tylko atrybuty, inicjatory konstruktorów, wyrażenia lub instrukcje @@ -42,11 +32,6 @@ Zaimplementuj interfejs - - Wrapping preferences - Preferencje zawijania - - \ No newline at end of file diff --git a/src/Workspaces/CSharp/Portable/xlf/CSharpWorkspaceResources.pt-BR.xlf b/src/Workspaces/CSharp/Portable/xlf/CSharpWorkspaceResources.pt-BR.xlf index 0965b568913e2..985ccfe7e1802 100644 --- a/src/Workspaces/CSharp/Portable/xlf/CSharpWorkspaceResources.pt-BR.xlf +++ b/src/Workspaces/CSharp/Portable/xlf/CSharpWorkspaceResources.pt-BR.xlf @@ -12,11 +12,6 @@ Regras de Formatação de C# - - Indentation preferences - Preferências de recuo - - R&emove and Sort Usings R&emover e Classificar Usos @@ -27,11 +22,6 @@ Cla&ssificar Usos - - Space preferences - Preferências de espaço - - Only attributes, constructor initializers, expressions or statements can be made explicit Somente atributos, inicializadores de construtor, expressões ou instruções podem ser tornados explícitos @@ -42,11 +32,6 @@ Implementar a interface - - Wrapping preferences - Preferências de quebra de linha - - \ No newline at end of file diff --git a/src/Workspaces/CSharp/Portable/xlf/CSharpWorkspaceResources.ru.xlf b/src/Workspaces/CSharp/Portable/xlf/CSharpWorkspaceResources.ru.xlf index f7caf77dbf6ac..4e2577909af26 100644 --- a/src/Workspaces/CSharp/Portable/xlf/CSharpWorkspaceResources.ru.xlf +++ b/src/Workspaces/CSharp/Portable/xlf/CSharpWorkspaceResources.ru.xlf @@ -12,11 +12,6 @@ Правила форматирования C# - - Indentation preferences - Предпочтения для отступов - - R&emove and Sort Usings У&далить и отсортировать директивы using @@ -27,11 +22,6 @@ &Сортировать директивы using - - Space preferences - Предпочтения для интервалов - - Only attributes, constructor initializers, expressions or statements can be made explicit Явными могут быть сделаны только атрибуты, инициализаторы конструктора, выражения или операторы @@ -42,11 +32,6 @@ Реализовать интерфейс - - Wrapping preferences - Предпочтения переноса - - \ No newline at end of file diff --git a/src/Workspaces/CSharp/Portable/xlf/CSharpWorkspaceResources.tr.xlf b/src/Workspaces/CSharp/Portable/xlf/CSharpWorkspaceResources.tr.xlf index 00ad07371cc67..c4a7ce714dd3c 100644 --- a/src/Workspaces/CSharp/Portable/xlf/CSharpWorkspaceResources.tr.xlf +++ b/src/Workspaces/CSharp/Portable/xlf/CSharpWorkspaceResources.tr.xlf @@ -12,11 +12,6 @@ C# biçimlendirme kuralları - - Indentation preferences - Girinti tercihleri - - R&emove and Sort Usings &Kaldır ve Sıralama Usings @@ -27,11 +22,6 @@ &Using’leri Sırala - - Space preferences - Boşluk tercihleri - - Only attributes, constructor initializers, expressions or statements can be made explicit Yalnızca öznitelikler, oluşturucu başlatıcıları, ifadeler veya deyimler açık hale getirilebilir @@ -42,11 +32,6 @@ Arabirimi uygula - - Wrapping preferences - Kaydırma tercihleri - - \ No newline at end of file diff --git a/src/Workspaces/CSharp/Portable/xlf/CSharpWorkspaceResources.zh-Hans.xlf b/src/Workspaces/CSharp/Portable/xlf/CSharpWorkspaceResources.zh-Hans.xlf index c699eb56b315a..a36cc4ba030f2 100644 --- a/src/Workspaces/CSharp/Portable/xlf/CSharpWorkspaceResources.zh-Hans.xlf +++ b/src/Workspaces/CSharp/Portable/xlf/CSharpWorkspaceResources.zh-Hans.xlf @@ -12,11 +12,6 @@ C# 格式规则 - - Indentation preferences - 缩进首选项 - - R&emove and Sort Usings 删除 Using 和对其排序(&E) @@ -27,11 +22,6 @@ 对 using 排序(&S) - - Space preferences - 空格键首选项 - - Only attributes, constructor initializers, expressions or statements can be made explicit 仅属性、构造函数初始值设定项、表达式或语句可为显式 @@ -42,11 +32,6 @@ 实现接口 - - Wrapping preferences - 包装首选项 - - \ No newline at end of file diff --git a/src/Workspaces/CSharp/Portable/xlf/CSharpWorkspaceResources.zh-Hant.xlf b/src/Workspaces/CSharp/Portable/xlf/CSharpWorkspaceResources.zh-Hant.xlf index 779ccfb7a7394..e29c508f42ffd 100644 --- a/src/Workspaces/CSharp/Portable/xlf/CSharpWorkspaceResources.zh-Hant.xlf +++ b/src/Workspaces/CSharp/Portable/xlf/CSharpWorkspaceResources.zh-Hant.xlf @@ -12,11 +12,6 @@ C# 格式化規則 - - Indentation preferences - 縮排喜好設定 - - R&emove and Sort Usings 移除和排序 Using(&E) @@ -27,11 +22,6 @@ 排序 Using(&S) - - Space preferences - 空格喜好設定 - - Only attributes, constructor initializers, expressions or statements can be made explicit 只有屬性、建構函式初始設定式、運算式或陳述式才可明確設定 @@ -42,11 +32,6 @@ 實作介面 - - Wrapping preferences - 換行喜好設定 - - \ No newline at end of file diff --git a/src/Workspaces/CSharpTest/CodeGeneration/SyntaxGeneratorTests.cs b/src/Workspaces/CSharpTest/CodeGeneration/SyntaxGeneratorTests.cs index 459ee718d0c3a..0c2cbcda08cff 100644 --- a/src/Workspaces/CSharpTest/CodeGeneration/SyntaxGeneratorTests.cs +++ b/src/Workspaces/CSharpTest/CodeGeneration/SyntaxGeneratorTests.cs @@ -2617,15 +2617,15 @@ private void AssertMemberNamesEqual(string[] expectedNames, SyntaxNode declarati => AssertNamesEqual(expectedNames, Generator.GetMembers(declaration)); private void AssertMemberNamesEqual(string expectedName, SyntaxNode declaration) - => AssertNamesEqual(new[] { expectedName }, Generator.GetMembers(declaration)); + => AssertNamesEqual([expectedName], Generator.GetMembers(declaration)); [Fact] public void TestAddNamespaceImports() { AssertNamesEqual("x.y", Generator.GetNamespaceImports(Generator.AddNamespaceImports(Generator.CompilationUnit(), Generator.NamespaceImportDeclaration("x.y")))); - AssertNamesEqual(new[] { "x.y", "z" }, Generator.GetNamespaceImports(Generator.AddNamespaceImports(Generator.CompilationUnit(), Generator.NamespaceImportDeclaration("x.y"), Generator.IdentifierName("z")))); + AssertNamesEqual(["x.y", "z"], Generator.GetNamespaceImports(Generator.AddNamespaceImports(Generator.CompilationUnit(), Generator.NamespaceImportDeclaration("x.y"), Generator.IdentifierName("z")))); AssertNamesEqual("", Generator.GetNamespaceImports(Generator.AddNamespaceImports(Generator.CompilationUnit(), Generator.MethodDeclaration("m")))); - AssertNamesEqual(new[] { "x", "y.z" }, Generator.GetNamespaceImports(Generator.AddNamespaceImports(Generator.CompilationUnit(Generator.IdentifierName("x")), Generator.DottedName("y.z")))); + AssertNamesEqual(["x", "y.z"], Generator.GetNamespaceImports(Generator.AddNamespaceImports(Generator.CompilationUnit(Generator.IdentifierName("x")), Generator.DottedName("y.z")))); } [Fact] @@ -2754,12 +2754,12 @@ public void TestAddMembers() AssertMemberNamesEqual("n2", Generator.AddMembers(Generator.NamespaceDeclaration("n"), [Generator.NamespaceDeclaration("n2")])); AssertMemberNamesEqual("n", Generator.AddMembers(Generator.CompilationUnit(), [Generator.NamespaceDeclaration("n")])); - AssertMemberNamesEqual(new[] { "m", "m2" }, Generator.AddMembers(Generator.ClassDeclaration("d", members: [Generator.MethodDeclaration("m")]), [Generator.MethodDeclaration("m2")])); - AssertMemberNamesEqual(new[] { "m", "m2" }, Generator.AddMembers(Generator.StructDeclaration("s", members: [Generator.MethodDeclaration("m")]), [Generator.MethodDeclaration("m2")])); - AssertMemberNamesEqual(new[] { "m", "m2" }, Generator.AddMembers(Generator.InterfaceDeclaration("i", members: [Generator.MethodDeclaration("m")]), [Generator.MethodDeclaration("m2")])); - AssertMemberNamesEqual(new[] { "v", "v2" }, Generator.AddMembers(Generator.EnumDeclaration("i", members: [Generator.EnumMember("v")]), [Generator.EnumMember("v2")])); - AssertMemberNamesEqual(new[] { "n1", "n2" }, Generator.AddMembers(Generator.NamespaceDeclaration("n", [Generator.NamespaceDeclaration("n1")]), [Generator.NamespaceDeclaration("n2")])); - AssertMemberNamesEqual(new[] { "n1", "n2" }, Generator.AddMembers(Generator.CompilationUnit(declarations: [Generator.NamespaceDeclaration("n1")]), [Generator.NamespaceDeclaration("n2")])); + AssertMemberNamesEqual(["m", "m2"], Generator.AddMembers(Generator.ClassDeclaration("d", members: [Generator.MethodDeclaration("m")]), [Generator.MethodDeclaration("m2")])); + AssertMemberNamesEqual(["m", "m2"], Generator.AddMembers(Generator.StructDeclaration("s", members: [Generator.MethodDeclaration("m")]), [Generator.MethodDeclaration("m2")])); + AssertMemberNamesEqual(["m", "m2"], Generator.AddMembers(Generator.InterfaceDeclaration("i", members: [Generator.MethodDeclaration("m")]), [Generator.MethodDeclaration("m2")])); + AssertMemberNamesEqual(["v", "v2"], Generator.AddMembers(Generator.EnumDeclaration("i", members: [Generator.EnumMember("v")]), [Generator.EnumMember("v2")])); + AssertMemberNamesEqual(["n1", "n2"], Generator.AddMembers(Generator.NamespaceDeclaration("n", [Generator.NamespaceDeclaration("n1")]), [Generator.NamespaceDeclaration("n2")])); + AssertMemberNamesEqual(["n1", "n2"], Generator.AddMembers(Generator.CompilationUnit(declarations: [Generator.NamespaceDeclaration("n1")]), [Generator.NamespaceDeclaration("n2")])); } [Fact] diff --git a/src/Workspaces/CSharpTest/Formatting/CSharpFormattingTestBase.cs b/src/Workspaces/CSharpTest/Formatting/CSharpFormattingTestBase.cs index 5be715eddfdfe..91bd5f6c19791 100644 --- a/src/Workspaces/CSharpTest/Formatting/CSharpFormattingTestBase.cs +++ b/src/Workspaces/CSharpTest/Formatting/CSharpFormattingTestBase.cs @@ -2,54 +2,51 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System.Collections.Generic; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Editor.UnitTests.CodeActions; using Microsoft.CodeAnalysis.Text; using Microsoft.CodeAnalysis.UnitTests.Formatting; -namespace Microsoft.CodeAnalysis.CSharp.UnitTests.Formatting +namespace Microsoft.CodeAnalysis.CSharp.UnitTests.Formatting; + +public class CSharpFormattingTestBase : FormattingTestBase { - public class CSharpFormattingTestBase : FormattingTestBase + private Workspace? _ws; + + protected Workspace DefaultWorkspace + => _ws ??= new AdhocWorkspace(); + + protected override SyntaxNode ParseCompilation(string text, ParseOptions? parseOptions) + => SyntaxFactory.ParseCompilationUnit(text, options: (CSharpParseOptions?)parseOptions); + + private protected Task AssertNoFormattingChangesAsync( + string code, + OptionsCollection? changedOptionSet = null, + bool testWithTransformation = true, + ParseOptions? parseOptions = null) + { + return AssertFormatAsync(code, code, [new TextSpan(0, code.Length)], changedOptionSet, testWithTransformation, parseOptions); + } + + private protected Task AssertFormatAsync( + string expected, + string code, + OptionsCollection? changedOptionSet = null, + bool testWithTransformation = true, + ParseOptions? parseOptions = null) + { + return AssertFormatAsync(expected, code, [new TextSpan(0, code.Length)], changedOptionSet, testWithTransformation, parseOptions); + } + + private protected Task AssertFormatAsync( + string expected, + string code, + IEnumerable spans, + OptionsCollection? changedOptionSet = null, + bool testWithTransformation = true, + ParseOptions? parseOptions = null) { - private Workspace _ws; - - protected Workspace DefaultWorkspace - => _ws ??= new AdhocWorkspace(); - - protected override SyntaxNode ParseCompilation(string text, ParseOptions parseOptions) - => SyntaxFactory.ParseCompilationUnit(text, options: (CSharpParseOptions)parseOptions); - - private protected Task AssertNoFormattingChangesAsync( - string code, - OptionsCollection changedOptionSet = null, - bool testWithTransformation = true, - ParseOptions parseOptions = null) - { - return AssertFormatAsync(code, code, [new TextSpan(0, code.Length)], changedOptionSet, testWithTransformation, parseOptions); - } - - private protected Task AssertFormatAsync( - string expected, - string code, - OptionsCollection changedOptionSet = null, - bool testWithTransformation = true, - ParseOptions parseOptions = null) - { - return AssertFormatAsync(expected, code, [new TextSpan(0, code.Length)], changedOptionSet, testWithTransformation, parseOptions); - } - - private protected Task AssertFormatAsync( - string expected, - string code, - IEnumerable spans, - OptionsCollection changedOptionSet = null, - bool testWithTransformation = true, - ParseOptions parseOptions = null) - { - return AssertFormatAsync(expected, code, spans, LanguageNames.CSharp, changedOptionSet, testWithTransformation, parseOptions); - } + return AssertFormatAsync(expected, code, spans, LanguageNames.CSharp, changedOptionSet, testWithTransformation, parseOptions); } } diff --git a/src/Workspaces/CSharpTest/Formatting/FormattingTests.cs b/src/Workspaces/CSharpTest/Formatting/FormattingTests.cs index a6668e8b9a77c..ae5911669009c 100644 --- a/src/Workspaces/CSharpTest/Formatting/FormattingTests.cs +++ b/src/Workspaces/CSharpTest/Formatting/FormattingTests.cs @@ -5605,6 +5605,45 @@ public object Method(int i) await AssertFormatAsync(expectedCode, code); } + [Theory, WorkItem("https://github.com/dotnet/roslyn/issues/72196")] + [InlineData("[]")] + [InlineData("[a]")] + [InlineData("[a, b]")] + [InlineData("[..]")] + [InlineData("[var a, .., var b]")] + [InlineData("[{ } a, null]")] + [InlineData("[a, []]")] + public async Task FormatSwitchExpression_ListPatternAligned(string listPattern) + { + var code = $$""" + class C + { + void M() + { + _ = Array.Empty() switch + { + {{listPattern}} => 0, + _ => 1, + }; + } + } + """; + var expectedCode = $$""" + class C + { + void M() + { + _ = Array.Empty() switch + { + {{listPattern}} => 0, + _ => 1, + }; + } + } + """; + await AssertFormatAsync(expectedCode, code); + } + [Fact] public async Task FormatSwitchWithPropertyPattern() { @@ -9115,7 +9154,7 @@ private Task AssertFormatBodyAsync(string expected, string input) { static string transform(string s) { - var lines = s.Split(new[] { Environment.NewLine }, StringSplitOptions.None); + var lines = s.Split([Environment.NewLine], StringSplitOptions.None); for (var i = 0; i < lines.Length; i++) { if (!string.IsNullOrEmpty(lines[i])) diff --git a/src/Workspaces/CSharpTest/OrganizeImports/OrganizeUsingsTests.cs b/src/Workspaces/CSharpTest/OrganizeImports/OrganizeUsingsTests.cs index fdcb1bb800d15..7e6d2ca93dcd6 100644 --- a/src/Workspaces/CSharpTest/OrganizeImports/OrganizeUsingsTests.cs +++ b/src/Workspaces/CSharpTest/OrganizeImports/OrganizeUsingsTests.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using System; +using System.Diagnostics.CodeAnalysis; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.OrganizeImports; @@ -16,10 +17,11 @@ namespace Microsoft.CodeAnalysis.CSharp.Workspaces.UnitTests.OrganizeImports; [UseExportProvider] [Trait(Traits.Feature, Traits.Features.Organizing)] -public class OrganizeUsingsTests +public sealed class OrganizeUsingsTests { - protected static async Task CheckAsync( - string initial, string final, + private static async Task CheckAsync( + string initial, + string final, bool placeSystemNamespaceFirst = false, bool separateImportGroups = false, string? endOfLine = null) @@ -76,6 +78,32 @@ public async Task AliasesAtBottom() await CheckAsync(initial, final); } + [Theory, WorkItem("https://github.com/dotnet/roslyn/issues/44136")] + [InlineData("\n")] + [InlineData("\r\n")] + public async Task PreserveExistingEndOfLine(string fallbackEndOfLine) + { + var initial = "using A = B;\nusing C;\nusing D = E;\nusing F;\n"; + + var final = "using C;\nusing F;\nusing A = B;\nusing D = E;\n"; + + using var workspace = new AdhocWorkspace(); + var project = workspace.CurrentSolution.AddProject("Project", "Project.dll", LanguageNames.CSharp); + var document = project.AddDocument("Document", initial); + + var options = new OrganizeImportsOptions() + { + PlaceSystemNamespaceFirst = false, + SeparateImportDirectiveGroups = false, + NewLine = fallbackEndOfLine, + }; + + var organizeImportsService = document.GetRequiredLanguageService(); + var newDocument = await organizeImportsService.OrganizeImportsAsync(document, options, CancellationToken.None); + var newRoot = await newDocument.GetRequiredSyntaxRootAsync(default); + Assert.Equal(final, newRoot.ToFullString()); + } + [Fact] public async Task UsingStaticsBetweenUsingsAndAliases() { diff --git a/src/Workspaces/Core/MSBuild.BuildHost/MSBuild/ProjectFile/Extensions.cs b/src/Workspaces/Core/MSBuild.BuildHost/MSBuild/ProjectFile/Extensions.cs index c38df008fd65e..10c641d4bf260 100644 --- a/src/Workspaces/Core/MSBuild.BuildHost/MSBuild/ProjectFile/Extensions.cs +++ b/src/Workspaces/Core/MSBuild.BuildHost/MSBuild/ProjectFile/Extensions.cs @@ -60,7 +60,7 @@ public static ImmutableArray GetAliases(this MSB.Framework.ITaskItem ite var aliasesText = item.GetMetadata(MetadataNames.Aliases); return !string.IsNullOrWhiteSpace(aliasesText) - ? ImmutableArray.CreateRange(aliasesText.Split([','], StringSplitOptions.RemoveEmptyEntries).Select(a => a.Trim())) + ? [.. aliasesText.Split([','], StringSplitOptions.RemoveEmptyEntries).Select(a => a.Trim())] : []; } diff --git a/src/Workspaces/Core/MSBuild.BuildHost/MSBuild/ProjectFile/ProjectFile.cs b/src/Workspaces/Core/MSBuild.BuildHost/MSBuild/ProjectFile/ProjectFile.cs index f869df293b45e..49dbebb4b17a6 100644 --- a/src/Workspaces/Core/MSBuild.BuildHost/MSBuild/ProjectFile/ProjectFile.cs +++ b/src/Workspaces/Core/MSBuild.BuildHost/MSBuild/ProjectFile/ProjectFile.cs @@ -198,7 +198,7 @@ private ProjectFileInfo CreateProjectFileInfo(MSB.Execution.ProjectInstance proj Documents = docs, AdditionalDocuments = additionalDocs, AnalyzerConfigDocuments = analyzerConfigDocs, - ProjectReferences = project.GetProjectReferences().ToImmutableArray(), + ProjectReferences = [.. project.GetProjectReferences()], PackageReferences = packageReferences, ProjectCapabilities = projectCapabilities, ContentFilePaths = contentFileInfo, @@ -207,7 +207,7 @@ private ProjectFileInfo CreateProjectFileInfo(MSB.Execution.ProjectInstance proj static FileGlobs GetFileGlobs(GlobResult g) { - return new FileGlobs(g.IncludeGlobs.ToImmutableArray(), g.Excludes.ToImmutableArray(), g.Removes.ToImmutableArray()); + return new FileGlobs([.. g.IncludeGlobs], [.. g.Excludes], [.. g.Removes]); } } diff --git a/src/Workspaces/Core/MSBuild.BuildHost/Microsoft.CodeAnalysis.Workspaces.MSBuild.BuildHost.csproj b/src/Workspaces/Core/MSBuild.BuildHost/Microsoft.CodeAnalysis.Workspaces.MSBuild.BuildHost.csproj index 96805e041d8cb..8101f56b8be6c 100644 --- a/src/Workspaces/Core/MSBuild.BuildHost/Microsoft.CodeAnalysis.Workspaces.MSBuild.BuildHost.csproj +++ b/src/Workspaces/Core/MSBuild.BuildHost/Microsoft.CodeAnalysis.Workspaces.MSBuild.BuildHost.csproj @@ -65,6 +65,7 @@ + diff --git a/src/Workspaces/Core/MSBuild.BuildHost/Program.cs b/src/Workspaces/Core/MSBuild.BuildHost/Program.cs index becfb6500fec1..48605a392742a 100644 --- a/src/Workspaces/Core/MSBuild.BuildHost/Program.cs +++ b/src/Workspaces/Core/MSBuild.BuildHost/Program.cs @@ -6,6 +6,7 @@ using System.Collections.Immutable; using System.CommandLine; using System.Globalization; +using System.IO.Pipes; using System.Threading.Tasks; using Roslyn.Utilities; @@ -15,11 +16,13 @@ internal static class Program { internal static async Task Main(string[] args) { + var pipeOption = new CliOption("--pipe") { Required = true }; var propertyOption = new CliOption("--property") { Arity = ArgumentArity.ZeroOrMore }; var binaryLogOption = new CliOption("--binlog") { Required = false }; var localeOption = new CliOption("--locale") { Required = true }; - var command = new CliRootCommand { binaryLogOption, propertyOption, localeOption }; + var command = new CliRootCommand { pipeOption, binaryLogOption, propertyOption, localeOption }; var parsedArguments = command.Parse(args); + var pipeName = parsedArguments.GetValue(pipeOption)!; var properties = parsedArguments.GetValue(propertyOption)!; var binaryLogPath = parsedArguments.GetValue(binaryLogOption); var locale = parsedArguments.GetValue(localeOption)!; @@ -46,7 +49,10 @@ internal static async Task Main(string[] args) logger.LogInformation($"BuildHost Runtime Version: {System.Runtime.InteropServices.RuntimeInformation.FrameworkDescription}"); - var server = new RpcServer(sendingStream: Console.OpenStandardOutput(), receivingStream: Console.OpenStandardInput()); + var pipeServer = NamedPipeUtil.CreateServer(pipeName, PipeDirection.InOut); + await pipeServer.WaitForConnectionAsync().ConfigureAwait(false); + + var server = new RpcServer(sendingStream: pipeServer, receivingStream: pipeServer); var targetObject = server.AddTarget(new BuildHost(logger, propertiesBuilder.ToImmutable(), binaryLogPath, server)); Contract.ThrowIfFalse(targetObject == 0, "The first object registered should have target 0, which is assumed by the client."); diff --git a/src/Workspaces/Core/MSBuild/MSBuild/BuildHostProcessManager.cs b/src/Workspaces/Core/MSBuild/MSBuild/BuildHostProcessManager.cs index db58752789fa4..1592705b0962a 100644 --- a/src/Workspaces/Core/MSBuild/MSBuild/BuildHostProcessManager.cs +++ b/src/Workspaces/Core/MSBuild/MSBuild/BuildHostProcessManager.cs @@ -7,6 +7,7 @@ using System.Collections.Immutable; using System.Diagnostics; using System.IO; +using System.IO.Pipes; using System.Linq; using System.Runtime.InteropServices; using System.Text; @@ -83,12 +84,13 @@ public async Task GetBuildHostAsync(BuildHostProcessKind buildH { if (!_processes.TryGetValue(buildHostKind, out var buildHostProcess)) { - var processStartInfo = CreateBuildHostStartInfo(buildHostKind); + var pipeName = Guid.NewGuid().ToString(); + var processStartInfo = CreateBuildHostStartInfo(buildHostKind, pipeName); var process = Process.Start(processStartInfo); Contract.ThrowIfNull(process, "Process.Start failed to launch a process."); - buildHostProcess = new BuildHostProcess(process, _loggerFactory); + buildHostProcess = new BuildHostProcess(process, pipeName, _loggerFactory); buildHostProcess.Disconnected += BuildHostProcess_Disconnected; // We've subscribed to Disconnected, but if the process crashed before that point we might have not seen it @@ -105,13 +107,13 @@ public async Task GetBuildHostAsync(BuildHostProcessKind buildH } } - internal ProcessStartInfo CreateBuildHostStartInfo(BuildHostProcessKind buildHostKind) + internal ProcessStartInfo CreateBuildHostStartInfo(BuildHostProcessKind buildHostKind, string pipeName) { return buildHostKind switch { - BuildHostProcessKind.NetCore => CreateDotNetCoreBuildHostStartInfo(), - BuildHostProcessKind.NetFramework => CreateDotNetFrameworkBuildHostStartInfo(), - BuildHostProcessKind.Mono => CreateMonoBuildHostStartInfo(), + BuildHostProcessKind.NetCore => CreateDotNetCoreBuildHostStartInfo(pipeName), + BuildHostProcessKind.NetFramework => CreateDotNetFrameworkBuildHostStartInfo(pipeName), + BuildHostProcessKind.Mono => CreateMonoBuildHostStartInfo(pipeName), _ => throw ExceptionUtilities.UnexpectedValue(buildHostKind) }; } @@ -160,7 +162,7 @@ public async ValueTask DisposeAsync() await process.DisposeAsync().ConfigureAwait(false); } - private ProcessStartInfo CreateDotNetCoreBuildHostStartInfo() + private ProcessStartInfo CreateDotNetCoreBuildHostStartInfo(string pipeName) { var processStartInfo = new ProcessStartInfo() { @@ -177,7 +179,7 @@ private ProcessStartInfo CreateDotNetCoreBuildHostStartInfo() AddArgument(processStartInfo, netCoreBuildHostPath); - AppendBuildHostCommandLineArgumentsConfigureProcess(processStartInfo); + AppendBuildHostCommandLineArgumentsConfigureProcess(processStartInfo, pipeName); return processStartInfo; } @@ -190,7 +192,7 @@ internal static string GetNetCoreBuildHostPath() return buildHostPath; } - private ProcessStartInfo CreateDotNetFrameworkBuildHostStartInfo() + private ProcessStartInfo CreateDotNetFrameworkBuildHostStartInfo(string pipeName) { var netFrameworkBuildHost = GetDotNetFrameworkBuildHostPath(); var processStartInfo = new ProcessStartInfo() @@ -198,12 +200,12 @@ private ProcessStartInfo CreateDotNetFrameworkBuildHostStartInfo() FileName = netFrameworkBuildHost, }; - AppendBuildHostCommandLineArgumentsConfigureProcess(processStartInfo); + AppendBuildHostCommandLineArgumentsConfigureProcess(processStartInfo, pipeName); return processStartInfo; } - private ProcessStartInfo CreateMonoBuildHostStartInfo() + private ProcessStartInfo CreateMonoBuildHostStartInfo(string pipeName) { var processStartInfo = new ProcessStartInfo { @@ -212,7 +214,7 @@ private ProcessStartInfo CreateMonoBuildHostStartInfo() AddArgument(processStartInfo, GetDotNetFrameworkBuildHostPath()); - AppendBuildHostCommandLineArgumentsConfigureProcess(processStartInfo); + AppendBuildHostCommandLineArgumentsConfigureProcess(processStartInfo, pipeName); return processStartInfo; } @@ -231,8 +233,11 @@ private static void AssertBuildHostExists(string buildHostPath) throw new Exception(string.Format(WorkspaceMSBuildResources.The_build_host_could_not_be_found_at_0, buildHostPath)); } - private void AppendBuildHostCommandLineArgumentsConfigureProcess(ProcessStartInfo processStartInfo) + private void AppendBuildHostCommandLineArgumentsConfigureProcess(ProcessStartInfo processStartInfo, string pipeName) { + AddArgument(processStartInfo, "--pipe"); + AddArgument(processStartInfo, pipeName); + foreach (var globalMSBuildProperty in _globalMSBuildProperties) { AddArgument(processStartInfo, "--property"); @@ -350,6 +355,11 @@ public enum BuildHostProcessKind private sealed class BuildHostProcess : IAsyncDisposable { + /// + /// The time to wait for a named pipe connection to complete for a newly started server + /// + internal const int TimeOutMsNewProcess = 60_000; + private readonly ILogger? _logger; private readonly Process _process; private readonly RpcClient _rpcClient; @@ -362,7 +372,7 @@ private sealed class BuildHostProcess : IAsyncDisposable private int _disposed = 0; - public BuildHostProcess(Process process, ILoggerFactory? loggerFactory) + public BuildHostProcess(Process process, string pipeName, ILoggerFactory? loggerFactory) { _logger = loggerFactory?.CreateLogger($"BuildHost PID {process.Id}"); _process = process; @@ -372,7 +382,14 @@ public BuildHostProcess(Process process, ILoggerFactory? loggerFactory) _process.ErrorDataReceived += Process_ErrorDataReceived; - _rpcClient = new RpcClient(sendingStream: _process.StandardInput.BaseStream, receivingStream: _process.StandardOutput.BaseStream); + var pipeClient = NamedPipeUtil.CreateClient(".", pipeName, PipeDirection.InOut, PipeOptions.Asynchronous); + pipeClient.Connect(TimeOutMsNewProcess); + if (!NamedPipeUtil.CheckPipeConnectionOwnership(pipeClient)) + { + throw new Exception("Ownership of BuildHost pipe is incorrect."); + } + + _rpcClient = new RpcClient(sendingStream: pipeClient, receivingStream: pipeClient); _rpcClient.Start(); _rpcClient.Disconnected += Process_Exited; BuildHost = new RemoteBuildHost(_rpcClient); diff --git a/src/Workspaces/Core/MSBuild/MSBuild/MSBuildProjectLoader.Worker.cs b/src/Workspaces/Core/MSBuild/MSBuild/MSBuildProjectLoader.Worker.cs index 0ed0792b650fd..1bbe85d588551 100644 --- a/src/Workspaces/Core/MSBuild/MSBuild/MSBuildProjectLoader.Worker.cs +++ b/src/Workspaces/Core/MSBuild/MSBuild/MSBuildProjectLoader.Worker.cs @@ -464,7 +464,7 @@ private static void GetDocumentNameAndFolders(string logicalPath, out string nam if (pathNames.Length > 0) { folders = pathNames.Length > 1 - ? pathNames.Take(pathNames.Length - 1).ToImmutableArray() + ? [.. pathNames.Take(pathNames.Length - 1)] : []; name = pathNames[^1]; diff --git a/src/Workspaces/Core/MSBuild/MSBuild/MSBuildProjectLoader.Worker_ResolveReferences.cs b/src/Workspaces/Core/MSBuild/MSBuild/MSBuildProjectLoader.Worker_ResolveReferences.cs index 26e000e02c6c5..7581dc892107e 100644 --- a/src/Workspaces/Core/MSBuild/MSBuild/MSBuildProjectLoader.Worker_ResolveReferences.cs +++ b/src/Workspaces/Core/MSBuild/MSBuild/MSBuildProjectLoader.Worker_ResolveReferences.cs @@ -57,7 +57,7 @@ private class ResolvedReferencesBuilder public ResolvedReferencesBuilder(IEnumerable metadataReferences) { - _metadataReferences = metadataReferences.ToImmutableArray(); + _metadataReferences = [.. metadataReferences]; _pathToIndicesMap = CreatePathToIndexMap(_metadataReferences); _indicesToRemove = []; _projectReferences = ImmutableHashSet.CreateBuilder(); diff --git a/src/Workspaces/Core/MSBuild/Microsoft.CodeAnalysis.Workspaces.MSBuild.csproj b/src/Workspaces/Core/MSBuild/Microsoft.CodeAnalysis.Workspaces.MSBuild.csproj index ce6eb532a8a5a..7ae2fe0f3bb6b 100644 --- a/src/Workspaces/Core/MSBuild/Microsoft.CodeAnalysis.Workspaces.MSBuild.csproj +++ b/src/Workspaces/Core/MSBuild/Microsoft.CodeAnalysis.Workspaces.MSBuild.csproj @@ -50,6 +50,7 @@ InternalUtilities\GlobalAssemblyCache.cs + diff --git a/src/Workspaces/Core/MSBuild/Rpc/RpcClient.cs b/src/Workspaces/Core/MSBuild/Rpc/RpcClient.cs index ef08e5b03402b..794030581ecbe 100644 --- a/src/Workspaces/Core/MSBuild/Rpc/RpcClient.cs +++ b/src/Workspaces/Core/MSBuild/Rpc/RpcClient.cs @@ -46,46 +46,63 @@ public void Start() // We'll start this and let it run until Shutdown has been called. Task.Run(async () => { - string? line; - while ((line = await _receivingStream.TryReadLineOrReturnNullIfCancelledAsync(_shutdownTokenSource.Token).ConfigureAwait(false)) != null) + Exception? processingException = null; + try { - var response = JsonConvert.DeserializeObject(line); + string? line; + while ((line = await _receivingStream.TryReadLineOrReturnNullIfCancelledAsync(_shutdownTokenSource.Token).ConfigureAwait(false)) != null) + { + Response? response; + try + { + response = JsonConvert.DeserializeObject(line); + } + catch (JsonException ex) + { + var message = $"Failed to deserialize response from build host:{Environment.NewLine}{line}"; + throw new AggregateException(message, ex); + } - Contract.ThrowIfNull(response); + Contract.ThrowIfNull(response); - Contract.ThrowIfFalse(_outstandingRequests.TryRemove(response.Id, out var completionSourceAndExpectedType), $"We got a response for request ID {response.Id} but that was already completed."); - var (completionSource, expectedType) = completionSourceAndExpectedType; + Contract.ThrowIfFalse(_outstandingRequests.TryRemove(response.Id, out var completionSourceAndExpectedType), $"We got a response for request ID {response.Id} but that was already completed."); + var (completionSource, expectedType) = completionSourceAndExpectedType; - if (response.Exception != null) - { - completionSource.SetException(new RemoteInvocationException(response.Exception)); - } - else - { - // If this is void-returning, then just set null - if (expectedType == null) + if (response.Exception != null) { - completionSource.SetResult(null); + completionSource.SetException(new RemoteInvocationException(response.Exception)); } else { - try + // If this is void-returning, then just set null + if (expectedType == null) { - // response.Value might be null if the response was in fact null. - var result = response.Value?.ToObject(expectedType); - completionSource.SetResult(result); + completionSource.SetResult(null); } - catch (Exception ex) + else { - completionSource.SetException(new Exception("Unable to deserialize the result", ex)); + try + { + // response.Value might be null if the response was in fact null. + var result = response.Value?.ToObject(expectedType); + completionSource.SetResult(result); + } + catch (Exception ex) + { + completionSource.SetException(new Exception("Unable to deserialize the result", ex)); + } } } } } + catch (Exception ex) + { + processingException = ex; + } // We've disconnected, so cancel any remaining outstanding tasks foreach (var (request, _) in _outstandingRequests.Values) - request.SetException(new System.Exception("The server disconnected unexpectedly.")); + request.SetException(processingException ?? new System.Exception("The server disconnected unexpectedly.")); Disconnected?.Invoke(this, EventArgs.Empty); }); diff --git a/src/Workspaces/Core/Portable/CaseCorrection/CaseCorrector.cs b/src/Workspaces/Core/Portable/CaseCorrection/CaseCorrector.cs index d1504360c91e2..b70b1a5045c64 100644 --- a/src/Workspaces/Core/Portable/CaseCorrection/CaseCorrector.cs +++ b/src/Workspaces/Core/Portable/CaseCorrection/CaseCorrector.cs @@ -46,7 +46,7 @@ public static async Task CaseCorrectAsync(Document document, SyntaxAnn throw new NotSupportedException(WorkspaceExtensionsResources.Document_does_not_support_syntax_trees); } - return await CaseCorrectAsync(document, root.GetAnnotatedNodesAndTokens(annotation).Select(n => n.Span).ToImmutableArray(), cancellationToken).ConfigureAwait(false); + return await CaseCorrectAsync(document, [.. root.GetAnnotatedNodesAndTokens(annotation).Select(n => n.Span)], cancellationToken).ConfigureAwait(false); } /// diff --git a/src/Workspaces/Core/Portable/CodeCleanup/AbstractCodeCleanerService.cs b/src/Workspaces/Core/Portable/CodeCleanup/AbstractCodeCleanerService.cs index d66fec3237654..0282c380e2a79 100644 --- a/src/Workspaces/Core/Portable/CodeCleanup/AbstractCodeCleanerService.cs +++ b/src/Workspaces/Core/Portable/CodeCleanup/AbstractCodeCleanerService.cs @@ -347,7 +347,7 @@ private static ImmutableArray GetNonOverlappingSpans( tokenSpans.Add(TextSpan.FromBounds(start, end)); } - return tokenSpans.ToNormalizedSpans().ToImmutableArray(); + return [.. tokenSpans.ToNormalizedSpans()]; } /// diff --git a/src/Workspaces/Core/Portable/CodeCleanup/CodeCleaner.cs b/src/Workspaces/Core/Portable/CodeCleanup/CodeCleaner.cs index 4d7508d2b16db..e1bb98484c3b0 100644 --- a/src/Workspaces/Core/Portable/CodeCleanup/CodeCleaner.cs +++ b/src/Workspaces/Core/Portable/CodeCleanup/CodeCleaner.cs @@ -60,7 +60,7 @@ public static async Task CleanupAsync(Document document, CodeCleanupOp public static async Task CleanupAsync(Document document, SyntaxAnnotation annotation, CodeCleanupOptions options, ImmutableArray providers = default, CancellationToken cancellationToken = default) { var root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); - return await CleanupAsync(document, root.GetAnnotatedNodesAndTokens(annotation).Select(n => n.Span).ToImmutableArray(), options, providers, cancellationToken: cancellationToken).ConfigureAwait(false); + return await CleanupAsync(document, [.. root.GetAnnotatedNodesAndTokens(annotation).Select(n => n.Span)], options, providers, cancellationToken: cancellationToken).ConfigureAwait(false); } /// diff --git a/src/Workspaces/Core/Portable/CodeFixes/CodeFixContext.cs b/src/Workspaces/Core/Portable/CodeFixes/CodeFixContext.cs index e09c4199551a7..d7d71fd48bfac 100644 --- a/src/Workspaces/Core/Portable/CodeFixes/CodeFixContext.cs +++ b/src/Workspaces/Core/Portable/CodeFixes/CodeFixContext.cs @@ -210,7 +210,7 @@ public void RegisterCodeFix(CodeAction action, IEnumerable diagnosti throw new ArgumentNullException(nameof(diagnostics)); } - RegisterCodeFix(action, diagnostics.ToImmutableArray()); + RegisterCodeFix(action, [.. diagnostics]); } /// diff --git a/src/Workspaces/Core/Portable/CodeFixes/FixAllOccurrences/FixAllContext.cs b/src/Workspaces/Core/Portable/CodeFixes/FixAllOccurrences/FixAllContext.cs index fe17d090ba470..942392fbbbd43 100644 --- a/src/Workspaces/Core/Portable/CodeFixes/FixAllOccurrences/FixAllContext.cs +++ b/src/Workspaces/Core/Portable/CodeFixes/FixAllOccurrences/FixAllContext.cs @@ -248,8 +248,8 @@ private static async Task> GetFilteredDiagnosticsAsyn var diagnostics = await getDiagnosticsTask.ConfigureAwait(false); if (diagnostics != null) { - return diagnostics.Where(d => d != null && diagnosticIds.Contains(d.Id) - && (filterSpan == null || filterSpan.Value.Contains(d.Location.SourceSpan))).ToImmutableArray(); + return [.. diagnostics.Where(d => d != null && diagnosticIds.Contains(d.Id) + && (filterSpan == null || filterSpan.Value.Contains(d.Location.SourceSpan)))]; } } diff --git a/src/Workspaces/Core/Portable/CodeFixes/FixAllOccurrences/FixAllContextHelper.cs b/src/Workspaces/Core/Portable/CodeFixes/FixAllOccurrences/FixAllContextHelper.cs index ea30bc2db59a8..21446325dc7e8 100644 --- a/src/Workspaces/Core/Portable/CodeFixes/FixAllOccurrences/FixAllContextHelper.cs +++ b/src/Workspaces/Core/Portable/CodeFixes/FixAllOccurrences/FixAllContextHelper.cs @@ -139,7 +139,7 @@ private static async Task -public class CodeStyleOptions +public static class CodeStyleOptions { /// public static readonly PerLanguageOption> QualifyFieldAccess = diff --git a/src/Workspaces/Core/Portable/Diagnostics/DiagnosticAnalysisResult.cs b/src/Workspaces/Core/Portable/Diagnostics/DiagnosticAnalysisResult.cs index 949bea98a8ebb..9cd424ee9c284 100644 --- a/src/Workspaces/Core/Portable/Diagnostics/DiagnosticAnalysisResult.cs +++ b/src/Workspaces/Core/Portable/Diagnostics/DiagnosticAnalysisResult.cs @@ -317,7 +317,7 @@ private static ImmutableHashSet GetDocumentIds( documents = documents.Concat(nonLocals.Keys); } - return ImmutableHashSet.CreateRange(documents); + return [.. documents]; } [Conditional("DEBUG")] diff --git a/src/Workspaces/Core/Portable/Diagnostics/DiagnosticData.cs b/src/Workspaces/Core/Portable/Diagnostics/DiagnosticData.cs index 39cf69d1943d9..cb6d63dd32c32 100644 --- a/src/Workspaces/Core/Portable/Diagnostics/DiagnosticData.cs +++ b/src/Workspaces/Core/Portable/Diagnostics/DiagnosticData.cs @@ -263,13 +263,24 @@ private static ImmutableArray GetAdditionalLocations(Tex { if (location.IsInSource) { - builder.AddIfNotNull(CreateLocation(document.Project.Solution.GetDocument(location.SourceTree), location)); + builder.Add(CreateLocation(document.Project.Solution.GetDocument(location.SourceTree), location)); } else if (location.Kind == LocationKind.ExternalFile) { var textDocumentId = document.Project.GetDocumentForExternalLocation(location); - builder.AddIfNotNull(CreateLocation(document.Project.GetTextDocument(textDocumentId), location)); + builder.Add(CreateLocation(document.Project.GetTextDocument(textDocumentId), location)); } + else if (location.Kind == LocationKind.None) + { + builder.Add(CreateLocation(document: null, location)); + } + // TODO: Should we throw an exception in an else? + // This will be reachable if a user creates his own type inheriting Location, and + // returns, e.g, LocationKind.XmlFile in Kind override. + // The case for custom `Location`s in general will be hard (if possible at all) to + // always round trip correctly. + // Or, maybe just always create a location with null document, so at least we guarantee that + // the count of additional location created by analyzer always matches what end up being in the code fix. } return builder.ToImmutableAndClear(); diff --git a/src/Workspaces/Core/Portable/Diagnostics/HostDiagnosticAnalyzers.cs b/src/Workspaces/Core/Portable/Diagnostics/HostDiagnosticAnalyzers.cs index 2da63eab4ed2a..e63221b427381 100644 --- a/src/Workspaces/Core/Portable/Diagnostics/HostDiagnosticAnalyzers.cs +++ b/src/Workspaces/Core/Portable/Diagnostics/HostDiagnosticAnalyzers.cs @@ -231,7 +231,7 @@ private static ImmutableDictionary> C } // input "analyzerReferencesMap" is a dictionary, so there will be no duplication here. - builder.Add(reference.Key, analyzers.WhereNotNull().ToImmutableArray()); + builder.Add(reference.Key, [.. analyzers.WhereNotNull()]); } return builder.ToImmutable(); @@ -290,7 +290,7 @@ private static ImmutableDictionary> M continue; } - current = current.Add(referenceIdentity, analyzers.Where(seen.Add).ToImmutableArray()); + current = current.Add(referenceIdentity, [.. analyzers.Where(seen.Add)]); } return current; diff --git a/src/Workspaces/Core/Portable/Diagnostics/SerializableDiagnosticAnalysisResultMap.cs b/src/Workspaces/Core/Portable/Diagnostics/SerializableDiagnosticAnalysisResultMap.cs index 14d9782869d0c..2a9b210b2c906 100644 --- a/src/Workspaces/Core/Portable/Diagnostics/SerializableDiagnosticAnalysisResultMap.cs +++ b/src/Workspaces/Core/Portable/Diagnostics/SerializableDiagnosticAnalysisResultMap.cs @@ -14,8 +14,8 @@ internal readonly struct SerializableDiagnosticAnalysisResults( ImmutableArray<(string analyzerId, AnalyzerTelemetryInfo)> telemetry) { public static readonly SerializableDiagnosticAnalysisResults Empty = new( - ImmutableArray<(string, SerializableDiagnosticMap)>.Empty, - ImmutableArray<(string, AnalyzerTelemetryInfo)>.Empty); + [], + []); [DataMember(Order = 0)] internal readonly ImmutableArray<(string analyzerId, SerializableDiagnosticMap diagnosticMap)> Diagnostics = diagnostics; diff --git a/src/Workspaces/Core/Portable/Editing/SyntaxEditor.cs b/src/Workspaces/Core/Portable/Editing/SyntaxEditor.cs index 3b0c8e09a5837..e18ee200d37fa 100644 --- a/src/Workspaces/Core/Portable/Editing/SyntaxEditor.cs +++ b/src/Workspaces/Core/Portable/Editing/SyntaxEditor.cs @@ -310,7 +310,7 @@ protected override SyntaxNode Apply(SyntaxNode root, SyntaxNode currentNode, Syn private sealed class InsertChange(SyntaxNode node, IEnumerable newNodes, bool isBefore) : Change(node) { - private readonly List _newNodes = newNodes.ToList(); + private readonly List _newNodes = [.. newNodes]; protected override SyntaxNode Apply(SyntaxNode root, SyntaxNode currentNode, SyntaxGenerator generator) => isBefore diff --git a/src/Workspaces/Core/Portable/Editing/SyntaxGenerator.cs b/src/Workspaces/Core/Portable/Editing/SyntaxGenerator.cs index e1dcfdf45f301..a6c528cdbcc8a 100644 --- a/src/Workspaces/Core/Portable/Editing/SyntaxGenerator.cs +++ b/src/Workspaces/Core/Portable/Editing/SyntaxGenerator.cs @@ -167,7 +167,7 @@ public SyntaxNode MethodDeclaration( IEnumerable? statements = null) { return MethodDeclaration( - name, parameters, typeParameters?.Select(n => TypeParameter(n)), returnType, accessibility, modifiers, statements); + name, parameters, typeParameters?.Select(TypeParameter), returnType, accessibility, modifiers, statements); } #pragma warning restore RS0026 // Do not add multiple public overloads with optional parameters @@ -192,7 +192,7 @@ internal SyntaxNode MethodDeclaration(IMethodSymbol method, string name, IEnumer name, typeParameters: method.TypeParameters.Select(p => TypeParameter(p)), parameters: method.Parameters.Select(p => ParameterDeclaration(p)), - returnType: method.ReturnType.IsSystemVoid() ? null : TypeExpression(method.ReturnType, method.RefKind), + returnType: method.ReturnType.IsSystemVoid() ? null : this.SyntaxGeneratorInternal.TypeExpression(method.ReturnType, method.RefKind), accessibility: method.DeclaredAccessibility, modifiers: DeclarationModifiers.From(method), statements: statements); @@ -284,7 +284,7 @@ public SyntaxNode OperatorDeclaration(IMethodSymbol method, IEnumerable ParameterDeclaration(p)), - returnType: method.ReturnType.IsSystemVoid() ? null : TypeExpression(method.ReturnType, method.RefKind), + returnType: method.ReturnType.IsSystemVoid() ? null : this.SyntaxGeneratorInternal.TypeExpression(method.ReturnType, method.RefKind), accessibility: method.DeclaredAccessibility, modifiers: DeclarationModifiers.From(method), statements: statements); @@ -389,7 +389,7 @@ public SyntaxNode PropertyDeclaration( var propDecl = PropertyDeclaration( property.Name, - TypeExpression(property.Type, property.RefKind), + this.SyntaxGeneratorInternal.TypeExpression(property.Type, property.RefKind), getAccessor, setAccessor, propertyAccessibility, @@ -450,7 +450,7 @@ public SyntaxNode IndexerDeclaration( { var indexerDecl = IndexerDeclaration( indexer.Parameters.Select(p => this.ParameterDeclaration(p)), - TypeExpression(indexer.Type, indexer.RefKind), + this.SyntaxGeneratorInternal.TypeExpression(indexer.Type, indexer.RefKind), indexer.DeclaredAccessibility, DeclarationModifiers.From(indexer), getAccessorStatements, @@ -1440,10 +1440,10 @@ public SyntaxNode RemoveNodes(SyntaxNode root, IEnumerable declarati internal static SyntaxTokenList Merge(SyntaxTokenList original, SyntaxTokenList newList) { // return tokens from newList, but use original tokens of kind matches - return new SyntaxTokenList(newList.Select( + return [.. newList.Select( token => Any(original, token.RawKind) ? original.First(tk => tk.RawKind == token.RawKind) - : token)); + : token)]; } private static bool Any(SyntaxTokenList original, int rawKind) @@ -1775,8 +1775,11 @@ internal SyntaxNode InterpolationFormatClause(string format) /// An expression that represents the default value of a type. /// This is typically a null value for reference types or a zero-filled value for value types. /// - public abstract SyntaxNode DefaultExpression(SyntaxNode type); - public abstract SyntaxNode DefaultExpression(ITypeSymbol type); + public SyntaxNode DefaultExpression(SyntaxNode type) + => this.SyntaxGeneratorInternal.DefaultExpression(type); + + public SyntaxNode DefaultExpression(ITypeSymbol type) + => this.SyntaxGeneratorInternal.DefaultExpression(type); /// /// Creates an expression that denotes the containing method's this-parameter. @@ -1828,7 +1831,8 @@ public SyntaxNode NullLiteralExpression() /// /// /// - public abstract SyntaxNode IdentifierName(string identifier); + public SyntaxNode IdentifierName(string identifier) + => this.SyntaxGeneratorInternal.IdentifierName(identifier); internal abstract SyntaxNode IdentifierName(SyntaxToken identifier); internal SyntaxToken Identifier(string identifier) => SyntaxGeneratorInternal.Identifier(identifier); @@ -1927,9 +1931,7 @@ public SyntaxNode DottedName(string dottedName) /// Creates an expression that denotes a type. /// public SyntaxNode TypeExpression(ITypeSymbol typeSymbol) - => TypeExpression(typeSymbol, RefKind.None); - - private protected abstract SyntaxNode TypeExpression(ITypeSymbol typeSymbol, RefKind refKind); + => this.SyntaxGeneratorInternal.TypeExpression(typeSymbol); /// /// Creates an expression that denotes a type. If addImport is false, @@ -2104,7 +2106,8 @@ public SyntaxNode TupleElementExpression(ITypeSymbol type, string? name = null) /// /// Creates an expression that denotes a bitwise-or operation. /// - public abstract SyntaxNode BitwiseOrExpression(SyntaxNode left, SyntaxNode right); + public SyntaxNode BitwiseOrExpression(SyntaxNode left, SyntaxNode right) + => this.SyntaxGeneratorInternal.BitwiseOrExpression(left, right); /// /// Creates an expression that denotes a bitwise-not operation @@ -2163,13 +2166,11 @@ public SyntaxNode ElementBindingExpression(params SyntaxNode[] arguments) /// /// Creates a member access expression. /// - public virtual SyntaxNode MemberAccessExpression(SyntaxNode? expression, SyntaxNode memberName) - { - return MemberAccessExpressionWorker(expression, memberName) - .WithAdditionalAnnotations(Simplifier.Annotation); - } + public SyntaxNode MemberAccessExpression(SyntaxNode? expression, SyntaxNode memberName) + => this.SyntaxGeneratorInternal.MemberAccessExpression(expression, memberName); - internal abstract SyntaxNode MemberAccessExpressionWorker(SyntaxNode? expression, SyntaxNode memberName); + internal SyntaxNode MemberAccessExpressionWorker(SyntaxNode? expression, SyntaxNode memberName) + => this.SyntaxGeneratorInternal.MemberAccessExpressionWorker(expression, memberName); internal SyntaxNode RefExpression(SyntaxNode expression) => SyntaxGeneratorInternal.RefExpression(expression); @@ -2285,24 +2286,26 @@ public SyntaxNode TryCastExpression(SyntaxNode expression, ITypeSymbol type) /// /// Creates an expression that denotes a type cast operation. /// - public abstract SyntaxNode CastExpression(SyntaxNode type, SyntaxNode expression); + public SyntaxNode CastExpression(SyntaxNode type, SyntaxNode expression) + => this.SyntaxGeneratorInternal.CastExpression(type, expression); /// /// Creates an expression that denotes a type cast operation. /// public SyntaxNode CastExpression(ITypeSymbol type, SyntaxNode expression) - => CastExpression(TypeExpression(type), expression); + => this.SyntaxGeneratorInternal.CastExpression(type, expression); /// /// Creates an expression that denotes a type conversion operation. /// - public abstract SyntaxNode ConvertExpression(SyntaxNode type, SyntaxNode expression); + public SyntaxNode ConvertExpression(SyntaxNode type, SyntaxNode expression) + => this.SyntaxGeneratorInternal.ConvertExpression(type, expression); /// /// Creates an expression that denotes a type conversion operation. /// public SyntaxNode ConvertExpression(ITypeSymbol type, SyntaxNode expression) - => ConvertExpression(TypeExpression(type), expression); + => this.SyntaxGeneratorInternal.ConvertExpression(type, expression); /// /// Creates an expression that declares a value returning lambda expression. diff --git a/src/Workspaces/Core/Portable/ExtractMethod/ExtractMethodOptions.cs b/src/Workspaces/Core/Portable/ExtractMethod/ExtractMethodOptions.cs index 00ed83a7d1461..2d715264d7ef6 100644 --- a/src/Workspaces/Core/Portable/ExtractMethod/ExtractMethodOptions.cs +++ b/src/Workspaces/Core/Portable/ExtractMethod/ExtractMethodOptions.cs @@ -11,6 +11,7 @@ using Microsoft.CodeAnalysis.CodeGeneration; using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.Host; +using Microsoft.CodeAnalysis.Simplification; namespace Microsoft.CodeAnalysis.ExtractMethod; @@ -36,16 +37,15 @@ public ExtractMethodGenerationOptions() public AddImportPlacementOptions AddImportOptions => CodeCleanupOptions.AddImportOptions; public LineFormattingOptions LineFormattingOptions => CodeCleanupOptions.FormattingOptions.LineFormatting; + public SimplifierOptions SimplifierOptions => CodeCleanupOptions.SimplifierOptions; } internal static class ExtractMethodGenerationOptionsProviders { public static async ValueTask GetExtractMethodGenerationOptionsAsync(this Document document, CancellationToken cancellationToken) - { - return new ExtractMethodGenerationOptions() + => new() { CodeGenerationOptions = await document.GetCodeGenerationOptionsAsync(cancellationToken).ConfigureAwait(false), CodeCleanupOptions = await document.GetCodeCleanupOptionsAsync(cancellationToken).ConfigureAwait(false), }; - } } diff --git a/src/Workspaces/Core/Portable/FindSymbols/FindReferences/DependentProjectsFinder.cs b/src/Workspaces/Core/Portable/FindSymbols/FindReferences/DependentProjectsFinder.cs index 0d8ff1ca6d95b..4ab41e349e177 100644 --- a/src/Workspaces/Core/Portable/FindSymbols/FindReferences/DependentProjectsFinder.cs +++ b/src/Workspaces/Core/Portable/FindSymbols/FindReferences/DependentProjectsFinder.cs @@ -42,7 +42,8 @@ public static async Task> GetDependentProjectsAsync( { // Namespaces are visible in all projects. // Preprocessing symbols are arbitrary identifiers that are not bound to specific projects. - if (symbols.Any(static s => s.Kind is SymbolKind.Namespace or SymbolKind.Preprocessing)) + // 'dynamic' can appear in any project. + if (symbols.Any(static s => s is INamespaceSymbol or IPreprocessingSymbol or IDynamicTypeSymbol)) return [.. projects]; var dependentProjects = await GetDependentProjectsWorkerAsync(solution, symbols, cancellationToken).ConfigureAwait(false); diff --git a/src/Workspaces/Core/Portable/FindSymbols/FindReferences/DependentTypeFinder.cs b/src/Workspaces/Core/Portable/FindSymbols/FindReferences/DependentTypeFinder.cs index 9e360bd3f47cb..1c86e9ee4a479 100644 --- a/src/Workspaces/Core/Portable/FindSymbols/FindReferences/DependentTypeFinder.cs +++ b/src/Workspaces/Core/Portable/FindSymbols/FindReferences/DependentTypeFinder.cs @@ -506,9 +506,7 @@ private static ImmutableArray GetProjectsToExamineWorker( // Finally, because we're searching metadata and source symbols, this needs to be a project // that actually supports compilations. - return projectsThatCouldReferenceType.Intersect(allProjectsThatTheseProjectsDependOn) - .Select(solution.GetRequiredProject) - .ToImmutableArray(); + return [.. projectsThatCouldReferenceType.Intersect(allProjectsThatTheseProjectsDependOn).Select(solution.GetRequiredProject)]; } private static bool TypeHasBaseTypeInSet(INamedTypeSymbol type, SymbolSet set) diff --git a/src/Workspaces/Core/Portable/FindSymbols/FindReferences/FindReferencesSearchEngine.SymbolSet.cs b/src/Workspaces/Core/Portable/FindSymbols/FindReferences/FindReferencesSearchEngine.SymbolSet.cs index 31e41ecb5ea83..76c2b5f4e9090 100644 --- a/src/Workspaces/Core/Portable/FindSymbols/FindReferences/FindReferencesSearchEngine.SymbolSet.cs +++ b/src/Workspaces/Core/Portable/FindSymbols/FindReferences/FindReferencesSearchEngine.SymbolSet.cs @@ -66,7 +66,7 @@ public static async Task CreateAsync( var options = engine._options; // Start by mapping the initial symbol to the appropriate source symbol in originating project if possible. - var searchSymbols = await MapToAppropriateSymbolsAsync(solution, symbols, cancellationToken).ConfigureAwait(false); + var searchSymbols = MapToAppropriateSymbols(solution, symbols, cancellationToken); // If the caller doesn't want any cascading then just return an appropriate set that will just point at // only the search symbol and won't cascade to any related symbols, linked symbols, or inheritance @@ -90,17 +90,17 @@ public static async Task CreateAsync( : new BidirectionalSymbolSet(engine, initialSymbols, upSymbols, includeImplementationsThroughDerivedTypes); } - private static async Task MapToAppropriateSymbolsAsync( + private static MetadataUnifyingSymbolHashSet MapToAppropriateSymbols( Solution solution, MetadataUnifyingSymbolHashSet symbols, CancellationToken cancellationToken) { var result = new MetadataUnifyingSymbolHashSet(); foreach (var symbol in symbols) - result.AddIfNotNull(await TryMapToAppropriateSymbolAsync(solution, symbol, cancellationToken).ConfigureAwait(false)); + result.AddIfNotNull(TryMapToAppropriateSymbol(solution, symbol, cancellationToken)); return result; } - private static async Task TryMapToAppropriateSymbolAsync( + private static ISymbol? TryMapToAppropriateSymbol( Solution solution, ISymbol symbol, CancellationToken cancellationToken) { // Never search for an alias. Always search for it's target. Note: if the caller was @@ -133,7 +133,7 @@ private static async Task MapToAppropriateSymbols // source definition as the 'truth' of a symbol versus seeing it projected into dependent cross language // projects as a metadata symbol. If there is no source symbol, then continue to just use the metadata // symbol as the one to be looking for. - var sourceSymbol = await SymbolFinder.FindSourceDefinitionAsync(searchSymbol, solution, cancellationToken).ConfigureAwait(false); + var sourceSymbol = SymbolFinder.FindSourceDefinition(searchSymbol, solution, cancellationToken); return sourceSymbol ?? searchSymbol; } @@ -210,7 +210,7 @@ protected static async Task AddCascadedAndLinkedSymbolsToAsync( async Task TryMapAndAddLinkedSymbolsAsync(ISymbol symbol) { - var mapped = await TryMapToAppropriateSymbolAsync(solution, symbol, cancellationToken).ConfigureAwait(false); + var mapped = TryMapToAppropriateSymbol(solution, symbol, cancellationToken); if (mapped is null) return null; diff --git a/src/Workspaces/Core/Portable/FindSymbols/FindReferences/FindReferencesSearchEngine.cs b/src/Workspaces/Core/Portable/FindSymbols/FindReferences/FindReferencesSearchEngine.cs index 66757d5a48ca9..ee82ecb3d4526 100644 --- a/src/Workspaces/Core/Portable/FindSymbols/FindReferences/FindReferencesSearchEngine.cs +++ b/src/Workspaces/Core/Portable/FindSymbols/FindReferences/FindReferencesSearchEngine.cs @@ -208,7 +208,7 @@ private Task> GetProjectsToSearchAsync( { var projects = _documents != null ? _documents.Select(d => d.Project).ToImmutableHashSet() - : _solution.Projects.ToImmutableHashSet(); + : [.. _solution.Projects]; return DependentProjectsFinder.GetDependentProjectsAsync(_solution, symbols, projects, cancellationToken); } diff --git a/src/Workspaces/Core/Portable/FindSymbols/FindReferences/Finders/AbstractReferenceFinder.cs b/src/Workspaces/Core/Portable/FindSymbols/FindReferences/Finders/AbstractReferenceFinder.cs index ea801ce612a45..7c542e1ab2d07 100644 --- a/src/Workspaces/Core/Portable/FindSymbols/FindReferences/Finders/AbstractReferenceFinder.cs +++ b/src/Workspaces/Core/Portable/FindSymbols/FindReferences/Finders/AbstractReferenceFinder.cs @@ -361,6 +361,9 @@ protected static Task FindDocumentsWithPredicateAsync( protected static Task FindDocumentsWithForEachStatementsAsync(Project project, IImmutableSet? documents, Action processResult, TData processResultData, CancellationToken cancellationToken) => FindDocumentsWithPredicateAsync(project, documents, static index => index.ContainsForEachStatement, processResult, processResultData, cancellationToken); + protected static Task FindDocumentsWithUsingStatementsAsync(Project project, IImmutableSet? documents, Action processResult, TData processResultData, CancellationToken cancellationToken) + => FindDocumentsWithPredicateAsync(project, documents, static index => index.ContainsUsingStatement, processResult, processResultData, cancellationToken); + /// /// If the `node` implicitly matches the `symbol`, then it will be added to `locations`. /// @@ -393,12 +396,9 @@ protected void FindReferencesInForEachStatements( TData processResultData, CancellationToken cancellationToken) { - FindReferencesInDocument(state, IsRelevantDocument, CollectMatchingReferences, processResult, processResultData, cancellationToken); + FindReferencesInDocument(state, static index => index.ContainsForEachStatement, CollectMatchingReferences, processResult, processResultData, cancellationToken); return; - static bool IsRelevantDocument(SyntaxTreeIndex syntaxTreeInfo) - => syntaxTreeInfo.ContainsForEachStatement; - void CollectMatchingReferences( SyntaxNode node, FindReferencesDocumentState state, Action processResult, TData processResultData) { @@ -608,7 +608,6 @@ protected static SymbolUsageInfo GetSymbolUsageInfo( topNameNode = topNameNode.Parent; var isInNamespaceNameContext = syntaxFacts.IsBaseNamespaceDeclaration(topNameNode.Parent); - return syntaxFacts.IsInNamespaceOrTypeContext(topNameNode) ? SymbolUsageInfo.Create(GetTypeOrNamespaceUsageInfo()) : GetSymbolUsageInfoCommon(); @@ -674,6 +673,9 @@ SymbolUsageInfo GetSymbolUsageInfoCommon() else { var operation = semanticModel.GetOperation(node, cancellationToken); + if (operation is IObjectCreationOperation) + return SymbolUsageInfo.Create(TypeOrNamespaceUsageInfo.ObjectCreation); + switch (operation?.Parent) { case INameOfOperation: diff --git a/src/Workspaces/Core/Portable/FindSymbols/FindReferences/Finders/ConstructorSymbolReferenceFinder.cs b/src/Workspaces/Core/Portable/FindSymbols/FindReferences/Finders/ConstructorSymbolReferenceFinder.cs index 05dcd0c0dc731..e7b4f0c98ed32 100644 --- a/src/Workspaces/Core/Portable/FindSymbols/FindReferences/Finders/ConstructorSymbolReferenceFinder.cs +++ b/src/Workspaces/Core/Portable/FindSymbols/FindReferences/Finders/ConstructorSymbolReferenceFinder.cs @@ -118,6 +118,9 @@ protected override void FindReferencesInDocument( FindReferencesInImplicitObjectCreationExpression( methodSymbol, state, processResult, processResultData, cancellationToken); + FindReferencesInPrimaryConstructorBaseType( + methodSymbol, state, processResult, processResultData, cancellationToken); + FindReferencesInDocumentInsideGlobalSuppressions( methodSymbol, state, processResult, processResultData, cancellationToken); } @@ -257,4 +260,45 @@ private static void FindReferencesInImplicitObjectCreationExpression( } } } + + private static void FindReferencesInPrimaryConstructorBaseType( + IMethodSymbol symbol, + FindReferencesDocumentState state, + Action processResult, + TData processResultData, + CancellationToken cancellationToken) + { + if (!state.Cache.SyntaxTreeIndex.ContainsPrimaryConstructorBaseType) + return; + + var syntaxFacts = state.SyntaxFacts; + foreach (var token in state.Cache.FindMatchingIdentifierTokens(symbol.ContainingType.Name, cancellationToken)) + { + cancellationToken.ThrowIfCancellationRequested(); + + var parent = token.GetRequiredParent(); + if (!syntaxFacts.IsSimpleName(parent)) + continue; + + if (syntaxFacts.IsRightOfQualifiedName(parent) || syntaxFacts.IsRightOfAliasQualifiedName(parent)) + parent = parent.GetRequiredParent(); + + var node = parent.GetRequiredParent(); + if (!syntaxFacts.IsPrimaryConstructorBaseType(node)) + continue; + + var constructor = state.SemanticModel.GetSymbolInfo(node, cancellationToken).Symbol; + if (Matches(constructor, symbol)) + { + var result = new FinderLocation(node, new ReferenceLocation( + state.Document, + alias: null, + token.GetLocation(), + isImplicit: false, + GetSymbolUsageInfo(node, state, cancellationToken), + GetAdditionalFindUsagesProperties(node, state), CandidateReason.None)); + processResult(result, processResultData); + } + } + } } diff --git a/src/Workspaces/Core/Portable/FindSymbols/FindReferences/Finders/DynamicTypeSymbolReferenceFinder.cs b/src/Workspaces/Core/Portable/FindSymbols/FindReferences/Finders/DynamicTypeSymbolReferenceFinder.cs new file mode 100644 index 0000000000000..e18ce05f26e27 --- /dev/null +++ b/src/Workspaces/Core/Portable/FindSymbols/FindReferences/Finders/DynamicTypeSymbolReferenceFinder.cs @@ -0,0 +1,49 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Threading; +using System.Threading.Tasks; + +namespace Microsoft.CodeAnalysis.FindSymbols.Finders; + +internal sealed class DynamicTypeSymbolReferenceFinder : AbstractReferenceFinder +{ + private const string DynamicIdentifier = "dynamic"; + public static readonly DynamicTypeSymbolReferenceFinder Instance = new(); + + private DynamicTypeSymbolReferenceFinder() + { + } + + protected override bool CanFind(IDynamicTypeSymbol symbol) + => true; + + protected override Task DetermineDocumentsToSearchAsync( + IDynamicTypeSymbol symbol, + HashSet? globalAliases, + Project project, + IImmutableSet? documents, + Action processResult, + TData processResultData, + FindReferencesSearchOptions options, + CancellationToken cancellationToken) + { + // For now, we're just looking for 'dynamic' itself, not an aliases to it. + return FindDocumentsAsync(project, documents, processResult, processResultData, cancellationToken, DynamicIdentifier); + } + + protected override void FindReferencesInDocument( + IDynamicTypeSymbol symbol, + FindReferencesDocumentState state, + Action processResult, + TData processResultData, + FindReferencesSearchOptions options, + CancellationToken cancellationToken) + { + FindReferencesInDocumentUsingIdentifier(symbol, DynamicIdentifier, state, processResult, processResultData, cancellationToken); + } +} diff --git a/src/Workspaces/Core/Portable/FindSymbols/FindReferences/Finders/NamedTypeSymbolReferenceFinder.cs b/src/Workspaces/Core/Portable/FindSymbols/FindReferences/Finders/NamedTypeSymbolReferenceFinder.cs index 96d55fd773a1e..7e50775f7fc1a 100644 --- a/src/Workspaces/Core/Portable/FindSymbols/FindReferences/Finders/NamedTypeSymbolReferenceFinder.cs +++ b/src/Workspaces/Core/Portable/FindSymbols/FindReferences/Finders/NamedTypeSymbolReferenceFinder.cs @@ -112,25 +112,26 @@ protected override void FindReferencesInDocument( FindReferencesSearchOptions options, CancellationToken cancellationToken) { - using var _ = ArrayBuilder.GetInstance(out var initialReferences); + using var _ = ArrayBuilder.GetInstance(out var tempReferences); - // First find all references to this type, either with it's actual name, or through potential - // global alises to it. + // First find all references to this type, using it's actual .Net name. AddReferencesToTypeOrGlobalAliasToIt( - namedType, state, StandardCallbacks.AddToArrayBuilder, initialReferences, cancellationToken); + namedType, state, StandardCallbacks.AddToArrayBuilder, tempReferences, cancellationToken); - // The items in initialReferences need to be both reported and used later to calculate additional results. - foreach (var location in initialReferences) + // Next, if this named type is a predefined type (like int/long), also search for it with the C# name, + // not the .Net one. + AddPredefinedTypeReferences(namedType, state, tempReferences, cancellationToken); + + // The items in tempReferences need to be both reported and used later to calculate additional results. + foreach (var location in tempReferences) processResult(location, processResultData); - // This named type may end up being locally aliased as well. If so, now find all the references - // to the local alias. + // This named type may end up being locally aliased as well. If so, now find all the references to the local + // alias. Note: the local alias may be like `using X = System.Int32` or it could be `using X = int`. Because + // we searched for both forms above, we'll find all references to the local aliases to either form here. FindLocalAliasReferences( - initialReferences, state, processResult, processResultData, cancellationToken); - - FindPredefinedTypeReferences( - namedType, state, processResult, processResultData, cancellationToken); + tempReferences, state, processResult, processResultData, cancellationToken); FindReferencesInDocumentInsideGlobalSuppressions( namedType, state, processResult, processResultData, cancellationToken); @@ -203,11 +204,10 @@ private static void FindOrdinaryReferences( namedType, name, state, processResult, processResultData, cancellationToken); } - private static void FindPredefinedTypeReferences( + private static void AddPredefinedTypeReferences( INamedTypeSymbol symbol, FindReferencesDocumentState state, - Action processResult, - TData processResultData, + ArrayBuilder tempReferences, CancellationToken cancellationToken) { var predefinedType = symbol.SpecialType.ToPredefinedType(); @@ -220,7 +220,8 @@ private static void FindPredefinedTypeReferences( static (token, tuple) => IsPotentialReference(tuple.predefinedType, tuple.state.SyntaxFacts, token), (state, predefinedType)); - FindReferencesInTokens(symbol, state, tokens, processResult, processResultData, cancellationToken); + FindReferencesInTokens( + symbol, state, tokens, StandardCallbacks.AddToArrayBuilder, tempReferences, cancellationToken); } private static void FindAttributeReferences( diff --git a/src/Workspaces/Core/Portable/FindSymbols/FindReferences/Finders/OrdinaryMethodReferenceFinder.cs b/src/Workspaces/Core/Portable/FindSymbols/FindReferences/Finders/OrdinaryMethodReferenceFinder.cs index 6813b72dd61ba..e7fbb5e2347ee 100644 --- a/src/Workspaces/Core/Portable/FindSymbols/FindReferences/Finders/OrdinaryMethodReferenceFinder.cs +++ b/src/Workspaces/Core/Portable/FindSymbols/FindReferences/Finders/OrdinaryMethodReferenceFinder.cs @@ -85,6 +85,9 @@ await FindDocumentsWithGlobalSuppressMessageAttributeAsync( if (IsAddMethod(methodSymbol)) await FindDocumentsWithCollectionInitializersAsync(project, documents, processResult, processResultData, cancellationToken).ConfigureAwait(false); + + if (IsDisposeMethod(methodSymbol)) + await FindDocumentsWithUsingStatementsAsync(project, documents, processResult, processResultData, cancellationToken).ConfigureAwait(false); } private static Task FindDocumentsWithDeconstructionAsync(Project project, IImmutableSet? documents, Action processResult, TData processResultData, CancellationToken cancellationToken) @@ -109,6 +112,9 @@ private static bool IsGetAwaiterMethod(IMethodSymbol methodSymbol) private static bool IsAddMethod(IMethodSymbol methodSymbol) => methodSymbol.Name == WellKnownMemberNames.CollectionInitializerAddMethodName; + private static bool IsDisposeMethod(IMethodSymbol methodSymbol) + => methodSymbol.Name == nameof(IDisposable.Dispose); + protected sealed override void FindReferencesInDocument( IMethodSymbol symbol, FindReferencesDocumentState state, @@ -134,5 +140,44 @@ protected sealed override void FindReferencesInDocument( if (IsAddMethod(symbol)) FindReferencesInCollectionInitializer(symbol, state, processResult, processResultData, cancellationToken); + + if (IsDisposeMethod(symbol)) + FindReferencesInUsingStatements(symbol, state, processResult, processResultData, cancellationToken); + } + + private void FindReferencesInUsingStatements( + IMethodSymbol symbol, + FindReferencesDocumentState state, + Action processResult, + TData processResultData, + CancellationToken cancellationToken) + { + FindReferencesInDocument(state, static index => index.ContainsUsingStatement, CollectMatchingReferences, processResult, processResultData, cancellationToken); + return; + + void CollectMatchingReferences( + SyntaxNode node, + FindReferencesDocumentState state, + Action processResult, + TData processResultData) + { + var disposeMethod = state.SemanticFacts.TryGetDisposeMethod(state.SemanticModel, node, cancellationToken); + + if (Matches(disposeMethod, symbol)) + { + var location = node.GetFirstToken().GetLocation(); + var symbolUsageInfo = GetSymbolUsageInfo(node, state, cancellationToken); + + var result = new FinderLocation(node, new ReferenceLocation( + state.Document, + alias: null, + location: location, + isImplicit: true, + symbolUsageInfo, + GetAdditionalFindUsagesProperties(node, state), + candidateReason: CandidateReason.None)); + processResult(result, processResultData); + } + } } } diff --git a/src/Workspaces/Core/Portable/FindSymbols/FindReferences/Finders/ReferenceFinders.cs b/src/Workspaces/Core/Portable/FindSymbols/FindReferences/Finders/ReferenceFinders.cs index 60820a4c14a0f..863c60a0b6830 100644 --- a/src/Workspaces/Core/Portable/FindSymbols/FindReferences/Finders/ReferenceFinders.cs +++ b/src/Workspaces/Core/Portable/FindSymbols/FindReferences/Finders/ReferenceFinders.cs @@ -14,6 +14,7 @@ internal static class ReferenceFinders ConstructorSymbolReferenceFinder.Instance, PropertySymbolReferenceFinder.Instance, new DestructorSymbolReferenceFinder(), + DynamicTypeSymbolReferenceFinder.Instance, new EventSymbolReferenceFinder(), new ExplicitConversionSymbolReferenceFinder(), new ExplicitInterfaceMethodReferenceFinder(), diff --git a/src/Workspaces/Core/Portable/FindSymbols/Shared/AbstractSyntaxIndex_Persistence.cs b/src/Workspaces/Core/Portable/FindSymbols/Shared/AbstractSyntaxIndex_Persistence.cs index 751594f213f6c..5b055b96423bd 100644 --- a/src/Workspaces/Core/Portable/FindSymbols/Shared/AbstractSyntaxIndex_Persistence.cs +++ b/src/Workspaces/Core/Portable/FindSymbols/Shared/AbstractSyntaxIndex_Persistence.cs @@ -23,7 +23,7 @@ internal abstract partial class AbstractSyntaxIndex /// that we will not try to read previously cached data from a prior version of roslyn with a different format and /// will instead regenerate all the indices with the new format. /// - private static readonly Checksum s_serializationFormatChecksum = CodeAnalysis.Checksum.Create("43"); + private static readonly Checksum s_serializationFormatChecksum = CodeAnalysis.Checksum.Create("45"); /// /// Cache of ParseOptions to a checksum for the contained diff --git a/src/Workspaces/Core/Portable/FindSymbols/SymbolFinder.cs b/src/Workspaces/Core/Portable/FindSymbols/SymbolFinder.cs index 5424f98041207..f30ad6bfdcc0e 100644 --- a/src/Workspaces/Core/Portable/FindSymbols/SymbolFinder.cs +++ b/src/Workspaces/Core/Portable/FindSymbols/SymbolFinder.cs @@ -6,7 +6,6 @@ using System.Collections.Generic; using System.Collections.Immutable; using System.Diagnostics; -using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Threading; using System.Threading.Tasks; @@ -58,11 +57,28 @@ public static Task FindSymbolAtPositionAsync( /// The semantic model associated with the document. /// The character position within the document. /// A CancellationToken. + internal static Task FindSymbolAtPositionAsync( + SemanticModel semanticModel, + int position, + SolutionServices services, + CancellationToken cancellationToken) + { + return FindSymbolAtPositionAsync(semanticModel, position, services, includeType: false, cancellationToken); + } + + /// + /// Finds the symbol that is associated with a position in the text of a document. + /// + /// The semantic model associated with the document. + /// The character position within the document. + /// True to include the type of the symbol in the search. + /// A CancellationToken. internal static async Task FindSymbolAtPositionAsync( SemanticModel semanticModel, int position, SolutionServices services, - CancellationToken cancellationToken = default) + bool includeType, + CancellationToken cancellationToken) { if (semanticModel is null) throw new ArgumentNullException(nameof(semanticModel)); @@ -71,7 +87,7 @@ internal static async Task FindSymbolAtPositionAsync( var semanticInfo = await GetSemanticInfoAtPositionAsync( semanticModel, position, services, cancellationToken).ConfigureAwait(false); - return semanticInfo.GetAnySymbol(includeType: false); + return semanticInfo.GetAnySymbol(includeType); } internal static async Task GetSemanticInfoAtPositionAsync( @@ -100,7 +116,8 @@ private static Task GetTokenAtPositionAsync( var syntaxTree = semanticModel.SyntaxTree; var syntaxFacts = services.GetRequiredLanguageService(semanticModel.Language); - return syntaxTree.GetTouchingTokenAsync(position, syntaxFacts.IsBindableToken, cancellationToken, findInsideTrivia: true); + return syntaxTree.GetTouchingTokenAsync( + semanticModel, position, syntaxFacts.IsBindableToken, cancellationToken, findInsideTrivia: true); } public static async Task FindSymbolAtPositionAsync( @@ -120,86 +137,10 @@ public static async Task FindSymbolAtPositionAsync( /// Returns null if no such symbol can be found in the specified solution. /// public static Task FindSourceDefinitionAsync(ISymbol? symbol, Solution solution, CancellationToken cancellationToken = default) - => Task.FromResult(FindSourceDefinition(symbol, solution, cancellationToken)); - - /// - internal static ISymbol? FindSourceDefinition( - ISymbol? symbol, Solution solution, CancellationToken cancellationToken) - { - if (symbol != null) - { - symbol = symbol.GetOriginalUnreducedDefinition(); - switch (symbol.Kind) - { - case SymbolKind.Event: - case SymbolKind.Field: - case SymbolKind.Method: - case SymbolKind.Local: - case SymbolKind.NamedType: - case SymbolKind.Parameter: - case SymbolKind.Property: - case SymbolKind.TypeParameter: - case SymbolKind.Namespace: - return FindSourceDefinitionWorker(symbol, solution, cancellationToken); - } - } + => Task.FromResult(SymbolFinderInternal.FindSourceDefinition(symbol, solution, cancellationToken)); - return null; - } - - private static ISymbol? FindSourceDefinitionWorker( - ISymbol symbol, - Solution solution, - CancellationToken cancellationToken) - { - // If it's already in source, then we might already be done - if (InSource(symbol)) - { - // If our symbol doesn't have a containing assembly, there's nothing better we can do to map this - // symbol somewhere else. The common case for this is a merged INamespaceSymbol that spans assemblies. - if (symbol.ContainingAssembly == null) - return symbol; - - // Just because it's a source symbol doesn't mean we have the final symbol we actually want. In retargeting cases, - // the retargeted symbol is from "source" but isn't equal to the actual source definition in the other project. Thus, - // we only want to return symbols from source here if it actually came from a project's compilation's assembly. If it isn't - // then we have a retargeting scenario and want to take our usual path below as if it was a metadata reference - foreach (var sourceProject in solution.Projects) - { - // If our symbol is actually a "regular" source symbol, then we know the compilation is holding the symbol alive - // and thus TryGetCompilation is sufficient. For another example of this pattern, see Solution.GetProject(IAssemblySymbol) - // which we happen to call below. - if (sourceProject.TryGetCompilation(out var compilation) && - symbol.ContainingAssembly.Equals(compilation.Assembly)) - { - return symbol; - } - } - } - else if (!symbol.Locations.Any(static loc => loc.IsInMetadata)) - { - // We have a symbol that's neither in source nor metadata - return null; - } - - var project = solution.GetProject(symbol.ContainingAssembly, cancellationToken); - - // Note: if the assembly came from a particular project, then we should be able to get the compilation without - // building it. That's because once we create the compilation, we'll hold onto it for the lifetime of the - // project, to avoid unnecessary recomputation. - if (project?.TryGetCompilation(out var projectCompilation) is true) - { - var symbolId = symbol.GetSymbolKey(cancellationToken); - var result = symbolId.Resolve(projectCompilation, ignoreAssemblyKey: true, cancellationToken: cancellationToken); - - return InSource(result.Symbol) ? result.Symbol : result.CandidateSymbols.FirstOrDefault(InSource); - } - - return null; - - static bool InSource([NotNullWhen(true)] ISymbol? symbol) - => symbol != null && symbol.Locations.Any(static loc => loc.IsInSource); - } + internal static ISymbol? FindSourceDefinition(ISymbol? symbol, Solution solution, CancellationToken cancellationToken) + => SymbolFinderInternal.FindSourceDefinition(symbol, solution, cancellationToken); /// /// Finds symbols in the given compilation that are similar to the specified symbol. diff --git a/src/Workspaces/Core/Portable/FindSymbols/SymbolFinder_Callers.cs b/src/Workspaces/Core/Portable/FindSymbols/SymbolFinder_Callers.cs index 6bc36c7403560..5d70854ba3423 100644 --- a/src/Workspaces/Core/Portable/FindSymbols/SymbolFinder_Callers.cs +++ b/src/Workspaces/Core/Portable/FindSymbols/SymbolFinder_Callers.cs @@ -38,7 +38,7 @@ public static async Task> FindCallersAsync( throw new System.ArgumentNullException(nameof(solution)); symbol = symbol.OriginalDefinition; - var foundSymbol = await FindSourceDefinitionAsync(symbol, solution, cancellationToken).ConfigureAwait(false); + var foundSymbol = FindSourceDefinition(symbol, solution, cancellationToken); symbol = foundSymbol ?? symbol; var references = await FindCallReferencesAsync(solution, symbol, documents, cancellationToken).ConfigureAwait(false); diff --git a/src/Workspaces/Core/Portable/FindSymbols/SymbolFinder_FindReferences_Legacy.cs b/src/Workspaces/Core/Portable/FindSymbols/SymbolFinder_FindReferences_Legacy.cs index 6763d3d3c4df8..c158ef141d3ef 100644 --- a/src/Workspaces/Core/Portable/FindSymbols/SymbolFinder_FindReferences_Legacy.cs +++ b/src/Workspaces/Core/Portable/FindSymbols/SymbolFinder_FindReferences_Legacy.cs @@ -22,7 +22,7 @@ public static partial class SymbolFinder /// The symbol to find references to. /// The solution to find references within. /// A cancellation token. - public static Task> FindReferencesAsync( + public static async Task> FindReferencesAsync( ISymbol symbol, Solution solution, CancellationToken cancellationToken = default) @@ -32,10 +32,10 @@ public static Task> FindReferencesAsync( if (solution is null) throw new System.ArgumentNullException(nameof(solution)); - return FindReferencesAsync(symbol, solution, FindReferencesSearchOptions.Default, cancellationToken); + return await FindReferencesAsync(symbol, solution, FindReferencesSearchOptions.Default, cancellationToken).ConfigureAwait(false); } - internal static async Task> FindReferencesAsync( + internal static async Task> FindReferencesAsync( ISymbol symbol, Solution solution, FindReferencesSearchOptions options, @@ -109,18 +109,4 @@ await FindReferencesAsync( options, cancellationToken).ConfigureAwait(false); return streamingProgress.GetReferencedSymbols(); } - - internal static class TestAccessor - { - internal static Task> FindReferencesAsync( - ISymbol symbol, - Solution solution, - IFindReferencesProgress progress, - IImmutableSet documents, - FindReferencesSearchOptions options, - CancellationToken cancellationToken) - { - return SymbolFinder.FindReferencesAsync(symbol, solution, progress, documents, options, cancellationToken); - } - } } diff --git a/src/Workspaces/Core/Portable/FindSymbols/SymbolFinder_Hierarchy.cs b/src/Workspaces/Core/Portable/FindSymbols/SymbolFinder_Hierarchy.cs index b00c9dcb4738a..43c5714c3ea5d 100644 --- a/src/Workspaces/Core/Portable/FindSymbols/SymbolFinder_Hierarchy.cs +++ b/src/Workspaces/Core/Portable/FindSymbols/SymbolFinder_Hierarchy.cs @@ -51,19 +51,19 @@ internal static async Task> FindOverridesArrayAsync( // First try finding exact overrides. If that fails to find anything, look for overrides that loosely // match due to errors. - await FindOverridesAsync(allowLooseMatch: false).ConfigureAwait(false); + FindOverrides(allowLooseMatch: false); if (results.Count == 0) - await FindOverridesAsync(allowLooseMatch: true).ConfigureAwait(false); + FindOverrides(allowLooseMatch: true); return results.ToImmutableAndClear(); - async Task FindOverridesAsync(bool allowLooseMatch) + void FindOverrides(bool allowLooseMatch) { foreach (var type in derivedTypes) { foreach (var m in type.GetMembers(symbol.Name)) { - var sourceMember = await FindSourceDefinitionAsync(m, solution, cancellationToken).ConfigureAwait(false); + var sourceMember = FindSourceDefinition(m, solution, cancellationToken); var bestMember = sourceMember ?? m; if (IsOverride(solution, bestMember, symbol, allowLooseMatch)) @@ -166,7 +166,7 @@ internal static async Task> FindImplementedInterfaceMemb { foreach (var interfaceMember in interfaceType.GetMembers(symbol.Name)) { - var sourceMethod = await FindSourceDefinitionAsync(interfaceMember, solution, cancellationToken).ConfigureAwait(false); + var sourceMethod = FindSourceDefinition(interfaceMember, solution, cancellationToken); var bestMethod = sourceMethod ?? interfaceMember; var implementations = type.FindImplementationsForInterfaceMember(bestMethod, solution, cancellationToken); @@ -183,7 +183,7 @@ internal static async Task> FindImplementedInterfaceMemb } } - return builder.Distinct(SymbolEquivalenceComparer.Instance).ToImmutableArray(); + return [.. builder.Distinct(SymbolEquivalenceComparer.Instance)]; } } @@ -373,13 +373,13 @@ internal static async Task> FindMemberImplementationsArr var implementations = t.FindImplementationsForInterfaceMember(symbol, solution, cancellationToken); foreach (var implementation in implementations) { - var sourceDef = await FindSourceDefinitionAsync(implementation, solution, cancellationToken).ConfigureAwait(false); + var sourceDef = FindSourceDefinition(implementation, solution, cancellationToken); var bestDef = sourceDef ?? implementation; if (IsAccessible(bestDef)) results.Add(bestDef.OriginalDefinition); } } - return results.Distinct(SymbolEquivalenceComparer.Instance).ToImmutableArray(); + return [.. results.Distinct(SymbolEquivalenceComparer.Instance)]; } } diff --git a/src/Workspaces/Core/Portable/FindSymbols/SyntaxTree/SyntaxTreeIndex.ContextInfo.cs b/src/Workspaces/Core/Portable/FindSymbols/SyntaxTree/SyntaxTreeIndex.ContextInfo.cs index e74a8d9c6e7bc..9a4229298e319 100644 --- a/src/Workspaces/Core/Portable/FindSymbols/SyntaxTree/SyntaxTreeIndex.ContextInfo.cs +++ b/src/Workspaces/Core/Portable/FindSymbols/SyntaxTree/SyntaxTreeIndex.ContextInfo.cs @@ -36,7 +36,8 @@ public ContextInfo( bool containsGlobalKeyword, bool containsCollectionInitializer, bool containsAttribute, - bool containsDirective) + bool containsDirective, + bool containsPrimaryConstructorBaseType) : this(predefinedTypes, predefinedOperators, ConvertToContainingNodeFlag( containsForEachStatement, @@ -56,7 +57,8 @@ public ContextInfo( containsGlobalKeyword, containsCollectionInitializer, containsAttribute, - containsDirective)) + containsDirective, + containsPrimaryConstructorBaseType)) { } @@ -85,7 +87,8 @@ private static ContainingNodes ConvertToContainingNodeFlag( bool containsGlobalKeyword, bool containsCollectionInitializer, bool containsAttribute, - bool containsDirective) + bool containsDirective, + bool containsPrimaryConstructorBaseType) { var containingNodes = ContainingNodes.None; @@ -107,6 +110,7 @@ private static ContainingNodes ConvertToContainingNodeFlag( containingNodes |= containsCollectionInitializer ? ContainingNodes.ContainsCollectionInitializer : 0; containingNodes |= containsAttribute ? ContainingNodes.ContainsAttribute : 0; containingNodes |= containsDirective ? ContainingNodes.ContainsDirective : 0; + containingNodes |= containsPrimaryConstructorBaseType ? ContainingNodes.ContainsPrimaryConstructorBaseType : 0; return containingNodes; } @@ -171,6 +175,9 @@ public bool ContainsAttribute public bool ContainsDirective => (_containingNodes & ContainingNodes.ContainsDirective) == ContainingNodes.ContainsDirective; + public bool ContainsPrimaryConstructorBaseType + => (_containingNodes & ContainingNodes.ContainsPrimaryConstructorBaseType) == ContainingNodes.ContainsPrimaryConstructorBaseType; + public void WriteTo(ObjectWriter writer) { writer.WriteInt32(_predefinedTypes); @@ -217,6 +224,7 @@ private enum ContainingNodes ContainsCollectionInitializer = 1 << 15, ContainsAttribute = 1 << 16, ContainsDirective = 1 << 17, + ContainsPrimaryConstructorBaseType = 1 << 18, } } } diff --git a/src/Workspaces/Core/Portable/FindSymbols/SyntaxTree/SyntaxTreeIndex_Create.cs b/src/Workspaces/Core/Portable/FindSymbols/SyntaxTree/SyntaxTreeIndex_Create.cs index fc76ff3f3bd5f..c0170cd52c5bb 100644 --- a/src/Workspaces/Core/Portable/FindSymbols/SyntaxTree/SyntaxTreeIndex_Create.cs +++ b/src/Workspaces/Core/Portable/FindSymbols/SyntaxTree/SyntaxTreeIndex_Create.cs @@ -74,6 +74,7 @@ private static SyntaxTreeIndex CreateIndex( var containsCollectionInitializer = false; var containsAttribute = false; var containsDirective = root.ContainsDirectives; + var containsPrimaryConstructorBaseType = false; var predefinedTypes = (int)PredefinedType.None; var predefinedOperators = (int)PredefinedOperator.None; @@ -89,7 +90,7 @@ private static SyntaxTreeIndex CreateIndex( containsForEachStatement = containsForEachStatement || syntaxFacts.IsForEachStatement(node); containsLockStatement = containsLockStatement || syntaxFacts.IsLockStatement(node); - containsUsingStatement = containsUsingStatement || syntaxFacts.IsUsingStatement(node); + containsUsingStatement = containsUsingStatement || syntaxFacts.IsUsingStatement(node) || syntaxFacts.IsUsingLocalDeclarationStatement(node); containsQueryExpression = containsQueryExpression || syntaxFacts.IsQueryExpression(node); containsElementAccess = containsElementAccess || (syntaxFacts.IsElementAccessExpression(node) || syntaxFacts.IsImplicitElementAccess(node)); containsIndexerMemberCref = containsIndexerMemberCref || syntaxFacts.IsIndexerMemberCref(node); @@ -105,6 +106,7 @@ private static SyntaxTreeIndex CreateIndex( containsConversion = containsConversion || syntaxFacts.IsConversionExpression(node); containsCollectionInitializer = containsCollectionInitializer || syntaxFacts.IsObjectCollectionInitializer(node); containsAttribute = containsAttribute || syntaxFacts.IsAttribute(node); + containsPrimaryConstructorBaseType = containsPrimaryConstructorBaseType || syntaxFacts.IsPrimaryConstructorBaseType(node); TryAddAliasInfo(syntaxFacts, ref aliasInfo, node); @@ -198,7 +200,8 @@ private static SyntaxTreeIndex CreateIndex( containsGlobalKeyword, containsCollectionInitializer, containsAttribute, - containsDirective), + containsDirective, + containsPrimaryConstructorBaseType), aliasInfo, interceptsLocationInfo); } diff --git a/src/Workspaces/Core/Portable/FindSymbols/SyntaxTree/SyntaxTreeIndex_Forwarders.cs b/src/Workspaces/Core/Portable/FindSymbols/SyntaxTree/SyntaxTreeIndex_Forwarders.cs index c67a2beaf74da..1ba1ff4d09862 100644 --- a/src/Workspaces/Core/Portable/FindSymbols/SyntaxTree/SyntaxTreeIndex_Forwarders.cs +++ b/src/Workspaces/Core/Portable/FindSymbols/SyntaxTree/SyntaxTreeIndex_Forwarders.cs @@ -39,6 +39,7 @@ internal sealed partial class SyntaxTreeIndex public bool ContainsCollectionInitializer => _contextInfo.ContainsCollectionInitializer; public bool ContainsAttribute => _contextInfo.ContainsAttribute; public bool ContainsDirective => _contextInfo.ContainsDirective; + public bool ContainsPrimaryConstructorBaseType => _contextInfo.ContainsPrimaryConstructorBaseType; /// /// Gets the set of global aliases that point to something with the provided name and arity. diff --git a/src/Workspaces/Core/Portable/FindSymbols/TopLevelSyntaxTree/TopLevelSyntaxTreeIndex.cs b/src/Workspaces/Core/Portable/FindSymbols/TopLevelSyntaxTree/TopLevelSyntaxTreeIndex.cs index 3d48e088ff6cb..87ad76a89f559 100644 --- a/src/Workspaces/Core/Portable/FindSymbols/TopLevelSyntaxTree/TopLevelSyntaxTreeIndex.cs +++ b/src/Workspaces/Core/Portable/FindSymbols/TopLevelSyntaxTree/TopLevelSyntaxTreeIndex.cs @@ -27,7 +27,7 @@ private TopLevelSyntaxTreeIndex( _declarationInfo = declarationInfo; _extensionMethodInfo = extensionMethodInfo; - _declaredSymbolInfoSet = new(() => new(this.DeclaredSymbolInfos)); + _declaredSymbolInfoSet = new(() => [.. this.DeclaredSymbolInfos]); } public ImmutableArray DeclaredSymbolInfos => _declarationInfo.DeclaredSymbolInfos; diff --git a/src/Workspaces/Core/Portable/LinkedFileDiffMerging/AbstractLinkedFileMergeConflictCommentAdditionService.cs b/src/Workspaces/Core/Portable/LinkedFileDiffMerging/AbstractLinkedFileMergeConflictCommentAdditionService.cs index 3f76b79b27406..c13f3a9bc9a98 100644 --- a/src/Workspaces/Core/Portable/LinkedFileDiffMerging/AbstractLinkedFileMergeConflictCommentAdditionService.cs +++ b/src/Workspaces/Core/Portable/LinkedFileDiffMerging/AbstractLinkedFileMergeConflictCommentAdditionService.cs @@ -2,23 +2,18 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; -using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; namespace Microsoft.CodeAnalysis; -internal abstract class AbstractLinkedFileMergeConflictCommentAdditionService : IMergeConflictHandler, ILanguageService, ILinkedFileMergeConflictCommentAdditionService +internal static class LinkedFileMergeConflictCommentAdditionService { - internal abstract string GetConflictCommentText(string header, string beforeString, string afterString); - - public ImmutableArray CreateEdits(SourceText originalSourceText, ArrayBuilder unmergedChanges) + public static ImmutableArray CreateEdits(SourceText originalSourceText, ArrayBuilder unmergedChanges) { using var _ = ArrayBuilder.GetInstance(out var commentChanges); @@ -64,9 +59,9 @@ private static List> PartitionChangesForDocument(IEnumerable GetCommentChangesForDocument(IEnumerable> partitionedChanges, string projectName, SourceText oldDocumentText) + private static ImmutableArray GetCommentChangesForDocument(IEnumerable> partitionedChanges, string projectName, SourceText oldDocumentText) { - var commentChanges = new List(); + using var _ = ArrayBuilder.GetInstance(out var commentChanges); foreach (var changePartition in partitionedChanges) { @@ -77,24 +72,56 @@ private List GetCommentChangesForDocument(IEnumerable new TextChange(TextSpan.FromBounds(c.Span.Start - startLineStartPosition, c.Span.End - startLineStartPosition), c.NewText)); + var adjustedChanges = changePartition.Select(c => new TextChange(TextSpan.FromBounds(c.Span.Start - startLineStartPosition, c.Span.End - startLineStartPosition), c.NewText!)); var newText = oldText.WithChanges(adjustedChanges); var warningText = GetConflictCommentText( - string.Format(WorkspacesResources.Unmerged_change_from_project_0, projectName), + string.Format(WorkspacesResources.TODO_Unmerged_change_from_project_0, projectName), TrimBlankLines(oldText), TrimBlankLines(newText)); if (warningText != null) - { commentChanges.Add(new TextChange(TextSpan.FromBounds(startLineStartPosition, startLineStartPosition), warningText)); - } } - return commentChanges; + return commentChanges.ToImmutableAndClear(); } - private static string TrimBlankLines(SourceText text) + private static string? GetConflictCommentText(string header, string? beforeString, string? afterString) + => (beforeString, afterString) switch + { + (null, null) => null, + (not null, not null) => + $""" + + <<<<<<< {header}, {WorkspacesResources.Before_colon} + {beforeString} + ======= + {afterString} + >>>>>>> {WorkspacesResources.After} + + """, + (null, not null) => + $""" + + <<<<<<< {header}, {WorkspacesResources.Before_colon} + ======= + {afterString} + >>>>>>> {WorkspacesResources.After} + + """, + (not null, null) => + $""" + + <<<<<<< {header}, {WorkspacesResources.Before_colon} + {beforeString} + ======= + >>>>>>> {WorkspacesResources.After} + + """, + }; + + private static string? TrimBlankLines(SourceText text) { int startLine, endLine; for (startLine = 0; startLine < text.Lines.Count; startLine++) diff --git a/src/Workspaces/Core/Portable/LinkedFileDiffMerging/DefaultDocumentTextDifferencingService.cs b/src/Workspaces/Core/Portable/LinkedFileDiffMerging/DefaultDocumentTextDifferencingService.cs index c58d86eaff7b7..80046b6b35ab8 100644 --- a/src/Workspaces/Core/Portable/LinkedFileDiffMerging/DefaultDocumentTextDifferencingService.cs +++ b/src/Workspaces/Core/Portable/LinkedFileDiffMerging/DefaultDocumentTextDifferencingService.cs @@ -27,6 +27,6 @@ public Task> GetTextChangesAsync(Document oldDocument public async Task> GetTextChangesAsync(Document oldDocument, Document newDocument, TextDifferenceTypes preferredDifferenceType, CancellationToken cancellationToken) { var changes = await newDocument.GetTextChangesAsync(oldDocument, cancellationToken).ConfigureAwait(false); - return changes.ToImmutableArray(); + return [.. changes]; } } diff --git a/src/Workspaces/Core/Portable/LinkedFileDiffMerging/IMergeConflictHandler.cs b/src/Workspaces/Core/Portable/LinkedFileDiffMerging/IMergeConflictHandler.cs deleted file mode 100644 index 14bb14633dcf3..0000000000000 --- a/src/Workspaces/Core/Portable/LinkedFileDiffMerging/IMergeConflictHandler.cs +++ /dev/null @@ -1,14 +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.Collections.Immutable; -using Microsoft.CodeAnalysis.PooledObjects; -using Microsoft.CodeAnalysis.Text; - -namespace Microsoft.CodeAnalysis; - -internal interface IMergeConflictHandler -{ - ImmutableArray CreateEdits(SourceText originalSourceText, ArrayBuilder unmergedChanges); -} diff --git a/src/Workspaces/Core/Portable/LinkedFileDiffMerging/LinkedFileDiffMergingSession.cs b/src/Workspaces/Core/Portable/LinkedFileDiffMerging/LinkedFileDiffMergingSession.cs index f55837400141f..be368ac9acf9a 100644 --- a/src/Workspaces/Core/Portable/LinkedFileDiffMerging/LinkedFileDiffMergingSession.cs +++ b/src/Workspaces/Core/Portable/LinkedFileDiffMerging/LinkedFileDiffMergingSession.cs @@ -18,7 +18,7 @@ namespace Microsoft.CodeAnalysis; internal sealed class LinkedFileDiffMergingSession(Solution oldSolution, Solution newSolution, SolutionChanges solutionChanges) { - internal async Task MergeDiffsAsync(IMergeConflictHandler? mergeConflictHandler, CancellationToken cancellationToken) + internal async Task MergeDiffsAsync(CancellationToken cancellationToken) { using var _1 = PooledDictionary.GetInstance(out var filePathToNewDocumentsAndHashes); try @@ -71,7 +71,7 @@ internal async Task MergeDiffsAsync(IMergeConflict else { // Otherwise, merge the changes and set all the linked files to that merged content. - var mergeGroupResult = await MergeLinkedDocumentGroupAsync(newDocumentsAndHashes, mergeConflictHandler, cancellationToken).ConfigureAwait(false); + var mergeGroupResult = await MergeLinkedDocumentGroupAsync(newDocumentsAndHashes, cancellationToken).ConfigureAwait(false); linkedFileMergeResults.Add(mergeGroupResult); updatedSolution = updatedSolution.WithDocumentTexts( relatedDocuments.SelectAsArray(d => (d, mergeGroupResult.MergedSourceText))); @@ -89,7 +89,6 @@ internal async Task MergeDiffsAsync(IMergeConflict private async Task MergeLinkedDocumentGroupAsync( DocumentAndHashBuilder newDocumentsAndHashes, - IMergeConflictHandler? mergeConflictHandler, CancellationToken cancellationToken) { Contract.ThrowIfTrue(newDocumentsAndHashes.Count < 2); @@ -125,8 +124,7 @@ private async Task MergeLinkedDocumentGroupAsync( if (unmergedChanges.Count == 0) return new LinkedFileMergeResult(linkedDocuments, firstOldSourceText.WithChanges(allTextChangesAcrossLinkedFiles), []); - mergeConflictHandler ??= firstOldDocument.GetRequiredLanguageService(); - var mergeConflictTextEdits = mergeConflictHandler.CreateEdits(firstOldSourceText, unmergedChanges); + var mergeConflictTextEdits = LinkedFileMergeConflictCommentAdditionService.CreateEdits(firstOldSourceText, unmergedChanges); // Add comments in source explaining diffs that could not be merged var (allChanges, mergeConflictResolutionSpans) = MergeChangesWithMergeFailComments(allTextChangesAcrossLinkedFiles, mergeConflictTextEdits); diff --git a/src/Workspaces/Core/Portable/Notification/AbstractGlobalOperationNotificationService.cs b/src/Workspaces/Core/Portable/Notification/AbstractGlobalOperationNotificationService.cs index fd61174c9d42d..1256b2fa12588 100644 --- a/src/Workspaces/Core/Portable/Notification/AbstractGlobalOperationNotificationService.cs +++ b/src/Workspaces/Core/Portable/Notification/AbstractGlobalOperationNotificationService.cs @@ -6,6 +6,7 @@ using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Collections; using Microsoft.CodeAnalysis.Shared.TestHooks; using Roslyn.Utilities; @@ -18,15 +19,20 @@ internal abstract partial class AbstractGlobalOperationNotificationService : IGl private readonly HashSet _registrations = []; private readonly HashSet _operations = []; - private readonly TaskQueue _eventQueue; + private readonly AsyncBatchingWorkQueue _eventQueue; public event EventHandler? Started; public event EventHandler? Stopped; protected AbstractGlobalOperationNotificationService( - IAsynchronousOperationListenerProvider listenerProvider) + IAsynchronousOperationListenerProvider listenerProvider, + CancellationToken disposalToken) { - _eventQueue = new TaskQueue(listenerProvider.GetListener(FeatureAttribute.GlobalOperation), TaskScheduler.Default); + _eventQueue = new AsyncBatchingWorkQueue( + TimeSpan.Zero, + ProcessEventsAsync, + listenerProvider.GetListener(FeatureAttribute.GlobalOperation), + disposalToken); } ~AbstractGlobalOperationNotificationService() @@ -38,18 +44,15 @@ protected AbstractGlobalOperationNotificationService( } } - private void RaiseGlobalOperationStarted() + private ValueTask ProcessEventsAsync(ImmutableSegmentedList list, CancellationToken cancellationToken) { - var started = this.Started; - if (started != null) - _eventQueue.ScheduleTask(nameof(RaiseGlobalOperationStarted), () => this.Started?.Invoke(this, EventArgs.Empty), CancellationToken.None); - } + foreach (var value in list) + { + var eventHandler = value ? Started : Stopped; + eventHandler?.Invoke(this, EventArgs.Empty); + } - private void RaiseGlobalOperationStopped() - { - var stopped = this.Stopped; - if (stopped != null) - _eventQueue.ScheduleTask(nameof(RaiseGlobalOperationStopped), () => this.Stopped?.Invoke(this, EventArgs.Empty), CancellationToken.None); + return ValueTaskFactory.CompletedTask; } public IDisposable Start(string operation) @@ -67,7 +70,7 @@ public IDisposable Start(string operation) if (_registrations.Count == 1) { Contract.ThrowIfFalse(_operations.Count == 1); - RaiseGlobalOperationStarted(); + _eventQueue.AddWork(true); } return registration; @@ -84,7 +87,7 @@ private void Done(GlobalOperationRegistration registration) if (_registrations.Count == 0) { _operations.Clear(); - RaiseGlobalOperationStopped(); + _eventQueue.AddWork(false); } } } diff --git a/src/Workspaces/Core/Portable/ObsoleteSymbol/AbstractObsoleteSymbolService.cs b/src/Workspaces/Core/Portable/ObsoleteSymbol/AbstractObsoleteSymbolService.cs index b5a946e686453..9afa1424cb332 100644 --- a/src/Workspaces/Core/Portable/ObsoleteSymbol/AbstractObsoleteSymbolService.cs +++ b/src/Workspaces/Core/Portable/ObsoleteSymbol/AbstractObsoleteSymbolService.cs @@ -46,7 +46,7 @@ public async Task> GetLocationsAsync(Document document, } if (result is null) - return ImmutableArray.Empty; + return []; result.RemoveDuplicates(); return result.ToImmutableAndClear(); diff --git a/src/Workspaces/Core/Portable/Options/GlobalOptionService.cs b/src/Workspaces/Core/Portable/Options/GlobalOptionService.cs index e3b8e60784b30..4418710c0c9a0 100644 --- a/src/Workspaces/Core/Portable/Options/GlobalOptionService.cs +++ b/src/Workspaces/Core/Portable/Options/GlobalOptionService.cs @@ -24,7 +24,7 @@ internal sealed class GlobalOptionService( [Import(AllowDefault = true)] IWorkspaceThreadingService? workspaceThreadingService, [ImportMany] IEnumerable> optionPersisters) : IGlobalOptionService { - private readonly ImmutableArray> _optionPersisterProviders = optionPersisters.ToImmutableArray(); + private readonly ImmutableArray> _optionPersisterProviders = [.. optionPersisters]; private readonly object _gate = new(); diff --git a/src/Workspaces/Core/Portable/Options/Option.cs b/src/Workspaces/Core/Portable/Options/Option.cs index 697908238fbde..e6a7bab492d7b 100644 --- a/src/Workspaces/Core/Portable/Options/Option.cs +++ b/src/Workspaces/Core/Portable/Options/Option.cs @@ -51,7 +51,7 @@ public Option(string feature, string name, T defaultValue, params OptionStorageL name ?? throw new ArgumentNullException(nameof(name)), OptionGroup.Default, defaultValue, - PublicContract.RequireNonNullItems(storageLocations, nameof(storageLocations)).ToImmutableArray(), + [.. PublicContract.RequireNonNullItems(storageLocations, nameof(storageLocations))], storageMapping: null, isEditorConfigOption: false) { diff --git a/src/Workspaces/Core/Portable/Options/OptionKey.cs b/src/Workspaces/Core/Portable/Options/OptionKey.cs index cf04d3e5781a4..f0e20986fe191 100644 --- a/src/Workspaces/Core/Portable/Options/OptionKey.cs +++ b/src/Workspaces/Core/Portable/Options/OptionKey.cs @@ -26,12 +26,12 @@ public OptionKey(IOption option, string? language = null) if (language != null && !option.IsPerLanguage) { - throw new ArgumentException(WorkspacesResources.A_language_name_cannot_be_specified_for_this_option); + throw new ArgumentException(CompilerExtensionsResources.A_language_name_cannot_be_specified_for_this_option); } if (language == null && option.IsPerLanguage) { - throw new ArgumentNullException(WorkspacesResources.A_language_name_must_be_specified_for_this_option); + throw new ArgumentNullException(CompilerExtensionsResources.A_language_name_must_be_specified_for_this_option); } Option = option; diff --git a/src/Workspaces/Core/Portable/Options/PerLanguageOption.cs b/src/Workspaces/Core/Portable/Options/PerLanguageOption.cs index 68c9864da0e14..d41c3ef0932e5 100644 --- a/src/Workspaces/Core/Portable/Options/PerLanguageOption.cs +++ b/src/Workspaces/Core/Portable/Options/PerLanguageOption.cs @@ -43,7 +43,7 @@ public PerLanguageOption(string feature, string name, T defaultValue, params Opt OptionGroup.Default, name ?? throw new ArgumentNullException(nameof(name)), defaultValue, - PublicContract.RequireNonNullItems(storageLocations, nameof(storageLocations)).ToImmutableArray(), + [.. PublicContract.RequireNonNullItems(storageLocations, nameof(storageLocations))], storageMapping: null, isEditorConfigOption: false) { diff --git a/src/Workspaces/Core/Portable/PatternMatching/ContainerPatternMatcher.cs b/src/Workspaces/Core/Portable/PatternMatching/ContainerPatternMatcher.cs index 5a9e12292c520..3e3100f55177b 100644 --- a/src/Workspaces/Core/Portable/PatternMatching/ContainerPatternMatcher.cs +++ b/src/Workspaces/Core/Portable/PatternMatching/ContainerPatternMatcher.cs @@ -25,9 +25,7 @@ public ContainerPatternMatcher( { _containerSplitCharacters = containerSplitCharacters; - _patternSegments = patternParts - .Select(text => new PatternSegment(text.Trim(), allowFuzzyMatching: allowFuzzyMatching)) - .ToArray(); + _patternSegments = [.. patternParts.Select(text => new PatternSegment(text.Trim(), allowFuzzyMatching: allowFuzzyMatching))]; _invalidPattern = _patternSegments.Length == 0 || _patternSegments.Any(s => s.IsInvalid); } diff --git a/src/Workspaces/Core/Portable/PublicAPI.Unshipped.txt b/src/Workspaces/Core/Portable/PublicAPI.Unshipped.txt index e93f8fd874de1..8de73f47e1af4 100644 --- a/src/Workspaces/Core/Portable/PublicAPI.Unshipped.txt +++ b/src/Workspaces/Core/Portable/PublicAPI.Unshipped.txt @@ -1,5 +1,20 @@ +*REMOVED*Microsoft.CodeAnalysis.CodeStyle.CodeStyleOptions.CodeStyleOptions() -> void +*REMOVED*abstract Microsoft.CodeAnalysis.Editing.SyntaxGenerator.BitwiseOrExpression(Microsoft.CodeAnalysis.SyntaxNode left, Microsoft.CodeAnalysis.SyntaxNode right) -> Microsoft.CodeAnalysis.SyntaxNode +*REMOVED*abstract Microsoft.CodeAnalysis.Editing.SyntaxGenerator.CastExpression(Microsoft.CodeAnalysis.SyntaxNode type, Microsoft.CodeAnalysis.SyntaxNode expression) -> Microsoft.CodeAnalysis.SyntaxNode +*REMOVED*abstract Microsoft.CodeAnalysis.Editing.SyntaxGenerator.ConvertExpression(Microsoft.CodeAnalysis.SyntaxNode type, Microsoft.CodeAnalysis.SyntaxNode expression) -> Microsoft.CodeAnalysis.SyntaxNode +*REMOVED*abstract Microsoft.CodeAnalysis.Editing.SyntaxGenerator.DefaultExpression(Microsoft.CodeAnalysis.ITypeSymbol type) -> Microsoft.CodeAnalysis.SyntaxNode +*REMOVED*abstract Microsoft.CodeAnalysis.Editing.SyntaxGenerator.DefaultExpression(Microsoft.CodeAnalysis.SyntaxNode type) -> Microsoft.CodeAnalysis.SyntaxNode +*REMOVED*abstract Microsoft.CodeAnalysis.Editing.SyntaxGenerator.IdentifierName(string identifier) -> Microsoft.CodeAnalysis.SyntaxNode +*REMOVED*virtual Microsoft.CodeAnalysis.Editing.SyntaxGenerator.MemberAccessExpression(Microsoft.CodeAnalysis.SyntaxNode expression, Microsoft.CodeAnalysis.SyntaxNode memberName) -> Microsoft.CodeAnalysis.SyntaxNode Microsoft.CodeAnalysis.CompilationOutputInfo.GeneratedFilesOutputDirectory.get -> string Microsoft.CodeAnalysis.CompilationOutputInfo.WithGeneratedFilesOutputDirectory(string path) -> Microsoft.CodeAnalysis.CompilationOutputInfo +Microsoft.CodeAnalysis.Editing.SyntaxGenerator.BitwiseOrExpression(Microsoft.CodeAnalysis.SyntaxNode left, Microsoft.CodeAnalysis.SyntaxNode right) -> Microsoft.CodeAnalysis.SyntaxNode +Microsoft.CodeAnalysis.Editing.SyntaxGenerator.CastExpression(Microsoft.CodeAnalysis.SyntaxNode type, Microsoft.CodeAnalysis.SyntaxNode expression) -> Microsoft.CodeAnalysis.SyntaxNode +Microsoft.CodeAnalysis.Editing.SyntaxGenerator.ConvertExpression(Microsoft.CodeAnalysis.SyntaxNode type, Microsoft.CodeAnalysis.SyntaxNode expression) -> Microsoft.CodeAnalysis.SyntaxNode +Microsoft.CodeAnalysis.Editing.SyntaxGenerator.DefaultExpression(Microsoft.CodeAnalysis.ITypeSymbol type) -> Microsoft.CodeAnalysis.SyntaxNode +Microsoft.CodeAnalysis.Editing.SyntaxGenerator.DefaultExpression(Microsoft.CodeAnalysis.SyntaxNode type) -> Microsoft.CodeAnalysis.SyntaxNode +Microsoft.CodeAnalysis.Editing.SyntaxGenerator.IdentifierName(string identifier) -> Microsoft.CodeAnalysis.SyntaxNode +Microsoft.CodeAnalysis.Editing.SyntaxGenerator.MemberAccessExpression(Microsoft.CodeAnalysis.SyntaxNode expression, Microsoft.CodeAnalysis.SyntaxNode memberName) -> Microsoft.CodeAnalysis.SyntaxNode Microsoft.CodeAnalysis.Project.HostAnalyzerOptions.get -> Microsoft.CodeAnalysis.Diagnostics.AnalyzerOptions Microsoft.CodeAnalysis.ProjectInfo.WithId(Microsoft.CodeAnalysis.ProjectId id) -> Microsoft.CodeAnalysis.ProjectInfo virtual Microsoft.CodeAnalysis.Host.HostLanguageServices.Dispose() -> void diff --git a/src/Workspaces/Core/Portable/Recommendations/AbstractRecommendationServiceRunner.cs b/src/Workspaces/Core/Portable/Recommendations/AbstractRecommendationServiceRunner.cs index b861712b760b8..46e89766482bf 100644 --- a/src/Workspaces/Core/Portable/Recommendations/AbstractRecommendationServiceRunner.cs +++ b/src/Workspaces/Core/Portable/Recommendations/AbstractRecommendationServiceRunner.cs @@ -528,6 +528,6 @@ static bool MatchesAnyBaseTypes(ITypeSymbol source, ITypeSymbol matched) protected static ImmutableArray SuppressDefaultTupleElements(INamespaceOrTypeSymbol container, ImmutableArray symbols) => container is not INamedTypeSymbol { IsTupleType: true } namedType ? symbols - : symbols.Where(s => s is not IFieldSymbol).Concat(namedType.TupleElements).ToImmutableArray(); + : [.. symbols.Where(s => s is not IFieldSymbol), .. namedType.TupleElements]; } } diff --git a/src/Workspaces/Core/Portable/Remote/RemoteArguments.cs b/src/Workspaces/Core/Portable/Remote/RemoteArguments.cs index 12be8476d9a86..a3929b872e3ed 100644 --- a/src/Workspaces/Core/Portable/Remote/RemoteArguments.cs +++ b/src/Workspaces/Core/Portable/Remote/RemoteArguments.cs @@ -201,7 +201,7 @@ public async ValueTask RehydrateAsync( internal sealed class SerializableSymbolGroup(HashSet symbols) : IEquatable { [DataMember(Order = 0)] - public readonly HashSet Symbols = new HashSet(symbols); + public readonly HashSet Symbols = [.. symbols]; private int _hashCode; @@ -234,8 +234,7 @@ public override int GetHashCode() public static SerializableSymbolGroup Dehydrate(Solution solution, SymbolGroup group, CancellationToken cancellationToken) { - return new SerializableSymbolGroup(new HashSet( - group.Symbols.Select(s => SerializableSymbolAndProjectId.Dehydrate(solution, s, cancellationToken)))); + return new SerializableSymbolGroup([.. group.Symbols.Select(s => SerializableSymbolAndProjectId.Dehydrate(solution, s, cancellationToken))]); } } diff --git a/src/Workspaces/Core/Portable/Rename/ConflictEngine/ConflictResolver.Session.cs b/src/Workspaces/Core/Portable/Rename/ConflictEngine/ConflictResolver.Session.cs index 7b56473fc7564..ed62b06e69b62 100644 --- a/src/Workspaces/Core/Portable/Rename/ConflictEngine/ConflictResolver.Session.cs +++ b/src/Workspaces/Core/Portable/Rename/ConflictEngine/ConflictResolver.Session.cs @@ -159,10 +159,9 @@ public async Task ResolveConflictsAsync() { Contract.ThrowIfTrue(conflictLocations.Count != 0, "We're the first phase, so we should have no conflict locations yet"); - conflictLocations = conflictResolution.RelatedLocations + conflictLocations = [.. conflictResolution.RelatedLocations .Where(loc => documentIdsThatGetsAnnotatedAndRenamed.Contains(loc.DocumentId) && loc.Type == RelatedLocationType.PossiblyResolvableConflict && loc.IsReference) - .Select(loc => new ConflictLocationInfo(loc)) - .ToImmutableHashSet(); + .Select(loc => new ConflictLocationInfo(loc))]; // If there were no conflicting locations in references, then the first conflict phase has to be skipped. if (conflictLocations.Count == 0) @@ -184,7 +183,7 @@ .. conflictResolution.RelatedLocations // Set the documents with conflicts that need to be processed in the next phase. // Note that we need to get the conflictLocations here since we're going to remove some locations below if phase == 2 - documentIdsThatGetsAnnotatedAndRenamed = new HashSet(conflictLocations.Select(l => l.DocumentId)); + documentIdsThatGetsAnnotatedAndRenamed = [.. conflictLocations.Select(l => l.DocumentId)]; if (phase == 2) { @@ -193,9 +192,7 @@ .. conflictResolution.RelatedLocations .Where(l => (l.Type & RelatedLocationType.UnresolvedConflict) != 0) .Select(l => Tuple.Create(l.ComplexifiedTargetSpan, l.DocumentId)).Distinct(); - conflictLocations = conflictLocations - .Where(l => !unresolvedLocations.Any(c => c.Item2 == l.DocumentId && c.Item1.Contains(l.OriginalIdentifierSpan))) - .ToImmutableHashSet(); + conflictLocations = [.. conflictLocations.Where(l => !unresolvedLocations.Any(c => c.Item2 == l.DocumentId && c.Item1.Contains(l.OriginalIdentifierSpan)))]; } // Clean up side effects from rename before entering the next phase @@ -475,8 +472,7 @@ await AddDeclarationConflictsAsync( return null; var compilation = await currentProject.GetRequiredCompilationAsync(_cancellationToken).ConfigureAwait(false); - return ImmutableHashSet.CreateRange( - _nonConflictSymbolKeys.Select(s => s.Resolve(compilation).GetAnySymbol()).WhereNotNull()); + return [.. _nonConflictSymbolKeys.Select(s => s.Resolve(compilation).GetAnySymbol()).WhereNotNull()]; } private static bool IsConflictFreeChange( @@ -539,8 +535,11 @@ private async Task CheckForConflictAsync( hasConflict = true; - var newLocationTasks = newReferencedSymbols.Select(async symbol => await GetSymbolLocationAsync(solution, symbol, _cancellationToken).ConfigureAwait(false)); - var newLocations = (await Task.WhenAll(newLocationTasks).ConfigureAwait(false)).WhereNotNull().Where(loc => loc.IsInSource); + var newLocations = newReferencedSymbols + .Select(symbol => GetSymbolLocation(solution, symbol, _cancellationToken)) + .WhereNotNull() + .Where(loc => loc.IsInSource) + .ToArray(); foreach (var originalReference in conflictAnnotation.RenameDeclarationLocationReferences.Where(loc => loc.IsSourceLocation)) { var adjustedStartPosition = conflictResolution.GetAdjustedTokenStartingPosition(originalReference.TextSpan.Start, originalReference.DocumentId); @@ -581,8 +580,7 @@ private async Task CheckForConflictAsync( break; } - var newLocation = await GetSymbolLocationAsync(solution, symbol, _cancellationToken).ConfigureAwait(false); - + var newLocation = GetSymbolLocation(solution, symbol, _cancellationToken); if (newLocation != null && conflictAnnotation.RenameDeclarationLocationReferences[symbolIndex].IsSourceLocation) { // location was in source before, but not after rename diff --git a/src/Workspaces/Core/Portable/Rename/ConflictEngine/ConflictResolver.cs b/src/Workspaces/Core/Portable/Rename/ConflictEngine/ConflictResolver.cs index fdbcd2a022040..8bffb26643a13 100644 --- a/src/Workspaces/Core/Portable/Rename/ConflictEngine/ConflictResolver.cs +++ b/src/Workspaces/Core/Portable/Rename/ConflictEngine/ConflictResolver.cs @@ -341,7 +341,7 @@ private static void AddConflictingSymbolLocations(IEnumerable conflicti } } - public static async Task CreateDeclarationLocationAnnotationsAsync( + public static RenameDeclarationLocationReference[] CreateDeclarationLocationAnnotations( Solution solution, IEnumerable symbols, CancellationToken cancellationToken) @@ -360,12 +360,12 @@ public static async Task CreateDeclaration if (overriddenSymbol != null) { - overriddenSymbol = await SymbolFinder.FindSourceDefinitionAsync(overriddenSymbol, solution, cancellationToken).ConfigureAwait(false); + overriddenSymbol = SymbolFinder.FindSourceDefinition(overriddenSymbol, solution, cancellationToken); overriddenFromMetadata = overriddenSymbol == null || overriddenSymbol.Locations.All(loc => loc.IsInMetadata); } } - var location = await GetSymbolLocationAsync(solution, symbol, cancellationToken).ConfigureAwait(false); + var location = GetSymbolLocation(solution, symbol, cancellationToken); if (location != null && location.IsInSource) { renameDeclarationLocations[symbolIndex] = new RenameDeclarationLocationReference(solution.GetDocumentId(location.SourceTree), location.SourceSpan, overriddenFromMetadata, locations.Length); @@ -398,15 +398,13 @@ private static string GetString(ISymbol symbol) /// /// Gives the First Location for a given Symbol by ordering the locations using DocumentId first and Location starting position second /// - private static async Task GetSymbolLocationAsync(Solution solution, ISymbol symbol, CancellationToken cancellationToken) + private static Location? GetSymbolLocation(Solution solution, ISymbol symbol, CancellationToken cancellationToken) { var locations = symbol.Locations; - var originalsourcesymbol = await SymbolFinder.FindSourceDefinitionAsync(symbol, solution, cancellationToken).ConfigureAwait(false); + var originalsourcesymbol = SymbolFinder.FindSourceDefinition(symbol, solution, cancellationToken); if (originalsourcesymbol != null) - { locations = originalsourcesymbol.Locations; - } var orderedLocations = locations .OrderBy(l => l.IsInSource ? solution.GetDocumentId(l.SourceTree)!.Id : Guid.Empty) diff --git a/src/Workspaces/Core/Portable/Rename/ConflictEngine/MutableConflictResolution.cs b/src/Workspaces/Core/Portable/Rename/ConflictEngine/MutableConflictResolution.cs index 61ccd36af02b5..640060742c13f 100644 --- a/src/Workspaces/Core/Portable/Rename/ConflictEngine/MutableConflictResolution.cs +++ b/src/Workspaces/Core/Portable/Rename/ConflictEngine/MutableConflictResolution.cs @@ -77,9 +77,9 @@ internal async Task RemoveAllRenameAnnotationsAsync( // the "updated" node to maintain any annotation removals from descendants. var newRoot = root.ReplaceSyntax( nodes: annotationSet.GetAnnotatedNodes(root), - computeReplacementNode: (original, updated) => annotationSet.WithoutAnnotations(updated, annotationSet.GetAnnotations(updated).ToArray()), + computeReplacementNode: (original, updated) => annotationSet.WithoutAnnotations(updated, [.. annotationSet.GetAnnotations(updated)]), tokens: annotationSet.GetAnnotatedTokens(root), - computeReplacementToken: (original, updated) => annotationSet.WithoutAnnotations(updated, annotationSet.GetAnnotations(updated).ToArray()), + computeReplacementToken: (original, updated) => annotationSet.WithoutAnnotations(updated, [.. annotationSet.GetAnnotations(updated)]), trivia: [], computeReplacementTrivia: null); diff --git a/src/Workspaces/Core/Portable/Rename/ConflictResolution.cs b/src/Workspaces/Core/Portable/Rename/ConflictResolution.cs index 397bce57d22a8..19a75f47e2218 100644 --- a/src/Workspaces/Core/Portable/Rename/ConflictResolution.cs +++ b/src/Workspaces/Core/Portable/Rename/ConflictResolution.cs @@ -98,7 +98,7 @@ public ConflictResolution( public ImmutableArray<(TextSpan oldSpan, TextSpan newSpan)> GetComplexifiedSpans(DocumentId documentId) => _documentToComplexifiedSpansMap.TryGetValue(documentId, out var complexifiedSpans) ? complexifiedSpans.SelectAsArray(c => (c.OriginalSpan, c.NewSpan)) - : ImmutableArray<(TextSpan oldSpan, TextSpan newSpan)>.Empty; + : []; public ImmutableDictionary GetModifiedSpanMap(DocumentId documentId) { diff --git a/src/Workspaces/Core/Portable/Rename/RenameUtilities.cs b/src/Workspaces/Core/Portable/Rename/RenameUtilities.cs index 20b22fff40bf7..def784de0012b 100644 --- a/src/Workspaces/Core/Portable/Rename/RenameUtilities.cs +++ b/src/Workspaces/Core/Portable/Rename/RenameUtilities.cs @@ -211,19 +211,15 @@ public static IEnumerable GetOverloadedSymbols(ISymbol symbol) ISymbol symbol, Solution solution, CancellationToken cancellationToken) { if (symbol.IsPropertyAccessor()) - { return ((IMethodSymbol)symbol).AssociatedSymbol; - } if (symbol.IsOverride && symbol.GetOverriddenMember() != null) { - var originalSourceSymbol = await SymbolFinder.FindSourceDefinitionAsync( - symbol.GetOverriddenMember(), solution, cancellationToken).ConfigureAwait(false); + var originalSourceSymbol = SymbolFinder.FindSourceDefinition( + symbol.GetOverriddenMember(), solution, cancellationToken); if (originalSourceSymbol != null) - { return await TryGetPropertyFromAccessorOrAnOverrideAsync(originalSourceSymbol, solution, cancellationToken).ConfigureAwait(false); - } } if (symbol.Kind == SymbolKind.Method && @@ -236,9 +232,7 @@ public static IEnumerable GetOverloadedSymbols(ISymbol symbol) { var propertyAccessorOrAnOverride = await TryGetPropertyFromAccessorOrAnOverrideAsync(methodImplementor, solution, cancellationToken).ConfigureAwait(false); if (propertyAccessorOrAnOverride != null) - { return propertyAccessorOrAnOverride; - } } } @@ -325,8 +319,8 @@ public static async Task FindDefinitionSymbolAsync( Contract.ThrowIfNull(solution); // Make sure we're on the original source definition if we can be - var foundSymbol = await SymbolFinder.FindSourceDefinitionAsync( - symbol, solution, cancellationToken).ConfigureAwait(false); + var foundSymbol = SymbolFinder.FindSourceDefinition( + symbol, solution, cancellationToken); var bestSymbol = foundSymbol ?? symbol; symbol = bestSymbol; @@ -384,7 +378,7 @@ MethodKind.StaticConstructor or } // in case this is e.g. an overridden property accessor, we'll treat the property itself as the definition symbol - var property = await RenameUtilities.TryGetPropertyFromAccessorOrAnOverrideAsync(bestSymbol, solution, cancellationToken).ConfigureAwait(false); + var property = await TryGetPropertyFromAccessorOrAnOverrideAsync(bestSymbol, solution, cancellationToken).ConfigureAwait(false); return property ?? bestSymbol; } diff --git a/src/Workspaces/Core/Portable/Serialization/AbstractOptionsSerializationService.cs b/src/Workspaces/Core/Portable/Serialization/AbstractOptionsSerializationService.cs index ef1ff19c1258e..3bc9a229e7357 100644 --- a/src/Workspaces/Core/Portable/Serialization/AbstractOptionsSerializationService.cs +++ b/src/Workspaces/Core/Portable/Serialization/AbstractOptionsSerializationService.cs @@ -159,7 +159,7 @@ protected static ( var xmlReferenceResolver = XmlFileResolver.Default; var sourceReferenceResolver = SourceFileResolver.Default; var assemblyIdentityComparer = DesktopAssemblyIdentityComparer.Default; - var strongNameProvider = new DesktopStrongNameProvider(ImmutableArray.Empty, Path.GetTempPath()); + var strongNameProvider = new DesktopStrongNameProvider([], Path.GetTempPath()); return ( outputKind, diff --git a/src/Workspaces/Core/Portable/Shared/Extensions/IFindReferencesResultExtensions.cs b/src/Workspaces/Core/Portable/Shared/Extensions/IFindReferencesResultExtensions.cs index af8456252d02c..8dd58484de661 100644 --- a/src/Workspaces/Core/Portable/Shared/Extensions/IFindReferencesResultExtensions.cs +++ b/src/Workspaces/Core/Portable/Shared/Extensions/IFindReferencesResultExtensions.cs @@ -107,7 +107,7 @@ public static ImmutableArray FilterToAliasMatches( where aliasLocations.Any() select new ReferencedSymbol(r.Definition, aliasLocations); - return q.ToImmutableArray(); + return [.. q]; } public static ImmutableArray FilterNonMatchingMethodNames( diff --git a/src/Workspaces/Core/Portable/Shared/Extensions/IMethodSymbolExtensions.cs b/src/Workspaces/Core/Portable/Shared/Extensions/IMethodSymbolExtensions.cs index a27788c516f15..2c72995aba362 100644 --- a/src/Workspaces/Core/Portable/Shared/Extensions/IMethodSymbolExtensions.cs +++ b/src/Workspaces/Core/Portable/Shared/Extensions/IMethodSymbolExtensions.cs @@ -84,6 +84,6 @@ public static bool CompatibleSignatureToDelegate(this IMethodSymbol method, INam // "C.Goo(int t)" (method2). p1 = method1.OriginalDefinition.Parameters; p2 = method2.OriginalDefinition.Parameters; - return p1.Select(p => p.Type).ToList().AreMoreSpecificThan(p2.Select(p => p.Type).ToList()); + return p1.Select(p => p.Type).ToList().AreMoreSpecificThan([.. p2.Select(p => p.Type)]); } } diff --git a/src/Workspaces/Core/Portable/Shared/Extensions/IParameterSymbolExtensions.cs b/src/Workspaces/Core/Portable/Shared/Extensions/IParameterSymbolExtensions.cs deleted file mode 100644 index d56f340cb57e2..0000000000000 --- a/src/Workspaces/Core/Portable/Shared/Extensions/IParameterSymbolExtensions.cs +++ /dev/null @@ -1,27 +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.Collections.Generic; -using System.Collections.Immutable; -using Microsoft.CodeAnalysis.CodeGeneration; - -namespace Microsoft.CodeAnalysis.Shared.Extensions; - -internal static partial class IParameterSymbolExtensions -{ - public static IParameterSymbol WithAttributes(this IParameterSymbol parameter, ImmutableArray attributes) - { - return parameter.GetAttributes() == attributes - ? parameter - : CodeGenerationSymbolFactory.CreateParameterSymbol( - attributes, - parameter.RefKind, - parameter.IsParams, - parameter.Type, - parameter.Name, - parameter.IsOptional, - parameter.HasExplicitDefaultValue, - parameter.HasExplicitDefaultValue ? parameter.ExplicitDefaultValue : null); - } -} diff --git a/src/Workspaces/Core/Portable/Shared/Extensions/ISymbolExtensions.cs b/src/Workspaces/Core/Portable/Shared/Extensions/ISymbolExtensions.cs index b9c122acd9dc0..aa92d60e0baa7 100644 --- a/src/Workspaces/Core/Portable/Shared/Extensions/ISymbolExtensions.cs +++ b/src/Workspaces/Core/Portable/Shared/Extensions/ISymbolExtensions.cs @@ -241,7 +241,7 @@ private static DocumentationComment GetDocumentationComment(ISymbol symbol, Hash try { var element = XElement.Parse(xmlText, LoadOptions.PreserveWhitespace); - element.ReplaceNodes(RewriteMany(symbol, visitedSymbols, compilation, element.Nodes().ToArray(), cancellationToken)); + element.ReplaceNodes(RewriteMany(symbol, visitedSymbols, compilation, [.. element.Nodes()], cancellationToken)); xmlText = element.ToString(SaveOptions.DisableFormatting); } catch (XmlException) @@ -324,7 +324,7 @@ private static XNode[] RewriteInheritdocElements(ISymbol symbol, HashSet(); var syntaxKinds = languageServices.GetRequiredService(); - if (!syntaxFacts.IsBindableToken(token)) + if (!syntaxFacts.IsBindableToken(semanticModel, token)) return TokenSemanticInfo.Empty; var semanticFacts = languageServices.GetRequiredService(); - var overriddingIdentifier = syntaxFacts.GetDeclarationIdentifierIfOverride(token); + var overridingIdentifier = syntaxFacts.GetDeclarationIdentifierIfOverride(token); IAliasSymbol? aliasSymbol = null; ITypeSymbol? type = null; @@ -97,11 +97,11 @@ public static TokenSemanticInfo GetSemanticInfo( var usingStatement = token.Parent; declaredSymbol = semanticFacts.TryGetDisposeMethod(semanticModel, tokenParent, cancellationToken); } - else if (overriddingIdentifier.HasValue) + else if (overridingIdentifier.HasValue) { // on an "override" token, we'll find the overridden symbol - var overriddingSymbol = semanticFacts.GetDeclaredSymbol(semanticModel, overriddingIdentifier.Value, cancellationToken); - var overriddenSymbol = overriddingSymbol.GetOverriddenMember(allowLooseMatch: true); + var overridingSymbol = semanticFacts.GetDeclaredSymbol(semanticModel, overridingIdentifier.Value, cancellationToken); + var overriddenSymbol = overridingSymbol.GetOverriddenMember(allowLooseMatch: true); allSymbols = overriddenSymbol is null ? [] : [overriddenSymbol]; } diff --git a/src/Workspaces/Core/Portable/Shared/Extensions/SyntaxGeneratorExtensions.cs b/src/Workspaces/Core/Portable/Shared/Extensions/SyntaxGeneratorExtensions.cs index 991cd1db6866a..d2345bb39a186 100644 --- a/src/Workspaces/Core/Portable/Shared/Extensions/SyntaxGeneratorExtensions.cs +++ b/src/Workspaces/Core/Portable/Shared/Extensions/SyntaxGeneratorExtensions.cs @@ -2,10 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System; -using System.Collections.Generic; -using System.Collections.Immutable; -using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Threading; using System.Threading.Tasks; @@ -13,8 +9,6 @@ using Microsoft.CodeAnalysis.CodeGeneration; using Microsoft.CodeAnalysis.Editing; using Microsoft.CodeAnalysis.FindSymbols; -using Microsoft.CodeAnalysis.PooledObjects; -using Microsoft.CodeAnalysis.Simplification; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Shared.Extensions; @@ -83,7 +77,7 @@ public static async Task OverridePropertyAsync( { // Call accessors directly if C# overriding VB if (document.Project.Language == LanguageNames.CSharp - && await SymbolFinder.FindSourceDefinitionAsync(overriddenProperty, document.Project.Solution, cancellationToken).ConfigureAwait(false) is { Language: LanguageNames.VisualBasic }) + && SymbolFinder.FindSourceDefinition(overriddenProperty, document.Project.Solution, cancellationToken) is { Language: LanguageNames.VisualBasic }) { var getName = overriddenProperty.GetMethod?.Name; var setName = overriddenProperty.SetMethod?.Name; diff --git a/src/Workspaces/Core/Portable/Shared/TestHooks/AsynchronousOperationListenerProvider.cs b/src/Workspaces/Core/Portable/Shared/TestHooks/AsynchronousOperationListenerProvider.cs index ed5be74296ee3..9151b056bf2ad 100644 --- a/src/Workspaces/Core/Portable/Shared/TestHooks/AsynchronousOperationListenerProvider.cs +++ b/src/Workspaces/Core/Portable/Shared/TestHooks/AsynchronousOperationListenerProvider.cs @@ -127,7 +127,7 @@ public async Task WaitAllAsync(Workspace? workspace, string[]? featureNames = nu while (true) { var waiters = GetCandidateWaiters(featureNames); - tasks = waiters.Select(x => x.ExpeditedWaitAsync()).Where(t => !t.IsCompleted).ToList(); + tasks = [.. waiters.Select(x => x.ExpeditedWaitAsync()).Where(t => !t.IsCompleted)]; if (remoteHostClient is not null) { @@ -195,7 +195,7 @@ public bool HasPendingWaiter(params string[] featureNames) /// Get all saved DiagnosticAsyncToken to investigate tests failure easier /// public List GetTokens() - => _singletonListeners.Values.Where(l => l.TrackActiveTokens).SelectMany(l => l.ActiveDiagnosticTokens).ToList(); + => [.. _singletonListeners.Values.Where(l => l.TrackActiveTokens).SelectMany(l => l.ActiveDiagnosticTokens)]; internal static bool IsEnabled { diff --git a/src/Workspaces/Core/Portable/Shared/TestHooks/TaskExtensions.cs b/src/Workspaces/Core/Portable/Shared/TestHooks/TaskExtensions.cs index 6b631dc40dece..5db50f3c9a6a9 100644 --- a/src/Workspaces/Core/Portable/Shared/TestHooks/TaskExtensions.cs +++ b/src/Workspaces/Core/Portable/Shared/TestHooks/TaskExtensions.cs @@ -36,13 +36,12 @@ public static Task CompletesTrackingOperation(this Task task, IDisposable token) return CompletesTrackingOperationSlow(task, token); - static Task CompletesTrackingOperationSlow(Task task, IDisposable token) + static async Task CompletesTrackingOperationSlow(Task task, IDisposable token) { - return task.SafeContinueWith( - t => token.Dispose(), - CancellationToken.None, - TaskContinuationOptions.ExecuteSynchronously, - TaskScheduler.Default); + using (token) + { + await task.NoThrowAwaitableInternal(captureContext: false); + } } } } diff --git a/src/Workspaces/Core/Portable/SolutionCrawler/InvocationReasons.cs b/src/Workspaces/Core/Portable/SolutionCrawler/InvocationReasons.cs index a18425e14fc90..f088ea363aab5 100644 --- a/src/Workspaces/Core/Portable/SolutionCrawler/InvocationReasons.cs +++ b/src/Workspaces/Core/Portable/SolutionCrawler/InvocationReasons.cs @@ -12,13 +12,13 @@ namespace Microsoft.CodeAnalysis.SolutionCrawler; [DataContract] internal partial struct InvocationReasons(ImmutableHashSet reasons) : IEnumerable { - public static readonly InvocationReasons Empty = new(ImmutableHashSet.Empty); + public static readonly InvocationReasons Empty = new([]); [DataMember(Order = 0)] private readonly ImmutableHashSet _reasons = reasons ?? []; public InvocationReasons(string reason) - : this(ImmutableHashSet.Create(reason)) + : this([reason]) { } diff --git a/src/Workspaces/Core/Portable/SolutionCrawler/InvocationReasons_Constants.cs b/src/Workspaces/Core/Portable/SolutionCrawler/InvocationReasons_Constants.cs index 2a0e133427317..31c3ecc9163ef 100644 --- a/src/Workspaces/Core/Portable/SolutionCrawler/InvocationReasons_Constants.cs +++ b/src/Workspaces/Core/Portable/SolutionCrawler/InvocationReasons_Constants.cs @@ -12,72 +12,64 @@ internal readonly partial struct InvocationReasons { public static readonly InvocationReasons DocumentAdded = new( - ImmutableHashSet.Create( - PredefinedInvocationReasons.DocumentAdded, - PredefinedInvocationReasons.SyntaxChanged, - PredefinedInvocationReasons.SemanticChanged)); + [ + PredefinedInvocationReasons.DocumentAdded, + PredefinedInvocationReasons.SyntaxChanged, + PredefinedInvocationReasons.SemanticChanged, + ]); public static readonly InvocationReasons DocumentRemoved = new( - ImmutableHashSet.Create( - PredefinedInvocationReasons.DocumentRemoved, - PredefinedInvocationReasons.SyntaxChanged, - PredefinedInvocationReasons.SemanticChanged, - PredefinedInvocationReasons.HighPriority)); + [ + PredefinedInvocationReasons.DocumentRemoved, + PredefinedInvocationReasons.SyntaxChanged, + PredefinedInvocationReasons.SemanticChanged, + PredefinedInvocationReasons.HighPriority, + ]); public static readonly InvocationReasons ProjectParseOptionChanged = new( - ImmutableHashSet.Create( - PredefinedInvocationReasons.ProjectParseOptionsChanged, - PredefinedInvocationReasons.SyntaxChanged, - PredefinedInvocationReasons.SemanticChanged)); + [ + PredefinedInvocationReasons.ProjectParseOptionsChanged, + PredefinedInvocationReasons.SyntaxChanged, + PredefinedInvocationReasons.SemanticChanged, + ]); public static readonly InvocationReasons ProjectConfigurationChanged = new( - ImmutableHashSet.Create( - PredefinedInvocationReasons.ProjectConfigurationChanged, - PredefinedInvocationReasons.SyntaxChanged, - PredefinedInvocationReasons.SemanticChanged)); + [ + PredefinedInvocationReasons.ProjectConfigurationChanged, + PredefinedInvocationReasons.SyntaxChanged, + PredefinedInvocationReasons.SemanticChanged, + ]); public static readonly InvocationReasons SolutionRemoved = new( - ImmutableHashSet.Create( - PredefinedInvocationReasons.SolutionRemoved, - PredefinedInvocationReasons.DocumentRemoved)); + [PredefinedInvocationReasons.SolutionRemoved, PredefinedInvocationReasons.DocumentRemoved]); public static readonly InvocationReasons DocumentOpened = new( - ImmutableHashSet.Create( - PredefinedInvocationReasons.DocumentOpened, - PredefinedInvocationReasons.HighPriority)); + [PredefinedInvocationReasons.DocumentOpened, PredefinedInvocationReasons.HighPriority]); public static readonly InvocationReasons DocumentClosed = new( - ImmutableHashSet.Create( - PredefinedInvocationReasons.DocumentClosed, - PredefinedInvocationReasons.HighPriority)); + [PredefinedInvocationReasons.DocumentClosed, PredefinedInvocationReasons.HighPriority]); public static readonly InvocationReasons DocumentChanged = new( - ImmutableHashSet.Create( - PredefinedInvocationReasons.SyntaxChanged, - PredefinedInvocationReasons.SemanticChanged)); + [PredefinedInvocationReasons.SyntaxChanged, PredefinedInvocationReasons.SemanticChanged]); public static readonly InvocationReasons AdditionalDocumentChanged = new( - ImmutableHashSet.Create( - PredefinedInvocationReasons.SyntaxChanged, - PredefinedInvocationReasons.SemanticChanged)); + [PredefinedInvocationReasons.SyntaxChanged, PredefinedInvocationReasons.SemanticChanged]); public static readonly InvocationReasons SyntaxChanged = new( - ImmutableHashSet.Create( - PredefinedInvocationReasons.SyntaxChanged)); + [PredefinedInvocationReasons.SyntaxChanged]); public static readonly InvocationReasons SemanticChanged = new( - ImmutableHashSet.Create( - PredefinedInvocationReasons.SemanticChanged)); + [PredefinedInvocationReasons.SemanticChanged]); public static readonly InvocationReasons Reanalyze = new(PredefinedInvocationReasons.Reanalyze); diff --git a/src/Workspaces/Core/Portable/SymbolSearch/IRemoteSymbolSearchUpdateEngine.cs b/src/Workspaces/Core/Portable/SymbolSearch/IRemoteSymbolSearchUpdateEngine.cs index f9d2ad46c64af..8bf1ad05301c0 100644 --- a/src/Workspaces/Core/Portable/SymbolSearch/IRemoteSymbolSearchUpdateEngine.cs +++ b/src/Workspaces/Core/Portable/SymbolSearch/IRemoteSymbolSearchUpdateEngine.cs @@ -11,7 +11,7 @@ namespace Microsoft.CodeAnalysis.SymbolSearch; internal interface IRemoteSymbolSearchUpdateService { ValueTask UpdateContinuouslyAsync(string sourceName, string localSettingsDirectory, CancellationToken cancellationToken); - ValueTask> FindPackagesWithTypeAsync(string source, string name, int arity, CancellationToken cancellationToken); + ValueTask> FindPackagesAsync(string source, TypeQuery typeQuery, NamespaceQuery namespaceQuery, CancellationToken cancellationToken); ValueTask> FindPackagesWithAssemblyAsync(string source, string name, CancellationToken cancellationToken); - ValueTask> FindReferenceAssembliesWithTypeAsync(string name, int arity, CancellationToken cancellationToken); + ValueTask> FindReferenceAssembliesAsync(TypeQuery typeQuery, NamespaceQuery namespaceQuery, CancellationToken cancellationToken); } diff --git a/src/Workspaces/Core/Portable/SymbolSearch/ISymbolSearchService.cs b/src/Workspaces/Core/Portable/SymbolSearch/ISymbolSearchService.cs index a9108466d1866..c1714d80fee7e 100644 --- a/src/Workspaces/Core/Portable/SymbolSearch/ISymbolSearchService.cs +++ b/src/Workspaces/Core/Portable/SymbolSearch/ISymbolSearchService.cs @@ -14,27 +14,51 @@ namespace Microsoft.CodeAnalysis.SymbolSearch; +/// The roslyn simple name of the type to search for. For example +/// would have the name ImmutableArray +/// The arity of the type. For example would have arity +/// 1. +[DataContract] +internal readonly record struct TypeQuery( + [property: DataMember(Order = 0)] string Name, + [property: DataMember(Order = 1)] int Arity) +{ + public static readonly TypeQuery Default = default; + + public bool IsDefault => string.IsNullOrEmpty(Name); +} + +/// The names comprising the namespace being searched for. For example ["System", "Collections", +/// "Immutable"]. +[DataContract] +internal readonly record struct NamespaceQuery( + [property: DataMember(Order = 0)] ImmutableArray Names) +{ + public static readonly NamespaceQuery Default = default; + + public static implicit operator NamespaceQuery(ImmutableArray names) + => new(names); + + public bool IsDefault => Names.IsDefaultOrEmpty; +} + internal interface ISymbolSearchService : IWorkspaceService { /// - /// Searches for packages that contain a type with the provided name and arity. - /// Note: Implementations are free to return the results they feel best for the - /// given data. Specifically, they can do exact or fuzzy matching on the name. - /// They can use or ignore the arity depending on their capabilities. + /// Searches for packages that contain a type with the provided name and arity. Note: Implementations are free to + /// return the results they feel best for the given data. Specifically, they can do exact or fuzzy matching on the + /// name. They can use or ignore the arity depending on their capabilities. /// - /// Implementations should return results in order from best to worst (from their - /// perspective). + /// Implementations should return results in order from best to worst (from their perspective). /// - ValueTask> FindPackagesWithTypeAsync( - string source, string name, int arity, CancellationToken cancellationToken); + ValueTask> FindPackagesAsync( + string source, TypeQuery typeQuery, NamespaceQuery namespaceQuery, CancellationToken cancellationToken); /// - /// Searches for packages that contain an assembly with the provided name. - /// Note: Implementations are free to return the results they feel best for the - /// given data. Specifically, they can do exact or fuzzy matching on the name. + /// Searches for packages that contain an assembly with the provided name. Note: Implementations are free to return + /// the results they feel best for the given data. Specifically, they can do exact or fuzzy matching on the name. /// - /// Implementations should return results in order from best to worst (from their - /// perspective). + /// Implementations should return results in order from best to worst (from their perspective). /// ValueTask> FindPackagesWithAssemblyAsync( string source, string assemblyName, CancellationToken cancellationToken); @@ -48,33 +72,27 @@ ValueTask> FindPackagesWithAssemblyAsy /// Implementations should return results in order from best to worst (from their /// perspective). /// - ValueTask> FindReferenceAssembliesWithTypeAsync( - string name, int arity, CancellationToken cancellationToken); + ValueTask> FindReferenceAssembliesAsync( + TypeQuery typeQuery, NamespaceQuery namespaceQuery, CancellationToken cancellationToken); } [DataContract] -internal abstract class PackageResult +internal abstract class AbstractPackageResult(string packageName, int rank) { [DataMember(Order = 0)] - public readonly string PackageName; + public readonly string PackageName = packageName; [DataMember(Order = 1)] - public readonly int Rank; - - protected PackageResult(string packageName, int rank) - { - PackageName = packageName; - Rank = rank; - } + public readonly int Rank = rank; } [DataContract] -internal sealed class PackageWithTypeResult( +internal sealed class PackageResult( string packageName, int rank, string typeName, string? version, - ImmutableArray containingNamespaceNames) : PackageResult(packageName, rank) + ImmutableArray containingNamespaceNames) : AbstractPackageResult(packageName, rank) { [DataMember(Order = 2)] public readonly string TypeName = typeName; @@ -90,7 +108,7 @@ internal sealed class PackageWithTypeResult( internal sealed class PackageWithAssemblyResult( string packageName, int rank, - string version) : PackageResult(packageName, rank), IEquatable, IComparable + string version) : AbstractPackageResult(packageName, rank), IEquatable, IComparable { [DataMember(Order = 2)] public readonly string? Version = version; @@ -117,7 +135,7 @@ public int CompareTo(PackageWithAssemblyResult? other) } [DataContract] -internal sealed class ReferenceAssemblyWithTypeResult( +internal sealed class ReferenceAssemblyResult( string assemblyName, string typeName, ImmutableArray containingNamespaceNames) @@ -133,20 +151,16 @@ internal sealed class ReferenceAssemblyWithTypeResult( } [ExportWorkspaceService(typeof(ISymbolSearchService)), Shared] -internal sealed class DefaultSymbolSearchService : ISymbolSearchService +[method: ImportingConstructor] +[method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] +internal sealed class DefaultSymbolSearchService() : ISymbolSearchService { - [ImportingConstructor] - [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - public DefaultSymbolSearchService() - { - } - - public ValueTask> FindPackagesWithTypeAsync(string source, string name, int arity, CancellationToken cancellationToken) - => ValueTaskFactory.FromResult(ImmutableArray.Empty); + public ValueTask> FindPackagesAsync(string source, TypeQuery typeQuery, NamespaceQuery namespaceQuery, CancellationToken cancellationToken) + => ValueTaskFactory.FromResult(ImmutableArray.Empty); public ValueTask> FindPackagesWithAssemblyAsync(string source, string assemblyName, CancellationToken cancellationToken) => ValueTaskFactory.FromResult(ImmutableArray.Empty); - public ValueTask> FindReferenceAssembliesWithTypeAsync(string name, int arity, CancellationToken cancellationToken) - => ValueTaskFactory.FromResult(ImmutableArray.Empty); + public ValueTask> FindReferenceAssembliesAsync(TypeQuery typeQuery, NamespaceQuery namespaceQuery, CancellationToken cancellationToken) + => ValueTaskFactory.FromResult(ImmutableArray.Empty); } diff --git a/src/Workspaces/Core/Portable/SymbolSearch/ISymbolSearchUpdateEngine.cs b/src/Workspaces/Core/Portable/SymbolSearch/ISymbolSearchUpdateEngine.cs index 2c5f5529dff5d..72a9d7e8d82d9 100644 --- a/src/Workspaces/Core/Portable/SymbolSearch/ISymbolSearchUpdateEngine.cs +++ b/src/Workspaces/Core/Portable/SymbolSearch/ISymbolSearchUpdateEngine.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System; using System.Collections.Immutable; using System.Threading; @@ -19,10 +17,10 @@ internal interface ISymbolSearchUpdateEngine : IDisposable { ValueTask UpdateContinuouslyAsync(string sourceName, string localSettingsDirectory, CancellationToken cancellationToken); - ValueTask> FindPackagesWithTypeAsync( - string source, string name, int arity, CancellationToken cancellationToken); + ValueTask> FindPackagesAsync( + string source, TypeQuery typeQuery, NamespaceQuery namespaceQuery, CancellationToken cancellationToken); ValueTask> FindPackagesWithAssemblyAsync( string source, string assemblyName, CancellationToken cancellationToken); - ValueTask> FindReferenceAssembliesWithTypeAsync( - string name, int arity, CancellationToken cancellationToken); + ValueTask> FindReferenceAssembliesAsync( + TypeQuery typeQuery, NamespaceQuery namespaceQuery, CancellationToken cancellationToken); } diff --git a/src/Workspaces/Core/Portable/Utilities/TaskQueue.cs b/src/Workspaces/Core/Portable/Utilities/TaskQueue.cs deleted file mode 100644 index a8b5380f6bae6..0000000000000 --- a/src/Workspaces/Core/Portable/Utilities/TaskQueue.cs +++ /dev/null @@ -1,119 +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.Threading; -using System.Threading.Tasks; -using Microsoft.CodeAnalysis.Shared.TestHooks; - -namespace Roslyn.Utilities; - -/// -/// Implements a queue of asynchronously executed tasks. -/// -internal sealed class TaskQueue -{ - public IAsynchronousOperationListener Listener { get; } - public TaskScheduler Scheduler { get; } - - private readonly object _gate = new(); - - public TaskQueue(IAsynchronousOperationListener operationListener, TaskScheduler taskScheduler) - { - Contract.ThrowIfNull(operationListener); - Contract.ThrowIfNull(taskScheduler); - - Listener = operationListener; - Scheduler = taskScheduler; - LastScheduledTask = Task.CompletedTask; - } - - public Task LastScheduledTask { get; private set; } - - private IAsyncToken BeginOperation(string taskName) - => Listener.BeginAsyncOperation(taskName); - - private static TTask EndOperation(IAsyncToken token, TTask task) where TTask : Task - { - // send the notification on operation being complete but do not wait for the notification to be delivered - _ = task.CompletesAsyncOperation(token); - - return task; - } - -#pragma warning disable VSTHRD200 // Use "Async" suffix for async methods (Task wrappers, not asynchronous methods) - - /// - /// Enqueue specified and notify of its start and completion. - /// - /// The that executes the operation. - public Task ScheduleTask(string taskName, Action operation, CancellationToken cancellationToken) - => EndOperation(BeginOperation(taskName), ScheduleTaskInProgress(operation, cancellationToken)); - - /// - public Task ScheduleTask(string taskName, Func operation, CancellationToken cancellationToken) - => EndOperation(BeginOperation(taskName), ScheduleTaskInProgress(operation, cancellationToken)); - - /// - public Task ScheduleTask(string taskName, Func operation, CancellationToken cancellationToken) - => EndOperation(BeginOperation(taskName), ScheduleTaskInProgress(operation, cancellationToken)); - - /// - public Task ScheduleTask(string taskName, Func> operation, CancellationToken cancellationToken) - => EndOperation(BeginOperation(taskName), ScheduleTaskInProgress(operation, cancellationToken)); - - /// - /// Enqueue specified . - /// Assumes has already been notified of its start and will be notified when it completes. - /// - /// The that executes the operation. - [PerformanceSensitive("https://developercommunity.visualstudio.com/content/problem/854696/changing-target-framework-takes-10-minutes-with-10.html", AllowCaptures = false)] - private Task ScheduleTaskInProgress(Action operation, CancellationToken cancellationToken) - { - lock (_gate) - { - var task = LastScheduledTask.SafeContinueWith(_ => operation(), cancellationToken, TaskContinuationOptions.None, Scheduler); - LastScheduledTask = task; - return task; - } - } - - /// - [PerformanceSensitive("https://developercommunity.visualstudio.com/content/problem/854696/changing-target-framework-takes-10-minutes-with-10.html", AllowCaptures = false)] - private Task ScheduleTaskInProgress(Func operation, CancellationToken cancellationToken) - { - lock (_gate) - { - var task = LastScheduledTask.SafeContinueWith(_ => operation(), cancellationToken, TaskContinuationOptions.None, Scheduler); - LastScheduledTask = task; - return task; - } - } - - /// - [PerformanceSensitive("https://developercommunity.visualstudio.com/content/problem/854696/changing-target-framework-takes-10-minutes-with-10.html", AllowCaptures = false)] - private Task ScheduleTaskInProgress(Func operation, CancellationToken cancellationToken) - { - lock (_gate) - { - var task = LastScheduledTask.SafeContinueWithFromAsync(_ => operation(), cancellationToken, TaskContinuationOptions.None, Scheduler); - LastScheduledTask = task; - return task; - } - } - - /// - [PerformanceSensitive("https://developercommunity.visualstudio.com/content/problem/854696/changing-target-framework-takes-10-minutes-with-10.html", AllowCaptures = false)] - private Task ScheduleTaskInProgress(Func> operation, CancellationToken cancellationToken) - { - lock (_gate) - { - var task = LastScheduledTask.SafeContinueWithFromAsync(_ => operation(), cancellationToken, TaskContinuationOptions.None, Scheduler); - LastScheduledTask = task; - return task; - } - } - -#pragma warning restore -} diff --git a/src/Workspaces/Core/Portable/Workspace/DocumentTracking/IDocumentTrackingServiceExtensions.cs b/src/Workspaces/Core/Portable/Workspace/DocumentTracking/IDocumentTrackingServiceExtensions.cs index 9a231ee40abbc..1451071571e3a 100644 --- a/src/Workspaces/Core/Portable/Workspace/DocumentTracking/IDocumentTrackingServiceExtensions.cs +++ b/src/Workspaces/Core/Portable/Workspace/DocumentTracking/IDocumentTrackingServiceExtensions.cs @@ -25,9 +25,8 @@ internal static class IDocumentTrackingServiceExtensions /// contained within . /// public static ImmutableArray GetVisibleDocuments(this IDocumentTrackingService service, Solution solution) - => service.GetVisibleDocuments() + => [.. service.GetVisibleDocuments() .Select(solution.GetDocument) .WhereNotNull() - .Distinct() - .ToImmutableArray(); + .Distinct()]; } diff --git a/src/Workspaces/Core/Portable/Workspace/Host/EventListener/EventListenerTracker.cs b/src/Workspaces/Core/Portable/Workspace/Host/EventListener/EventListenerTracker.cs index 95e288c22270a..620179260d5af 100644 --- a/src/Workspaces/Core/Portable/Workspace/Host/EventListener/EventListenerTracker.cs +++ b/src/Workspaces/Core/Portable/Workspace/Host/EventListener/EventListenerTracker.cs @@ -23,7 +23,7 @@ internal sealed class EventListenerTracker( /// Workspace kind this event listener is initialized for /// private readonly HashSet _eventListenerInitialized = []; - private readonly ImmutableArray> _eventListeners = eventListeners.Where(el => el.Metadata.Service == kind).ToImmutableArray(); + private readonly ImmutableArray> _eventListeners = [.. eventListeners.Where(el => el.Metadata.Service == kind)]; public void EnsureEventListener(Workspace workspace, TService serviceOpt) { diff --git a/src/Workspaces/Core/Portable/Workspace/Host/EventListener/IWorkspaceEventListenerProvider.cs b/src/Workspaces/Core/Portable/Workspace/Host/EventListener/IWorkspaceEventListenerProvider.cs index 538bba6e481aa..48fc12f4b5475 100644 --- a/src/Workspaces/Core/Portable/Workspace/Host/EventListener/IWorkspaceEventListenerProvider.cs +++ b/src/Workspaces/Core/Portable/Workspace/Host/EventListener/IWorkspaceEventListenerProvider.cs @@ -37,7 +37,7 @@ internal sealed class Service(Workspace workspace, IEnumerable> _eventListeners = eventListeners.ToImmutableArray(); + private readonly ImmutableArray> _eventListeners = [.. eventListeners]; public void EnsureListeners() { diff --git a/src/Workspaces/Core/Portable/Workspace/Host/Metadata/IAnalyzerAssemblyLoaderProvider.cs b/src/Workspaces/Core/Portable/Workspace/Host/Metadata/IAnalyzerAssemblyLoaderProvider.cs index 9c5626f1e5fc8..9acb18e7fd0e8 100644 --- a/src/Workspaces/Core/Portable/Workspace/Host/Metadata/IAnalyzerAssemblyLoaderProvider.cs +++ b/src/Workspaces/Core/Portable/Workspace/Host/Metadata/IAnalyzerAssemblyLoaderProvider.cs @@ -40,7 +40,7 @@ internal abstract class AbstractAnalyzerAssemblyLoaderProvider : IAnalyzerAssemb public AbstractAnalyzerAssemblyLoaderProvider(IEnumerable externalResolvers) { - _externalResolvers = externalResolvers.ToImmutableArray(); + _externalResolvers = [.. externalResolvers]; _shadowCopyLoader = new(CreateNewShadowCopyLoader); } diff --git a/src/Workspaces/Core/Portable/Workspace/Host/PersistentStorage/IPersistentStorageConfiguration.cs b/src/Workspaces/Core/Portable/Workspace/Host/PersistentStorage/IPersistentStorageConfiguration.cs index 823d3ae7e5cca..0e747988fbb70 100644 --- a/src/Workspaces/Core/Portable/Workspace/Host/PersistentStorage/IPersistentStorageConfiguration.cs +++ b/src/Workspaces/Core/Portable/Workspace/Host/PersistentStorage/IPersistentStorageConfiguration.cs @@ -93,7 +93,7 @@ private static string SafeName(string fullPath) private static string StripInvalidPathChars(string val) { - val = new string(val.Where(c => !s_invalidPathChars.Contains(c)).ToArray()); + val = new string([.. val.Where(c => !s_invalidPathChars.Contains(c))]); return string.IsNullOrWhiteSpace(val) ? "None" : val; } diff --git a/src/Workspaces/Core/Portable/Workspace/ProjectSystem/ProjectSystemProject.BatchingDocumentCollection.cs b/src/Workspaces/Core/Portable/Workspace/ProjectSystem/ProjectSystemProject.BatchingDocumentCollection.cs index d0d9ffcd09ec1..4bafa8a44f84b 100644 --- a/src/Workspaces/Core/Portable/Workspace/ProjectSystem/ProjectSystemProject.BatchingDocumentCollection.cs +++ b/src/Workspaces/Core/Portable/Workspace/ProjectSystem/ProjectSystemProject.BatchingDocumentCollection.cs @@ -547,7 +547,7 @@ public void ReorderFiles(ImmutableArray filePaths) // State is cleared at the end once the solution changes are actually applied via ClearBatchState. return UpdateSolutionForBatch(solutionChanges, documentFileNamesAdded, addDocuments, addDocumentChangeKind, removeDocuments, removeDocumentChangeKind, _project.Id, _documentsAddedInBatch.ToImmutableArray(), - _documentsRemovedInBatch.ToImmutableArray(), _orderedDocumentsInBatch, + [.. _documentsRemovedInBatch], _orderedDocumentsInBatch, documentId => _sourceTextContainersToDocumentIds.GetKeyOrDefault(documentId)); static ImmutableArray<(DocumentId documentId, SourceTextContainer textContainer)> UpdateSolutionForBatch( diff --git a/src/Workspaces/Core/Portable/Workspace/ProjectSystem/ProjectSystemProjectOptionsProcessor.cs b/src/Workspaces/Core/Portable/Workspace/ProjectSystem/ProjectSystemProjectOptionsProcessor.cs index 968b8f698f896..dd48638b65ad9 100644 --- a/src/Workspaces/Core/Portable/Workspace/ProjectSystem/ProjectSystemProjectOptionsProcessor.cs +++ b/src/Workspaces/Core/Portable/Workspace/ProjectSystem/ProjectSystemProjectOptionsProcessor.cs @@ -97,7 +97,7 @@ public void SetCommandLine(string commandLine) var arguments = CommandLineParser.SplitCommandLineIntoArguments(commandLine, removeHashComments: false); - SetCommandLine(arguments.ToImmutableArray()); + SetCommandLine([.. arguments]); } public void SetCommandLine(ImmutableArray arguments) @@ -199,7 +199,7 @@ private void UpdateProjectOptions_NoLock() .WithConcurrentBuild(concurrent: false) .WithXmlReferenceResolver(new XmlFileResolver(_commandLineArgumentsForCommandLine.BaseDirectory)) .WithAssemblyIdentityComparer(DesktopAssemblyIdentityComparer.Default) - .WithStrongNameProvider(new DesktopStrongNameProvider(_commandLineArgumentsForCommandLine.KeyFileSearchPaths.WhereNotNull().ToImmutableArray(), Path.GetTempPath())); + .WithStrongNameProvider(new DesktopStrongNameProvider([.. _commandLineArgumentsForCommandLine.KeyFileSearchPaths.WhereNotNull()], Path.GetTempPath())); // Override the default documentation mode. var documentationMode = _commandLineArgumentsForCommandLine.DocumentationPath != null ? DocumentationMode.Diagnose : DocumentationMode.Parse; @@ -246,7 +246,7 @@ private void RuleSetFile_UpdatedOnDisk(object? sender, EventArgs e) // the effective result did. Then we call UpdateProjectOptions_NoLock to reapply any values; that will also re-acquire the new ruleset // includes in the IDE so we can be watching for changes again. var commandLine = _commandLineStorageHandle == null - ? ImmutableArray.Empty + ? [] : EnumerateLines(_commandLineStorageHandle).ToImmutableArray(); DisposeOfRuleSetFile_NoLock(); diff --git a/src/Workspaces/Core/Portable/Workspace/Solution/Checksum_Factory.cs b/src/Workspaces/Core/Portable/Workspace/Solution/Checksum_Factory.cs index e0804d3d9eb69..9583c253e5886 100644 --- a/src/Workspaces/Core/Portable/Workspace/Solution/Checksum_Factory.cs +++ b/src/Workspaces/Core/Portable/Workspace/Solution/Checksum_Factory.cs @@ -23,6 +23,11 @@ internal readonly partial record struct Checksum private static readonly ObjectPool s_incrementalHashPool = new(() => new(), size: 20); + // Pool of ObjectWriters to reduce allocations. The pool size is intentionally small as the writers are used for such + // a short period that concurrent usage of different items from the pool is infrequent. + private static readonly ObjectPool s_objectWriterPool = + new(() => new(SerializableBytes.CreateWritableStream(), leaveOpen: true, writeValidationBytes: true), size: 4); + public static Checksum Create(IEnumerable values) { using var pooledHash = s_incrementalHashPool.GetPooledObject(); @@ -57,15 +62,25 @@ public static Checksum Create(Stream stream) public static Checksum Create(T @object, Action writeObject) { - using var stream = SerializableBytes.CreateWritableStream(); + // Obtain a writer from the pool + var objectWriter = s_objectWriterPool.Allocate(); - using (var objectWriter = new ObjectWriter(stream, leaveOpen: true)) - { - writeObject(@object, objectWriter); - } + // Invoke the callback to Write object into objectWriter + writeObject(@object, objectWriter); + // Include validation bytes in the new checksum from the stream + var stream = objectWriter.BaseStream; stream.Position = 0; - return Create(stream); + var newChecksum = Create(stream); + + // Reset object writer back to it's initial state, including the validation bytes + objectWriter.Reset(); + objectWriter.WriteValidationBytes(); + + // Release the writer back to the pool + s_objectWriterPool.Free(objectWriter); + + return newChecksum; } public static Checksum Create(Checksum checksum1, Checksum checksum2) diff --git a/src/Workspaces/Core/Portable/Workspace/Solution/Document.cs b/src/Workspaces/Core/Portable/Workspace/Solution/Document.cs index 2e77e388f6c74..59be45860e30e 100644 --- a/src/Workspaces/Core/Portable/Workspace/Solution/Document.cs +++ b/src/Workspaces/Core/Portable/Workspace/Solution/Document.cs @@ -416,10 +416,28 @@ public Document WithFilePath(string? filePath) => this.Project.Solution.WithDocumentFilePath(this.Id, filePath).GetRequiredDocument(Id); /// - /// Get the text changes between this document and a prior version of the same document. - /// The changes, when applied to the text of the old document, will produce the text of the current document. + /// Get the text changes between this document and a prior version of the same document. The changes, when applied + /// to the text of the old document, will produce the text of the current document. /// public async Task> GetTextChangesAsync(Document oldDocument, CancellationToken cancellationToken = default) + { + return await GetTextChangesAsync(useAsync: true, oldDocument, cancellationToken).ConfigureAwait(false); + } + + /// + /// Similar to , but should be used when in a forced + /// synchronous context. + /// + internal ImmutableArray GetTextChangesSynchronously( + Document oldDocument, CancellationToken cancellationToken) + { + // Should always complete synchronously since we passed in 'useAsync: false' + var result = GetTextChangesAsync(useAsync: false, oldDocument, cancellationToken); + return result.VerifyCompleted(); + } + + private async Task> GetTextChangesAsync( + bool useAsync, Document oldDocument, CancellationToken cancellationToken) { try { @@ -443,10 +461,10 @@ public async Task> GetTextChangesAsync(Document oldDocum var container = text.Container; if (container != null) { - var textChanges = text.GetTextChanges(oldText).ToList(); + var textChanges = text.GetTextChanges(oldText).ToImmutableArray(); // if changes are significant (not the whole document being replaced) then use these changes - if (textChanges.Count > 1 || (textChanges.Count == 1 && textChanges[0].Span != new TextSpan(0, oldText.Length))) + if (textChanges.Length > 1 || (textChanges.Length == 1 && textChanges[0].Span != new TextSpan(0, oldText.Length))) { return textChanges; } @@ -456,17 +474,18 @@ public async Task> GetTextChangesAsync(Document oldDocum // get changes by diffing the trees if (this.SupportsSyntaxTree) { - var tree = (await this.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false))!; - var oldTree = await oldDocument.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false); + var tree = useAsync ? await GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false) : this.GetSyntaxTreeSynchronously(cancellationToken); + var oldTree = useAsync ? await oldDocument.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false) : oldDocument.GetSyntaxTreeSynchronously(cancellationToken); + RoslynDebug.Assert(tree is object); RoslynDebug.Assert(oldTree is object); - return tree.GetChanges(oldTree); + return [.. tree.GetChanges(oldTree)]; } - text = await this.GetValueTextAsync(cancellationToken).ConfigureAwait(false); - oldText = await oldDocument.GetValueTextAsync(cancellationToken).ConfigureAwait(false); + text = useAsync ? await this.GetTextAsync(cancellationToken).ConfigureAwait(false) : this.GetTextSynchronously(cancellationToken); + oldText = useAsync ? await oldDocument.GetTextAsync(cancellationToken).ConfigureAwait(false) : oldDocument.GetTextSynchronously(cancellationToken); - return text.GetTextChanges(oldText).ToList(); + return [.. text.GetTextChanges(oldText)]; } } catch (Exception e) when (FatalError.ReportAndPropagateUnlessCanceled(e, cancellationToken)) diff --git a/src/Workspaces/Core/Portable/Workspace/Solution/DocumentState.cs b/src/Workspaces/Core/Portable/Workspace/Solution/DocumentState.cs index 8579fba2f1ba8..07baa5aaf65f9 100644 --- a/src/Workspaces/Core/Portable/Workspace/Solution/DocumentState.cs +++ b/src/Workspaces/Core/Portable/Workspace/Solution/DocumentState.cs @@ -495,23 +495,8 @@ internal DocumentState UpdateTree(SyntaxNode newRoot, PreservationMode mode) var newTextVersion = GetNewerVersion(); var newTreeVersion = GetNewTreeVersionForUpdatedTree(newRoot, newTextVersion, mode); - // determine encoding - Encoding? encoding; - - if (TryGetSyntaxTree(out var priorTree)) - { - // this is most likely available since UpdateTree is normally called after modifying the existing tree. - encoding = priorTree.Encoding; - } - else if (TryGetText(out var priorText)) - { - encoding = priorText.Encoding; - } - else - { - // the existing encoding was never observed so is unknown. - encoding = null; - } + // use the encoding that we get from the new root + var encoding = newRoot.SyntaxTree.Encoding; var syntaxTreeFactory = LanguageServices.GetRequiredService(); diff --git a/src/Workspaces/Core/Portable/Workspace/Solution/ProjectDependencyGraph.cs b/src/Workspaces/Core/Portable/Workspace/Solution/ProjectDependencyGraph.cs index d972b541b4d0b..93b2b5fa0d589 100644 --- a/src/Workspaces/Core/Portable/Workspace/Solution/ProjectDependencyGraph.cs +++ b/src/Workspaces/Core/Portable/Workspace/Solution/ProjectDependencyGraph.cs @@ -8,6 +8,7 @@ using System.Diagnostics; using System.Linq; using System.Threading; +using Microsoft.CodeAnalysis.PooledObjects; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis; @@ -55,6 +56,9 @@ public partial class ProjectDependencyGraph private ImmutableDictionary> _transitiveReferencesMap; private ImmutableDictionary> _reverseTransitiveReferencesMap; + // Pool of ImmutableHashSet builders used in ComputeReverseReferencesMap to avoid temporary HashSet allocations. + private static readonly ObjectPool.Builder> s_reverseReferencesBuilderPool = new(static () => ImmutableHashSet.CreateBuilder(), size: 256); + /// /// Intentionally created with a null reverseReferencesMap. Doing so indicates _lazyReverseReferencesMap /// shouldn't be calculated until reverse reference information is requested. Once this information @@ -209,17 +213,36 @@ private ImmutableHashSet GetProjectsThatDirectlyDependOnThisProject_N private ImmutableDictionary> ComputeReverseReferencesMap() { - var reverseReferencesMap = new Dictionary>(); - + using var _1 = PooledDictionary.Builder>.GetInstance(out var reverseReferencesMapBuilders); foreach (var (projectId, references) in _referencesMap) { foreach (var referencedId in references) - reverseReferencesMap.MultiAdd(referencedId, projectId); + { + if (!reverseReferencesMapBuilders.TryGetValue(referencedId, out var builder)) + { + builder = s_reverseReferencesBuilderPool.Allocate(); + reverseReferencesMapBuilders.Add(referencedId, builder); + } + + builder.Add(projectId); + } + } + + // Convert all the populated ImmutableHashSet.Builder objects to ImmutableHashSets + var reverseReferencesBuilder = ImmutableDictionary.CreateBuilder>(); + foreach (var (projectId, builder) in reverseReferencesMapBuilders) + { + // Realize an ImmutableHashSet from the builder + var reverseReferencesForProject = builder.ToImmutableHashSet(); + + // Clear out the builder and release it back to the pool + builder.Clear(); + s_reverseReferencesBuilderPool.Free(builder); + + reverseReferencesBuilder.Add(projectId, reverseReferencesForProject); } - return reverseReferencesMap - .Select(kvp => KeyValuePairUtil.Create(kvp.Key, kvp.Value.ToImmutableHashSet())) - .ToImmutableDictionary(); + return reverseReferencesBuilder.ToImmutable(); } /// @@ -543,9 +566,9 @@ internal bool DoesProjectTransitivelyDependOnProject(ProjectId id, ProjectId pot // Check the dependency graph to see if project 'id' directly or transitively depends on 'projectId'. // If the information is not available, do not compute it. var forwardDependencies = TryGetProjectsThatThisProjectTransitivelyDependsOn(id); - if (forwardDependencies is object && forwardDependencies.Contains(potentialDependency)) + if (forwardDependencies is object) { - return true; + return forwardDependencies.Contains(potentialDependency); } // Compute the set of all projects that depend on 'potentialDependency'. This information answers the same diff --git a/src/Workspaces/Core/Portable/Workspace/Solution/ProjectState.cs b/src/Workspaces/Core/Portable/Workspace/Solution/ProjectState.cs index 63bd72d51d552..94bd2575abfd3 100644 --- a/src/Workspaces/Core/Portable/Workspace/Solution/ProjectState.cs +++ b/src/Workspaces/Core/Portable/Workspace/Solution/ProjectState.cs @@ -3,7 +3,6 @@ // See the LICENSE file in the project root for more information. using System; -using System.Collections.Concurrent; using System.Collections.Generic; using System.Collections.Immutable; using System.Diagnostics; @@ -12,7 +11,6 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.Collections; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Diagnostics.Analyzers.NamingStyles; using Microsoft.CodeAnalysis.Host; @@ -49,10 +47,11 @@ internal sealed partial class ProjectState private readonly AsyncLazy _lazyLatestDocumentVersion; private readonly AsyncLazy _lazyLatestDocumentTopLevelChangeVersion; - // Checksums for this solution state - private readonly AsyncLazy _lazyChecksums; + // Checksums for this solution state (access via LazyChecksums) + private AsyncLazy? _lazyChecksums; - private readonly AsyncLazy, DocumentId>> _lazyContentHashToDocumentId; + // Mapping from content has to document id (access via LazyContentHashToDocumentId) + private AsyncLazy, DocumentId>>? _lazyContentHashToDocumentId; /// /// Analyzer config options to be used for specific trees. @@ -87,9 +86,6 @@ private ProjectState( // holding on. otherwise, these information will be held onto unnecessarily by projectInfo even after // the info has changed by DocumentState. ProjectInfo = ClearAllDocumentsFromProjectInfo(projectInfo); - - _lazyChecksums = AsyncLazy.Create(static (self, cancellationToken) => self.ComputeChecksumsAsync(cancellationToken), arg: this); - _lazyContentHashToDocumentId = AsyncLazy.Create(static (self, cancellationToken) => self.ComputeContentHashToDocumentIdAsync(cancellationToken), arg: this); } public ProjectState(LanguageServices languageServices, ProjectInfo projectInfo, StructuredAnalyzerConfigOptions fallbackAnalyzerOptions) @@ -128,9 +124,6 @@ public ProjectState(LanguageServices languageServices, ProjectInfo projectInfo, // the info has changed by DocumentState. // we hold onto the info so that we don't need to duplicate all information info already has in the state ProjectInfo = ClearAllDocumentsFromProjectInfo(projectInfoFixed); - - _lazyChecksums = AsyncLazy.Create(static (self, cancellationToken) => self.ComputeChecksumsAsync(cancellationToken), arg: this); - _lazyContentHashToDocumentId = AsyncLazy.Create(static (self, cancellationToken) => self.ComputeContentHashToDocumentIdAsync(cancellationToken), arg: this); } public TextDocumentStates GetDocumentStates() @@ -158,6 +151,38 @@ private async Task, DocumentId>> ComputeContentH return result; } + private AsyncLazy LazyChecksums + { + get + { + if (_lazyChecksums is null) + { + Interlocked.CompareExchange( + ref _lazyChecksums, + AsyncLazy.Create(static (self, cancellationToken) => self.ComputeChecksumsAsync(cancellationToken), arg: this), + null); + } + + return _lazyChecksums; + } + } + + private AsyncLazy, DocumentId>> LazyContentHashToDocumentId + { + get + { + if (_lazyContentHashToDocumentId is null) + { + Interlocked.CompareExchange( + ref _lazyContentHashToDocumentId, + AsyncLazy.Create(static (self, cancellationToken) => self.ComputeContentHashToDocumentIdAsync(cancellationToken), arg: this), + null); + } + + return _lazyContentHashToDocumentId; + } + } + private static ProjectInfo ClearAllDocumentsFromProjectInfo(ProjectInfo projectInfo) { return projectInfo @@ -168,7 +193,7 @@ private static ProjectInfo ClearAllDocumentsFromProjectInfo(ProjectInfo projectI public async ValueTask GetDocumentIdAsync(ImmutableArray contentHash, CancellationToken cancellationToken) { - var map = await _lazyContentHashToDocumentId.GetValueAsync(cancellationToken).ConfigureAwait(false); + var map = await LazyContentHashToDocumentId.GetValueAsync(cancellationToken).ConfigureAwait(false); return map.TryGetValue(contentHash, out var documentId) ? documentId : null; } diff --git a/src/Workspaces/Core/Portable/Workspace/Solution/ProjectState_Checksum.cs b/src/Workspaces/Core/Portable/Workspace/Solution/ProjectState_Checksum.cs index 7f48c388751ad..f9a3bd91b7fe4 100644 --- a/src/Workspaces/Core/Portable/Workspace/Solution/ProjectState_Checksum.cs +++ b/src/Workspaces/Core/Portable/Workspace/Solution/ProjectState_Checksum.cs @@ -16,17 +16,17 @@ namespace Microsoft.CodeAnalysis; internal sealed partial class ProjectState { public bool TryGetStateChecksums([NotNullWhen(true)] out ProjectStateChecksums? stateChecksums) - => _lazyChecksums.TryGetValue(out stateChecksums); + => LazyChecksums.TryGetValue(out stateChecksums); public Task GetStateChecksumsAsync(CancellationToken cancellationToken) - => _lazyChecksums.GetValueAsync(cancellationToken); + => LazyChecksums.GetValueAsync(cancellationToken); public Task GetChecksumAsync(CancellationToken cancellationToken) { return SpecializedTasks.TransformWithoutIntermediateCancellationExceptionAsync( static (lazyChecksums, cancellationToken) => new ValueTask(lazyChecksums.GetValueAsync(cancellationToken)), static (projectStateChecksums, _) => projectStateChecksums.Checksum, - _lazyChecksums, + LazyChecksums, cancellationToken).AsTask(); } diff --git a/src/Workspaces/Core/Portable/Workspace/Solution/Solution.cs b/src/Workspaces/Core/Portable/Workspace/Solution/Solution.cs index ecb35bc29f284..4a5835def2736 100644 --- a/src/Workspaces/Core/Portable/Workspace/Solution/Solution.cs +++ b/src/Workspaces/Core/Portable/Workspace/Solution/Solution.cs @@ -1550,13 +1550,12 @@ static Solution ComputeFrozenSolution(SolutionCompilationState compilationState, internal async Task WithMergedLinkedFileChangesAsync( Solution oldSolution, SolutionChanges? solutionChanges = null, - IMergeConflictHandler? mergeConflictHandler = null, CancellationToken cancellationToken = default) { // we only log sessioninfo for actual changes committed to workspace which should exclude ones from preview var session = new LinkedFileDiffMergingSession(oldSolution, this, solutionChanges ?? this.GetChanges(oldSolution)); - return (await session.MergeDiffsAsync(mergeConflictHandler, cancellationToken).ConfigureAwait(false)).MergedSolution; + return (await session.MergeDiffsAsync(cancellationToken).ConfigureAwait(false)).MergedSolution; } internal ImmutableArray GetRelatedDocumentIds(DocumentId documentId, bool includeDifferentLanguages = false) diff --git a/src/Workspaces/Core/Portable/Workspace/Solution/SolutionCompilationState.cs b/src/Workspaces/Core/Portable/Workspace/Solution/SolutionCompilationState.cs index 7a638eda52f0e..83eb6fae6fa13 100644 --- a/src/Workspaces/Core/Portable/Workspace/Solution/SolutionCompilationState.cs +++ b/src/Workspaces/Core/Portable/Workspace/Solution/SolutionCompilationState.cs @@ -1454,36 +1454,7 @@ public SolutionCompilationState WithFrozenPartialCompilations(CancellationToken private SolutionCompilationState ComputeFrozenSnapshot(CancellationToken cancellationToken) { - var newIdToProjectStateMapBuilder = this.SolutionState.ProjectStates.ToBuilder(); - var newIdToTrackerMapBuilder = _projectIdToTrackerMap.ToBuilder(); - - foreach (var projectId in this.SolutionState.ProjectIds) - { - cancellationToken.ThrowIfCancellationRequested(); - - // Definitely do nothing for non-C#/VB projects. We have nothing to freeze in that case. - var oldProjectState = this.SolutionState.GetRequiredProjectState(projectId); - if (!oldProjectState.SupportsCompilation) - continue; - - var oldTracker = GetCompilationTracker(projectId); - - // Since we're freezing, set both generators and skeletons to not be created. We don't want to take any - // perf hit on either of those at all for our clients. - var newTracker = oldTracker.WithDoNotCreateCreationPolicy(); - if (oldTracker == newTracker) - continue; - - Contract.ThrowIfFalse(newIdToProjectStateMapBuilder.ContainsKey(projectId)); - - var newProjectState = newTracker.ProjectState; - - newIdToProjectStateMapBuilder[projectId] = newProjectState; - newIdToTrackerMapBuilder[projectId] = newTracker; - } - - var newIdToProjectStateMap = newIdToProjectStateMapBuilder.ToImmutable(); - var newIdToTrackerMap = newIdToTrackerMapBuilder.ToImmutable(); + var (newIdToProjectStateMap, newIdToTrackerMap) = ComputeFrozenSnapshotMaps(cancellationToken); var dependencyGraph = SolutionState.CreateDependencyGraph(this.SolutionState.ProjectIds, newIdToProjectStateMap); @@ -1500,6 +1471,58 @@ private SolutionCompilationState ComputeFrozenSnapshot(CancellationToken cancell return newCompilationState; } + private (ImmutableDictionary, ImmutableSegmentedDictionary) ComputeFrozenSnapshotMaps(CancellationToken cancellationToken) + { + // Loop until we have calculated the maps against a set of compilation trackers that hasn't changed during our calculation. + while (true) + { + var originalProjectIdToTrackerMap = _projectIdToTrackerMap; + var newIdToProjectStateMapBuilder = this.SolutionState.ProjectStates.ToBuilder(); + var newIdToTrackerMapBuilder = originalProjectIdToTrackerMap.ToBuilder(); + + // Used to track any new compilation trackers created in the loop. This is done to avoid allocations + // from individually adding to the _projectIdToTrackerMap ImmutableSegmentedDictionary . + var updatedIdToTrackerMapBuilder = originalProjectIdToTrackerMap.ToBuilder(); + + foreach (var projectId in this.SolutionState.ProjectIds) + { + cancellationToken.ThrowIfCancellationRequested(); + + // Definitely do nothing for non-C#/VB projects. We have nothing to freeze in that case. + var oldProjectState = this.SolutionState.GetRequiredProjectState(projectId); + if (!oldProjectState.SupportsCompilation) + continue; + + if (!originalProjectIdToTrackerMap.TryGetValue(projectId, out var oldTracker)) + { + oldTracker = CreateCompilationTracker(projectId, this.SolutionState); + + // Collect all compilation trackers that needed to be created + updatedIdToTrackerMapBuilder[projectId] = oldTracker; + } + + // Since we're freezing, set both generators and skeletons to not be created. We don't want to take any + // perf hit on either of those at all for our clients. + var newTracker = oldTracker.WithDoNotCreateCreationPolicy(); + if (oldTracker == newTracker) + continue; + + Contract.ThrowIfFalse(newIdToProjectStateMapBuilder.ContainsKey(projectId)); + + var newProjectState = newTracker.ProjectState; + + newIdToProjectStateMapBuilder[projectId] = newProjectState; + newIdToTrackerMapBuilder[projectId] = newTracker; + } + + // Attempt to update _projectIdToTrackerMap to include all the newly created compilation trackers. If another thread has updated + // it since we captured it, then we'll need to loop again to ensure we've operated on the latest compilation trackers. + var updatedIdToTrackerMap = updatedIdToTrackerMapBuilder.ToImmutable(); + if (originalProjectIdToTrackerMap == RoslynImmutableInterlocked.InterlockedCompareExchange(ref _projectIdToTrackerMap, updatedIdToTrackerMap, originalProjectIdToTrackerMap)) + return (newIdToProjectStateMapBuilder.ToImmutable(), newIdToTrackerMapBuilder.ToImmutable()); + } + } + /// /// Creates a branch of the solution that has its compilations frozen in whatever state they are in at the time, /// assuming a background compiler is busy building this compilations. diff --git a/src/Workspaces/Core/Portable/Workspace/Solution/TextDocumentStates.cs b/src/Workspaces/Core/Portable/Workspace/Solution/TextDocumentStates.cs index 1e5f9513360dc..45b1e2c254d8d 100644 --- a/src/Workspaces/Core/Portable/Workspace/Solution/TextDocumentStates.cs +++ b/src/Workspaces/Core/Portable/Workspace/Solution/TextDocumentStates.cs @@ -49,6 +49,7 @@ internal sealed class TextDocumentStates #endif private readonly ImmutableList _ids; + private ImmutableArray _statesInCompilationOrder; private FilePathToDocumentIds? _filePathToDocumentIds; private TextDocumentStates( @@ -64,14 +65,14 @@ private TextDocumentStates( } public TextDocumentStates(IEnumerable states) - : this(states.Select(s => s.Id).ToImmutableList(), + : this([.. states.Select(s => s.Id)], states.ToImmutableSortedDictionary(state => state.Id, state => state, DocumentIdComparer.Instance), filePathToDocumentIds: null) { } public TextDocumentStates(IEnumerable infos, Func stateConstructor) - : this(infos.Select(info => info.Id).ToImmutableList(), + : this([.. infos.Select(info => info.Id)], infos.ToImmutableSortedDictionary(info => info.Id, stateConstructor, DocumentIdComparer.Instance), filePathToDocumentIds: null) { @@ -117,10 +118,12 @@ public TState GetRequiredState(DocumentId documentId) /// Get states ordered in compilation order. /// /// - public IEnumerable GetStatesInCompilationOrder() + public ImmutableArray GetStatesInCompilationOrder() { - var map = States; - return Ids.Select(id => map[id]); + if (_statesInCompilationOrder.IsDefault) + _statesInCompilationOrder = Ids.SelectAsArray(static (id, map) => map[id], States); + + return _statesInCompilationOrder; } public ImmutableArray SelectAsArray(Func selector) diff --git a/src/Workspaces/Core/Portable/Workspace/Workspace.cs b/src/Workspaces/Core/Portable/Workspace/Workspace.cs index 9972fc121a607..2e71d615b880c 100644 --- a/src/Workspaces/Core/Portable/Workspace/Workspace.cs +++ b/src/Workspaces/Core/Portable/Workspace/Workspace.cs @@ -11,6 +11,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Collections; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.ErrorReporting; using Microsoft.CodeAnalysis.Host; @@ -19,7 +20,6 @@ using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.TestHooks; -using Microsoft.CodeAnalysis.Shared.Utilities; using Microsoft.CodeAnalysis.Text; using Roslyn.Utilities; @@ -36,6 +36,12 @@ public abstract partial class Workspace : IDisposable { private readonly ILegacyGlobalOptionService _legacyOptions; + private readonly IAsynchronousOperationListener _asyncOperationListener; + + private readonly AsyncBatchingWorkQueue _workQueue; + private readonly CancellationTokenSource _workQueueTokenSource = new(); + private readonly ITaskSchedulerProvider _taskSchedulerProvider; + // forces serialization of mutation calls from host (OnXXX methods). Must take this lock before taking stateLock. private readonly SemaphoreSlim _serializationLock = new(initialCount: 1); @@ -47,8 +53,6 @@ public abstract partial class Workspace : IDisposable /// private Solution _latestSolution; - private readonly TaskQueue _taskQueue; - // test hooks. internal static bool TestHookStandaloneProjectsDoNotHoldReferences = false; @@ -74,16 +78,22 @@ protected Workspace(HostServices host, string? workspaceKind) _legacyOptions.RegisterWorkspace(this); // queue used for sending events - var schedulerProvider = Services.GetRequiredService(); + _taskSchedulerProvider = Services.GetRequiredService(); + var listenerProvider = Services.GetRequiredService(); - _taskQueue = new TaskQueue(listenerProvider.GetListener(), schedulerProvider.CurrentContextScheduler); + _asyncOperationListener = listenerProvider.GetListener(); + _workQueue = new( + TimeSpan.Zero, + ProcessWorkQueueAsync, + _asyncOperationListener, + _workQueueTokenSource.Token); // initialize with empty solution - var info = SolutionInfo.Create(SolutionId.CreateNewId(), VersionStamp.Create()); - - var emptyOptions = new SolutionOptionSet(_legacyOptions); - - _latestSolution = CreateSolution(info, emptyOptions, analyzerReferences: [], fallbackAnalyzerOptions: ImmutableDictionary.Empty); + _latestSolution = CreateSolution( + SolutionInfo.Create(SolutionId.CreateNewId(), VersionStamp.Create()), + new SolutionOptionSet(_legacyOptions), + analyzerReferences: [], + fallbackAnalyzerOptions: ImmutableDictionary.Empty); _updateSourceGeneratorsQueue = new AsyncBatchingWorkQueue<(ProjectId? projectId, bool forceRegeneration)>( // Idle processing speed @@ -581,15 +591,25 @@ internal void UpdateCurrentSolutionOnOptionsChanged() /// Executes an action as a background task, as part of a sequential queue of tasks. /// [SuppressMessage("Style", "VSTHRD200:Use \"Async\" suffix for async methods", Justification = "This is a Task wrapper, not an asynchronous method.")] +#pragma warning disable IDE0060 // Remove unused parameter protected internal Task ScheduleTask(Action action, string? taskName = "Workspace.Task") - => _taskQueue.ScheduleTask(taskName ?? "Workspace.Task", action, CancellationToken.None); + { + _workQueue.AddWork(action); + return _workQueue.WaitUntilCurrentBatchCompletesAsync(); + } /// /// Execute a function as a background task, as part of a sequential queue of tasks. /// [SuppressMessage("Style", "VSTHRD200:Use \"Async\" suffix for async methods", Justification = "This is a Task wrapper, not an asynchronous method.")] - protected internal Task ScheduleTask(Func func, string? taskName = "Workspace.Task") - => _taskQueue.ScheduleTask(taskName ?? "Workspace.Task", func, CancellationToken.None); + protected internal async Task ScheduleTask(Func func, string? taskName = "Workspace.Task") + { + T? result = default; + _workQueue.AddWork(() => result = func()); + await _workQueue.WaitUntilCurrentBatchCompletesAsync().ConfigureAwait(false); + return result!; + } +#pragma warning restore IDE0060 // Remove unused parameter /// /// Override this method to act immediately when the text of a document has changed, as opposed @@ -695,6 +715,28 @@ protected virtual void Dispose(bool finalize) // We're disposing this workspace. Stop any work to update SG docs in the background. _updateSourceGeneratorsQueueTokenSource.Cancel(); + _workQueueTokenSource.Cancel(); + } + + private async ValueTask ProcessWorkQueueAsync(ImmutableSegmentedList list, CancellationToken cancellationToken) + { + // Hop over to the right scheduler to execute all this work. + await Task.Factory.StartNew(() => + { + foreach (var item in list) + { + cancellationToken.ThrowIfCancellationRequested(); + + try + { + item(); + } + catch (Exception e) when (FatalError.ReportAndCatchUnlessCanceled(e)) + { + // Ensure we continue onto further items, even if one particular item fails. + } + } + }, cancellationToken, TaskCreationOptions.None, _taskSchedulerProvider.CurrentContextScheduler).ConfigureAwait(false); } #region Host API @@ -1971,7 +2013,7 @@ private void ApplyChangedDocument( { // We have the old text, but no new text is easily available. This typically happens when the content is modified via changes to the syntax tree. // Ask document to compute equivalent text changes by comparing the syntax trees, and use them to - var textChanges = newDoc.GetTextChangesAsync(oldDoc, CancellationToken.None).WaitAndGetResult_CanCallOnBackground(CancellationToken.None); // needs wait + var textChanges = newDoc.GetTextChangesSynchronously(oldDoc, CancellationToken.None); this.ApplyDocumentTextChanged(documentId, oldText.WithChanges(textChanges)); } else @@ -1983,15 +2025,6 @@ private void ApplyChangedDocument( } } - [Conditional("DEBUG")] - private static void CheckNoChanges(Solution oldSolution, Solution newSolution) - { - var changes = newSolution.GetChanges(oldSolution); - Contract.ThrowIfTrue(changes.GetAddedProjects().Any()); - Contract.ThrowIfTrue(changes.GetRemovedProjects().Any()); - Contract.ThrowIfTrue(changes.GetProjectChanges().Any()); - } - private static ProjectInfo CreateProjectInfo(Project project) { return ProjectInfo.Create( diff --git a/src/Workspaces/Core/Portable/Workspace/Workspace_Editor.cs b/src/Workspaces/Core/Portable/Workspace/Workspace_Editor.cs index 1b56baae52f2c..24bf354de7229 100644 --- a/src/Workspaces/Core/Portable/Workspace/Workspace_Editor.cs +++ b/src/Workspaces/Core/Portable/Workspace/Workspace_Editor.cs @@ -53,7 +53,7 @@ internal void ClearOpenDocuments() List docIds; using (_stateLock.DisposableWait()) { - docIds = _projectToOpenDocumentsMap.Values.SelectMany(x => x).ToList(); + docIds = [.. _projectToOpenDocumentsMap.Values.SelectMany(x => x)]; } foreach (var docId in docIds) @@ -455,9 +455,9 @@ internal void OnSourceGeneratedDocumentOpened( // Fire and forget that the workspace is changing. // We raise 2 events for source document opened. - var token = _taskQueue.Listener.BeginAsyncOperation(nameof(OnSourceGeneratedDocumentOpened)); + var token = _asyncOperationListener.BeginAsyncOperation(nameof(OnSourceGeneratedDocumentOpened)); _ = RaiseDocumentOpenedEventAsync(document).CompletesAsyncOperation(token); - token = _taskQueue.Listener.BeginAsyncOperation(TextDocumentOpenedEventName); + token = _asyncOperationListener.BeginAsyncOperation(TextDocumentOpenedEventName); _ = RaiseTextDocumentOpenedEventAsync(document).CompletesAsyncOperation(token); } @@ -475,9 +475,9 @@ internal void OnSourceGeneratedDocumentClosed(SourceGeneratedDocument document) // Fire and forget that the workspace is changing. // We raise 2 events for source document closed. - var token = _taskQueue.Listener.BeginAsyncOperation(nameof(OnSourceGeneratedDocumentClosed)); + var token = _asyncOperationListener.BeginAsyncOperation(nameof(OnSourceGeneratedDocumentClosed)); _ = RaiseDocumentClosedEventAsync(document).CompletesAsyncOperation(token); - token = _taskQueue.Listener.BeginAsyncOperation(TextDocumentClosedEventName); + token = _asyncOperationListener.BeginAsyncOperation(TextDocumentClosedEventName); _ = RaiseTextDocumentClosedEventAsync(document).CompletesAsyncOperation(token); } } diff --git a/src/Workspaces/Core/Portable/WorkspacesResources.resx b/src/Workspaces/Core/Portable/WorkspacesResources.resx index 4d20a5721081b..1b22399b7d47f 100644 --- a/src/Workspaces/Core/Portable/WorkspacesResources.resx +++ b/src/Workspaces/Core/Portable/WorkspacesResources.resx @@ -201,12 +201,6 @@ '{0}' is not open. - - A language name cannot be specified for this option. - - - A language name must be specified for this option. - File was externally modified: {0}. @@ -237,9 +231,6 @@ {0} is still open. - - Value too large to be represented as a 30 bit unsigned integer. - Cannot open project '{0}' because the file extension '{1}' is not associated with a language. @@ -258,21 +249,16 @@ Solution file not found: '{0}' - - Unmerged change from project '{0}' - - - Added: + + TODO: Unmerged change from project '{0}' + {Locked="TODO"} - - After: + + After Before: - - Removed: - Adding additional documents is not supported. @@ -381,9 +367,6 @@ Show Stack Trace - - Stream is too long. - Async Method {locked: async}{locked: method} These are keywords (unless the order of words or capitalization should be handled differently) @@ -421,12 +404,6 @@ .NET Coding Conventions - - Indentation and spacing - - - New line preferences - Visual Basic files diff --git a/src/Workspaces/Core/Portable/xlf/WorkspacesResources.cs.xlf b/src/Workspaces/Core/Portable/xlf/WorkspacesResources.cs.xlf index df10bef463fe6..dcdc5ce3056c4 100644 --- a/src/Workspaces/Core/Portable/xlf/WorkspacesResources.cs.xlf +++ b/src/Workspaces/Core/Portable/xlf/WorkspacesResources.cs.xlf @@ -17,6 +17,11 @@ Přidávání dokumentů konfigurace analyzátoru se nepodporuje. + + After + After + + An error occurred while reading the specified configuration file: {0} Došlo k chybě při čtení zadaného konfiguračního souboru: {0} @@ -92,16 +97,6 @@ FixAllScope.Custom se s tímto rozhraním API nepodporuje. - - Indentation and spacing - Odsazení a mezery - - - - New line preferences - Předvolby nových řádků - - Only submission project can reference submission projects. Na projekty odeslání se může odkazovat jen projekt odeslání. @@ -202,6 +197,11 @@ Synchronizovat obor názvů se strukturou složek + + TODO: Unmerged change from project '{0}' + TODO: Unmerged change from project '{0}' + {Locked="TODO"} + The contents of a SourceGeneratedDocument may not be changed. Obsah dokumentu SourceGeneratedDocument nesmí být změněn. @@ -337,16 +337,6 @@ {0} není otevřený. - - A language name cannot be specified for this option. - Pro tuto možnost se nesmí zadat název jazyka. - - - - A language name must be specified for this option. - Pro tuto možnost se musí zadat název jazyka. - - File was externally modified: {0}. Došlo k externí úpravě souboru: {0}. @@ -392,11 +382,6 @@ {0} je pořád otevřený. - - Value too large to be represented as a 30 bit unsigned integer. - Hodnota je moc velká, než aby se dala vyjádřit jako 30bitové nepodepsané celé číslo. - - Cannot open project '{0}' because the file extension '{1}' is not associated with a language. Nejde otevřít projekt {0}, protože přípona souboru {1} není přidružená k jazyku. @@ -427,31 +412,11 @@ Nenalezený soubor řešení: {0} - - Unmerged change from project '{0}' - Nesloučené změny z projektu '{0}' - - - - Added: - Přidáno: - - - - After: - Po: - - Before: Před: - - Removed: - Odebráno: - - Adding additional documents is not supported. Přidávání dalších dokumentů se nepodporuje. @@ -607,11 +572,6 @@ Zobrazit trasování zásobníku - - Stream is too long. - Stream je moc dlouhý. - - Async Method Asynchronní metoda diff --git a/src/Workspaces/Core/Portable/xlf/WorkspacesResources.de.xlf b/src/Workspaces/Core/Portable/xlf/WorkspacesResources.de.xlf index 9b26fd656fac1..0697a2bedfacf 100644 --- a/src/Workspaces/Core/Portable/xlf/WorkspacesResources.de.xlf +++ b/src/Workspaces/Core/Portable/xlf/WorkspacesResources.de.xlf @@ -17,6 +17,11 @@ Das Hinzufügen von Konfigurationsdokumenten des Analysetools wird nicht unterstützt. + + After + After + + An error occurred while reading the specified configuration file: {0} Beim Lesen der angegebenen Konfigurationsdatei ist ein Fehler aufgetreten: {0} @@ -92,16 +97,6 @@ "FixAllScope.Custom" wird mit dieser API nicht unterstützt - - Indentation and spacing - Einzüge und Abstände - - - - New line preferences - Einstellungen für neue Zeilen - - Only submission project can reference submission projects. Nur ein Übermittlungsprojekt kann auf Übermittlungsprojekte verweisen. @@ -202,6 +197,11 @@ Namespace mit Ordnerstruktur synchronisieren + + TODO: Unmerged change from project '{0}' + TODO: Unmerged change from project '{0}' + {Locked="TODO"} + The contents of a SourceGeneratedDocument may not be changed. Der Inhalt eines SourceGeneratedDocument kann nicht geändert werden. @@ -337,16 +337,6 @@ "{0}" ist nicht geöffnet. - - A language name cannot be specified for this option. - Für diese Option kann kein Sprachenname angegeben werden. - - - - A language name must be specified for this option. - Für diese Option muss ein Sprachenname angegeben werden. - - File was externally modified: {0}. Datei wurde extern modifiziert: {0}. @@ -392,11 +382,6 @@ "{0}" ist noch geöffnet. - - Value too large to be represented as a 30 bit unsigned integer. - Der Wert ist zu groß, um als ganze 30-Bit-Zahl ohne Vorzeichen dargestellt zu werden. - - Cannot open project '{0}' because the file extension '{1}' is not associated with a language. Projekt "{0}" kann nicht geöffnet werden, da die Dateierweiterung "{1}" keiner Sprache zugeordnet ist. @@ -427,31 +412,11 @@ Lösungsdatei nicht gefunden: "{0}" - - Unmerged change from project '{0}' - Nicht gemergte Änderung aus Projekt "{0}" - - - - Added: - Hinzugefügt: - - - - After: - Nach: - - Before: Vor: - - Removed: - Entfernt: - - Adding additional documents is not supported. Das Hinzufügen weitere Dokumente wird nicht unterstützt. @@ -607,11 +572,6 @@ Stapelüberwachung anzeigen - - Stream is too long. - Der Datenstrom ist zu lang. - - Async Method Asynchrone Methode diff --git a/src/Workspaces/Core/Portable/xlf/WorkspacesResources.es.xlf b/src/Workspaces/Core/Portable/xlf/WorkspacesResources.es.xlf index 2e1ce78abfa0d..4685888ed854e 100644 --- a/src/Workspaces/Core/Portable/xlf/WorkspacesResources.es.xlf +++ b/src/Workspaces/Core/Portable/xlf/WorkspacesResources.es.xlf @@ -17,6 +17,11 @@ No se permite agregar documentos de configuración del analizador. + + After + After + + An error occurred while reading the specified configuration file: {0} Error al leer el archivo de configuración especificado: {0} @@ -92,16 +97,6 @@ "FixAllScope.Custom" no se admite con esta API - - Indentation and spacing - Sangría y espaciado - - - - New line preferences - Nuevas preferencias de línea - - Only submission project can reference submission projects. Solo un proyecto de envío puede hacer referencia a proyectos de envío. @@ -202,6 +197,11 @@ Sincronizar espacio de nombres con estructura de carpetas + + TODO: Unmerged change from project '{0}' + TODO: Unmerged change from project '{0}' + {Locked="TODO"} + The contents of a SourceGeneratedDocument may not be changed. No se puede cambiar el contenido de un elemento SourceGeneratedDocument. @@ -337,16 +337,6 @@ '{0}' no está abierto. - - A language name cannot be specified for this option. - No se puede especificar un nombre de lenguaje para esta opción. - - - - A language name must be specified for this option. - Se debe especificar un nombre de lenguaje para esta opción. - - File was externally modified: {0}. El archivo se modificó externamente: {0}. @@ -392,11 +382,6 @@ {0} aún está abierto. - - Value too large to be represented as a 30 bit unsigned integer. - Valor demasiado largo para representarse como entero sin signo de 30 bits. - - Cannot open project '{0}' because the file extension '{1}' is not associated with a language. No se puede abrir el proyecto '{0}' porque la extensión de archivo '{1}' no está asociada a un lenguaje. @@ -427,31 +412,11 @@ Archivo de solución no encontrado: '{0}' - - Unmerged change from project '{0}' - Cambio no fusionado mediante combinación del proyecto '{0}' - - - - Added: - Agregado: - - - - After: - Después: - - Before: Antes: - - Removed: - Quitado: - - Adding additional documents is not supported. No se permite agregar documentos adicionales. @@ -607,11 +572,6 @@ Mostrar seguimiento de la pila - - Stream is too long. - Secuencia demasiado larga. - - Async Method Metodo asincrónico diff --git a/src/Workspaces/Core/Portable/xlf/WorkspacesResources.fr.xlf b/src/Workspaces/Core/Portable/xlf/WorkspacesResources.fr.xlf index d0767ada4ed19..81c10f6a042fd 100644 --- a/src/Workspaces/Core/Portable/xlf/WorkspacesResources.fr.xlf +++ b/src/Workspaces/Core/Portable/xlf/WorkspacesResources.fr.xlf @@ -17,6 +17,11 @@ L'ajout de documents de configuration de l'analyseur n'est pas pris en charge. + + After + After + + An error occurred while reading the specified configuration file: {0} Une erreur s'est produite lors de la lecture du fichier de configuration spécifié : {0} @@ -92,16 +97,6 @@ 'FixAllScope.Custom' n’est pas pris en charge avec cette API - - Indentation and spacing - Indentation et espacement - - - - New line preferences - Préférences de nouvelle ligne - - Only submission project can reference submission projects. Seul un projet de soumission peut référencer des projets de soumission. @@ -202,6 +197,11 @@ Synchroniser l'espace de noms avec la structure de dossier + + TODO: Unmerged change from project '{0}' + TODO: Unmerged change from project '{0}' + {Locked="TODO"} + The contents of a SourceGeneratedDocument may not be changed. Le contenu de SourceGeneratedDocument ne doit pas être changé. @@ -337,16 +337,6 @@ '{0}' n'est pas ouvert. - - A language name cannot be specified for this option. - Impossible de spécifier un nom de langage pour cette option. - - - - A language name must be specified for this option. - Un nom de langage doit être spécifié pour cette option. - - File was externally modified: {0}. Le fichier a été modifié en externe : {0}. @@ -392,11 +382,6 @@ {0} est toujours ouvert. - - Value too large to be represented as a 30 bit unsigned integer. - La valeur est trop grande pour être représentée comme un entier non signé 30 bits. - - Cannot open project '{0}' because the file extension '{1}' is not associated with a language. Impossible d'ouvrir le projet '{0}', car l'extension de fichier '{1}' n'est pas associée à un langage. @@ -427,31 +412,11 @@ Fichier solution introuvable : '{0}' - - Unmerged change from project '{0}' - Modification non fusionnée à partir du projet '{0}' - - - - Added: - Ajouté : - - - - After: - Après : - - Before: Avant : - - Removed: - Supprimé : - - Adding additional documents is not supported. L'ajout de documents supplémentaires n'est pas pris en charge. @@ -607,11 +572,6 @@ Afficher l'arborescence des appels de procédure - - Stream is too long. - Le flux est trop long. - - Async Method Méthode async diff --git a/src/Workspaces/Core/Portable/xlf/WorkspacesResources.it.xlf b/src/Workspaces/Core/Portable/xlf/WorkspacesResources.it.xlf index 5278d01f20d54..21f1fbfdc3521 100644 --- a/src/Workspaces/Core/Portable/xlf/WorkspacesResources.it.xlf +++ b/src/Workspaces/Core/Portable/xlf/WorkspacesResources.it.xlf @@ -17,6 +17,11 @@ L'aggiunta di documenti di configurazione dell'analizzatore non è supportata. + + After + After + + An error occurred while reading the specified configuration file: {0} Si è verificato un errore durante la lettura del file di configurazione specificato: {0} @@ -92,16 +97,6 @@ 'FixAllScope.Custom' non è supportato con questa API - - Indentation and spacing - Rientro e spaziatura - - - - New line preferences - Preferenze per nuova riga - - Only submission project can reference submission projects. Solo il progetto di invio può fare riferimento a progetti di invio. @@ -202,6 +197,11 @@ Sincronizza lo spazio dei nomi con la struttura di cartelle + + TODO: Unmerged change from project '{0}' + TODO: Unmerged change from project '{0}' + {Locked="TODO"} + The contents of a SourceGeneratedDocument may not be changed. Non è possibile modificare il contenuto di un elemento SourceGeneratedDocument. @@ -337,16 +337,6 @@ '{0}' non è aperto. - - A language name cannot be specified for this option. - Non è possibile specificare un nome di linguaggio per questa opzione. - - - - A language name must be specified for this option. - È necessario specificare un nome di linguaggio per questa opzione. - - File was externally modified: {0}. Il file è stato modificato esternamente: {0}. @@ -392,11 +382,6 @@ {0} è ancora aperto. - - Value too large to be represented as a 30 bit unsigned integer. - Il valore è troppo grande per essere rappresentato come intero senza segno a 30 bit. - - Cannot open project '{0}' because the file extension '{1}' is not associated with a language. Non è possibile aprire il progetto '{0}' perché l'estensione di file '{1}' non è associata a un linguaggio. @@ -427,31 +412,11 @@ Il file di soluzione non è stato trovato: '{0}' - - Unmerged change from project '{0}' - Modifica senza merge dal progetto '{0}' - - - - Added: - Aggiunto: - - - - After: - Dopo: - - Before: Prima: - - Removed: - Elementi rimossi: - - Adding additional documents is not supported. L'aggiunta di altri documenti non è supportata. @@ -607,11 +572,6 @@ Mostra analisi dello stack - - Stream is too long. - Il flusso è troppo lungo. - - Async Method Metodo asincrono diff --git a/src/Workspaces/Core/Portable/xlf/WorkspacesResources.ja.xlf b/src/Workspaces/Core/Portable/xlf/WorkspacesResources.ja.xlf index 2e904cf4e0995..e62af1b168890 100644 --- a/src/Workspaces/Core/Portable/xlf/WorkspacesResources.ja.xlf +++ b/src/Workspaces/Core/Portable/xlf/WorkspacesResources.ja.xlf @@ -17,6 +17,11 @@ アナライザー構成ドキュメントの追加はサポートされていません。 + + After + After + + An error occurred while reading the specified configuration file: {0} 指定した構成ファイルの読み取り中にエラーが発生しました: {0} @@ -92,16 +97,6 @@ 'FixAllScope.Custom' は、この API ではサポートされていません - - Indentation and spacing - インデントと間隔 - - - - New line preferences - 改行設定 - - Only submission project can reference submission projects. 送信プロジェクトを参照できるのは、送信プロジェクトのみです。 @@ -202,6 +197,11 @@ 名前空間とフォルダー構造の同期 + + TODO: Unmerged change from project '{0}' + TODO: Unmerged change from project '{0}' + {Locked="TODO"} + The contents of a SourceGeneratedDocument may not be changed. SourceGeneratedDocument のコンテンツが変更されない可能性があります。 @@ -337,16 +337,6 @@ '{0}' が開いていません。 - - A language name cannot be specified for this option. - 言語名は、このオプションでは指定できません。 - - - - A language name must be specified for this option. - このオプションの言語名を指定する必要があります。 - - File was externally modified: {0}. ファイルが外部で変更されました: {0}。 @@ -392,11 +382,6 @@ {0} が開いたままです。 - - Value too large to be represented as a 30 bit unsigned integer. - 値が大きすぎるため、30 ビットの符号なし整数として表すことができません。 - - Cannot open project '{0}' because the file extension '{1}' is not associated with a language. ファイルの拡張子 '{1}' が言語に関連付けられていないため、プロジェクト '{0}' を開くことができません。 @@ -427,31 +412,11 @@ ソリューション ファイルが見つかりません: '{0}' - - Unmerged change from project '{0}' - プロジェクト '{0}' からのマージされていない変更 - - - - Added: - 追加済み: - - - - After: - 後: - - Before: 前: - - Removed: - 削除済み: - - Adding additional documents is not supported. 追加ドキュメントの追加はサポートされていません。 @@ -607,11 +572,6 @@ スタック トレースを表示します - - Stream is too long. - ストリームが長すぎます。 - - Async Method 非同期メソッド diff --git a/src/Workspaces/Core/Portable/xlf/WorkspacesResources.ko.xlf b/src/Workspaces/Core/Portable/xlf/WorkspacesResources.ko.xlf index 51ca8ed823f49..dd8f82d862a27 100644 --- a/src/Workspaces/Core/Portable/xlf/WorkspacesResources.ko.xlf +++ b/src/Workspaces/Core/Portable/xlf/WorkspacesResources.ko.xlf @@ -17,6 +17,11 @@ 분석기 구성 문서 추가는 지원되지 않습니다. + + After + After + + An error occurred while reading the specified configuration file: {0} 지정한 구성 파일을 읽는 동안 오류가 발생했습니다({0}). @@ -92,16 +97,6 @@ 이 API에서는 'FixAllScope.Custom'이 지원되지 않습니다. - - Indentation and spacing - 들여쓰기 및 간격 - - - - New line preferences - 새 줄 기본 설정 - - Only submission project can reference submission projects. 제출 프로젝트만 제출 프로젝트를 참조할 수 있습니다. @@ -202,6 +197,11 @@ 네임스페이스를 폴더 구조로 동기화 + + TODO: Unmerged change from project '{0}' + TODO: Unmerged change from project '{0}' + {Locked="TODO"} + The contents of a SourceGeneratedDocument may not be changed. SourceGeneratedDocument의 콘텐츠는 변경할 수 없습니다. @@ -337,16 +337,6 @@ '{0}'이(가) 열리지 않았습니다. - - A language name cannot be specified for this option. - 이 옵션에 대한 언어 이름을 지정할 수 없습니다. - - - - A language name must be specified for this option. - 이 옵션에 대한 언어 이름을 지정해야 합니다. - - File was externally modified: {0}. 파일이 외부에서 수정되었습니다({0}). @@ -392,11 +382,6 @@ {0}이(가) 열려 있습니다. - - Value too large to be represented as a 30 bit unsigned integer. - 값이 너무 커서 30비트 정수로 표시할 수 없습니다. - - Cannot open project '{0}' because the file extension '{1}' is not associated with a language. '{1}' 파일 확장명이 언어에 연결되어 있지 않아 '{0}' 프로젝트를 열 수 없습니다. @@ -427,31 +412,11 @@ '{0}' 솔루션 파일을 찾을 수 없습니다. - - Unmerged change from project '{0}' - '{0}' 프로젝트에서 병합되지 않은 변경 내용 - - - - Added: - 추가됨: - - - - After: - 이후: - - Before: 이전: - - Removed: - 제거됨: - - Adding additional documents is not supported. 추가 문서 추가는 지원되지 않았습니다. @@ -607,11 +572,6 @@ 스택 추적 표시 - - Stream is too long. - 스트림이 너무 깁니다. - - Async Method 비동기 메서드 diff --git a/src/Workspaces/Core/Portable/xlf/WorkspacesResources.pl.xlf b/src/Workspaces/Core/Portable/xlf/WorkspacesResources.pl.xlf index c64c161fb2e1f..29488806bb315 100644 --- a/src/Workspaces/Core/Portable/xlf/WorkspacesResources.pl.xlf +++ b/src/Workspaces/Core/Portable/xlf/WorkspacesResources.pl.xlf @@ -17,6 +17,11 @@ Dodawanie dokumentów z konfiguracją analizatora nie jest obsługiwane. + + After + After + + An error occurred while reading the specified configuration file: {0} Wystąpił błąd podczas odczytywania określonego pliku konfiguracji: {0} @@ -92,16 +97,6 @@ Element „FixAllScope.Custom” nie jest obsługiwany w tym interfejsie API - - Indentation and spacing - Wcięcia i odstępy - - - - New line preferences - Preferencje nowego wiersza - - Only submission project can reference submission projects. Tylko przesyłany projekt może odwoływać się do przesyłanych projektów. @@ -202,6 +197,11 @@ Synchronizuj przestrzeń nazw ze strukturą folderów + + TODO: Unmerged change from project '{0}' + TODO: Unmerged change from project '{0}' + {Locked="TODO"} + The contents of a SourceGeneratedDocument may not be changed. Nie można zmienić zawartości elementu SourceGeneratedDocument. @@ -337,16 +337,6 @@ 'Element „{0}” nie jest otwarty. - - A language name cannot be specified for this option. - Nie można określić nazwy języka dla tej opcji. - - - - A language name must be specified for this option. - Nazwa języka musi zostać określona dla tej opcji. - - File was externally modified: {0}. Plik został zmodyfikowany na zewnątrz: {0}. @@ -392,11 +382,6 @@ Element {0} jest nadal otwarty. - - Value too large to be represented as a 30 bit unsigned integer. - Wartość jest zbyt duża, dlatego nie może być reprezentowana jako 30-bitowa liczba całkowita bez znaku. - - Cannot open project '{0}' because the file extension '{1}' is not associated with a language. Nie można otworzyć projektu „{0}”, ponieważ rozszerzenie pliku „{1}” nie jest skojarzone z językiem. @@ -427,31 +412,11 @@ Nie znaleziono pliku rozwiązania: „{0}” - - Unmerged change from project '{0}' - Niescalona zmiana z projektu „{0}” - - - - Added: - Dodano: - - - - After: - Po: - - Before: Przed: - - Removed: - Usunięto: - - Adding additional documents is not supported. Dodawanie kolejnych dokumentów nie jest obsługiwane. @@ -607,11 +572,6 @@ Pokaż ślad stosu - - Stream is too long. - Strumień jest za długi. - - Async Method Metoda asynchroniczna diff --git a/src/Workspaces/Core/Portable/xlf/WorkspacesResources.pt-BR.xlf b/src/Workspaces/Core/Portable/xlf/WorkspacesResources.pt-BR.xlf index c3063219f0026..7c43186d24b47 100644 --- a/src/Workspaces/Core/Portable/xlf/WorkspacesResources.pt-BR.xlf +++ b/src/Workspaces/Core/Portable/xlf/WorkspacesResources.pt-BR.xlf @@ -17,6 +17,11 @@ Não há suporte para a adição de documentos da configuração do analisador. + + After + After + + An error occurred while reading the specified configuration file: {0} Ocorreu um erro ao ler o arquivo de configuração especificado: {0} @@ -92,16 +97,6 @@ Não há suporte para 'FixAllScope.Custom' com esta API - - Indentation and spacing - Recuo e espaçamento - - - - New line preferences - Preferências de nova linha - - Only submission project can reference submission projects. Somente o projeto de envio pode fazer referência a projetos de envio. @@ -202,6 +197,11 @@ Sincronizar namespace com a estrutura de pasta + + TODO: Unmerged change from project '{0}' + TODO: Unmerged change from project '{0}' + {Locked="TODO"} + The contents of a SourceGeneratedDocument may not be changed. O conteúdo de um SourceGeneratedDocument não pode ser alterado. @@ -337,16 +337,6 @@ "{0}" não está aberto. - - A language name cannot be specified for this option. - Um nome de idioma não pode ser especificado para essa opção. - - - - A language name must be specified for this option. - Um nome de idioma deve ser especificado para esta opção. - - File was externally modified: {0}. Arquivo foi modificado externamente: {0}. @@ -392,11 +382,6 @@ {0} ainda está aberto. - - Value too large to be represented as a 30 bit unsigned integer. - Valor muito grande para ser representado como um inteiro não assinado de 30 bits. - - Cannot open project '{0}' because the file extension '{1}' is not associated with a language. Não é possível abrir o projeto "{0}" porque a extensão de arquivo "{1}" não está associada a um idioma. @@ -427,31 +412,11 @@ Arquivo de solução não encontrado: "{0}" - - Unmerged change from project '{0}' - Alteração não mesclada do projeto '{0}' - - - - Added: - Adicionado: - - - - After: - Após: - - Before: Antes: - - Removed: - Removido: - - Adding additional documents is not supported. Não há suporte para a adição de documentos adicionais. @@ -607,11 +572,6 @@ Mostrar o Rastreamento de Pilha - - Stream is too long. - O fluxo é muito longo. - - Async Method Método Assíncrono diff --git a/src/Workspaces/Core/Portable/xlf/WorkspacesResources.ru.xlf b/src/Workspaces/Core/Portable/xlf/WorkspacesResources.ru.xlf index 37d4aeca4ef81..749bedd7e4a7f 100644 --- a/src/Workspaces/Core/Portable/xlf/WorkspacesResources.ru.xlf +++ b/src/Workspaces/Core/Portable/xlf/WorkspacesResources.ru.xlf @@ -17,6 +17,11 @@ Добавление документов конфигурации анализатора не поддерживается. + + After + After + + An error occurred while reading the specified configuration file: {0} Произошла ошибка при чтении указанного файла конфигурации: {0} @@ -92,16 +97,6 @@ "FixAllScope.Custom" не поддерживается с этим API - - Indentation and spacing - Отступы и интервалы - - - - New line preferences - Предпочтения для новых строк - - Only submission project can reference submission projects. Только проект отправки может ссылаться на другие проекты отправки. @@ -202,6 +197,11 @@ Синхронизировать пространство имен со структурой папок + + TODO: Unmerged change from project '{0}' + TODO: Unmerged change from project '{0}' + {Locked="TODO"} + The contents of a SourceGeneratedDocument may not be changed. Содержимое SourceGeneratedDocument не может быть изменено. @@ -337,16 +337,6 @@ "{0}" не открыт. - - A language name cannot be specified for this option. - Для данного параметра невозможно указать имя языка. - - - - A language name must be specified for this option. - Для данного параметра необходимо указать имя языка. - - File was externally modified: {0}. Файл был изменен извне: {0}. @@ -392,11 +382,6 @@ {0} все еще открыт. - - Value too large to be represented as a 30 bit unsigned integer. - Слишком большое значение для представления в виде 30-разрядного целого числа без знака. - - Cannot open project '{0}' because the file extension '{1}' is not associated with a language. Не удается открыть проект "{0}", так как расширение файла "{1}" не связано с языком. @@ -427,31 +412,11 @@ Не удалось найти файл решения: "{0}" - - Unmerged change from project '{0}' - Необъединенное слияние из проекта "{0}" - - - - Added: - Добавлены: - - - - After: - После: - - Before: До: - - Removed: - Удалено: - - Adding additional documents is not supported. Добавление дополнительных документов не поддерживается. @@ -607,11 +572,6 @@ Показать трассировку стека - - Stream is too long. - Слишком длинный поток. - - Async Method Асинхронный метод diff --git a/src/Workspaces/Core/Portable/xlf/WorkspacesResources.tr.xlf b/src/Workspaces/Core/Portable/xlf/WorkspacesResources.tr.xlf index cb18f55bba6eb..7cd712a7128b1 100644 --- a/src/Workspaces/Core/Portable/xlf/WorkspacesResources.tr.xlf +++ b/src/Workspaces/Core/Portable/xlf/WorkspacesResources.tr.xlf @@ -17,6 +17,11 @@ Çözümleyici yapılandırma belgelerinin eklenmesi desteklenmiyor. + + After + After + + An error occurred while reading the specified configuration file: {0} Belirtilen yapılandırma dosyası okunurken bir hata oluştu: {0} @@ -92,16 +97,6 @@ 'FixAllScope.Custom' bu API ile desteklenmiyor - - Indentation and spacing - Girinti ve aralığı - - - - New line preferences - Yeni satır tercihleri - - Only submission project can reference submission projects. Gönderim projelerine yalnızca gönderim projesi başvurabilir. @@ -202,6 +197,11 @@ Ad alanını klasör yapısına eşitle + + TODO: Unmerged change from project '{0}' + TODO: Unmerged change from project '{0}' + {Locked="TODO"} + The contents of a SourceGeneratedDocument may not be changed. SourceGeneratedDocument'ın içeriği değiştirilemez. @@ -337,16 +337,6 @@ '{0}' açık değil. - - A language name cannot be specified for this option. - Bu seçenek için bir dil adı belirtilemiyor. - - - - A language name must be specified for this option. - Bu seçenek için bir dil adı belirtilmelidir. - - File was externally modified: {0}. Dosya dışarıdan değiştirildi: {0}. @@ -392,11 +382,6 @@ {0} hala açık. - - Value too large to be represented as a 30 bit unsigned integer. - Değer, 30 bit işaretsiz tamsayı olarak temsil edilemeyecek kadar büyük. - - Cannot open project '{0}' because the file extension '{1}' is not associated with a language. Dosya uzantısı '{1}' bir dil ile ilişkili olmadığı için '{0}' projesi açılamıyor. @@ -427,31 +412,11 @@ Çözüm dosyası bulunamadı: '{0}' - - Unmerged change from project '{0}' - '{0}' projesinden birleştirilmemiş değişiklik - - - - Added: - Eklendi: - - - - After: - Önce: - - Before: Sonra: - - Removed: - Kaldırıldı: - - Adding additional documents is not supported. Ek belgelerin eklenmesi desteklenmiyor. @@ -607,11 +572,6 @@ Yığın İzlemesini Göster - - Stream is too long. - Akış çok uzun. - - Async Method Zaman Uyumsuz Metot diff --git a/src/Workspaces/Core/Portable/xlf/WorkspacesResources.zh-Hans.xlf b/src/Workspaces/Core/Portable/xlf/WorkspacesResources.zh-Hans.xlf index e57971c54d489..7b799695cae87 100644 --- a/src/Workspaces/Core/Portable/xlf/WorkspacesResources.zh-Hans.xlf +++ b/src/Workspaces/Core/Portable/xlf/WorkspacesResources.zh-Hans.xlf @@ -17,6 +17,11 @@ 不支持添加分析器配置文档。 + + After + After + + An error occurred while reading the specified configuration file: {0} 读取指定的配置文件时出错: {0} @@ -92,16 +97,6 @@ 此 API 不支持 'FixAllScope.Custom' - - Indentation and spacing - 缩进和间距 - - - - New line preferences - 新行首选项 - - Only submission project can reference submission projects. 只有提交项目才能引用提交项目。 @@ -202,6 +197,11 @@ 将命名空间同步到文件夹结构 + + TODO: Unmerged change from project '{0}' + TODO: Unmerged change from project '{0}' + {Locked="TODO"} + The contents of a SourceGeneratedDocument may not be changed. 不能更改 SourceGeneratedDocument 的内容。 @@ -337,16 +337,6 @@ '未打开“{0}”。 - - A language name cannot be specified for this option. - 无法为此选项指定语言名称。 - - - - A language name must be specified for this option. - 必须为此选项指定语言名称。 - - File was externally modified: {0}. 已从外部修改文件: {0}。 @@ -392,11 +382,6 @@ {0}仍处于打开状态。 - - Value too large to be represented as a 30 bit unsigned integer. - 值太大,无法表示为 30 位无符号整数。 - - Cannot open project '{0}' because the file extension '{1}' is not associated with a language. 无法打开项目“{0}”, 因为文件扩展名“{1}”没有与某种语言关联。 @@ -427,31 +412,11 @@ 找不到解决方案文件:“{0}” - - Unmerged change from project '{0}' - 项目“{0}”的未合并的更改 - - - - Added: - 添加项: - - - - After: - 在此之后: - - Before: 在此之前: - - Removed: - 已移除: - - Adding additional documents is not supported. 不支持添加其他文档。 @@ -607,11 +572,6 @@ 显示“堆栈跟踪” - - Stream is too long. - “流”过长。 - - Async Method 异步方法 diff --git a/src/Workspaces/Core/Portable/xlf/WorkspacesResources.zh-Hant.xlf b/src/Workspaces/Core/Portable/xlf/WorkspacesResources.zh-Hant.xlf index fa22dd91f1381..df3a6afe4911b 100644 --- a/src/Workspaces/Core/Portable/xlf/WorkspacesResources.zh-Hant.xlf +++ b/src/Workspaces/Core/Portable/xlf/WorkspacesResources.zh-Hant.xlf @@ -17,6 +17,11 @@ 不支援新增分析器組態文件。 + + After + After + + An error occurred while reading the specified configuration file: {0} 讀取指定的組態檔時發生錯誤: {0} @@ -92,16 +97,6 @@ 此 API 不支援 'FixAllScope.Custom' - - Indentation and spacing - 縮排和間距 - - - - New line preferences - 新行喜好設定 - - Only submission project can reference submission projects. 只有提交專案可以參考提交專案。 @@ -202,6 +197,11 @@ 將命名空間同步到資料夾結構 + + TODO: Unmerged change from project '{0}' + TODO: Unmerged change from project '{0}' + {Locked="TODO"} + The contents of a SourceGeneratedDocument may not be changed. SourceGeneratedDocument 的內容可能無法變更。 @@ -337,16 +337,6 @@ '{0}' 未開啟。 - - A language name cannot be specified for this option. - 無法指定此選項的語言名稱。 - - - - A language name must be specified for this option. - 必須指定此選項的語言名稱。 - - File was externally modified: {0}. 已在外部修改檔案: {0}。 @@ -392,11 +382,6 @@ {0} 仍在開啟中。 - - Value too large to be represented as a 30 bit unsigned integer. - 值太大,無法呈現為 30 位元不帶正負號的整數。 - - Cannot open project '{0}' because the file extension '{1}' is not associated with a language. 無法開啟專案 '{0}',因為副檔名 '{1}' 未與語言相關聯。 @@ -427,31 +412,11 @@ 找不到方案檔: '{0}' - - Unmerged change from project '{0}' - 取消合併專案 '{0}' 的變更 - - - - Added: - 已加入: - - - - After: - 之後: - - Before: 之前: - - Removed: - 已移除: - - Adding additional documents is not supported. 不支援新增其他文件。 @@ -607,11 +572,6 @@ 顯示堆疊追蹤 - - Stream is too long. - 資料流過長。 - - Async Method 非同步方法 diff --git a/src/Workspaces/CoreTest/EditorConfigStorageLocation/NamingStylePreferenceEditorConfigStorageLocationTests.cs b/src/Workspaces/CoreTest/EditorConfigStorageLocation/NamingStylePreferenceEditorConfigStorageLocationTests.cs index f17e4e198e1b0..ef11afbbf4ac6 100644 --- a/src/Workspaces/CoreTest/EditorConfigStorageLocation/NamingStylePreferenceEditorConfigStorageLocationTests.cs +++ b/src/Workspaces/CoreTest/EditorConfigStorageLocation/NamingStylePreferenceEditorConfigStorageLocationTests.cs @@ -12,7 +12,7 @@ namespace Microsoft.CodeAnalysis.UnitTests.EditorConfig.StorageLocation public class NamingStylePreferenceEditorConfigStorageLocationTests { [Fact] - public static void TestEmptyDictionaryReturnNoNamingStylePreferencesObjectReturnsFalse() + public void TestEmptyDictionaryReturnNoNamingStylePreferencesObjectReturnsFalse() { var options = StructuredAnalyzerConfigOptions.Create(DictionaryAnalyzerConfigOptions.Empty); var value = options.GetNamingStylePreferences(); @@ -20,7 +20,7 @@ public static void TestEmptyDictionaryReturnNoNamingStylePreferencesObjectReturn } [Fact] - public static void TestNonEmptyDictionaryReturnsTrue() + public void TestNonEmptyDictionaryReturnsTrue() { var options = StructuredAnalyzerConfigOptions.Create(new DictionaryAnalyzerConfigOptions(new Dictionary() { diff --git a/src/Workspaces/CoreTest/FindReferencesTests.cs b/src/Workspaces/CoreTest/FindReferencesTests.cs index 45edebba88936..c83a6b909403c 100644 --- a/src/Workspaces/CoreTest/FindReferencesTests.cs +++ b/src/Workspaces/CoreTest/FindReferencesTests.cs @@ -337,7 +337,7 @@ public override void Boo() { } // Line 13 // Find references on definition C.Boo() var typeC = comp.GetTypeByMetadataName("C"); boo = typeC.GetMembers("Boo").First(); - result = (await SymbolFinder.FindReferencesAsync(boo, solution)).ToList(); + result = [.. (await SymbolFinder.FindReferencesAsync(boo, solution))]; Assert.Equal(2, result.Count); // 2 symbols found expectedMatchedLines = [3, 13, 14]; @@ -348,7 +348,7 @@ public override void Boo() { } // Line 13 // Find references on definition A.Boo() var typeA = comp.GetTypeByMetadataName("A"); boo = typeA.GetMembers("Boo").First(); - result = (await SymbolFinder.FindReferencesAsync(boo, solution)).ToList(); + result = [.. (await SymbolFinder.FindReferencesAsync(boo, solution))]; Assert.Equal(2, result.Count); // 2 symbols found expectedMatchedLines = [7, 12]; diff --git a/src/Workspaces/CoreTest/LinkedFileDiffMerging/LinkedFileDiffMergingTests.Features.cs b/src/Workspaces/CoreTest/LinkedFileDiffMerging/LinkedFileDiffMergingTests.Features.cs index 59e1c844e7446..257d59cb42955 100644 --- a/src/Workspaces/CoreTest/LinkedFileDiffMerging/LinkedFileDiffMergingTests.Features.cs +++ b/src/Workspaces/CoreTest/LinkedFileDiffMerging/LinkedFileDiffMergingTests.Features.cs @@ -2,168 +2,181 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using Microsoft.CodeAnalysis.Test.Utilities; using Xunit; -namespace Microsoft.CodeAnalysis.UnitTests.LinkedFileDiffMerging -{ - [Trait(Traits.Feature, Traits.Features.LinkedFileDiffMerging)] - public partial class LinkedFileDiffMergingTests - { - [Fact(Skip = "https://github.com/dotnet/roslyn/issues/18432")] - public void TestChangeSignature() - { - TestLinkedFileSet( - @"public class Class1 -{ - void M(int x, string y, int z) - { - } -#if LIB1 - void N() - { - M(2, ""A"", 1); - } -#elif LIB2 - void N() - { - M(4, ""B"", 3); - } -#endif -}", - [ - @"public class Class1 -{ - void M(int z, int x) - { - } -#if LIB1 - void N() - { - M(1, 2); - } -#elif LIB2 - void N() - { - M(4, ""B"", 3); - } -#endif -}", - @"public class Class1 -{ - void M(int z, int x) - { - } -#if LIB1 - void N() - { - M(2, ""A"", 1); - } -#elif LIB2 - void N() - { - M(3, 4); - } -#endif -}" - ], - @"public class Class1 -{ - void M(int z, int x) - { - } -#if LIB1 - void N() - { - M(1, 2); - } -#elif LIB2 - void N() - { - M(3, 4); - } -#endif -}", - LanguageNames.CSharp); - } +namespace Microsoft.CodeAnalysis.UnitTests.LinkedFileDiffMerging; - [Fact] - public void TestRename() - { - TestLinkedFileSet( - @"public class Class1 +[Trait(Traits.Feature, Traits.Features.LinkedFileDiffMerging)] +public sealed partial class LinkedFileDiffMergingTests { - void M() - { - } -#if LIB1 - void N() - { - M(); - } -#elif LIB2 - void N() - { - M(); + [Fact] + public void TestChangeSignature() + { + TestLinkedFileSet( + """ + public class Class1 + { + void M(int x, string y, int z) + { + } + #if LIB1 + void N() + { + M(2, "A", 1); + } + #elif LIB2 + void N() + { + M(4, "B", 3); + } + #endif + } + """, + [ + """ + public class Class1 + { + void M(int z, int x) + { + } + #if LIB1 + void N() + { + M(1, 2); + } + #elif LIB2 + void N() + { + M(4, "B", 3); + } + #endif + } + """, + """ + public class Class1 + { + void M(int z, int x) + { + } + #if LIB1 + void N() + { + M(2, "A", 1); + } + #elif LIB2 + void N() + { + M(3, 4); + } + #endif + } + """ + ], + """ + public class Class1 + { + void M(int z, int x) + { + } + #if LIB1 + void N() + { + M(1, 2); + } + #elif LIB2 + void N() + { + M(3, 4); + } + #endif + } + """, + LanguageNames.CSharp); } -#endif -}", - [ - @"public class Class1 -{ - void Method() - { - } -#if LIB1 - void N() - { - Method(); - } -#elif LIB2 - void N() - { - M(); - } -#endif -}", - @"public class Class1 -{ - void Method() - { - } -#if LIB1 - void N() - { - M(); - } -#elif LIB2 - void N() - { - Method(); - } -#endif -}" - ], - @"public class Class1 -{ - void Method() - { - } -#if LIB1 - void N() - { - Method(); - } -#elif LIB2 - void N() - { - Method(); - } -#endif -}", - LanguageNames.CSharp); - } + + [Fact] + public void TestRename() + { + TestLinkedFileSet( + """ + public class Class1 + { + void M() + { + } + #if LIB1 + void N() + { + M(); + } + #elif LIB2 + void N() + { + M(); + } + #endif + } + """, + [ + """ + public class Class1 + { + void Method() + { + } + #if LIB1 + void N() + { + Method(); + } + #elif LIB2 + void N() + { + M(); + } + #endif + } + """, + """ + public class Class1 + { + void Method() + { + } + #if LIB1 + void N() + { + M(); + } + #elif LIB2 + void N() + { + Method(); + } + #endif + } + """ + ], + """ + public class Class1 + { + void Method() + { + } + #if LIB1 + void N() + { + Method(); + } + #elif LIB2 + void N() + { + Method(); + } + #endif + } + """, + LanguageNames.CSharp); } } diff --git a/src/Workspaces/CoreTest/LinkedFileDiffMerging/LinkedFileDiffMergingTests.TextMerging.cs b/src/Workspaces/CoreTest/LinkedFileDiffMerging/LinkedFileDiffMergingTests.TextMerging.cs index 0e1506b6cbb0f..11e0617fd4b8a 100644 --- a/src/Workspaces/CoreTest/LinkedFileDiffMerging/LinkedFileDiffMergingTests.TextMerging.cs +++ b/src/Workspaces/CoreTest/LinkedFileDiffMerging/LinkedFileDiffMergingTests.TextMerging.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using Microsoft.CodeAnalysis.Test.Utilities; using Roslyn.Test.Utilities; using Xunit; @@ -59,14 +57,15 @@ public void TestOneConflict() TestLinkedFileSet( "a b c d e", ["a b y d e", "a b z d e"], - @" -/* " + string.Format(WorkspacesResources.Unmerged_change_from_project_0, "ProjectName1") + @" -" + WorkspacesResources.Before_colon + @" -a b c d e -" + WorkspacesResources.After_colon + @" -a b z d e -*/ -a b y d e", + $""" + + <<<<<<< {string.Format(WorkspacesResources.TODO_Unmerged_change_from_project_0, "ProjectName1")}, {WorkspacesResources.Before_colon} + a b c d e + ======= + a b z d e + >>>>>>> {WorkspacesResources.After} + a b y d e + """, LanguageNames.CSharp); } @@ -76,14 +75,15 @@ public void TestTwoConflictsOnSameLine() TestLinkedFileSet( "a b c d e", ["a q1 c z1 e", "a q2 c z2 e"], - @" -/* " + string.Format(WorkspacesResources.Unmerged_change_from_project_0, "ProjectName1") + @" -" + WorkspacesResources.Before_colon + @" -a b c d e -" + WorkspacesResources.After_colon + @" -a q2 c z2 e -*/ -a q1 c z1 e", + $""" + + <<<<<<< {string.Format(WorkspacesResources.TODO_Unmerged_change_from_project_0, "ProjectName1")}, {WorkspacesResources.Before_colon} + a b c d e + ======= + a q2 c z2 e + >>>>>>> {WorkspacesResources.After} + a q1 c z1 e + """, LanguageNames.CSharp); } @@ -91,33 +91,40 @@ a q2 c z2 e public void TestTwoConflictsOnAdjacentLines() { TestLinkedFileSet( - @"One -Two -Three -Four", + """ + One + Two + Three + Four + """, [ - @"One -TwoY -ThreeY -Four", - @"One -TwoZ -ThreeZ -Four" + """ + One + TwoY + ThreeY + Four + """, + """ + One + TwoZ + ThreeZ + Four + """ ], - @"One - -/* " + string.Format(WorkspacesResources.Unmerged_change_from_project_0, "ProjectName1") + @" -" + WorkspacesResources.Before_colon + @" -Two -Three -" + WorkspacesResources.After_colon + @" -TwoZ -ThreeZ -*/ -TwoY -ThreeY -Four", + $""" + One + + <<<<<<< {string.Format(WorkspacesResources.TODO_Unmerged_change_from_project_0, "ProjectName1")}, {WorkspacesResources.Before_colon} + Two + Three + ======= + TwoZ + ThreeZ + >>>>>>> {WorkspacesResources.After} + TwoY + ThreeY + Four + """, LanguageNames.CSharp); } @@ -125,42 +132,48 @@ public void TestTwoConflictsOnAdjacentLines() public void TestTwoConflictsOnSeparatedLines() { TestLinkedFileSet( - @"One; -Two; -Three; -Four; -Five;", + """ + One; + Two; + Three; + Four; + Five; + """, [ - @"One; -TwoY; -Three; -FourY; -Five;", - @"One; -TwoZ; -Three; -FourZ; -Five;" + """ + One; + TwoY; + Three; + FourY; + Five; + """, + """ + One; + TwoZ; + Three; + FourZ; + Five; + """ ], - @"One; - -/* " + string.Format(WorkspacesResources.Unmerged_change_from_project_0, "ProjectName1") + @" -" + WorkspacesResources.Before_colon + @" -Two; -" + WorkspacesResources.After_colon + @" -TwoZ; -*/ -TwoY; -Three; - -/* " + string.Format(WorkspacesResources.Unmerged_change_from_project_0, "ProjectName1") + @" -" + WorkspacesResources.Before_colon + @" -Four; -" + WorkspacesResources.After_colon + @" -FourZ; -*/ -FourY; -Five;", + $""" + One; + + <<<<<<< {string.Format(WorkspacesResources.TODO_Unmerged_change_from_project_0, "ProjectName1")}, {WorkspacesResources.Before_colon} + Two; + ======= + TwoZ; + >>>>>>> {WorkspacesResources.After} + TwoY; + Three; + + <<<<<<< {string.Format(WorkspacesResources.TODO_Unmerged_change_from_project_0, "ProjectName1")}, {WorkspacesResources.Before_colon} + Four; + ======= + FourZ; + >>>>>>> {WorkspacesResources.After} + FourY; + Five; + """, LanguageNames.CSharp); } @@ -175,24 +188,27 @@ public void TestManyLinkedFilesWithOverlappingChange() @"C", @"", ], - @" -/* " + string.Format(WorkspacesResources.Unmerged_change_from_project_0, "ProjectName2") + @" -" + WorkspacesResources.Before_colon + @" -A -" + WorkspacesResources.After_colon + @" -C -*/ - -/* " + string.Format(WorkspacesResources.Unmerged_change_from_project_0, "ProjectName3") + @" -" + WorkspacesResources.Removed_colon + @" -A -*/ -B", + $""" + + <<<<<<< {string.Format(WorkspacesResources.TODO_Unmerged_change_from_project_0, "ProjectName2")}, {WorkspacesResources.Before_colon} + A + ======= + C + >>>>>>> {WorkspacesResources.After} + + <<<<<<< {string.Format(WorkspacesResources.TODO_Unmerged_change_from_project_0, "ProjectName3")}, {WorkspacesResources.Before_colon} + A + ======= + >>>>>>> {WorkspacesResources.After} + B + """, LanguageNames.CSharp); } - [Fact] - public void TestCommentsAddedCodeCSharp() + [Theory] + [InlineData(LanguageNames.CSharp)] + [InlineData(LanguageNames.VisualBasic)] + public void TestCommentsAddedCode(string language) { TestLinkedFileSet( @"", @@ -200,52 +216,21 @@ public void TestCommentsAddedCodeCSharp() @"A", @"B", ], - @" -/* " + string.Format(WorkspacesResources.Unmerged_change_from_project_0, "ProjectName1") + @" -" + WorkspacesResources.Added_colon + @" -B -*/ -A", - LanguageNames.CSharp); + $""" + + <<<<<<< {string.Format(WorkspacesResources.TODO_Unmerged_change_from_project_0, "ProjectName1")}, {WorkspacesResources.Before_colon} + ======= + B + >>>>>>> {WorkspacesResources.After} + A + """, + language); } - [Fact] - public void TestCommentsAddedCodeVB() - { - TestLinkedFileSet( - @"", - [ - @"A", - @"B", - ], - @" -' " + string.Format(WorkspacesResources.Unmerged_change_from_project_0, "ProjectName1") + @" -' " + WorkspacesResources.Added_colon + @" -' B -A", - LanguageNames.VisualBasic); - } - - [Fact] - public void TestCommentsRemovedCodeCSharp() - { - TestLinkedFileSet( - @"A", - [ - @"B", - @"", - ], - @" -/* " + string.Format(WorkspacesResources.Unmerged_change_from_project_0, "ProjectName1") + @" -" + WorkspacesResources.Removed_colon + @" -A -*/ -B", - LanguageNames.CSharp); - } - - [Fact] - public void TestCommentsRemovedCodeVB() + [Theory] + [InlineData(LanguageNames.CSharp)] + [InlineData(LanguageNames.VisualBasic)] + public void TestCommentsRemovedCode(string language) { TestLinkedFileSet( @"A", @@ -253,12 +238,15 @@ public void TestCommentsRemovedCodeVB() @"B", @"", ], - @" -' " + string.Format(WorkspacesResources.Unmerged_change_from_project_0, "ProjectName1") + @" -' " + WorkspacesResources.Removed_colon + @" -' A -B", - LanguageNames.VisualBasic); + $""" + + <<<<<<< {string.Format(WorkspacesResources.TODO_Unmerged_change_from_project_0, "ProjectName1")}, {WorkspacesResources.Before_colon} + A + ======= + >>>>>>> {WorkspacesResources.After} + B + """, + language); } } } diff --git a/src/Workspaces/CoreTest/SolutionTests/SolutionTests.cs b/src/Workspaces/CoreTest/SolutionTests/SolutionTests.cs index 4c6a7e391cdf1..61d30023fc8ea 100644 --- a/src/Workspaces/CoreTest/SolutionTests/SolutionTests.cs +++ b/src/Workspaces/CoreTest/SolutionTests/SolutionTests.cs @@ -5695,7 +5695,7 @@ public async Task TestFrozenPartialSolution5() Assert.Single(frozenCompilation2.SyntaxTrees); Assert.True(frozenCompilation2.ContainsSyntaxTree(await frozenProject2.Documents.Single().GetSyntaxTreeAsync())); - Assert.Single(frozenCompilation2.References.Where(r => r is CompilationReference c && c.Compilation == frozenCompilation1)); + Assert.Single(frozenCompilation2.References, r => r is CompilationReference c && c.Compilation == frozenCompilation1); } [Fact] diff --git a/src/Workspaces/CoreTest/SolutionTests/SolutionWithSourceGeneratorTests.cs b/src/Workspaces/CoreTest/SolutionTests/SolutionWithSourceGeneratorTests.cs index de80e417b1cae..ca70a51b6606c 100644 --- a/src/Workspaces/CoreTest/SolutionTests/SolutionWithSourceGeneratorTests.cs +++ b/src/Workspaces/CoreTest/SolutionTests/SolutionWithSourceGeneratorTests.cs @@ -271,7 +271,7 @@ static async Task AssertCompilationContainsOneRegularAndOneGeneratedFile(Project var regularDocumentSyntaxTree = await project.GetRequiredDocument(documentId).GetRequiredSyntaxTreeAsync(CancellationToken.None); Assert.Contains(regularDocumentSyntaxTree, compilation.SyntaxTrees); - var generatedSyntaxTree = Assert.Single(compilation.SyntaxTrees.Where(t => t != regularDocumentSyntaxTree)); + var generatedSyntaxTree = Assert.Single(compilation.SyntaxTrees, t => t != regularDocumentSyntaxTree); Assert.IsType(project.GetDocument(generatedSyntaxTree)); Assert.Equal(expectedGeneratedContents, generatedSyntaxTree.GetText().ToString()); diff --git a/src/Workspaces/CoreTest/UtilityTest/IntervalTreeTests.cs b/src/Workspaces/CoreTest/UtilityTest/IntervalTreeTests.cs index e34f781dfead6..25b4339f818e5 100644 --- a/src/Workspaces/CoreTest/UtilityTest/IntervalTreeTests.cs +++ b/src/Workspaces/CoreTest/UtilityTest/IntervalTreeTests.cs @@ -345,7 +345,7 @@ private static ISet Set(params T[] values) => new HashSet(values); private static IList List(params T[] values) - => new List(values); + => [.. values]; } public sealed class BinaryIntervalTreeTests : IntervalTreeTests @@ -375,7 +375,7 @@ public sealed class FlatArrayIntervalTreeTests : IntervalTreeTests { private protected override IEnumerable>> CreateTrees(IEnumerable> values) { - yield return ImmutableIntervalTree>.CreateFromUnsorted(new TupleIntrospector(), new SegmentedList>(values)); + yield return ImmutableIntervalTree>.CreateFromUnsorted(new TupleIntrospector(), [.. values]); } private protected override bool HasIntervalThatIntersectsWith(IIntervalTree> tree, int position) @@ -410,7 +410,7 @@ public void TestProperBalancing() { for (var i = 0; i < 3000; i++) { - var tree = ImmutableIntervalTree.CreateFromUnsorted(new Int32IntervalIntrospector(), new(Enumerable.Range(1, i))); + var tree = ImmutableIntervalTree.CreateFromUnsorted(new Int32IntervalIntrospector(), [.. Enumerable.Range(1, i)]); // Ensure that the tree produces the same elements in sorted order. AssertEx.Equal(tree, Enumerable.Range(1, i)); @@ -436,7 +436,7 @@ static void Iterate(int totalCount) for (var j = -3; j <= 2; j++) { var allInts = Enumerable.Range(1, totalCount + j); - var tree = ImmutableIntervalTree.CreateFromSorted(new Int32IntervalIntrospector(), new(allInts)); + var tree = ImmutableIntervalTree.CreateFromSorted(new Int32IntervalIntrospector(), [.. allInts]); // Ensure that the tree produces the same elements in sorted order. Assert.True(tree.SequenceEqual(allInts)); diff --git a/src/Workspaces/CoreTest/WorkspaceServiceTests/TemporaryStorageServiceTests.cs b/src/Workspaces/CoreTest/WorkspaceServiceTests/TemporaryStorageServiceTests.cs index fa8d099d836dc..26c28eb0ae428 100644 --- a/src/Workspaces/CoreTest/WorkspaceServiceTests/TemporaryStorageServiceTests.cs +++ b/src/Workspaces/CoreTest/WorkspaceServiceTests/TemporaryStorageServiceTests.cs @@ -134,7 +134,7 @@ public void TestTemporaryStorageMemoryMappedFileManagement() } }); - Task.WaitAll(tasks.ToArray()); + Task.WaitAll([.. tasks]); GC.Collect(2); GC.WaitForPendingFinalizers(); GC.Collect(2); diff --git a/src/Workspaces/CoreTestUtilities/Microsoft.CodeAnalysis.Workspaces.Test.Utilities.csproj b/src/Workspaces/CoreTestUtilities/Microsoft.CodeAnalysis.Workspaces.Test.Utilities.csproj index d0f1477e85b71..33edabf4394ff 100644 --- a/src/Workspaces/CoreTestUtilities/Microsoft.CodeAnalysis.Workspaces.Test.Utilities.csproj +++ b/src/Workspaces/CoreTestUtilities/Microsoft.CodeAnalysis.Workspaces.Test.Utilities.csproj @@ -62,9 +62,9 @@ - - - + + + diff --git a/src/Workspaces/CoreTestUtilities/NoCompilationConstants.cs b/src/Workspaces/CoreTestUtilities/NoCompilationConstants.cs index e1624a80a69f5..c3584ea4790f2 100644 --- a/src/Workspaces/CoreTestUtilities/NoCompilationConstants.cs +++ b/src/Workspaces/CoreTestUtilities/NoCompilationConstants.cs @@ -4,7 +4,7 @@ namespace Microsoft.CodeAnalysis.UnitTests { - public class NoCompilationConstants + public static class NoCompilationConstants { public const string LanguageName = "NoCompilation"; } diff --git a/src/Workspaces/CoreTestUtilities/Options/OptionsTestHelpers.cs b/src/Workspaces/CoreTestUtilities/Options/OptionsTestHelpers.cs index 9e285851f4198..c4d68060fefca 100644 --- a/src/Workspaces/CoreTestUtilities/Options/OptionsTestHelpers.cs +++ b/src/Workspaces/CoreTestUtilities/Options/OptionsTestHelpers.cs @@ -133,7 +133,7 @@ _ when Nullable.GetUnderlyingType(type) is { IsEnum: true } underlying => value _ when type == typeof(int?) => value is null ? 1 : null, _ when type == typeof(long?) => value is null ? 1L : null, ImmutableArray array => array.IsEmpty ? ImmutableArray.Create(true) : [], - ImmutableArray array => array is ["X"] ? ImmutableArray.Create("X", "Y") : ImmutableArray.Create("X"), + ImmutableArray array => array is ["X"] ? ["X", "Y"] : ImmutableArray.Create("X"), ImmutableArray array => array.IsEmpty ? ImmutableArray.Create(1) : [], ImmutableArray array => array.IsEmpty ? ImmutableArray.Create(1L) : [], diff --git a/src/Workspaces/CoreTestUtilities/Options/OptionsTestInfo.cs b/src/Workspaces/CoreTestUtilities/Options/OptionsTestInfo.cs index 072d3ec89eb42..3a47801c2fa9d 100644 --- a/src/Workspaces/CoreTestUtilities/Options/OptionsTestInfo.cs +++ b/src/Workspaces/CoreTestUtilities/Options/OptionsTestInfo.cs @@ -69,7 +69,7 @@ public static ImmutableDictionary CollectOptions(string } else { - optionInfo = new OptionsTestInfo(option, ImmutableList.Create<(string, string, bool, IOption2)>((accessorNamespace!, accessor, isPublic, option))); + optionInfo = new OptionsTestInfo(option, [(accessorNamespace!, accessor, isPublic, option)]); } resultBuilder[configName] = optionInfo; diff --git a/src/Workspaces/CoreTestUtilities/SolutionUtilities.cs b/src/Workspaces/CoreTestUtilities/SolutionUtilities.cs index bbedf94119bb1..930abfa397518 100644 --- a/src/Workspaces/CoreTestUtilities/SolutionUtilities.cs +++ b/src/Workspaces/CoreTestUtilities/SolutionUtilities.cs @@ -12,7 +12,7 @@ namespace Microsoft.CodeAnalysis.UnitTests { - public class SolutionUtilities + public static class SolutionUtilities { public static ProjectChanges GetSingleChangedProjectChanges(Solution oldSolution, Solution newSolution) { diff --git a/src/Workspaces/CoreTestUtilities/TestAnalyzerReferenceByLanguage.cs b/src/Workspaces/CoreTestUtilities/TestAnalyzerReferenceByLanguage.cs index 65912111018e5..c8a762042ae32 100644 --- a/src/Workspaces/CoreTestUtilities/TestAnalyzerReferenceByLanguage.cs +++ b/src/Workspaces/CoreTestUtilities/TestAnalyzerReferenceByLanguage.cs @@ -41,7 +41,7 @@ public override ImmutableArray GetAnalyzers(string language) return analyzers; } - return ImmutableArray.Empty; + return []; } public TestAnalyzerReferenceByLanguage WithAdditionalAnalyzers(string language, IEnumerable analyzers) diff --git a/src/Workspaces/CoreTestUtilities/Workspaces/TestWorkspace_XmlConsumption.cs b/src/Workspaces/CoreTestUtilities/Workspaces/TestWorkspace_XmlConsumption.cs index 596c68692ebe6..3d36f1b541d45 100644 --- a/src/Workspaces/CoreTestUtilities/Workspaces/TestWorkspace_XmlConsumption.cs +++ b/src/Workspaces/CoreTestUtilities/Workspaces/TestWorkspace_XmlConsumption.cs @@ -418,8 +418,7 @@ private CompilationOptions CreateCompilationOptions(string language, XElement co if (compilationOptionsElement != null) { - globalImports = compilationOptionsElement.Elements(GlobalImportElementName) - .Select(x => GlobalImport.Parse(x.Value)).ToList(); + globalImports = [.. compilationOptionsElement.Elements(GlobalImportElementName).Select(x => GlobalImport.Parse(x.Value))]; var rootNamespaceAttribute = compilationOptionsElement.Attribute(RootNamespaceAttributeName); if (rootNamespaceAttribute != null) { @@ -713,8 +712,8 @@ private static IReadOnlyList GetFolders(XElement documentElement) return null; } - var folderContainers = folderAttribute.Value.Split(new[] { PathUtilities.DirectorySeparatorChar }, StringSplitOptions.RemoveEmptyEntries); - return new ReadOnlyCollection(folderContainers.ToList()); + var folderContainers = folderAttribute.Value.Split([PathUtilities.DirectorySeparatorChar], StringSplitOptions.RemoveEmptyEntries); + return new ReadOnlyCollection([.. folderContainers]); } /// diff --git a/src/Workspaces/MSBuildTest/BuildHostProcessManagerTests.cs b/src/Workspaces/MSBuildTest/BuildHostProcessManagerTests.cs index 8d356e132b1a2..b0ba91fed52f2 100644 --- a/src/Workspaces/MSBuildTest/BuildHostProcessManagerTests.cs +++ b/src/Workspaces/MSBuildTest/BuildHostProcessManagerTests.cs @@ -1,4 +1,4 @@ -// Licensed to the .NET Foundation under one or more agreements. +// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. @@ -17,7 +17,7 @@ public class BuildHostProcessManagerTests public void ProcessStartInfo_ForNetCore_RollsForwardToLatestPreview() { var processStartInfo = new BuildHostProcessManager() - .CreateBuildHostStartInfo(BuildHostProcessKind.NetCore); + .CreateBuildHostStartInfo(BuildHostProcessKind.NetCore, pipeName: ""); #if NET var rollForwardIndex = processStartInfo.ArgumentList.IndexOf("--roll-forward"); @@ -34,7 +34,7 @@ public void ProcessStartInfo_ForNetCore_RollsForwardToLatestPreview() public void ProcessStartInfo_ForNetCore_LaunchesDotNetCLI() { var processStartInfo = new BuildHostProcessManager() - .CreateBuildHostStartInfo(BuildHostProcessKind.NetCore); + .CreateBuildHostStartInfo(BuildHostProcessKind.NetCore, pipeName: ""); Assert.StartsWith("dotnet", processStartInfo.FileName); } @@ -43,7 +43,7 @@ public void ProcessStartInfo_ForNetCore_LaunchesDotNetCLI() public void ProcessStartInfo_ForMono_LaunchesMono() { var processStartInfo = new BuildHostProcessManager() - .CreateBuildHostStartInfo(BuildHostProcessKind.Mono); + .CreateBuildHostStartInfo(BuildHostProcessKind.Mono, pipeName: ""); Assert.Equal("mono", processStartInfo.FileName); } @@ -52,7 +52,7 @@ public void ProcessStartInfo_ForMono_LaunchesMono() public void ProcessStartInfo_ForNetFramework_LaunchesBuildHost() { var processStartInfo = new BuildHostProcessManager() - .CreateBuildHostStartInfo(BuildHostProcessKind.NetFramework); + .CreateBuildHostStartInfo(BuildHostProcessKind.NetFramework, pipeName: ""); Assert.EndsWith("Microsoft.CodeAnalysis.Workspaces.MSBuild.BuildHost.exe", processStartInfo.FileName); } @@ -66,7 +66,7 @@ internal void ProcessStartInfo_PassesBinLogPath(BuildHostProcessKind buildHostKi const string BinaryLogPath = "test.binlog"; var processStartInfo = new BuildHostProcessManager(binaryLogPath: BinaryLogPath) - .CreateBuildHostStartInfo(buildHostKind); + .CreateBuildHostStartInfo(buildHostKind, pipeName: ""); #if NET var binlogIndex = processStartInfo.ArgumentList.IndexOf("--binlog"); @@ -77,6 +77,26 @@ internal void ProcessStartInfo_PassesBinLogPath(BuildHostProcessKind buildHostKi #endif } + [Theory] + [InlineData(BuildHostProcessKind.NetFramework)] + [InlineData(BuildHostProcessKind.NetCore)] + [InlineData(BuildHostProcessKind.Mono)] + internal void ProcessStartInfo_PassesPipeName(BuildHostProcessKind buildHostKind) + { + const string PipeName = "TestPipe"; + + var processStartInfo = new BuildHostProcessManager() + .CreateBuildHostStartInfo(buildHostKind, PipeName); + +#if NET + var binlogIndex = processStartInfo.ArgumentList.IndexOf("--pipe"); + Assert.True(binlogIndex >= 0); + Assert.Equal(PipeName, processStartInfo.ArgumentList[binlogIndex + 1]); +#else + Assert.Contains($"--pipe {PipeName}", processStartInfo.Arguments); +#endif + } + [Theory] [InlineData(BuildHostProcessKind.NetFramework)] [InlineData(BuildHostProcessKind.NetCore)] @@ -87,7 +107,7 @@ internal void ProcessStartInfo_PassesLocale(BuildHostProcessKind buildHostKind) const string Locale = "de-DE"; var processStartInfo = new BuildHostProcessManager() - .CreateBuildHostStartInfo(buildHostKind); + .CreateBuildHostStartInfo(buildHostKind, pipeName: ""); #if NET var localeIndex = processStartInfo.ArgumentList.IndexOf("--locale"); @@ -112,7 +132,7 @@ internal void ProcessStartInfo_PassesProperties(BuildHostProcessKind buildHostKi var buildHostProcessManager = new BuildHostProcessManager(globalMSBuildProperties); - var processStartInfo = buildHostProcessManager.CreateBuildHostStartInfo(buildHostKind); + var processStartInfo = buildHostProcessManager.CreateBuildHostStartInfo(buildHostKind, pipeName: ""); #if NET foreach (var kvp in globalMSBuildProperties) diff --git a/src/Workspaces/MSBuildTest/VisualStudioMSBuildWorkspaceTests.cs b/src/Workspaces/MSBuildTest/VisualStudioMSBuildWorkspaceTests.cs index 8ff00ac110e18..bf9c8b2000665 100644 --- a/src/Workspaces/MSBuildTest/VisualStudioMSBuildWorkspaceTests.cs +++ b/src/Workspaces/MSBuildTest/VisualStudioMSBuildWorkspaceTests.cs @@ -100,7 +100,7 @@ public async Task TestDirectUseOfMSBuildProjectLoader() var solutionInfo = await msbuildProjectLoader.LoadSolutionInfoAsync(solutionFilePath); var projectInfo = Assert.Single(solutionInfo.Projects); - Assert.Single(projectInfo.Documents.Where(d => d.Name == "CSharpClass.cs")); + Assert.Single(projectInfo.Documents, d => d.Name == "CSharpClass.cs"); } [ConditionalFact(typeof(VisualStudioMSBuildInstalled))] @@ -2487,7 +2487,7 @@ private static FileSet VisitProjectReferences(FileSet files, Action vi result.Add((fileName, text)); } - return new FileSet(result.ToArray()); + return new FileSet([.. result]); } private static string VisitProjectReferences(string projectFileText, Action visitProjectReference) @@ -2893,14 +2893,13 @@ class C { }"; Assert.Equal(encoding.EncodingName, text.Encoding.EncodingName); Assert.Equal(fileContent, text.ToString()); - // update root blindly again, after observing encoding, see that now encoding is known + // update root blindly again, after observing encoding, see that encoding is overridden to null var doc3 = document.WithSyntaxRoot(gen.CompilationUnit()); // empty CU var doc3text = await doc3.GetTextAsync(); - Assert.NotNull(doc3text.Encoding); - Assert.Equal(encoding.EncodingName, doc3text.Encoding.EncodingName); + Assert.Null(doc3text.Encoding); var doc3tree = await doc3.GetSyntaxTreeAsync(); - Assert.Equal(doc3text.Encoding, doc3tree.GetText().Encoding); - Assert.Equal(doc3text.Encoding, doc3tree.Encoding); + Assert.Null(doc3tree.Encoding); + Assert.Null(doc3tree.GetText().Encoding); // change doc to have no encoding, still succeeds at writing to disk with old encoding var root = await document.GetSyntaxRootAsync(); @@ -3241,7 +3240,7 @@ public async Task TestEditorConfigDiscovery() // We should have exactly one .editorconfig corresponding to the file we had. We may also // have other files if there is a .editorconfig floating around somewhere higher on the disk. - var analyzerConfigDocument = Assert.Single(project.AnalyzerConfigDocuments.Where(d => d.FilePath == expectedEditorConfigPath)); + var analyzerConfigDocument = Assert.Single(project.AnalyzerConfigDocuments, d => d.FilePath == expectedEditorConfigPath); Assert.Equal(".editorconfig", analyzerConfigDocument.Name); var text = await analyzerConfigDocument.GetTextAsync(); Assert.Equal("root = true", text.ToString()); diff --git a/src/Workspaces/Remote/Core/EditAndContinue/ManagedHotReloadLanguageService.cs b/src/Workspaces/Remote/Core/EditAndContinue/ManagedHotReloadLanguageService.cs index 2e7d6487c75d7..71d36631b5070 100644 --- a/src/Workspaces/Remote/Core/EditAndContinue/ManagedHotReloadLanguageService.cs +++ b/src/Workspaces/Remote/Core/EditAndContinue/ManagedHotReloadLanguageService.cs @@ -176,7 +176,7 @@ public async ValueTask UpdateBaselinesAsync(ImmutableArray projectPaths, where projectId != null select projectId; - encService.UpdateBaselines(_debuggingSession.Value, currentCompileTimeSolution, projectIds.ToImmutableArray()); + encService.UpdateBaselines(_debuggingSession.Value, currentCompileTimeSolution, [.. projectIds]); } catch (Exception e) when (FatalError.ReportAndCatchUnlessCanceled(e, cancellationToken)) { diff --git a/src/Workspaces/Remote/ServiceHub/Services/DependentTypeFinder/RemoteDependentTypeFinderService.cs b/src/Workspaces/Remote/ServiceHub/Services/DependentTypeFinder/RemoteDependentTypeFinderService.cs index 59b6f592c331b..f6db2bbe579a5 100644 --- a/src/Workspaces/Remote/ServiceHub/Services/DependentTypeFinder/RemoteDependentTypeFinderService.cs +++ b/src/Workspaces/Remote/ServiceHub/Services/DependentTypeFinder/RemoteDependentTypeFinderService.cs @@ -39,7 +39,7 @@ public ValueTask> FindTypesAsync( var symbol = await typeAndProjectId.TryRehydrateAsync(solution, cancellationToken).ConfigureAwait(false); if (symbol is not INamedTypeSymbol namedType) - return ImmutableArray.Empty; + return []; var projects = projectIdsOpt.IsDefault ? null : projectIdsOpt.Select(id => solution.GetRequiredProject(id)).ToImmutableHashSet(); diff --git a/src/Workspaces/Remote/ServiceHub/Services/EncapsulateField/RemoteEncapsulateFieldService.cs b/src/Workspaces/Remote/ServiceHub/Services/EncapsulateField/RemoteEncapsulateFieldService.cs index 2dfe968997cd7..3986f4d2d7618 100644 --- a/src/Workspaces/Remote/ServiceHub/Services/EncapsulateField/RemoteEncapsulateFieldService.cs +++ b/src/Workspaces/Remote/ServiceHub/Services/EncapsulateField/RemoteEncapsulateFieldService.cs @@ -41,7 +41,7 @@ protected override IRemoteEncapsulateFieldService CreateService(in ServiceConstr { var resolved = SymbolKey.ResolveString(key, compilation, cancellationToken: cancellationToken).GetAnySymbol() as IFieldSymbol; if (resolved == null) - return ImmutableArray<(DocumentId, ImmutableArray)>.Empty; + return []; fields.Add(resolved); } diff --git a/src/Workspaces/Remote/ServiceHub/Services/MissingImportDiscovery/RemoteMissingImportDiscoveryService.cs b/src/Workspaces/Remote/ServiceHub/Services/MissingImportDiscovery/RemoteMissingImportDiscoveryService.cs index 8261f14ec5cd5..029001631aa0d 100644 --- a/src/Workspaces/Remote/ServiceHub/Services/MissingImportDiscovery/RemoteMissingImportDiscoveryService.cs +++ b/src/Workspaces/Remote/ServiceHub/Services/MissingImportDiscovery/RemoteMissingImportDiscoveryService.cs @@ -103,13 +103,13 @@ private sealed class SymbolSearchService( private readonly RemoteCallback _callback = callback; private readonly RemoteServiceCallbackId _callbackId = callbackId; - public ValueTask> FindPackagesWithTypeAsync(string source, string name, int arity, CancellationToken cancellationToken) - => _callback.InvokeAsync((callback, cancellationToken) => callback.FindPackagesWithTypeAsync(_callbackId, source, name, arity, cancellationToken), cancellationToken); + public ValueTask> FindPackagesAsync(string source, TypeQuery typeQuery, NamespaceQuery namespaceQuery, CancellationToken cancellationToken) + => _callback.InvokeAsync((callback, cancellationToken) => callback.FindPackagesAsync(_callbackId, source, typeQuery, namespaceQuery, cancellationToken), cancellationToken); public ValueTask> FindPackagesWithAssemblyAsync(string source, string assemblyName, CancellationToken cancellationToken) => _callback.InvokeAsync((callback, cancellationToken) => callback.FindPackagesWithAssemblyAsync(_callbackId, source, assemblyName, cancellationToken), cancellationToken); - public ValueTask> FindReferenceAssembliesWithTypeAsync(string name, int arity, CancellationToken cancellationToken) - => _callback.InvokeAsync((callback, cancellationToken) => callback.FindReferenceAssembliesWithTypeAsync(_callbackId, name, arity, cancellationToken), cancellationToken); + public ValueTask> FindReferenceAssembliesAsync(TypeQuery typeQuery, NamespaceQuery namespaceQuery, CancellationToken cancellationToken) + => _callback.InvokeAsync((callback, cancellationToken) => callback.FindReferenceAssembliesAsync(_callbackId, typeQuery, namespaceQuery, cancellationToken), cancellationToken); } } diff --git a/src/Workspaces/Remote/ServiceHub/Services/SymbolSearchUpdate/RemoteSymbolSearchUpdateService.cs b/src/Workspaces/Remote/ServiceHub/Services/SymbolSearchUpdate/RemoteSymbolSearchUpdateService.cs index 98ff512306b03..4da4859d7e319 100644 --- a/src/Workspaces/Remote/ServiceHub/Services/SymbolSearchUpdate/RemoteSymbolSearchUpdateService.cs +++ b/src/Workspaces/Remote/ServiceHub/Services/SymbolSearchUpdate/RemoteSymbolSearchUpdateService.cs @@ -33,10 +33,10 @@ public ValueTask UpdateContinuouslyAsync(string sourceName, string localSettings cancellationToken); } - public ValueTask> FindPackagesWithTypeAsync(string source, string name, int arity, CancellationToken cancellationToken) + public ValueTask> FindPackagesAsync(string source, TypeQuery typeQuery, NamespaceQuery namespaceQuery, CancellationToken cancellationToken) { return RunServiceAsync(cancellationToken => - _updateEngine.FindPackagesWithTypeAsync(source, name, arity, cancellationToken), + _updateEngine.FindPackagesAsync(source, typeQuery, namespaceQuery, cancellationToken), cancellationToken); } @@ -47,10 +47,10 @@ public ValueTask> FindPackagesWithAsse cancellationToken); } - public ValueTask> FindReferenceAssembliesWithTypeAsync(string name, int arity, CancellationToken cancellationToken) + public ValueTask> FindReferenceAssembliesAsync(TypeQuery typeQuery, NamespaceQuery namespaceQuery, CancellationToken cancellationToken) { return RunServiceAsync(cancellationToken => - _updateEngine.FindReferenceAssembliesWithTypeAsync(name, arity, cancellationToken), + _updateEngine.FindReferenceAssembliesAsync(typeQuery, namespaceQuery, cancellationToken), cancellationToken); } } diff --git a/src/Workspaces/Remote/ServiceHub/Services/ValueTracking/RemoteValueTrackingService.cs b/src/Workspaces/Remote/ServiceHub/Services/ValueTracking/RemoteValueTrackingService.cs index 6226e1fceabe0..91253ba95c4d2 100644 --- a/src/Workspaces/Remote/ServiceHub/Services/ValueTracking/RemoteValueTrackingService.cs +++ b/src/Workspaces/Remote/ServiceHub/Services/ValueTracking/RemoteValueTrackingService.cs @@ -56,7 +56,7 @@ public ValueTask> TrackValueSourceA var previousItem = await previousTrackedItem.RehydrateAsync(solution, cancellationToken).ConfigureAwait(false); if (previousItem is null) { - return ImmutableArray.Empty; + return []; } var progress = new ValueTrackingProgressCollector(); diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/CSharpCompilerExtensionsResources.resx b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/CSharpCompilerExtensionsResources.resx index dc36bf2f7cf41..fe3c19961606c 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/CSharpCompilerExtensionsResources.resx +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/CSharpCompilerExtensionsResources.resx @@ -142,4 +142,13 @@ EditorConfig option '{0}' contains unrecognized value '{1}' + + Indentation preferences + + + Space preferences + + + Wrapping preferences + \ No newline at end of file diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/CodeStyle/TypeStyle/TypeStyleHelper.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/CodeStyle/TypeStyle/TypeStyleHelper.cs index 1cef0f1a6c039..3e8d199278fcd 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/CodeStyle/TypeStyle/TypeStyleHelper.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/CodeStyle/TypeStyle/TypeStyleHelper.cs @@ -6,6 +6,7 @@ using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Threading; +using System.Threading.Tasks; using Microsoft.CodeAnalysis.CSharp.Extensions; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Shared.Extensions; @@ -113,22 +114,18 @@ public static bool IsTypeApparentInAssignmentExpression( return false; } - private static bool IsPossibleCreationOrConversionMethod(IMethodSymbol methodSymbol, + private static bool IsPossibleCreationOrConversionMethod( + IMethodSymbol methodSymbol, ITypeSymbol? typeInDeclaration, SemanticModel semanticModel, ExpressionSyntax containingTypeName, CancellationToken cancellationToken) { if (methodSymbol.ReturnsVoid) - { return false; - } - - var containingType = semanticModel.GetTypeInfo(containingTypeName, cancellationToken).Type; - // The containing type was determined from an expression of the form ContainingType.MemberName, and the - // caller verifies that MemberName resolves to a method symbol. - Contract.ThrowIfNull(containingType); + if (semanticModel.GetTypeInfo(containingTypeName, cancellationToken).Type is not INamedTypeSymbol containingType) + return false; return IsPossibleCreationMethod(methodSymbol, typeInDeclaration, containingType) || IsPossibleConversionMethod(methodSymbol); @@ -138,16 +135,34 @@ private static bool IsPossibleCreationOrConversionMethod(IMethodSymbol methodSym /// Looks for types that have static methods that return the same type as the container. /// e.g: int.Parse, XElement.Load, Tuple.Create etc. /// - private static bool IsPossibleCreationMethod(IMethodSymbol methodSymbol, + private static bool IsPossibleCreationMethod( + IMethodSymbol methodSymbol, ITypeSymbol? typeInDeclaration, - ITypeSymbol containingType) + INamedTypeSymbol containingType) { if (!methodSymbol.IsStatic) - { return false; + + // Check the simple case of the type the method is in returning an instance of that type. + var returnType = UnwrapTupleType(methodSymbol.ReturnType); + if (UnwrapTupleType(containingType).Equals(returnType)) + return true; + + // Now check for cases like `Tuple.Create(0, true)`. This is a static factory without type arguments + // that returns instances of a generic type. + // + // We explicitly disallow this for Task.X and ValueTask.X as the final type is generally not apparent due to + // complex type inference. + if (UnwrapTupleType(typeInDeclaration)?.GetTypeArguments().Length > 0 && + containingType.TypeArguments.Length == 0 && + returnType.Name is not nameof(Task) and not nameof(ValueTask) && + UnwrapTupleType(containingType).Name.Equals(returnType.Name) && + containingType.ContainingNamespace.Equals(returnType.ContainingNamespace)) + { + return true; } - return IsContainerTypeEqualToReturnType(methodSymbol, typeInDeclaration, containingType); + return false; } /// @@ -164,29 +179,6 @@ private static bool IsPossibleConversionMethod(IMethodSymbol methodSymbol) return methodSymbol.Name.Equals("To" + returnTypeName, StringComparison.Ordinal); } - /// - /// If there are type arguments on either side of assignment, we match type names instead of type equality - /// to account for inferred generic type arguments. - /// e.g: Tuple.Create(0, true) returns Tuple<X,y> which isn't the same as type Tuple. - /// otherwise, we match for type equivalence - /// - private static bool IsContainerTypeEqualToReturnType(IMethodSymbol methodSymbol, - ITypeSymbol? typeInDeclaration, - ITypeSymbol containingType) - { - var returnType = UnwrapTupleType(methodSymbol.ReturnType); - - if (UnwrapTupleType(typeInDeclaration)?.GetTypeArguments().Length > 0 || - containingType.GetTypeArguments().Length > 0) - { - return UnwrapTupleType(containingType).Name.Equals(returnType.Name); - } - else - { - return UnwrapTupleType(containingType).Equals(returnType); - } - } - [return: NotNullIfNotNull(nameof(symbol))] private static ITypeSymbol? UnwrapTupleType(ITypeSymbol? symbol) { @@ -200,29 +192,14 @@ private static bool IsContainerTypeEqualToReturnType(IMethodSymbol methodSymbol, } private static ExpressionSyntax GetRightmostInvocationExpression(ExpressionSyntax node) - { - if (node is AwaitExpressionSyntax awaitExpression && awaitExpression.Expression != null) - { - return GetRightmostInvocationExpression(awaitExpression.Expression); - } - - if (node is InvocationExpressionSyntax invocationExpression && invocationExpression.Expression != null) + => node switch { - return GetRightmostInvocationExpression(invocationExpression.Expression); - } - - if (node is ConditionalAccessExpressionSyntax conditional) - { - return GetRightmostInvocationExpression(conditional.WhenNotNull); - } - - return node; - } + AwaitExpressionSyntax { Expression: not null } awaitExpression => GetRightmostInvocationExpression(awaitExpression.Expression), + InvocationExpressionSyntax { Expression: not null } invocationExpression => GetRightmostInvocationExpression(invocationExpression.Expression), + ConditionalAccessExpressionSyntax conditional => GetRightmostInvocationExpression(conditional.WhenNotNull), + _ => node + }; public static bool IsPredefinedType(TypeSyntax type) - { - return type is PredefinedTypeSyntax predefinedType - ? SyntaxFacts.IsPredefinedType(predefinedType.Keyword.Kind()) - : false; - } + => type is PredefinedTypeSyntax predefinedType && SyntaxFacts.IsPredefinedType(predefinedType.Keyword.Kind()); } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Extensions/DirectiveSyntaxExtensions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Extensions/DirectiveSyntaxExtensions.cs index ccba09234c3c7..dcfb7721ff8e2 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Extensions/DirectiveSyntaxExtensions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Extensions/DirectiveSyntaxExtensions.cs @@ -35,7 +35,7 @@ private static DirectiveInfo GetDirectiveInfoForRoot(Synt => CodeAnalysis.Shared.Extensions.SyntaxNodeExtensions.GetDirectiveInfoForRoot( root, CSharpSyntaxKinds.Instance, cancellationToken); - internal static DirectiveTriviaSyntax? GetMatchingDirective(this DirectiveTriviaSyntax directive, CancellationToken cancellationToken) + public static DirectiveTriviaSyntax? GetMatchingDirective(this DirectiveTriviaSyntax directive, CancellationToken cancellationToken) { if (IsConditionalDirective(directive) || IsRegionDirective(directive)) diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Extensions/ExpressionSyntaxExtensions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Extensions/ExpressionSyntaxExtensions.cs index 45a5af43bbbde..1e7c5eef36bae 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Extensions/ExpressionSyntaxExtensions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Extensions/ExpressionSyntaxExtensions.cs @@ -364,7 +364,7 @@ public static bool IsWrittenTo( return true; // An extension method invocation with a ref-this parameter can write to an expression. - if (expression.Parent is MemberAccessExpressionSyntax memberAccess && + if (expression.Parent is MemberAccessExpressionSyntax { Parent: InvocationExpressionSyntax } memberAccess && expression == memberAccess.Expression) { var symbol = semanticModel.GetSymbolInfo(memberAccess, cancellationToken).Symbol; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Extensions/ParenthesizedExpressionSyntaxExtensions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Extensions/ParenthesizedExpressionSyntaxExtensions.cs index 4c3dbcd9d9ef9..e654b58820d16 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Extensions/ParenthesizedExpressionSyntaxExtensions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Extensions/ParenthesizedExpressionSyntaxExtensions.cs @@ -259,7 +259,17 @@ nodeParent is BinaryExpressionSyntax(SyntaxKind.CoalesceExpression) binary && // case x when (y): -> case x when y: if (nodeParent.IsKind(SyntaxKind.WhenClause)) + { + // Subtle case, `when (x?[] ...):`. Can't remove the parentheses here as it can the conditional access + // become a conditional expression. + for (var current = expression; current != null; current = current.ChildNodes().FirstOrDefault() as ExpressionSyntax) + { + if (current is ConditionalAccessExpressionSyntax) + return false; + } + return true; + } // #if (x) -> #if x if (nodeParent is DirectiveTriviaSyntax) @@ -270,6 +280,13 @@ nodeParent is BinaryExpressionSyntax(SyntaxKind.CoalesceExpression) binary && if (nodeParent is SwitchExpressionArmSyntax arm && arm.Expression == node) return true; + // [.. (expr)] -> [.. expr] + // + // Note: There is no precedence with `..` it's always just part of the collection expr, with the expr being + // parsed independently of it. That's why no parens are ever needed here. + if (nodeParent is SpreadElementSyntax) + return true; + // If we have: (X)(++x) or (X)(--x), we don't want to remove the parens. doing so can // make the ++/-- now associate with the previous part of the cast expression. if (parentExpression.IsKind(SyntaxKind.CastExpression) && diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Extensions/SemanticModelExtensions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Extensions/SemanticModelExtensions.cs index 477782ad8e6ca..1dd4b4a27f6f3 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Extensions/SemanticModelExtensions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Extensions/SemanticModelExtensions.cs @@ -362,44 +362,48 @@ public static string GenerateNameForExpression( current = current.WalkDownParentheses(); if (current is IdentifierNameSyntax identifierName) - { return identifierName.Identifier.ValueText.ToCamelCase(); - } - else if (current is MemberAccessExpressionSyntax memberAccess) - { + + if (current is MemberAccessExpressionSyntax memberAccess) return memberAccess.Name.Identifier.ValueText.ToCamelCase(); - } - else if (current is MemberBindingExpressionSyntax memberBinding) - { + + if (current is MemberBindingExpressionSyntax memberBinding) return memberBinding.Name.Identifier.ValueText.ToCamelCase(); - } - else if (current is ConditionalAccessExpressionSyntax conditionalAccess) - { - current = conditionalAccess.WhenNotNull; - } - else if (current is CastExpressionSyntax castExpression) - { - current = castExpression.Expression; - } - else if (current is DeclarationExpressionSyntax decl) + + if (current is DeclarationExpressionSyntax decl) { if (decl.Designation is not SingleVariableDesignationSyntax name) - { break; - } return name.Identifier.ValueText.ToCamelCase(); } - else if (current.Parent is ForEachStatementSyntax foreachStatement && - foreachStatement.Expression == expression) + + if (current.Parent is ForEachStatementSyntax foreachStatement && + foreachStatement.Expression == expression) { var word = foreachStatement.Identifier.ValueText.ToCamelCase(); return CodeAnalysis.Shared.Extensions.SemanticModelExtensions.Pluralize(word); } - else + + if (current.Parent is AnonymousObjectMemberDeclaratorSyntax { NameEquals: { } nameEquals } anonymousObjectMemberDeclarator && + anonymousObjectMemberDeclarator.Expression == current) { - break; + return nameEquals.Name.Identifier.ValueText.ToCamelCase(); } + + if (current is ConditionalAccessExpressionSyntax conditionalAccess) + { + current = conditionalAccess.WhenNotNull; + continue; + } + + if (current is CastExpressionSyntax castExpression) + { + current = castExpression.Expression; + continue; + } + + break; } // there was nothing in the expression to signify a name. If we're in an argument @@ -483,6 +487,12 @@ public static IPropertySymbol GetRequiredDeclaredSymbol(this SemanticModel seman ?? throw new InvalidOperationException(); } + public static IMethodSymbol GetRequiredDeclaredSymbol(this SemanticModel semanticModel, BaseMethodDeclarationSyntax syntax, CancellationToken cancellationToken) + { + return semanticModel.GetDeclaredSymbol(syntax, cancellationToken) + ?? throw new InvalidOperationException(); + } + public static ISymbol GetRequiredDeclaredSymbol(this SemanticModel semanticModel, VariableDeclaratorSyntax syntax, CancellationToken cancellationToken) { return semanticModel.GetDeclaredSymbol(syntax, cancellationToken) @@ -494,4 +504,16 @@ public static ISymbol GetRequiredDeclaredSymbol(this SemanticModel semanticModel return semanticModel.GetDeclaredSymbol(syntax, cancellationToken) ?? throw new InvalidOperationException(); } + + /// + /// Returns whether or not and are exactly identical to and respectively. + /// + public static bool UnifiesNativeIntegers(this SemanticModel semanticModel) + { + var languageVersion = semanticModel.SyntaxTree.Options.LanguageVersion(); + + // In C# 11 we made it so that IntPtr and nint are identical as long as the runtime unifies them. + return languageVersion >= LanguageVersion.CSharp11 && semanticModel.Compilation.SupportsRuntimeCapability(RuntimeCapability.NumericIntPtr); + } } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Extensions/SyntaxNodeExtensions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Extensions/SyntaxNodeExtensions.cs index 9507a6b00bcbe..4ef6792ee67c5 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Extensions/SyntaxNodeExtensions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Extensions/SyntaxNodeExtensions.cs @@ -648,7 +648,7 @@ public static IList> SplitNodesOnPreprocessorBoundaries !group.IsEmpty()).ToList(); + result = [.. result.Where(group => !group.IsEmpty())]; return result; } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Extensions/SyntaxTreeExtensions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Extensions/SyntaxTreeExtensions.cs index 7dbc892640b25..9a0645dc6e0c0 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Extensions/SyntaxTreeExtensions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Extensions/SyntaxTreeExtensions.cs @@ -84,6 +84,7 @@ public static IEnumerable GetContainingTypeOrEnumDecl return token.GetAncestors().Where(t => BaseTypeDeclarationContainsPosition(t, position)); } + private static readonly Func s_isDot = k => k is SyntaxKind.DotToken; private static readonly Func s_isDotOrArrow = k => k is SyntaxKind.DotToken or SyntaxKind.MinusGreaterThanToken; private static readonly Func s_isDotOrArrowOrColonColon = k => k is SyntaxKind.DotToken or SyntaxKind.MinusGreaterThanToken or SyntaxKind.ColonColonToken; @@ -98,6 +99,9 @@ public static bool IsRightOfDotOrArrowOrColonColon(this SyntaxTree syntaxTree, i public static bool IsRightOfDotOrArrow(this SyntaxTree syntaxTree, int position, CancellationToken cancellationToken) => syntaxTree.IsRightOf(position, s_isDotOrArrow, cancellationToken); + public static bool IsRightOfDot(this SyntaxTree syntaxTree, int position, CancellationToken cancellationToken) + => syntaxTree.IsRightOf(position, s_isDot, cancellationToken); + private static bool IsRightOf( this SyntaxTree syntaxTree, int position, Func predicate, CancellationToken cancellationToken) { diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Extensions/SyntaxTriviaListExtensions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Extensions/SyntaxTriviaListExtensions.cs index c31b753b4e551..99692c2e045a0 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Extensions/SyntaxTriviaListExtensions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Extensions/SyntaxTriviaListExtensions.cs @@ -69,7 +69,7 @@ private static ImmutableArray> GetLeadingBlankLines public static SyntaxTriviaList WithoutLeadingBlankLines(this SyntaxTriviaList triviaList) { var triviaInLeadingBlankLines = GetLeadingBlankLines(triviaList).SelectMany(l => l); - return new SyntaxTriviaList(triviaList.Skip(triviaInLeadingBlankLines.Count())); + return [.. triviaList.Skip(triviaInLeadingBlankLines.Count())]; } /// diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Formatting/CSharpFormattingOptions2.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Formatting/CSharpFormattingOptions2.cs index 62669e9750b21..6f77426cb7fb1 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Formatting/CSharpFormattingOptions2.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Formatting/CSharpFormattingOptions2.cs @@ -324,7 +324,7 @@ public enum BinaryOperatorSpacingOptions internal static class CSharpFormattingOptionGroups { - public static readonly OptionGroup Indentation = new("csharp_indentation", CSharpWorkspaceResources.Indentation_preferences, priority: 3, parent: FormattingOptionGroups.FormattingOptionGroup); - public static readonly OptionGroup Spacing = new("csharp_spacing", CSharpWorkspaceResources.Space_preferences, priority: 4, parent: FormattingOptionGroups.FormattingOptionGroup); - public static readonly OptionGroup Wrapping = new("csharp_wrapping", CSharpWorkspaceResources.Wrapping_preferences, priority: 5, parent: FormattingOptionGroups.FormattingOptionGroup); + public static readonly OptionGroup Indentation = new("csharp_indentation", CSharpCompilerExtensionsResources.Indentation_preferences, priority: 3, parent: FormattingOptionGroups.FormattingOptionGroup); + public static readonly OptionGroup Spacing = new("csharp_spacing", CSharpCompilerExtensionsResources.Space_preferences, priority: 4, parent: FormattingOptionGroups.FormattingOptionGroup); + public static readonly OptionGroup Wrapping = new("csharp_wrapping", CSharpCompilerExtensionsResources.Wrapping_preferences, priority: 5, parent: FormattingOptionGroups.FormattingOptionGroup); } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Formatting/Rules/IndentBlockFormattingRule.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Formatting/Rules/IndentBlockFormattingRule.cs index d6331a303a26d..3dccbd3dbe01e 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Formatting/Rules/IndentBlockFormattingRule.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Formatting/Rules/IndentBlockFormattingRule.cs @@ -252,6 +252,13 @@ private void AddBlockIndentationOperation(List list, Synta private static void AddBracketIndentationOperation(List list, SyntaxNode node) { + // Indentation inside the pattern of a switch statement is handled by AddBlockIndentationOperation. This continue ensures that bracket-specific + // operations are skipped for switch patterns, as they are not formatted like blocks. + if (node.Parent is SwitchExpressionArmSyntax arm && arm.Pattern == node) + { + return; + } + var bracketPair = node.GetBracketPair(); if (!bracketPair.IsValidBracketOrBracePair()) @@ -259,7 +266,6 @@ private static void AddBracketIndentationOperation(List li if (node.Parent != null && node.Kind() is SyntaxKind.ListPattern or SyntaxKind.CollectionExpression) { - // Brackets in list patterns are formatted like blocks, so align close bracket with open bracket AddIndentBlockOperation(list, bracketPair.openBracket.GetNextToken(includeZeroWidth: true), bracketPair.closeBracket.GetPreviousToken(includeZeroWidth: true)); // If we have: diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Formatting/Rules/TokenBasedFormattingRule.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Formatting/Rules/TokenBasedFormattingRule.cs index 7d887aa88f093..45ad7c8cc728b 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Formatting/Rules/TokenBasedFormattingRule.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Formatting/Rules/TokenBasedFormattingRule.cs @@ -8,6 +8,7 @@ using Microsoft.CodeAnalysis.CSharp.Utilities; using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.Formatting.Rules; +using Microsoft.CodeAnalysis.Shared.Extensions; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CSharp.Formatting; @@ -196,6 +197,13 @@ public override AbstractFormattingRule WithOptions(SyntaxFormattingOptions optio return AdjustNewLinesAfterSemicolonToken(previousToken, currentToken); } + if (currentToken.Kind() == SyntaxKind.SemicolonToken && + currentToken.Parent is EmptyStatementSyntax && + currentToken.GetPreviousToken().IsLastTokenOfNode()) + { + return CreateAdjustNewLinesOperation(1, AdjustNewLinesOption.ForceLinesIfOnSingleLine); + } + // attribute case ] * // force to next line for top level attributes if (previousToken.Kind() == SyntaxKind.CloseBracketToken && previousToken.Parent is AttributeListSyntax) @@ -261,15 +269,11 @@ private static SyntaxList GetUsings(SyntaxNode node) { // ; ; if (previousToken.Kind() == SyntaxKind.SemicolonToken) - { return CreateAdjustSpacesOperation(1, AdjustSpacesOption.ForceSpacesIfOnSingleLine); - } // ) ; with embedded statement case if (previousToken.Kind() == SyntaxKind.CloseParenToken && previousToken.Parent.IsEmbeddedStatementOwnerWithCloseParen()) - { return CreateAdjustSpacesOperation(1, AdjustSpacesOption.ForceSpacesIfOnSingleLine); - } // * ; return CreateAdjustSpacesOperation(0, AdjustSpacesOption.ForceSpacesIfOnSingleLine); diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Services/SyntaxFacts/CSharpBlockFacts.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Services/SyntaxFacts/CSharpBlockFacts.cs index 322ffe818a291..bbdecabd8cbea 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Services/SyntaxFacts/CSharpBlockFacts.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Services/SyntaxFacts/CSharpBlockFacts.cs @@ -15,9 +15,9 @@ namespace Microsoft.CodeAnalysis.CSharp.LanguageService; -internal class CSharpBlockFacts : AbstractBlockFacts +internal class CSharpBlockFacts : AbstractBlockFacts { - public static readonly IBlockFacts Instance = new CSharpBlockFacts(); + public static readonly CSharpBlockFacts Instance = new(); public override bool IsScopeBlock([NotNullWhen(true)] SyntaxNode? node) => node.IsKind(SyntaxKind.Block); @@ -25,7 +25,16 @@ public override bool IsScopeBlock([NotNullWhen(true)] SyntaxNode? node) public override bool IsExecutableBlock([NotNullWhen(true)] SyntaxNode? node) => node is (kind: SyntaxKind.Block or SyntaxKind.SwitchSection or SyntaxKind.CompilationUnit); - public override IReadOnlyList GetExecutableBlockStatements(SyntaxNode? node) + public override SyntaxNode? GetImmediateParentExecutableBlockForStatement(StatementSyntax statement) + => statement.Parent switch + { + BlockSyntax block => block, + SwitchSectionSyntax switchSection => switchSection, + GlobalStatementSyntax globalStatement => globalStatement.Parent, + _ => null, + }; + + public override IReadOnlyList GetExecutableBlockStatements(SyntaxNode? node) { return node switch { @@ -37,17 +46,17 @@ public override IReadOnlyList GetExecutableBlockStatements(SyntaxNod } public override SyntaxNode? FindInnermostCommonExecutableBlock(IEnumerable nodes) - => nodes.FindInnermostCommonNode(node => IsExecutableBlock(node)); + => nodes.FindInnermostCommonNode(IsExecutableBlock); public override bool IsStatementContainer([NotNullWhen(true)] SyntaxNode? node) => IsExecutableBlock(node) || node.IsEmbeddedStatementOwner(); - public override IReadOnlyList GetStatementContainerStatements(SyntaxNode? node) + public override IReadOnlyList GetStatementContainerStatements(SyntaxNode? node) { if (IsExecutableBlock(node)) return GetExecutableBlockStatements(node); else if (node.GetEmbeddedStatement() is { } embeddedStatement) - return ImmutableArray.Create(embeddedStatement); + return [embeddedStatement]; else return []; } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Services/SyntaxFacts/CSharpFileBannerFacts.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Services/SyntaxFacts/CSharpFileBannerFacts.cs index d03290c6e25ce..91e151dbe1439 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Services/SyntaxFacts/CSharpFileBannerFacts.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Services/SyntaxFacts/CSharpFileBannerFacts.cs @@ -17,4 +17,9 @@ protected CSharpFileBannerFacts() protected override ISyntaxFacts SyntaxFacts => CSharpSyntaxFacts.Instance; protected override IDocumentationCommentService DocumentationCommentService => CSharpDocumentationCommentService.Instance; + + public override SyntaxTrivia CreateTrivia(SyntaxTrivia trivia, string text) + => trivia.Kind() is SyntaxKind.SingleLineCommentTrivia or SyntaxKind.MultiLineCommentTrivia or SyntaxKind.SingleLineDocumentationCommentTrivia or SyntaxKind.MultiLineDocumentationCommentTrivia + ? SyntaxFactory.Comment(text) + : trivia; } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Services/SyntaxFacts/CSharpSyntaxFacts.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Services/SyntaxFacts/CSharpSyntaxFacts.cs index b22d533aaec0d..bad510b09163a 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Services/SyntaxFacts/CSharpSyntaxFacts.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Services/SyntaxFacts/CSharpSyntaxFacts.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; +using System.Collections.Immutable; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Linq; @@ -11,13 +12,13 @@ using System.Threading; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Extensions; +using Microsoft.CodeAnalysis.CSharp.Extensions.ContextQuery; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; using Roslyn.Utilities; -using Microsoft.CodeAnalysis.CSharp.Extensions.ContextQuery; namespace Microsoft.CodeAnalysis.CSharp.LanguageService; @@ -72,6 +73,9 @@ public bool SupportsTupleDeconstruction(ParseOptions options) public bool SupportsCollectionExpressionNaturalType(ParseOptions options) => false; + public bool SupportsImplicitImplementationOfNonPublicInterfaceMembers(ParseOptions options) + => options.LanguageVersion() >= LanguageVersion.CSharp10; + public SyntaxToken ParseToken(string text) => SyntaxFactory.ParseToken(text); @@ -206,6 +210,9 @@ public void GetPartsOfUsingAliasDirective(SyntaxNode node, out SyntaxToken globa public bool IsDeconstructionForEachStatement([NotNullWhen(true)] SyntaxNode? node) => node is ForEachVariableStatementSyntax; + public bool IsUsingLocalDeclarationStatement([NotNullWhen(true)] SyntaxNode? node) + => node is LocalDeclarationStatementSyntax { UsingKeyword.RawKind: not (int)SyntaxKind.None }; + public bool IsDeconstructionAssignment([NotNullWhen(true)] SyntaxNode? node) => node is AssignmentExpressionSyntax assignment && assignment.IsDeconstruction(); @@ -231,25 +238,6 @@ public bool IsGlobalStatement([NotNullWhen(true)] SyntaxNode? node) public SyntaxNode GetStatementOfGlobalStatement(SyntaxNode node) => ((GlobalStatementSyntax)node).Statement; - public bool AreStatementsInSameContainer(SyntaxNode firstStatement, SyntaxNode secondStatement) - { - Debug.Assert(IsStatement(firstStatement)); - Debug.Assert(IsStatement(secondStatement)); - - if (firstStatement.Parent == secondStatement.Parent) - return true; - - if (IsGlobalStatement(firstStatement.Parent) - && IsGlobalStatement(secondStatement.Parent) - && firstStatement.Parent.Parent == secondStatement.Parent.Parent) - { - return true; - } - - return false; - - } - public bool IsMethodBody([NotNullWhen(true)] SyntaxNode? node) { if (node is BlockSyntax or @@ -503,11 +491,11 @@ public bool IsLiteral(SyntaxToken token) public bool IsStringLiteralOrInterpolatedStringLiteral(SyntaxToken token) => token.Kind() is SyntaxKind.StringLiteralToken or SyntaxKind.InterpolatedStringTextToken; - public bool IsBindableToken(SyntaxToken token) + public bool IsBindableToken(SemanticModel? semanticModel, SyntaxToken token) { if (this.IsWord(token) || this.IsLiteral(token) || this.IsOperator(token)) { - switch ((SyntaxKind)token.RawKind) + switch (token.Kind()) { case SyntaxKind.DelegateKeyword: case SyntaxKind.VoidKeyword: @@ -519,14 +507,15 @@ public bool IsBindableToken(SyntaxToken token) // In the order by clause a comma might be bound to ThenBy or ThenByDescending if (token.Kind() == SyntaxKind.CommaToken && token.Parent.IsKind(SyntaxKind.OrderByClause)) - { return true; - } - if (token.Kind() is SyntaxKind.OpenBracketToken or SyntaxKind.CloseBracketToken - && token.Parent.IsKind(SyntaxKind.CollectionExpression)) + if (token.Kind() is SyntaxKind.OpenBracketToken or SyntaxKind.CloseBracketToken) { - return true; + if (token.Parent.IsKind(SyntaxKind.CollectionExpression)) + return true; + + if (semanticModel != null && token.Parent is BracketedArgumentListSyntax { Parent: ElementAccessExpressionSyntax elementAccessExpression }) + return semanticModel.GetSymbolInfo(elementAccessExpression).GetAnySymbol() != null; } return false; @@ -1000,45 +989,34 @@ private static TextSpan GetBlockBodySpan(BlockSyntax body) { var parent = node.Parent; - // If this node is on the left side of a member access expression, don't ascend - // further or we'll end up binding to something else. - if (parent is MemberAccessExpressionSyntax memberAccess) - { - if (memberAccess.Expression == node) - { - break; - } - } + // If this node is on the left side of a member access expression, don't ascend further or we'll end up + // binding to something else. + if (parent is MemberAccessExpressionSyntax memberAccess && memberAccess.Expression == node) + break; - // If this node is on the left side of a qualified name, don't ascend - // further or we'll end up binding to something else. - if (parent is QualifiedNameSyntax qualifiedName) - { - if (qualifiedName.Left == node) - { - break; - } - } + // If this node is on the left side of a qualified name, don't ascend further or we'll end up binding to + // something else. + if (parent is QualifiedNameSyntax qualifiedName && qualifiedName.Left == node) + break; + + // If this node is on the left side of a alias-qualified name, don't ascend further or we'll end up binding + // to something else. + if (parent is AliasQualifiedNameSyntax aliasQualifiedName && aliasQualifiedName.Alias == node) + break; - // If this node is on the left side of a alias-qualified name, don't ascend - // further or we'll end up binding to something else. - if (parent is AliasQualifiedNameSyntax aliasQualifiedName) + // If this node is the type of an object creation expression, return the object creation expression. + if (parent is ObjectCreationExpressionSyntax objectCreation && objectCreation.Type == node) { - if (aliasQualifiedName.Alias == node) - { - break; - } + node = parent; + break; } - // If this node is the type of an object creation expression, return the - // object creation expression. - if (parent is ObjectCreationExpressionSyntax objectCreation) + // If we're on the argument list `[...]` of an index expression, return the index expression itself as we + // want to bind to whatever symbol that binds to. + if (parent is ElementAccessExpressionSyntax elementAccess && elementAccess.ArgumentList == node) { - if (objectCreation.Type == node) - { - node = parent; - break; - } + node = parent; + break; } // The inside of an interpolated string is treated as its own token so we @@ -1376,6 +1354,12 @@ public void GetPartsOfTupleExpression(SyntaxNode node, public bool IsPreprocessorDirective(SyntaxTrivia trivia) => SyntaxFacts.IsPreprocessorDirective(trivia.Kind()); + public SyntaxNode? GetMatchingDirective(SyntaxNode directive, CancellationToken cancellationToken) + => ((DirectiveTriviaSyntax)directive).GetMatchingDirective(cancellationToken); + + public ImmutableArray GetMatchingConditionalDirectives(SyntaxNode directive, CancellationToken cancellationToken) + => ((DirectiveTriviaSyntax)directive).GetMatchingConditionalDirectives(cancellationToken).CastArray(); + public bool ContainsInterleavedDirective(TextSpan span, SyntaxToken token, CancellationToken cancellationToken) => token.ContainsInterleavedDirective(span, cancellationToken); @@ -1585,6 +1569,14 @@ public bool IsObjectCollectionInitializer([NotNullWhen(true)] SyntaxNode? node) #region GetPartsOfXXX members + public void GetPartsOfAliasQualifiedName(SyntaxNode node, out SyntaxNode alias, out SyntaxToken colonColonToken, out SyntaxNode name) + { + var qualifiedName = (AliasQualifiedNameSyntax)node; + alias = qualifiedName.Alias; + colonColonToken = qualifiedName.ColonColonToken; + name = qualifiedName.Name; + } + public void GetPartsOfArgumentList(SyntaxNode node, out SyntaxToken openParenToken, out SeparatedSyntaxList arguments, out SyntaxToken closeParenToken) { var argumentListNode = (ArgumentListSyntax)node; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Services/SyntaxFacts/CSharpSyntaxKinds.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Services/SyntaxFacts/CSharpSyntaxKinds.cs index bef0199ad2181..918895ef01572 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Services/SyntaxFacts/CSharpSyntaxKinds.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Services/SyntaxFacts/CSharpSyntaxKinds.cs @@ -73,6 +73,7 @@ public int Convert(TSyntaxKind kind) where TSyntaxKind : struct public int TrueKeyword => (int)SyntaxKind.TrueKeyword; public int UsingKeyword => (int)SyntaxKind.UsingKeyword; + public int? AliasQualifiedName => (int)SyntaxKind.AliasQualifiedName; public int GenericName => (int)SyntaxKind.GenericName; public int IdentifierName => (int)SyntaxKind.IdentifierName; public int QualifiedName => (int)SyntaxKind.QualifiedName; @@ -96,6 +97,7 @@ public int Convert(TSyntaxKind kind) where TSyntaxKind : struct public int CollectionInitializerExpression => (int)SyntaxKind.CollectionInitializerExpression; public int ConditionalAccessExpression => (int)SyntaxKind.ConditionalAccessExpression; public int ConditionalExpression => (int)SyntaxKind.ConditionalExpression; + public int? FieldExpression => (int)SyntaxKind.FieldExpression; public int? ImplicitArrayCreationExpression => (int)SyntaxKind.ImplicitArrayCreationExpression; public int? ImplicitObjectCreationExpression => (int)SyntaxKind.ImplicitObjectCreationExpression; public int? IndexExpression => (int)SyntaxKind.IndexExpression; @@ -113,6 +115,7 @@ public int Convert(TSyntaxKind kind) where TSyntaxKind : struct public int? RefExpression => (int)SyntaxKind.RefExpression; public int ReferenceEqualsExpression => (int)SyntaxKind.EqualsExpression; public int ReferenceNotEqualsExpression => (int)SyntaxKind.NotEqualsExpression; + public int SimpleAssignmentExpression => (int)SyntaxKind.SimpleAssignmentExpression; public int SimpleMemberAccessExpression => (int)SyntaxKind.SimpleMemberAccessExpression; public int? SuppressNullableWarningExpression => (int)SyntaxKind.SuppressNullableWarningExpression; public int TernaryConditionalExpression => (int)SyntaxKind.ConditionalExpression; @@ -175,4 +178,5 @@ public int Convert(TSyntaxKind kind) where TSyntaxKind : struct public int InterpolatedStringExpression => (int)SyntaxKind.InterpolatedStringExpression; public int InterpolatedStringText => (int)SyntaxKind.InterpolatedStringText; public int? IndexerMemberCref => (int)SyntaxKind.IndexerMemberCref; + public int? PrimaryConstructorBaseType => (int)SyntaxKind.PrimaryConstructorBaseType; } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Simplification/CSharpSimplifierOptions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Simplification/CSharpSimplifierOptions.cs index e52fe6aa0b0eb..bd616fa208148 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Simplification/CSharpSimplifierOptions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Simplification/CSharpSimplifierOptions.cs @@ -28,6 +28,7 @@ internal sealed record class CSharpSimplifierOptions : SimplifierOptions, IEquat [DataMember] public CodeStyleOption2 AllowEmbeddedStatementsOnSameLine { get; init; } = CodeStyleOption2.TrueWithSilentEnforcement; [DataMember] public CodeStyleOption2 PreferBraces { get; init; } = s_defaultPreferBraces; [DataMember] public CodeStyleOption2 PreferThrowExpression { get; init; } = CodeStyleOption2.TrueWithSuggestionEnforcement; + [DataMember] public CodeStyleOption2 ImplicitObjectCreationWhenTypeIsApparent { get; init; } = CodeStyleOption2.FalseWithSilentEnforcement; public CSharpSimplifierOptions() { @@ -43,6 +44,7 @@ public CSharpSimplifierOptions(IOptionsReader options) AllowEmbeddedStatementsOnSameLine = options.GetOption(CSharpCodeStyleOptions.AllowEmbeddedStatementsOnSameLine); PreferBraces = options.GetOption(CSharpCodeStyleOptions.PreferBraces); PreferThrowExpression = options.GetOption(CSharpCodeStyleOptions.PreferThrowExpression); + ImplicitObjectCreationWhenTypeIsApparent = options.GetOption(CSharpCodeStyleOptions.ImplicitObjectCreationWhenTypeIsApparent); } public UseVarPreference GetUseVarPreference() diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Simplification/Simplifiers/CastSimplifier.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Simplification/Simplifiers/CastSimplifier.cs index b8933465c52de..6cb9eaca9a9fa 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Simplification/Simplifiers/CastSimplifier.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Simplification/Simplifiers/CastSimplifier.cs @@ -89,21 +89,28 @@ public static bool IsUnnecessaryCast(CastExpressionSyntax cast, SemanticModel se { Kind: OperationKind.MethodReference, Parent.Kind: OperationKind.DelegateCreation, - Parent.Parent: IConversionOperation { Type.SpecialType: SpecialType.System_Object } conversionOperation + IsImplicit: false, }) { - // If we have a double cast, report as unnecessary, e.g: - // (object)(object)MethodGroup - // (Delegate)(object)MethodGroup - // If we have a single object cast, don't report as unnecessary e.g: - // (object)MethodGroup - if (conversionOperation.Parent is IConversionOperation { Type: { } parentConversionType } && - semanticModel.ClassifyConversion(cast.Expression, parentConversionType).Exists) + var current = castExpressionOperation.Parent.Parent; + while (current is IConversionOperation { Type.SpecialType: SpecialType.System_Delegate or SpecialType.System_MulticastDelegate }) + current = current.Parent; + + if (current is IConversionOperation { Type.SpecialType: SpecialType.System_Object }) { - return true; - } + // If we have a double cast, report as unnecessary, e.g: + // (object)(object)MethodGroup + // (Delegate)(object)MethodGroup + // If we have a single object cast, don't report as unnecessary e.g: + // (object)MethodGroup + if (current.Parent is IConversionOperation { Type: { } parentConversionType, IsImplicit: false } && + semanticModel.ClassifyConversion(cast.Expression, parentConversionType).Exists) + { + return true; + } - return false; + return false; + } } return IsCastSafeToRemove(cast, cast.Expression, semanticModel, cancellationToken); @@ -349,6 +356,14 @@ private static bool IsConversionCastSafeToRemove( if (rewrittenConvertedType is null || rewrittenConvertedType.TypeKind == TypeKind.Error || !rewrittenConversion.Exists) return false; + // If removing the conversion caused us to now become an explicit conversion (a conversion that can cause + // lossyness), then we must block as that's disallowed by the language. + // + // Note: compiler API is slightly odd here as they return such an 'IsExplicit+Exists' conversion when casting + // the expression inside a string interpolation. So we ignore that case here + if (rewrittenConversion.IsExplicit && castNode.WalkUpParentheses().Parent is not InterpolationSyntax) + return false; + if (CastRemovalWouldCauseUnintendedReferenceComparisonWarning(rewrittenExpression, rewrittenSemanticModel, cancellationToken)) return false; @@ -420,22 +435,27 @@ private static bool IsConversionCastSafeToRemove( #region allowed cases that allow this cast to be removed. - // In code like `((X)y).Z()` the cast to (X) can be removed if the same 'Z' method would be called. - // The rules here can be subtle. For example, if Z is virtual, and (X) is a cast up the inheritance - // hierarchy then this is *normally* ok. HOwever, the language resolve default parameter values - // from the overridden method. So if they differ, we can't actually remove the cast. + // In code like `((X)y).Z()` the cast to (X) can be removed if the same 'Z' method would be called. The rules + // here can be subtle. For example, if Z is virtual, and (X) is a cast up the inheritance hierarchy then this + // is *normally* ok. However, the language resolve default parameter values from the overridden method. So if + // they differ, we can't actually remove the cast. // - // Similarly, if (X) is a cast to an interface, and Z is an impl of that interface method, it might - // be possible to remove, but only if y's type is sealed, as otherwise the interface method could be - // reimplemented in a derived type. + // Similarly, if (X) is a cast to an interface, and Z is an impl of that interface method, it might be possible + // to remove, but only if y's type is sealed, as otherwise the interface method could be reimplemented in a + // derived type. // - // Note: this path is fundamentally different from the other forms of cast removal we perform. The - // casts are removed because statically they make no difference to the meaning of the code. Here, - // the code statically changes meaning. However, we can use our knowledge of how the language/runtime - // works to know at *runtime* that the user will get the exact same behavior. + // Note: this path is fundamentally different from the other forms of cast removal we perform. The casts are + // removed because statically they make no difference to the meaning of the code. Here, the code statically + // changes meaning. However, we can use our knowledge of how the language/runtime works to know at *runtime* + // that the user will get the exact same behavior. if (castNode.WalkUpParentheses().Parent is MemberAccessExpressionSyntax memberAccessExpression) { - if (IsComplementaryMemberAccessAfterCastRemoval( + // Note: because this involves virtual calls, it is only safe if the original cast didn't change the runtime + // representation of the value at all. So we only allow this for representation preserving casts. For example, + // `string->object` preserves representation. As does `int -> icomparable` + var isRepresentationPreservingCast = originalConversion.IsIdentityOrImplicitReference() || originalConversion.IsBoxing; + if (isRepresentationPreservingCast && + IsComplementaryMemberAccessAfterCastRemoval( memberAccessExpression, rewrittenExpression, originalSemanticModel, rewrittenSemanticModel, cancellationToken)) { return true; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Utilities/FormattingRangeHelper.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Utilities/FormattingRangeHelper.cs index 0fab4e5369a2b..13e6a23bf678b 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Utilities/FormattingRangeHelper.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Utilities/FormattingRangeHelper.cs @@ -270,15 +270,14 @@ OperatorDeclarationSyntax or // don't do anything if there is no proper parent var parent = endToken.Parent; if (parent == null || parent.Kind() == SyntaxKind.SkippedTokensTrivia) - { return null; - } // cases such as namespace, type, enum, method almost any top level elements if (IsColonInSwitchLabel(endToken)) - { - return ValueTuple.Create(GetPreviousTokenIfNotFirstTokenInTree(parent.GetFirstToken()), parent.GetLastToken()); - } + return (GetPreviousTokenIfNotFirstTokenInTree(parent.GetFirstToken()), parent.GetLastToken()); + + if (endToken.Kind() == SyntaxKind.ColonToken && parent is LabeledStatementSyntax) + return (GetPreviousTokenIfNotFirstTokenInTree(parent.GetFirstToken()), parent.GetLastToken()); return null; } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Utilities/TypeStyle/CSharpUseImplicitTypeHelper.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Utilities/TypeStyle/CSharpUseImplicitTypeHelper.cs index 85aef94d0079b..0ad0363d96bfd 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Utilities/TypeStyle/CSharpUseImplicitTypeHelper.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Utilities/TypeStyle/CSharpUseImplicitTypeHelper.cs @@ -2,19 +2,19 @@ // 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.Linq; using System.Threading; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.CodeStyle.TypeStyle; using Microsoft.CodeAnalysis.CSharp.Extensions; -using Microsoft.CodeAnalysis.CSharp.Formatting; +using Microsoft.CodeAnalysis.CSharp.Simplification; using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.Operations; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.Utilities; using Microsoft.CodeAnalysis.Simplification; -using Microsoft.CodeAnalysis.Operations; -using Microsoft.CodeAnalysis.CSharp.Simplification; namespace Microsoft.CodeAnalysis.CSharp.Utilities; @@ -46,12 +46,10 @@ public override TypeStyleResult AnalyzeTypeName( public override bool ShouldAnalyzeVariableDeclaration(VariableDeclarationSyntax variableDeclaration, CancellationToken cancellationToken) { + // If the type is already 'var' or 'ref var', this analyzer has no work to do var type = variableDeclaration.Type.StripRefIfNeeded(); if (type.IsVar) - { - // If the type is already 'var' or 'ref var', this analyzer has no work to do return false; - } // The base analyzer may impose further limitations return base.ShouldAnalyzeVariableDeclaration(variableDeclaration, cancellationToken); @@ -59,17 +57,25 @@ public override bool ShouldAnalyzeVariableDeclaration(VariableDeclarationSyntax protected override bool ShouldAnalyzeForEachStatement(ForEachStatementSyntax forEachStatement, SemanticModel semanticModel, CancellationToken cancellationToken) { - var type = forEachStatement.Type; - if (type.IsVar || (type.Kind() == SyntaxKind.RefType && ((RefTypeSyntax)type).Type.IsVar)) - { - // If the type is already 'var', this analyze has no work to do + // If the type is already 'var' or 'ref var', this analyzer has no work to do + var type = forEachStatement.Type.StripRefIfNeeded(); + if (type.IsVar) return false; - } // The base analyzer may impose further limitations return base.ShouldAnalyzeForEachStatement(forEachStatement, semanticModel, cancellationToken); } + protected override bool ShouldAnalyzeDeclarationExpression(DeclarationExpressionSyntax declaration, SemanticModel semanticModel, CancellationToken cancellationToken) + { + // If the type is already 'var' or 'ref var', this analyzer has no work to do + if (declaration.Type.StripRefIfNeeded().IsVar) + return false; + + // The base analyzer may impose further limitations + return base.ShouldAnalyzeDeclarationExpression(declaration, semanticModel, cancellationToken); + } + protected override bool IsStylePreferred(in State state) { var stylePreferences = state.TypeStylePreference; @@ -110,23 +116,11 @@ SyntaxKind.ForStatement or SyntaxKind.UsingStatement)) { // implicitly typed variables cannot be constants. - if ((variableDeclaration.Parent as LocalDeclarationStatementSyntax)?.IsConst == true) - { - return false; - } - - if (variableDeclaration.Variables.Count != 1) - { + if (variableDeclaration.Parent is LocalDeclarationStatementSyntax { IsConst: true }) return false; - } - var variable = variableDeclaration.Variables[0]; - if (variable.Initializer == null) - { + if (variableDeclaration.Variables is not [{ Initializer.Value: var initializer } variable]) return false; - } - - var initializer = variable.Initializer.Value; // Do not suggest var replacement for stackalloc span expressions. // This will change the bound type from a span to a pointer. @@ -220,9 +214,10 @@ private static bool IsSafeToSwitchToVarWithoutNeedingSpeculation(DeclarationExpr // If there was only one member in the group, and it was non-generic itself, then this // change is commonly safe to make without having to actually change to `var` and // speculatively determine if the change is ok or not. - if (declarationExpression.Parent is not ArgumentSyntax argument || - argument.Parent is not ArgumentListSyntax argumentList || - argumentList.Parent is not InvocationExpressionSyntax invocationExpression) + if (declarationExpression.Parent is not ArgumentSyntax + { + Parent: ArgumentListSyntax { Parent: InvocationExpressionSyntax invocationExpression } + } argument) { return false; } @@ -231,33 +226,21 @@ argument.Parent is not ArgumentListSyntax argumentList || if (memberGroup.Length != 1) return false; - var method = memberGroup[0] as IMethodSymbol; - if (method == null) - return false; - - if (!method.GetTypeParameters().IsEmpty) + if (memberGroup[0] is not IMethodSymbol { TypeParameters.IsEmpty: true } method) return false; - // Looks pretty good so far. However, this change is not allowed if the user is - // specifying something like `out (int x, int y) t` and the method signature has - // different names for those tuple elements. Check and make sure the types are the - // same before proceeding. + // Looks pretty good so far. However, this change is not allowed if the user is specifying something like `out + // (int x, int y) t` and the method signature has different names for those tuple elements. Check and make sure + // the types are the same before proceeding. - var invocationOp = semanticModel.GetOperation(invocationExpression, cancellationToken) as IInvocationOperation; - if (invocationOp == null) + if (semanticModel.GetOperation(invocationExpression, cancellationToken) is not IInvocationOperation invocationOp) return false; var argumentOp = invocationOp.Arguments.FirstOrDefault(a => a.Syntax == argument); - if (argumentOp == null) - return false; - - if (argumentOp.Value?.Type == null) + if (argumentOp is not { Value.Type: { } valueType, Parameter.Type: { } parameterType }) return false; - if (argumentOp.Parameter?.Type == null) - return false; - - return argumentOp.Value.Type.Equals(argumentOp.Parameter.Type); + return valueType.Equals(parameterType); } /// @@ -279,22 +262,19 @@ protected override bool AssignmentSupportsStylePreference( // var cannot be assigned null if (expression.IsKind(SyntaxKind.NullLiteralExpression)) - { return false; - } // var cannot be used with target typed new if (expression.IsKind(SyntaxKind.ImplicitObjectCreationExpression)) - { return false; - } // cannot use implicit typing on method group or on dynamic var declaredType = semanticModel.GetTypeInfo(typeName.StripRefIfNeeded(), cancellationToken).Type; - if (declaredType != null && declaredType.TypeKind == TypeKind.Dynamic) - { + if (declaredType is null) + return false; + + if (declaredType.TypeKind == TypeKind.Dynamic) return false; - } // variables declared using var cannot be used further in the same initialization expression. if (initializer.DescendantNodesAndSelf() @@ -322,9 +302,9 @@ protected override bool AssignmentSupportsStylePreference( } // Get the conversion that occurred between the expression's type and type implied by the expression's context - // and filter out implicit conversions. If an implicit conversion (other than identity) exists - // and if we're replacing the declaration with 'var' we'd be changing the semantics by inferring type of - // initializer expression and thereby losing the conversion. + // and filter out implicit conversions. If an implicit conversion (other than identity) exists and if we're + // replacing the declaration with 'var' we'd be changing the semantics by inferring type of initializer + // expression and thereby losing the conversion. var conversion = semanticModel.GetConversion(expression, cancellationToken); if (conversion.IsIdentity) { @@ -333,6 +313,19 @@ protected override bool AssignmentSupportsStylePreference( return declaredType != null && declaredType.Equals(initializerType); } + // This also applies to a lambda assigned to a variable. This will have no conversion, but can be converted as + // long as the type is Func<> or Action<> as that's what the language will infer here. + if (!conversion.Exists && expression is LambdaExpressionSyntax && semanticModel.Compilation.LanguageVersion() >= LanguageVersion.CSharp10) + { + var initializerType = semanticModel.GetTypeInfo(expression, cancellationToken).Type; + return declaredType.Equals(initializerType) && + declaredType is + { + Name: nameof(Func) or nameof(Action), + ContainingSymbol: INamespaceSymbol { Name: nameof(System), ContainingNamespace.IsGlobalNamespace: true } + }; + } + return false; } @@ -342,16 +335,4 @@ internal static ExpressionSyntax GetInitializerExpression(ExpressionSyntax initi current = (current as CheckedExpressionSyntax)?.Expression ?? current; return current.WalkDownParentheses(); } - - protected override bool ShouldAnalyzeDeclarationExpression(DeclarationExpressionSyntax declaration, SemanticModel semanticModel, CancellationToken cancellationToken) - { - if (declaration.Type.IsVar) - { - // If the type is already 'var', this analyze has no work to do - return false; - } - - // The base analyzer may impose further limitations - return base.ShouldAnalyzeDeclarationExpression(declaration, semanticModel, cancellationToken); - } } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Utilities/UsingsAndExternAliasesOrganizer.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Utilities/UsingsAndExternAliasesOrganizer.cs index 370db510b5877..ad7f321121729 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Utilities/UsingsAndExternAliasesOrganizer.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Utilities/UsingsAndExternAliasesOrganizer.cs @@ -16,11 +16,20 @@ internal static partial class UsingsAndExternAliasesOrganizer public static void Organize( SyntaxList externAliasList, SyntaxList usingList, - bool placeSystemNamespaceFirst, bool separateGroups, - SyntaxTrivia newLineTrivia, + bool placeSystemNamespaceFirst, + bool separateGroups, + SyntaxTrivia fallbackTrivia, out SyntaxList organizedExternAliasList, out SyntaxList organizedUsingList) { + // Attempt to use an existing newline trivia from the existing usings/externs. If we can't find any use what + // the caller passed in. + var newLineTrivia = ((IEnumerable)externAliasList) + .Concat(usingList) + .Select(n => n.GetTrailingTrivia().FirstOrNull(t => t.Kind() == SyntaxKind.EndOfLineTrivia)) + .Where(t => t != null) + .FirstOrDefault() ?? fallbackTrivia; + OrganizeWorker( externAliasList, usingList, placeSystemNamespaceFirst, newLineTrivia, diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/xlf/CSharpCompilerExtensionsResources.cs.xlf b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/xlf/CSharpCompilerExtensionsResources.cs.xlf index d32fa26eedbfb..5960e43ab93f7 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/xlf/CSharpCompilerExtensionsResources.cs.xlf +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/xlf/CSharpCompilerExtensionsResources.cs.xlf @@ -22,6 +22,11 @@ Členy s výrazem v těle + + Indentation preferences + Indentation preferences + + Null-checking preferences Předvolby kontrol hodnoty null @@ -32,6 +37,16 @@ Předvolby porovnávání vzorů + + Space preferences + Space preferences + + + + Wrapping preferences + Wrapping preferences + + 'using' directive preferences Předvolby direktivy using diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/xlf/CSharpCompilerExtensionsResources.de.xlf b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/xlf/CSharpCompilerExtensionsResources.de.xlf index b85e143ec80b7..39c9b890e4de5 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/xlf/CSharpCompilerExtensionsResources.de.xlf +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/xlf/CSharpCompilerExtensionsResources.de.xlf @@ -22,6 +22,11 @@ Ausdruckskörpermember + + Indentation preferences + Indentation preferences + + Null-checking preferences Einstellungen für NULL-Überprüfung @@ -32,6 +37,16 @@ Einstellungen für den Musterabgleich + + Space preferences + Space preferences + + + + Wrapping preferences + Wrapping preferences + + 'using' directive preferences Einstellungen für using-Anweisungen diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/xlf/CSharpCompilerExtensionsResources.es.xlf b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/xlf/CSharpCompilerExtensionsResources.es.xlf index 788a8f9574971..18aef8ccd6681 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/xlf/CSharpCompilerExtensionsResources.es.xlf +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/xlf/CSharpCompilerExtensionsResources.es.xlf @@ -22,6 +22,11 @@ Miembros en cuerpo de expresión + + Indentation preferences + Indentation preferences + + Null-checking preferences Preferencias de comprobación de nulo @@ -32,6 +37,16 @@ Preferencias de coincidencia de patrón + + Space preferences + Space preferences + + + + Wrapping preferences + Wrapping preferences + + 'using' directive preferences Preferencias de directiva "using" diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/xlf/CSharpCompilerExtensionsResources.fr.xlf b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/xlf/CSharpCompilerExtensionsResources.fr.xlf index 07772c15d1958..8bae513a134bc 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/xlf/CSharpCompilerExtensionsResources.fr.xlf +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/xlf/CSharpCompilerExtensionsResources.fr.xlf @@ -22,6 +22,11 @@ Membres expression-bodied + + Indentation preferences + Indentation preferences + + Null-checking preferences Préférences de vérification de valeur Null @@ -32,6 +37,16 @@ Préférences correspondants au modèle + + Space preferences + Space preferences + + + + Wrapping preferences + Wrapping preferences + + 'using' directive preferences Préférences pour la directive 'using' diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/xlf/CSharpCompilerExtensionsResources.it.xlf b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/xlf/CSharpCompilerExtensionsResources.it.xlf index f235d51396d01..6f43c85f2f0b5 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/xlf/CSharpCompilerExtensionsResources.it.xlf +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/xlf/CSharpCompilerExtensionsResources.it.xlf @@ -22,6 +22,11 @@ Membri con corpo di espressione + + Indentation preferences + Indentation preferences + + Null-checking preferences Preference per controllo valori Null @@ -32,6 +37,16 @@ Preferenze per criteri di ricerca + + Space preferences + Space preferences + + + + Wrapping preferences + Wrapping preferences + + 'using' directive preferences Preferenze per direttive 'using' diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/xlf/CSharpCompilerExtensionsResources.ja.xlf b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/xlf/CSharpCompilerExtensionsResources.ja.xlf index aba490097239f..f7f5fe6bda2a6 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/xlf/CSharpCompilerExtensionsResources.ja.xlf +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/xlf/CSharpCompilerExtensionsResources.ja.xlf @@ -22,6 +22,11 @@ 式のようなメンバー + + Indentation preferences + Indentation preferences + + Null-checking preferences Null チェック設定 @@ -32,6 +37,16 @@ パターン マッチング設定 + + Space preferences + Space preferences + + + + Wrapping preferences + Wrapping preferences + + 'using' directive preferences 'using' ディレクティブの基本設定 diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/xlf/CSharpCompilerExtensionsResources.ko.xlf b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/xlf/CSharpCompilerExtensionsResources.ko.xlf index 20c86bb508b72..a8734395e5cb6 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/xlf/CSharpCompilerExtensionsResources.ko.xlf +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/xlf/CSharpCompilerExtensionsResources.ko.xlf @@ -22,6 +22,11 @@ 식 본문 멤버 + + Indentation preferences + Indentation preferences + + Null-checking preferences Null 검사 기본 설정 @@ -32,6 +37,16 @@ 패턴 일치 기본 설정 + + Space preferences + Space preferences + + + + Wrapping preferences + Wrapping preferences + + 'using' directive preferences 'using' 지시문 기본 설정 diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/xlf/CSharpCompilerExtensionsResources.pl.xlf b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/xlf/CSharpCompilerExtensionsResources.pl.xlf index a88315e954e08..7b70ff0a5bac1 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/xlf/CSharpCompilerExtensionsResources.pl.xlf +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/xlf/CSharpCompilerExtensionsResources.pl.xlf @@ -22,6 +22,11 @@ Składowe z wyrażeniem w treści + + Indentation preferences + Indentation preferences + + Null-checking preferences Preferencje sprawdzania wartości null @@ -32,6 +37,16 @@ Preferencje dopasowywania do wzorca + + Space preferences + Space preferences + + + + Wrapping preferences + Wrapping preferences + + 'using' directive preferences Preferencje dyrektywy „using” diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/xlf/CSharpCompilerExtensionsResources.pt-BR.xlf b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/xlf/CSharpCompilerExtensionsResources.pt-BR.xlf index a892025e17056..9b354dd9495ac 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/xlf/CSharpCompilerExtensionsResources.pt-BR.xlf +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/xlf/CSharpCompilerExtensionsResources.pt-BR.xlf @@ -22,6 +22,11 @@ Membros aptos para expressão + + Indentation preferences + Indentation preferences + + Null-checking preferences Preferências de verificação nula @@ -32,6 +37,16 @@ Preferências de correspondência de padrões + + Space preferences + Space preferences + + + + Wrapping preferences + Wrapping preferences + + 'using' directive preferences Preferências da diretiva 'using' diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/xlf/CSharpCompilerExtensionsResources.ru.xlf b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/xlf/CSharpCompilerExtensionsResources.ru.xlf index 46a9cb21a9c94..c739367280c32 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/xlf/CSharpCompilerExtensionsResources.ru.xlf +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/xlf/CSharpCompilerExtensionsResources.ru.xlf @@ -22,6 +22,11 @@ Члены, заданные выражениями + + Indentation preferences + Indentation preferences + + Null-checking preferences Настройки проверки на null @@ -32,6 +37,16 @@ Настройки соответствия шаблонов + + Space preferences + Space preferences + + + + Wrapping preferences + Wrapping preferences + + 'using' directive preferences предпочтения для директивы using diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/xlf/CSharpCompilerExtensionsResources.tr.xlf b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/xlf/CSharpCompilerExtensionsResources.tr.xlf index 3d57cea68c8ca..a47ef56c136cf 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/xlf/CSharpCompilerExtensionsResources.tr.xlf +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/xlf/CSharpCompilerExtensionsResources.tr.xlf @@ -22,6 +22,11 @@ İfade gövdeli Üyeler + + Indentation preferences + Indentation preferences + + Null-checking preferences Null denetimi tercihleri @@ -32,6 +37,16 @@ Desen eşleştirme tercihleri + + Space preferences + Space preferences + + + + Wrapping preferences + Wrapping preferences + + 'using' directive preferences 'using' yönergesi tercihleri diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/xlf/CSharpCompilerExtensionsResources.zh-Hans.xlf b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/xlf/CSharpCompilerExtensionsResources.zh-Hans.xlf index d29b4437bd71c..f7719e3167450 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/xlf/CSharpCompilerExtensionsResources.zh-Hans.xlf +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/xlf/CSharpCompilerExtensionsResources.zh-Hans.xlf @@ -22,6 +22,11 @@ Expression-bodied 成员 + + Indentation preferences + Indentation preferences + + Null-checking preferences Null 检查首选项 @@ -32,6 +37,16 @@ 模式匹配首选项 + + Space preferences + Space preferences + + + + Wrapping preferences + Wrapping preferences + + 'using' directive preferences "using" 指令首选项 diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/xlf/CSharpCompilerExtensionsResources.zh-Hant.xlf b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/xlf/CSharpCompilerExtensionsResources.zh-Hant.xlf index 2977802093cab..6e9cb79e56496 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/xlf/CSharpCompilerExtensionsResources.zh-Hant.xlf +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/xlf/CSharpCompilerExtensionsResources.zh-Hant.xlf @@ -22,6 +22,11 @@ 運算式主體成員 + + Indentation preferences + Indentation preferences + + Null-checking preferences Null 檢查喜好設定 @@ -32,6 +37,16 @@ 模式比對喜好設定 + + Space preferences + Space preferences + + + + Wrapping preferences + Wrapping preferences + + 'using' directive preferences 'using' 指示詞的喜好設定 diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CodeGeneration/Argument.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CodeGeneration/Argument.cs new file mode 100644 index 0000000000000..6480e678835ea --- /dev/null +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CodeGeneration/Argument.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. + +namespace Microsoft.CodeAnalysis.CodeGeneration; + +internal readonly struct Argument(RefKind refKind, string? name, TExpressionSyntax? expression) + where TExpressionSyntax : SyntaxNode +{ + public readonly RefKind RefKind = refKind; + public readonly string Name = name ?? ""; + public readonly TExpressionSyntax? Expression = expression; + + public bool IsNamed => !string.IsNullOrEmpty(Name); +} diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/ParameterName.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CodeGeneration/ParameterName.cs similarity index 89% rename from src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/ParameterName.cs rename to src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CodeGeneration/ParameterName.cs index a6e0141b1abcd..6844e2014c4d8 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/ParameterName.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CodeGeneration/ParameterName.cs @@ -9,7 +9,7 @@ using Microsoft.CodeAnalysis.Diagnostics.Analyzers.NamingStyles; using Roslyn.Utilities; -namespace Microsoft.CodeAnalysis.Utilities; +namespace Microsoft.CodeAnalysis.CodeGeneration; internal readonly struct ParameterName : IEquatable { @@ -26,7 +26,7 @@ namespace Microsoft.CodeAnalysis.Utilities; /// public readonly string BestNameForParameter; - public ParameterName(string nameBasedOnArgument, bool isFixed) + public ParameterName(string nameBasedOnArgument, bool isFixed, bool tryMakeCamelCase = true) { NameBasedOnArgument = nameBasedOnArgument; @@ -37,10 +37,9 @@ public ParameterName(string nameBasedOnArgument, bool isFixed) } else { - // Otherwise, massage it a bit to be a more suitable match for - // how people actually writing parameters. + // Otherwise, massage it a bit to be a more suitable match for how people actually writing parameters. var trimmed = nameBasedOnArgument.TrimStart('_'); - BestNameForParameter = trimmed.Length > 0 ? trimmed.ToCamelCase() : nameBasedOnArgument; + BestNameForParameter = trimmed.Length > 0 ? tryMakeCamelCase ? trimmed.ToCamelCase() : trimmed : nameBasedOnArgument; } } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CodeStyle/CodeStyleOptions2.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CodeStyle/CodeStyleOptions2.cs index eb193d5eec38d..26084a44ee77c 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CodeStyle/CodeStyleOptions2.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CodeStyle/CodeStyleOptions2.cs @@ -5,7 +5,6 @@ using System; using System.Collections.Immutable; using System.Diagnostics; -using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Shared.CodeStyle; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CodeStyle/FadingOptions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CodeStyle/FadingOptions.cs index 7028792d88af3..0a4cd95db9c33 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CodeStyle/FadingOptions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CodeStyle/FadingOptions.cs @@ -10,5 +10,6 @@ namespace Microsoft.CodeAnalysis.CodeStyle; internal static class FadingOptions { public static readonly PerLanguageOption2 FadeOutUnusedImports = new("dotnet_fade_out_unused_imports", defaultValue: true); + public static readonly PerLanguageOption2 FadeOutUnusedMembers = new("dotnet_fade_out_unused_members", defaultValue: true); public static readonly PerLanguageOption2 FadeOutUnreachableCode = new("dotnet_fade_out_unreachable_code", defaultValue: true); } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CompilerExtensions.projitems b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CompilerExtensions.projitems index e47ce24e5224c..56d65226cc0ea 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CompilerExtensions.projitems +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CompilerExtensions.projitems @@ -190,6 +190,7 @@ InternalUtilities\UnicodeCharacterUtilities.cs + @@ -277,6 +278,7 @@ + @@ -519,7 +521,7 @@ - + @@ -580,7 +582,6 @@ - diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CompilerExtensionsResources.resx b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CompilerExtensionsResources.resx index 7e4f99739d401..2209229465be2 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CompilerExtensionsResources.resx +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CompilerExtensionsResources.resx @@ -276,4 +276,19 @@ Instantiated part(s) threw exception(s) from IDisposable.Dispose(). + + Indentation and spacing + + + Value too large to be represented as a 30 bit unsigned integer. + + + A language name cannot be specified for this option. + + + A language name must be specified for this option. + + + Stream must support read and seek operations. + \ No newline at end of file diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/DiagnosticDescriptorExtensions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/DiagnosticDescriptorExtensions.cs index 121aa8bcd6e62..08e6b1626fb48 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/DiagnosticDescriptorExtensions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/DiagnosticDescriptorExtensions.cs @@ -261,7 +261,7 @@ public static DiagnosticDescriptor WithMessageFormat(this DiagnosticDescriptor d #pragma warning disable RS0030 // Do not used banned APIs - DiagnosticDescriptor .ctor is banned in this project, but fine to use here. return new DiagnosticDescriptor(descriptor.Id, descriptor.Title, messageFormat, descriptor.Category, descriptor.DefaultSeverity, descriptor.IsEnabledByDefault, - descriptor.Description, descriptor.HelpLinkUri, descriptor.CustomTags.ToArray()); + descriptor.Description, descriptor.HelpLinkUri, [.. descriptor.CustomTags]); #pragma warning restore RS0030 // Do not used banned APIs } } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/ICompilationExtensions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/ICompilationExtensions.cs index ca5e10666e4c4..c48696e6c277d 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/ICompilationExtensions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/ICompilationExtensions.cs @@ -69,6 +69,9 @@ public static ImmutableArray GetReferencedAssemblySymbols(this return builder.ToImmutableAndFree(); } + public static INamedTypeSymbol? ArrayType(this Compilation compilation) + => compilation.GetTypeByMetadataName(typeof(Array).FullName!); + public static INamedTypeSymbol? AttributeType(this Compilation compilation) => compilation.GetTypeByMetadataName(typeof(Attribute).FullName!); @@ -79,7 +82,10 @@ public static ImmutableArray GetReferencedAssemblySymbols(this => compilation.GetTypeByMetadataName(typeof(System.Diagnostics.DebuggerDisplayAttribute).FullName!); public static INamedTypeSymbol? StructLayoutAttributeType(this Compilation compilation) - => compilation.GetTypeByMetadataName(typeof(System.Runtime.InteropServices.StructLayoutAttribute).FullName!); + => compilation.GetTypeByMetadataName(typeof(StructLayoutAttribute).FullName!); + + public static INamedTypeSymbol? InlineArrayAttributeType(this Compilation compilation) + => compilation.GetTypeByMetadataName("System.Runtime.CompilerServices.InlineArrayAttribute"); public static INamedTypeSymbol? DesignerCategoryAttributeType(this Compilation compilation) => compilation.GetTypeByMetadataName("System.ComponentModel.DesignerCategoryAttribute"); @@ -141,6 +147,12 @@ public static ImmutableArray GetReferencedAssemblySymbols(this public static INamedTypeSymbol? IReadOnlyListOfTType(this Compilation compilation) => compilation.GetTypeByMetadataName(typeof(IReadOnlyList<>).FullName!); + public static INamedTypeSymbol? ISetOfTType(this Compilation compilation) + => compilation.GetTypeByMetadataName(typeof(ISet<>).FullName!); + + public static INamedTypeSymbol? IReadOnlySetOfTType(this Compilation compilation) + => compilation.GetTypeByMetadataName(typeof(IReadOnlySet<>).FullName!); + public static INamedTypeSymbol? IAsyncEnumerableOfTType(this Compilation compilation) => compilation.GetTypeByMetadataName("System.Collections.Generic.IAsyncEnumerable`1"); diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/IMethodSymbolExtensions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/IMethodSymbolExtensions.cs index 87a272da45712..b1d0f13b0eb05 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/IMethodSymbolExtensions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/IMethodSymbolExtensions.cs @@ -120,6 +120,6 @@ public static bool IsAsyncReturningVoidTask(this IMethodSymbol method, Compilati // `Task` type doesn't have an `AsyncMethodBuilder` attribute, so we need to check for it separately return method.ReturnType.Equals(compilation.TaskType()) || - method.ReturnType.GetAttributes().Any(a => a.AttributeClass?.Equals(compilation.AsyncMethodBuilderAttribute()) ?? false); + method.ReturnType.HasAttribute(compilation.AsyncMethodBuilderAttribute()); } } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/INamedTypeSymbolExtensions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/INamedTypeSymbolExtensions.cs index da3c86ea8f721..28a8cdf916c9e 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/INamedTypeSymbolExtensions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/INamedTypeSymbolExtensions.cs @@ -33,10 +33,10 @@ public static ImmutableArray GetAllTypeParameters(this INa return stack.SelectManyAsArray(n => n.TypeParameters); } - public static IEnumerable GetAllTypeArguments(this INamedTypeSymbol? symbol) + public static ImmutableArray GetAllTypeArguments(this INamedTypeSymbol? symbol) { var stack = GetContainmentStack(symbol); - return stack.SelectMany(n => n.TypeArguments); + return stack.SelectManyAsArray(n => n.TypeArguments); } private static Stack GetContainmentStack(INamedTypeSymbol? symbol) @@ -195,10 +195,12 @@ static ImmutableArray GetImplicitlyImplementableMembers(INamedTypeSymbo { if (type.TypeKind == TypeKind.Interface) { - return type.GetMembers().WhereAsArray(m => m.DeclaredAccessibility == Accessibility.Public && - m.Kind != SymbolKind.NamedType && IsImplementable(m) && - !IsPropertyWithNonPublicImplementableAccessor(m) && - IsImplicitlyImplementable(m, within)); + return type.GetMembers().WhereAsArray( + m => m.DeclaredAccessibility is Accessibility.Public or Accessibility.Protected && + m.Kind != SymbolKind.NamedType && + IsImplementable(m) && + !IsPropertyWithNonPublicImplementableAccessor(m) && + IsImplicitlyImplementable(m, within)); } return type.GetMembers(); @@ -367,9 +369,7 @@ private static ImmutableArray GetTypesToImplement( private static ImmutableArray GetAbstractClassesToImplement( IEnumerable abstractClasses) { - return abstractClasses.SelectMany(a => a.GetBaseTypesAndThis()) - .Where(t => t.IsAbstractClass()) - .ToImmutableArray(); + return [.. abstractClasses.SelectMany(a => a.GetBaseTypesAndThis()).Where(t => t.IsAbstractClass())]; } private static ImmutableArray GetInterfacesToImplement( diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/ISymbolExtensions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/ISymbolExtensions.cs index 64152ff9a6ad2..cc25196f81a12 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/ISymbolExtensions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/ISymbolExtensions.cs @@ -9,6 +9,7 @@ using System.Linq; using System.Threading; using Microsoft.CodeAnalysis.PooledObjects; +using Microsoft.CodeAnalysis.Shared.Collections; using Microsoft.CodeAnalysis.Shared.Utilities; using Roslyn.Utilities; @@ -147,17 +148,28 @@ public static ImmutableArray ExplicitOrImplicitInterfaceImplementations if (symbol.Kind is not SymbolKind.Method and not SymbolKind.Property and not SymbolKind.Event) return []; - var containingType = symbol.ContainingType; - var query = from iface in containingType.AllInterfaces - from interfaceMember in iface.GetMembers() - let impl = containingType.FindImplementationForInterfaceMember(interfaceMember) - where symbol.Equals(impl) - select interfaceMember; - return query.ToImmutableArray(); + using var _ = ArrayBuilder.GetInstance(out var result); + + foreach (var iface in symbol.ContainingType.AllInterfaces) + { + foreach (var interfaceMember in iface.GetMembers()) + { + var impl = symbol.ContainingType.FindImplementationForInterfaceMember(interfaceMember); + if (symbol.Equals(impl)) + result.Add(interfaceMember); + } + } + + // There are explicit methods that FindImplementationForInterfaceMember. For exampl `abstract explicit impls` + // like `abstract void I.M()`. So add these back in directly using symbol.ExplicitInterfaceImplementations. + result.AddRange(symbol.ExplicitInterfaceImplementations()); + result.RemoveDuplicates(); + + return result.ToImmutableAndClear(); } public static ImmutableArray ImplicitInterfaceImplementations(this ISymbol symbol) - => symbol.ExplicitOrImplicitInterfaceImplementations().Except(symbol.ExplicitInterfaceImplementations()).ToImmutableArray(); + => [.. symbol.ExplicitOrImplicitInterfaceImplementations().Except(symbol.ExplicitInterfaceImplementations())]; public static bool IsOverridable([NotNullWhen(true)] this ISymbol? symbol) { @@ -505,7 +517,7 @@ public static ITypeSymbol ConvertToType( types = types.Concat((method.ReturnType ?? compilation.GetSpecialType(SpecialType.System_Object)).WithNullableAnnotation(method.ReturnNullableAnnotation)); } - return delegateType.TryConstruct(types.ToArray()); + return delegateType.TryConstruct([.. types]); } } @@ -796,4 +808,12 @@ public static bool IsObsolete(this ISymbol symbol) MetadataName: nameof(ObsoleteAttribute), ContainingNamespace.Name: nameof(System), }); + + public static bool HasAttribute([NotNullWhen(true)] this ISymbol? symbol, [NotNullWhen(true)] INamedTypeSymbol? attributeClass) + { + if (symbol is null || attributeClass is null) + return false; + + return symbol.GetAttributes().Any(static (attribute, attributeClass) => attributeClass.Equals(attribute.AttributeClass), attributeClass); + } } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/ITypeSymbolExtensions.SubstituteTypesVisitor.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/ITypeSymbolExtensions.SubstituteTypesVisitor.cs index 2114faae37b16..8d06aabb6cc66 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/ITypeSymbolExtensions.SubstituteTypesVisitor.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/ITypeSymbolExtensions.SubstituteTypesVisitor.cs @@ -68,8 +68,8 @@ public override ITypeSymbol VisitNamedType(INamedTypeSymbol symbol) } // If we don't even have any type arguments, then there's nothing to do. - var allTypeArguments = symbol.GetAllTypeArguments().ToList(); - if (allTypeArguments.Count == 0) + var allTypeArguments = symbol.GetAllTypeArguments(); + if (allTypeArguments.Length == 0) { return symbol; } @@ -89,7 +89,7 @@ public override ITypeSymbol VisitNamedType(INamedTypeSymbol symbol) return symbol; } - return _typeGenerator.Construct(symbol.OriginalDefinition, substitutedArguments.ToArray()).WithNullableAnnotation(symbol.NullableAnnotation); + return _typeGenerator.Construct(symbol.OriginalDefinition, [.. substitutedArguments]).WithNullableAnnotation(symbol.NullableAnnotation); } public override ITypeSymbol VisitArrayType(IArrayTypeSymbol symbol) diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/ITypeSymbolExtensions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/ITypeSymbolExtensions.cs index 1de694e2114dc..dfa471e44ec1e 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/ITypeSymbolExtensions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/ITypeSymbolExtensions.cs @@ -447,17 +447,17 @@ public static ImmutableArray GetAccessibleMembersInThisAndBaseTypes(this I return []; } - return containingType.GetBaseTypesAndThis().SelectAccessibleMembers(within).ToImmutableArray(); + return [.. containingType.GetBaseTypesAndThis().SelectAccessibleMembers(within)]; } public static ImmutableArray GetAccessibleMembersInThisAndBaseTypes(this ITypeSymbol? containingType, string memberName, ISymbol within) where T : class, ISymbol { if (containingType == null) { - return ImmutableArray.Empty; + return []; } - return containingType.GetBaseTypesAndThis().SelectAccessibleMembers(memberName, within).ToImmutableArray(); + return [.. containingType.GetBaseTypesAndThis().SelectAccessibleMembers(memberName, within)]; } public static bool? AreMoreSpecificThan(this IList t1, IList t2) @@ -588,8 +588,8 @@ private static IEnumerable SelectAccessibleMembers(this IEnumerable TakeAsArray(this ImmutableArray array, int public static ImmutableArray ToImmutableAndClear(this ImmutableArray.Builder builder) { if (builder.Count == 0) - return ImmutableArray.Empty; + return []; if (builder.Count == builder.Capacity) return builder.MoveToImmutable(); diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/SemanticEquivalence.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/SemanticEquivalence.cs index 3b65858127df7..b9805bdfe3e96 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/SemanticEquivalence.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/SemanticEquivalence.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System; using System.Collections.Generic; using Microsoft.CodeAnalysis.Operations; @@ -20,9 +18,9 @@ public static bool AreEquivalent(SemanticModel semanticModel, SyntaxNode node1, public static bool AreEquivalent( SemanticModel semanticModel1, SemanticModel semanticModel2, - SyntaxNode node1, - SyntaxNode node2, - Func predicate = null) + SyntaxNode? node1, + SyntaxNode? node2, + Func? predicate = null) { // First check for syntactic equivalency. If two nodes aren't structurally equivalent, // then they're not semantically equivalent. @@ -52,7 +50,7 @@ private static bool AreSemanticallyEquivalentWorker( SemanticModel semanticModel2, SyntaxNode node1, SyntaxNode node2, - Func predicate) + Func? predicate) { if (node1 == node2) { @@ -115,9 +113,9 @@ private static bool AreSemanticallyEquivalentWorker( var c1 = e1.Current; var c2 = e2.Current; - if (c1.IsNode && c2.IsNode) + if (c1.AsNode(out var c1Node) && c2.AsNode(out var c2Node)) { - if (!AreSemanticallyEquivalentWorker(semanticModel1, semanticModel2, c1.AsNode(), c2.AsNode(), predicate)) + if (!AreSemanticallyEquivalentWorker(semanticModel1, semanticModel2, c1Node, c2Node, predicate)) { return false; } @@ -134,13 +132,8 @@ private static bool AreEquals( SymbolInfo info1, SymbolInfo info2) { - if (semanticModel1 == semanticModel2) - { - return EqualityComparer.Default.Equals(info1.Symbol, info2.Symbol); - } - else - { - return SymbolEquivalenceComparer.Instance.Equals(info1.Symbol, info2.Symbol); - } + return semanticModel1 == semanticModel2 + ? EqualityComparer.Default.Equals(info1.Symbol, info2.Symbol) + : SymbolEquivalenceComparer.Instance.Equals(info1.Symbol, info2.Symbol); } } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/SemanticModelExtensions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/SemanticModelExtensions.cs index 22d9ed8f0b157..e56f7b96c179f 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/SemanticModelExtensions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/SemanticModelExtensions.cs @@ -91,7 +91,7 @@ public static ISymbol GetEnclosingNamedTypeOrAssembly(this SemanticModel semanti => semanticModel.GetEnclosingSymbol(position, cancellationToken); public static IEnumerable GetExistingSymbols( - this SemanticModel semanticModel, SyntaxNode? container, CancellationToken cancellationToken, Func? descendInto = null) + this SemanticModel semanticModel, SyntaxNode? container, CancellationToken cancellationToken, Func? descendInto = null) { // Ignore an anonymous type property or tuple field. It's ok if they have a name that // matches the name of the local we're introducing. diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/SymbolInfoExtensions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/SymbolInfoExtensions.cs index fdec7e9dd2999..f0ee4c3271d18 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/SymbolInfoExtensions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/SymbolInfoExtensions.cs @@ -24,7 +24,7 @@ private static ImmutableArray GetAllSymbolsWorker(this SymbolInfo info) public static ImmutableArray GetBestOrAllSymbols(this SymbolInfo info) { if (info.Symbol != null) - return ImmutableArray.Create(info.Symbol); + return [info.Symbol]; if (info.CandidateSymbols.Contains(null!)) { diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/SyntaxNodeExtensions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/SyntaxNodeExtensions.cs index 09f7c90cb9d45..8f10729a22ed1 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/SyntaxNodeExtensions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/SyntaxNodeExtensions.cs @@ -940,6 +940,57 @@ void FinishIf(TDirectiveTriviaSyntax? directive) } } + public static SyntaxTriviaList GetLeadingTriviaIncludingMissingTokens(this SyntaxNode node) + { + var triviaList = new SyntaxTriviaList(); + foreach (var token in node.DescendantTokens()) + { + triviaList = triviaList.AddRange(token.LeadingTrivia); + + if (!token.IsMissing) + break; + + triviaList = triviaList.AddRange(token.TrailingTrivia); + } + + return triviaList; + } + + public static SyntaxTriviaList GetTrailingTriviaIncludingMissingTokens(this SyntaxNode node) + { + var triviaList = new SyntaxTriviaList(); + var fullSpan = node.FullSpan; + var current = node.GetLastToken(includeZeroWidth: true); + while (fullSpan.Contains(current.Span)) + { + triviaList = triviaList.InsertRange(0, current.TrailingTrivia); + + if (!current.IsMissing) + break; + + triviaList = triviaList.InsertRange(0, current.LeadingTrivia); + current = current.GetPreviousToken(includeZeroWidth: true); + } + + return triviaList; + } + + public static SyntaxNode WithLeadingTriviaFromIncludingMissingTokens(this SyntaxNode node, SyntaxNode other) + { + return node.WithLeadingTrivia(other.GetLeadingTriviaIncludingMissingTokens()); + } + + public static SyntaxNode WithTrailingTriviaFromIncludingMissingTokens(this SyntaxNode node, SyntaxNode other) + { + return node.WithTrailingTrivia(other.GetTrailingTriviaIncludingMissingTokens()); + } + + public static SyntaxNode WithTriviaFromIncludingMissingTokens(this SyntaxNode node, SyntaxNode other) + { + return node.WithLeadingTriviaFromIncludingMissingTokens(other) + .WithTrailingTriviaFromIncludingMissingTokens(other); + } + /// /// Gets a list of ancestor nodes (including this node) /// diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/SyntaxNodeOrTokenExtensions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/SyntaxNodeOrTokenExtensions.cs index bf41872059309..eb1143e57e489 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/SyntaxNodeOrTokenExtensions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/SyntaxNodeOrTokenExtensions.cs @@ -51,7 +51,7 @@ public static IEnumerable DepthFirstTraversalNodes(this SyntaxNodeOr } public static SyntaxTrivia[] GetTrivia(params SyntaxNodeOrToken[] nodesOrTokens) - => nodesOrTokens.SelectMany(nodeOrToken => nodeOrToken.GetLeadingTrivia().Concat(nodeOrToken.GetTrailingTrivia())).ToArray(); + => [.. nodesOrTokens.SelectMany(nodeOrToken => nodeOrToken.GetLeadingTrivia().Concat(nodeOrToken.GetTrailingTrivia()))]; public static SyntaxNodeOrToken WithAppendedTrailingTrivia(this SyntaxNodeOrToken nodeOrToken, params SyntaxTrivia[] trivia) => WithAppendedTrailingTrivia(nodeOrToken, (IEnumerable)trivia); diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/SyntaxTokenExtensions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/SyntaxTokenExtensions.cs index 3452fa0214efe..0408f09cefafa 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/SyntaxTokenExtensions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/SyntaxTokenExtensions.cs @@ -36,19 +36,8 @@ public static IEnumerable GetAncestors(this SyntaxToken token, Func< : []; } - public static SyntaxNode? GetCommonRoot(this SyntaxToken token1, SyntaxToken token2) - { - Contract.ThrowIfTrue(token1.RawKind == 0 || token2.RawKind == 0); - - // find common starting node from two tokens. - // as long as two tokens belong to same tree, there must be at least on common root (Ex, compilation unit) - if (token1.Parent == null || token2.Parent == null) - { - return null; - } - - return token1.Parent.GetCommonRoot(token2.Parent); - } + public static SyntaxNode GetCommonRoot(this SyntaxToken token1, SyntaxToken token2) + => token1.GetRequiredParent().GetCommonRoot(token2.GetRequiredParent()); public static bool CheckParent(this SyntaxToken token, Func valueChecker) where T : SyntaxNode { @@ -159,7 +148,7 @@ public static SyntaxToken WithAppendedTrailingTrivia( } public static SyntaxTrivia[] GetTrivia(this IEnumerable tokens) - => tokens.SelectMany(token => SyntaxNodeOrTokenExtensions.GetTrivia(token)).ToArray(); + => [.. tokens.SelectMany(token => SyntaxNodeOrTokenExtensions.GetTrivia(token))]; public static SyntaxNode GetRequiredParent(this SyntaxToken token) => token.Parent ?? throw new InvalidOperationException("Token's parent was null"); diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/SyntaxTreeExtensions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/SyntaxTreeExtensions.cs index ef3bff26d9394..77d4b1e1d214c 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/SyntaxTreeExtensions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/SyntaxTreeExtensions.cs @@ -47,7 +47,7 @@ public static Task GetTouchingWordAsync( CancellationToken cancellationToken, bool findInsideTrivia = false) { - return GetTouchingTokenAsync(syntaxTree, position, syntaxFacts.IsWord, cancellationToken, findInsideTrivia); + return GetTouchingTokenAsync(syntaxTree, semanticModel: null, position, (_, t) => syntaxFacts.IsWord(t), cancellationToken, findInsideTrivia); } public static Task GetTouchingTokenAsync( @@ -56,13 +56,14 @@ public static Task GetTouchingTokenAsync( CancellationToken cancellationToken, bool findInsideTrivia = false) { - return GetTouchingTokenAsync(syntaxTree, position, _ => true, cancellationToken, findInsideTrivia); + return GetTouchingTokenAsync(syntaxTree, semanticModel: null, position, (_, _) => true, cancellationToken, findInsideTrivia); } public static async Task GetTouchingTokenAsync( this SyntaxTree syntaxTree, + SemanticModel? semanticModel, int position, - Predicate predicate, + Func predicate, CancellationToken cancellationToken, bool findInsideTrivia = false) { @@ -76,14 +77,14 @@ public static async Task GetTouchingTokenAsync( var root = await syntaxTree.GetRootAsync(cancellationToken).ConfigureAwait(false); var token = root.FindToken(position, findInsideTrivia); - if ((token.Span.Contains(position) || token.Span.End == position) && predicate(token)) + if ((token.Span.Contains(position) || token.Span.End == position) && predicate(semanticModel, token)) { return token; } token = token.GetPreviousToken(); - if (token.Span.End == position && predicate(token)) + if (token.Span.End == position && predicate(semanticModel, token)) { return token; } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/TextSpanExtensions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/TextSpanExtensions.cs index f787fa6345d4b..24f692335761d 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/TextSpanExtensions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/TextSpanExtensions.cs @@ -19,7 +19,7 @@ public static IEnumerable ToNormalizedSpans(this IEnumerable => new NormalizedTextSpanCollection(spans); public static ImmutableArray ToNormalizedSpans(this ImmutableArray spans) - => new NormalizedTextSpanCollection(spans).ToImmutableArray(); + => [.. spans]; public static TextSpan Collapse(this IEnumerable spans) { diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Engine/TokenStream.Changes.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Engine/TokenStream.Changes.cs index fd7544dfefa3e..2e40bc0df4da3 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Engine/TokenStream.Changes.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Engine/TokenStream.Changes.cs @@ -36,9 +36,7 @@ public void AddOrReplace(int key, TriviaData triviaInfo) public readonly bool TryGet(int key, [NotNullWhen(true)] out TriviaData? triviaInfo) { triviaInfo = null; -#pragma warning disable CS8762 // Parameter may not have a null value when exiting in some condition. https://github.com/dotnet/roslyn/issues/43241 return _map?.TryGetValue(key, out triviaInfo) ?? false; -#pragma warning restore CS8762 // Parameter may not have a null value when exiting in some condition. } } } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/FormattingOptions2.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/FormattingOptions2.cs index 42ab66ec74a49..94cb4ad8f07b7 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/FormattingOptions2.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/FormattingOptions2.cs @@ -107,6 +107,6 @@ internal sealed partial class FormattingOptions2 internal static class FormattingOptionGroups { public static readonly OptionGroup FormattingOptionGroup = new(name: "formatting", description: "", parent: CodeStyleOptionGroups.CodeStyle); - public static readonly OptionGroup IndentationAndSpacing = new(name: "indentation_and_spacing", description: WorkspacesResources.Indentation_and_spacing, priority: 1, parent: FormattingOptionGroup); - public static readonly OptionGroup NewLine = new(name: "new_line", description: WorkspacesResources.New_line_preferences, priority: 2, parent: FormattingOptionGroup); + public static readonly OptionGroup IndentationAndSpacing = new(name: "indentation_and_spacing", description: CompilerExtensionsResources.Indentation_and_spacing, priority: 1, parent: FormattingOptionGroup); + public static readonly OptionGroup NewLine = new(name: "new_line", description: CompilerExtensionsResources.New_line_preferences, priority: 2, parent: FormattingOptionGroup); } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/TriviaEngine/AbstractTriviaFormatter.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/TriviaEngine/AbstractTriviaFormatter.cs index d1723001a4b91..b99da34f0b4c1 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/TriviaEngine/AbstractTriviaFormatter.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/TriviaEngine/AbstractTriviaFormatter.cs @@ -247,14 +247,14 @@ public SyntaxTriviaList FormatToSyntaxTrivia(CancellationToken cancellationToken if (Succeeded()) { - return new SyntaxTriviaList(triviaList); + return [.. triviaList]; } triviaList.Clear(); AddRange(triviaList, this.Token1.TrailingTrivia); AddRange(triviaList, this.Token2.LeadingTrivia); - return new SyntaxTriviaList(triviaList); + return [.. triviaList]; } private static void AddRange(ArrayBuilder result, SyntaxTriviaList triviaList) diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/TriviaEngine/TriviaHelpers.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/TriviaEngine/TriviaHelpers.cs index 8bd826381c892..04fc913710333 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/TriviaEngine/TriviaHelpers.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/TriviaEngine/TriviaHelpers.cs @@ -20,6 +20,6 @@ public static SyntaxTriviaList CreateTriviaListFromTo(SyntaxTriviaList triviaLis for (var i = startIndex; i <= endIndex; i++) builder.Add(triviaList[i]); - return new SyntaxTriviaList(builder); + return [.. builder]; } } diff --git a/src/Features/Core/Portable/Shared/Naming/IdentifierNameParts.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/NamingStyles/Naming/IdentifierNameParts.cs similarity index 94% rename from src/Features/Core/Portable/Shared/Naming/IdentifierNameParts.cs rename to src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/NamingStyles/Naming/IdentifierNameParts.cs index 1c875cd1ed625..3faa922906d29 100644 --- a/src/Features/Core/Portable/Shared/Naming/IdentifierNameParts.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/NamingStyles/Naming/IdentifierNameParts.cs @@ -22,6 +22,11 @@ public static IdentifierNameParts CreateIdentifierNameParts(ISymbol symbol, Immu { var baseName = RemovePrefixesAndSuffixes(symbol, rules, symbol.Name); + return CreateIdentifierNameParts(baseName); + } + + public static IdentifierNameParts CreateIdentifierNameParts(string baseName) + { using var parts = TemporaryArray.Empty; StringBreaker.AddWordParts(baseName, ref parts.AsRef()); var words = CreateWords(parts, baseName); diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/NamingStyles/Serialization/NamingStylePreferences.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/NamingStyles/Serialization/NamingStylePreferences.cs index af5720dbb4839..97a9950851493 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/NamingStyles/Serialization/NamingStylePreferences.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/NamingStyles/Serialization/NamingStylePreferences.cs @@ -314,7 +314,7 @@ internal SymbolSpecification GetSymbolSpecification(Guid symbolSpecificationID) public NamingStyleRules Rules => _lazyRules.Value; public NamingStyleRules CreateRules() - => new(NamingRules.Select(r => r.GetRule(this)).ToImmutableArray()); + => new([.. NamingRules.Select(r => r.GetRule(this))]); internal XElement CreateXElement() { @@ -330,12 +330,9 @@ internal static NamingStylePreferences FromXElement(XElement element) element = GetUpgradedSerializationIfNecessary(element); return new NamingStylePreferences( - element.Element("SymbolSpecifications").Elements(nameof(SymbolSpecification)) - .Select(SymbolSpecification.FromXElement).ToImmutableArray(), - element.Element("NamingStyles").Elements(nameof(NamingStyle)) - .Select(NamingStyle.FromXElement).ToImmutableArray(), - element.Element("NamingRules").Elements(nameof(SerializableNamingRule)) - .Select(SerializableNamingRule.FromXElement).ToImmutableArray()); + [.. element.Element("SymbolSpecifications").Elements(nameof(SymbolSpecification)).Select(SymbolSpecification.FromXElement)], + [.. element.Element("NamingStyles").Elements(nameof(NamingStyle)).Select(NamingStyle.FromXElement)], + [.. element.Element("NamingRules").Elements(nameof(SerializableNamingRule)).Select(SerializableNamingRule.FromXElement)]); } public override bool Equals(object obj) diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/NamingStyles/Serialization/NamingStylePreferencesEditorConfigSerializer.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/NamingStyles/Serialization/NamingStylePreferencesEditorConfigSerializer.cs index 6b6d3349e001c..0789208458138 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/NamingStyles/Serialization/NamingStylePreferencesEditorConfigSerializer.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/NamingStyles/Serialization/NamingStylePreferencesEditorConfigSerializer.cs @@ -152,7 +152,7 @@ private static ImmutableDictionary AssignNamesToNamingStyleElement static string ToSnakeCaseName(string name) { - return new string(name + return new string([.. name .Select(ch => { if (char.IsLetterOrDigit(ch)) @@ -163,8 +163,7 @@ static string ToSnakeCaseName(string name) { return '_'; } - }) - .ToArray()); + })]); } } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/OptionKey2.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/OptionKey2.cs index aa1da0eed5a0d..b2eaabcd75f7c 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/OptionKey2.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/OptionKey2.cs @@ -31,7 +31,7 @@ public OptionKey2(IPerLanguageValuedOption option, string language) Debug.Assert(option.IsPerLanguage); if (language == null) { - throw new ArgumentNullException(WorkspacesResources.A_language_name_must_be_specified_for_this_option); + throw new ArgumentNullException(CompilerExtensionsResources.A_language_name_must_be_specified_for_this_option); } this.Option = option ?? throw new ArgumentNullException(nameof(option)); diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Serialization/ObjectWriter.WriterReferenceMap.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Serialization/ObjectWriter.WriterReferenceMap.cs index d0a4b2a77fbb0..7a93830163835 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Serialization/ObjectWriter.WriterReferenceMap.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Serialization/ObjectWriter.WriterReferenceMap.cs @@ -42,6 +42,12 @@ public readonly void Dispose() } } + public void Reset() + { + _valueToIdMap.Clear(); + _nextId = 0; + } + public bool TryGetReferenceId(string value, out int referenceId) => _valueToIdMap.TryGetValue(value, out referenceId); diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Serialization/ObjectWriter.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Serialization/ObjectWriter.cs index 93ba501d46f77..31e1adb719e71 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Serialization/ObjectWriter.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Serialization/ObjectWriter.cs @@ -14,12 +14,6 @@ namespace Roslyn.Utilities; -#if CODE_STYLE -using Resources = CodeStyleResources; -#else -using Resources = WorkspacesResources; -#endif - /// /// An that serializes objects to a byte stream. /// @@ -135,6 +129,28 @@ public void Dispose() public void WriteUInt16(ushort value) => _writer.Write(value); public void WriteString(string? value) => WriteStringValue(value); + public Stream BaseStream => _writer.BaseStream; + + public void Reset() + { + _stringReferenceMap.Reset(); + + // Reset the position and length back to zero + _writer.BaseStream.Position = 0; + + if (_writer.BaseStream is SerializableBytes.ReadWriteStream pooledStream) + { + // ReadWriteStream.SetLength allows us to indicate to not truncate, allowing + // reuse of the backing arrays. + pooledStream.SetLength(0, truncate: false); + } + else + { + // Otherwise, set the new length via the standard Stream.SetLength + _writer.BaseStream.SetLength(0); + } + } + /// /// Used so we can easily grab the low/high 64bits of a guid for serialization. /// @@ -435,7 +451,7 @@ internal void WriteCompressedUInt(uint value) } else { - throw new ArgumentException(Resources.Value_too_large_to_be_represented_as_a_30_bit_unsigned_integer); + throw new ArgumentException(CompilerExtensionsResources.Value_too_large_to_be_represented_as_a_30_bit_unsigned_integer); } } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Services/BlockFacts/AbstractBlockFacts.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Services/BlockFacts/AbstractBlockFacts.cs index 984af0b6d29c3..0c6f116d633bb 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Services/BlockFacts/AbstractBlockFacts.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Services/BlockFacts/AbstractBlockFacts.cs @@ -7,12 +7,25 @@ namespace Microsoft.CodeAnalysis.LanguageService; -internal abstract class AbstractBlockFacts : IBlockFacts +internal abstract class AbstractBlockFacts : IBlockFacts + where TStatementSyntax : SyntaxNode { public abstract bool IsScopeBlock([NotNullWhen(true)] SyntaxNode? node); public abstract bool IsExecutableBlock([NotNullWhen(true)] SyntaxNode? node); - public abstract IReadOnlyList GetExecutableBlockStatements(SyntaxNode? node); + + public abstract SyntaxNode? GetImmediateParentExecutableBlockForStatement(TStatementSyntax statement); + + public abstract IReadOnlyList GetExecutableBlockStatements(SyntaxNode? node); public abstract SyntaxNode? FindInnermostCommonExecutableBlock(IEnumerable nodes); public abstract bool IsStatementContainer([NotNullWhen(true)] SyntaxNode? node); - public abstract IReadOnlyList GetStatementContainerStatements(SyntaxNode? node); + public abstract IReadOnlyList GetStatementContainerStatements(SyntaxNode? node); + + SyntaxNode? IBlockFacts.GetImmediateParentExecutableBlockForStatement(SyntaxNode statement) + => GetImmediateParentExecutableBlockForStatement((TStatementSyntax)statement); + + IReadOnlyList IBlockFacts.GetExecutableBlockStatements(SyntaxNode? node) + => GetExecutableBlockStatements(node); + + IReadOnlyList IBlockFacts.GetStatementContainerStatements(SyntaxNode? node) + => GetStatementContainerStatements(node); } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Services/BlockFacts/IBlockFacts.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Services/BlockFacts/IBlockFacts.cs index 7b90758592f7f..dc4fd5c125299 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Services/BlockFacts/IBlockFacts.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Services/BlockFacts/IBlockFacts.cs @@ -22,8 +22,17 @@ internal interface IBlockFacts bool IsScopeBlock([NotNullWhen(true)] SyntaxNode? node); /// - /// A node that contains a list of statements. In C#, this is BlockSyntax and SwitchSectionSyntax. In VB, this - /// includes all block statements such as a MultiLineIfBlockSyntax. + /// Gets the directly parenting block for the statement if it has one. For C#, this is the direct parent + /// BlockSyntax, SwitchSectionSyntax, or CompilationUnit if the statement is parented by a GlobalStatementSyntax. + /// This returns for any other cases (like an embedded statement). + /// + /// If this returns a parent value then the will always be found within the + /// statements returned by on that value + SyntaxNode? GetImmediateParentExecutableBlockForStatement(SyntaxNode statement); + + /// + /// A node that contains a list of statements. In C#, this is BlockSyntax, SwitchSectionSyntax and + /// CompilationUnitSyntax. In VB, this includes all block statements such as a MultiLineIfBlockSyntax. /// bool IsExecutableBlock([NotNullWhen(true)] SyntaxNode? node); diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Services/FileBannerFacts/AbstractFileBannerFacts.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Services/FileBannerFacts/AbstractFileBannerFacts.cs index 4bf5a87ee261d..422832c267aac 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Services/FileBannerFacts/AbstractFileBannerFacts.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Services/FileBannerFacts/AbstractFileBannerFacts.cs @@ -58,6 +58,8 @@ protected AbstractFileBannerFacts() protected abstract ISyntaxFacts SyntaxFacts { get; } protected abstract IDocumentationCommentService DocumentationCommentService { get; } + public abstract SyntaxTrivia CreateTrivia(SyntaxTrivia trivia, string text); + public string GetBannerText(SyntaxNode? documentationCommentTriviaSyntax, int bannerLength, CancellationToken cancellationToken) => DocumentationCommentService.GetBannerText(documentationCommentTriviaSyntax, bannerLength, cancellationToken); @@ -86,7 +88,7 @@ public TSyntaxNode GetNodeWithoutLeadingBlankLines( var index = 0; _oneOrMoreBlankLines.TryMatch(leadingTriviaToKeep, ref index); - strippedTrivia = leadingTriviaToKeep.Take(index).ToImmutableArray(); + strippedTrivia = [.. leadingTriviaToKeep.Take(index)]; return node.WithLeadingTrivia(leadingTriviaToKeep.Skip(index)); } @@ -135,12 +137,12 @@ public TSyntaxNode GetNodeWithoutLeadingBannerAndPreprocessorDirectives(leadingTrivia.Take(ppIndex + 1)); - leadingTriviaToKeep = new List(leadingTrivia.Skip(ppIndex + 1)); + leadingTriviaToStrip = [.. leadingTrivia.Take(ppIndex + 1)]; + leadingTriviaToKeep = [.. leadingTrivia.Skip(ppIndex + 1)]; } else { - leadingTriviaToKeep = new List(leadingTrivia); + leadingTriviaToKeep = [.. leadingTrivia]; leadingTriviaToStrip = []; } @@ -173,8 +175,8 @@ public ImmutableArray GetFileBanner(SyntaxToken firstToken) var leadingTrivia = firstToken.LeadingTrivia; var index = 0; - _fileBannerMatcher.TryMatch(leadingTrivia.ToList(), ref index); + _fileBannerMatcher.TryMatch([.. leadingTrivia], ref index); - return ImmutableArray.CreateRange(leadingTrivia.Take(index)); + return [.. leadingTrivia.Take(index)]; } } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Services/FileBannerFacts/IFileBannerFacts.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Services/FileBannerFacts/IFileBannerFacts.cs index 7e40d0aca3c52..e680971ab5302 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Services/FileBannerFacts/IFileBannerFacts.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Services/FileBannerFacts/IFileBannerFacts.cs @@ -9,6 +9,8 @@ namespace Microsoft.CodeAnalysis.LanguageService; internal interface IFileBannerFacts { + SyntaxTrivia CreateTrivia(SyntaxTrivia trivia, string text); + ImmutableArray GetFileBanner(SyntaxNode root); ImmutableArray GetFileBanner(SyntaxToken firstToken); string GetBannerText(SyntaxNode? documentationCommentTriviaSyntax, int maxBannerLength, CancellationToken cancellationToken); diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Services/FileBannerFacts/IFileBannerFactsExtensions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Services/FileBannerFacts/IFileBannerFactsExtensions.cs index e79d305bd33dc..704cf52832804 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Services/FileBannerFacts/IFileBannerFactsExtensions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Services/FileBannerFacts/IFileBannerFactsExtensions.cs @@ -13,6 +13,6 @@ public static ImmutableArray GetTriviaAfterLeadingBlankLines( this IFileBannerFacts bannerService, SyntaxNode node) { var leadingBlankLines = bannerService.GetLeadingBlankLines(node); - return node.GetLeadingTrivia().Skip(leadingBlankLines.Length).ToImmutableArray(); + return [.. node.GetLeadingTrivia().Skip(leadingBlankLines.Length)]; } } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Services/SyntaxFacts/ISyntaxFacts.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Services/SyntaxFacts/ISyntaxFacts.cs index d4b01afb7e636..511e68649d0fe 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Services/SyntaxFacts/ISyntaxFacts.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Services/SyntaxFacts/ISyntaxFacts.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; +using System.Collections.Immutable; using System.Diagnostics.CodeAnalysis; using System.Threading; using Microsoft.CodeAnalysis.Text; @@ -101,6 +102,7 @@ internal interface ISyntaxFacts bool SupportsConstantInterpolatedStrings(ParseOptions options); bool SupportsTupleDeconstruction(ParseOptions options); bool SupportsCollectionExpressionNaturalType(ParseOptions options); + bool SupportsImplicitImplementationOfNonPublicInterfaceMembers(ParseOptions options); SyntaxToken ParseToken(string text); SyntaxTriviaList ParseLeadingTrivia(string text); @@ -178,6 +180,8 @@ internal interface ISyntaxFacts bool IsPragmaDirective(SyntaxTrivia trivia, out bool isDisable, out bool isActive, out SeparatedSyntaxList errorCodes); bool IsPreprocessorDirective(SyntaxTrivia trivia); + SyntaxNode? GetMatchingDirective(SyntaxNode directive, CancellationToken cancellationToken); + ImmutableArray GetMatchingConditionalDirectives(SyntaxNode directive, CancellationToken cancellationToken); bool IsDocumentationComment(SyntaxNode node); @@ -332,10 +336,10 @@ void GetPartsOfTupleExpression(SyntaxNode node, bool IsExecutableStatement([NotNullWhen(true)] SyntaxNode? node); bool IsGlobalStatement([NotNullWhen(true)] SyntaxNode? node); SyntaxNode GetStatementOfGlobalStatement(SyntaxNode node); - bool AreStatementsInSameContainer(SyntaxNode firstStatement, SyntaxNode secondStatement); bool IsDeconstructionAssignment([NotNullWhen(true)] SyntaxNode? node); bool IsDeconstructionForEachStatement([NotNullWhen(true)] SyntaxNode? node); + bool IsUsingLocalDeclarationStatement(SyntaxNode node); /// /// Returns true for nodes that represent the body of a method. @@ -375,7 +379,7 @@ void GetPartsOfTupleExpression(SyntaxNode node, bool IsTypeCharacter(char c); // Violation. This is a feature level API for QuickInfo. - bool IsBindableToken(SyntaxToken token); + bool IsBindableToken(SemanticModel? semanticModel, SyntaxToken token); bool IsInStaticContext(SyntaxNode node); bool IsUnsafeContext(SyntaxNode node); @@ -508,6 +512,7 @@ void GetPartsOfTupleExpression(SyntaxNode node, #region GetPartsOfXXX members + void GetPartsOfAliasQualifiedName(SyntaxNode node, out SyntaxNode alias, out SyntaxToken colonColonToken, out SyntaxNode name); void GetPartsOfAnyIsTypeExpression(SyntaxNode node, out SyntaxNode expression, out SyntaxNode type); void GetPartsOfArgumentList(SyntaxNode node, out SyntaxToken openParenToken, out SeparatedSyntaxList arguments, out SyntaxToken closeParenToken); void GetPartsOfAttribute(SyntaxNode node, out SyntaxNode name, out SyntaxNode? argumentList); diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Services/SyntaxFacts/ISyntaxFactsExtensions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Services/SyntaxFacts/ISyntaxFactsExtensions.cs index ee3b94171b050..7c00e010eb54a 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Services/SyntaxFacts/ISyntaxFactsExtensions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Services/SyntaxFacts/ISyntaxFactsExtensions.cs @@ -655,6 +655,16 @@ public static bool IsRightOfQualifiedName(this ISyntaxFacts syntaxFacts, [NotNul return node == right; } + public static bool IsRightOfAliasQualifiedName(this ISyntaxFacts syntaxFacts, [NotNullWhen(true)] SyntaxNode? node) + { + var parent = node?.Parent; + if (!syntaxFacts.IsAliasQualifiedName(parent)) + return false; + + syntaxFacts.GetPartsOfAliasQualifiedName(parent, out _, out _, out var right); + return node == right; + } + public static bool IsTypeOfObjectCreationExpression(this ISyntaxFacts syntaxFacts, [NotNullWhen(true)] SyntaxNode? node) { var parent = node?.Parent; @@ -732,6 +742,9 @@ public static bool IsInterpolatedStringTextToken(this ISyntaxFacts syntaxFacts, #region names + public static bool IsAliasQualifiedName(this ISyntaxFacts syntaxFacts, [NotNullWhen(true)] SyntaxNode? node) + => node?.RawKind == syntaxFacts.SyntaxKinds.AliasQualifiedName; + public static bool IsGenericName(this ISyntaxFacts syntaxFacts, [NotNullWhen(true)] SyntaxNode? node) => node?.RawKind == syntaxFacts.SyntaxKinds.GenericName; @@ -792,6 +805,9 @@ public static bool IsConditionalExpression(this ISyntaxFacts syntaxFacts, [NotNu public static bool IsConditionalAccessExpression(this ISyntaxFacts syntaxFacts, [NotNullWhen(true)] SyntaxNode? node) => node?.RawKind == syntaxFacts.SyntaxKinds.ConditionalAccessExpression; + public static bool IsFieldExpression(this ISyntaxFacts syntaxFacts, [NotNullWhen(true)] SyntaxNode? node) + => node?.RawKind == syntaxFacts.SyntaxKinds.FieldExpression; + public static bool IsImplicitArrayCreationExpression(this ISyntaxFacts syntaxFacts, [NotNullWhen(true)] SyntaxNode? node) => node?.RawKind == syntaxFacts.SyntaxKinds.ImplicitArrayCreationExpression; @@ -1000,6 +1016,9 @@ public static bool IsImplicitElementAccess(this ISyntaxFacts syntaxFacts, [NotNu public static bool IsIndexerMemberCref(this ISyntaxFacts syntaxFacts, [NotNullWhen(true)] SyntaxNode? node) => node?.RawKind == syntaxFacts.SyntaxKinds.IndexerMemberCref; + public static bool IsPrimaryConstructorBaseType(this ISyntaxFacts syntaxFacts, [NotNullWhen(true)] SyntaxNode? node) + => node?.RawKind == syntaxFacts.SyntaxKinds.PrimaryConstructorBaseType; + #endregion #endregion diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Services/SyntaxFacts/ISyntaxKinds.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Services/SyntaxFacts/ISyntaxKinds.cs index 432397875f90d..72a9316a37c15 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Services/SyntaxFacts/ISyntaxKinds.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Services/SyntaxFacts/ISyntaxKinds.cs @@ -103,6 +103,7 @@ internal interface ISyntaxKinds #region names + int? AliasQualifiedName { get; } int GenericName { get; } int IdentifierName { get; } int QualifiedName { get; } @@ -138,6 +139,7 @@ internal interface ISyntaxKinds int CollectionInitializerExpression { get; } int ConditionalAccessExpression { get; } int ConditionalExpression { get; } + int? FieldExpression { get; } int? ImplicitArrayCreationExpression { get; } int? ImplicitObjectCreationExpression { get; } int? IndexExpression { get; } @@ -156,6 +158,7 @@ internal interface ISyntaxKinds int? RefExpression { get; } int ReferenceEqualsExpression { get; } int ReferenceNotEqualsExpression { get; } + int SimpleAssignmentExpression { get; } int SimpleMemberAccessExpression { get; } int? SuppressNullableWarningExpression { get; } int TernaryConditionalExpression { get; } @@ -231,6 +234,7 @@ internal interface ISyntaxKinds int Interpolation { get; } int InterpolatedStringText { get; } int? IndexerMemberCref { get; } + int? PrimaryConstructorBaseType { get; } #endregion } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Simplification/SymbolAnnotation.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Simplification/SymbolAnnotation.cs index d356e2b45a816..df28cd110d436 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Simplification/SymbolAnnotation.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Simplification/SymbolAnnotation.cs @@ -10,7 +10,7 @@ namespace Microsoft.CodeAnalysis.Simplification; /// /// An annotation that holds onto information about a type or namespace symbol. /// -internal sealed class SymbolAnnotation +internal static class SymbolAnnotation { public const string Kind = "SymbolId"; @@ -22,6 +22,6 @@ public static SyntaxAnnotation Create(ISymbol symbol) public static ImmutableArray GetSymbols(SyntaxAnnotation annotation, Compilation compilation) => annotation.Data is null - ? ImmutableArray.Empty + ? [] : DocumentationCommentId.GetSymbolsForReferenceId(annotation.Data, compilation); } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/SymbolKey/SymbolKey.AliasSymbolKey.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/SymbolKey/SymbolKey.AliasSymbolKey.cs index b1e8faec2503d..9da81289a2745 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/SymbolKey/SymbolKey.AliasSymbolKey.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/SymbolKey/SymbolKey.AliasSymbolKey.cs @@ -59,23 +59,27 @@ protected sealed override SymbolKeyResolution Resolve( SemanticModel semanticModel, SyntaxNode syntaxNode, string name, ISymbol target, CancellationToken cancellationToken) { - var symbol = semanticModel.GetDeclaredSymbol(syntaxNode, cancellationToken); - if (symbol != null) + // Don't call on the root compilation unit itself. For top level programs this will be the synthesized + // '
' entrypoint. + if (syntaxNode is not ICompilationUnitSyntax) { - if (symbol.Kind == SymbolKind.Alias) + var symbol = semanticModel.GetDeclaredSymbol(syntaxNode, cancellationToken); + if (symbol != null) { - var aliasSymbol = (IAliasSymbol)symbol; - if (aliasSymbol.Name == name && - SymbolEquivalenceComparer.Instance.Equals(aliasSymbol.Target, target)) + if (symbol is IAliasSymbol aliasSymbol) { - return new SymbolKeyResolution(aliasSymbol); + if (aliasSymbol.Name == name && + SymbolEquivalenceComparer.Instance.Equals(aliasSymbol.Target, target)) + { + return new SymbolKeyResolution(aliasSymbol); + } + } + else if (symbol.Kind != SymbolKind.Namespace) + { + // Don't recurse into anything except namespaces. We can't find aliases + // any deeper than that. + return null; } - } - else if (symbol.Kind != SymbolKind.Namespace) - { - // Don't recurse into anything except namespaces. We can't find aliases - // any deeper than that. - return null; } } @@ -85,9 +89,7 @@ protected sealed override SymbolKeyResolution Resolve( { var result = Resolve(semanticModel, childNode, name, target, cancellationToken); if (result.HasValue) - { return result; - } } } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/AnnotationTable.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/AnnotationTable.cs index affa0452d4617..ad49ecaec55fb 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/AnnotationTable.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/AnnotationTable.cs @@ -73,28 +73,28 @@ private IEnumerable GetRealAnnotations(TAnnotation[] annotatio } public TSyntaxNode WithAdditionalAnnotations(TSyntaxNode node, params TAnnotation[] annotations) where TSyntaxNode : SyntaxNode - => node.WithAdditionalAnnotations(this.GetOrCreateRealAnnotations(annotations).ToArray()); + => node.WithAdditionalAnnotations([.. this.GetOrCreateRealAnnotations(annotations)]); public SyntaxToken WithAdditionalAnnotations(SyntaxToken token, params TAnnotation[] annotations) - => token.WithAdditionalAnnotations(this.GetOrCreateRealAnnotations(annotations).ToArray()); + => token.WithAdditionalAnnotations([.. this.GetOrCreateRealAnnotations(annotations)]); public SyntaxTrivia WithAdditionalAnnotations(SyntaxTrivia trivia, params TAnnotation[] annotations) - => trivia.WithAdditionalAnnotations(this.GetOrCreateRealAnnotations(annotations).ToArray()); + => trivia.WithAdditionalAnnotations([.. this.GetOrCreateRealAnnotations(annotations)]); public SyntaxNodeOrToken WithAdditionalAnnotations(SyntaxNodeOrToken nodeOrToken, params TAnnotation[] annotations) - => nodeOrToken.WithAdditionalAnnotations(this.GetOrCreateRealAnnotations(annotations).ToArray()); + => nodeOrToken.WithAdditionalAnnotations([.. this.GetOrCreateRealAnnotations(annotations)]); public TSyntaxNode WithoutAnnotations(TSyntaxNode node, params TAnnotation[] annotations) where TSyntaxNode : SyntaxNode - => node.WithoutAnnotations(GetRealAnnotations(annotations).ToArray()); + => node.WithoutAnnotations([.. GetRealAnnotations(annotations)]); public SyntaxToken WithoutAnnotations(SyntaxToken token, params TAnnotation[] annotations) - => token.WithoutAnnotations(GetRealAnnotations(annotations).ToArray()); + => token.WithoutAnnotations([.. GetRealAnnotations(annotations)]); public SyntaxTrivia WithoutAnnotations(SyntaxTrivia trivia, params TAnnotation[] annotations) - => trivia.WithoutAnnotations(GetRealAnnotations(annotations).ToArray()); + => trivia.WithoutAnnotations([.. GetRealAnnotations(annotations)]); public SyntaxNodeOrToken WithoutAnnotations(SyntaxNodeOrToken nodeOrToken, params TAnnotation[] annotations) - => nodeOrToken.WithoutAnnotations(GetRealAnnotations(annotations).ToArray()); + => nodeOrToken.WithoutAnnotations([.. GetRealAnnotations(annotations)]); private IEnumerable GetAnnotations(IEnumerable realAnnotations) { diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/FixedSizeArrayBuilder.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/FixedSizeArrayBuilder.cs index 1a0ade6ecf363..fa5dbe2bd226d 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/FixedSizeArrayBuilder.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/FixedSizeArrayBuilder.cs @@ -106,7 +106,7 @@ public T[] MoveToArray() { Contract.ThrowIfTrue(_index != _values.Length); var result = _values; - _values = Array.Empty(); + _values = []; _index = 0; return result; } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/SerializableBytes.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/SerializableBytes.cs index 70b9041991463..4a6627fc6292b 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/SerializableBytes.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/SerializableBytes.cs @@ -272,7 +272,7 @@ public override void Write(byte[] buffer, int offset, int count) => throw new NotSupportedException(); } - private sealed class ReadStream(long length, byte[][] chunks) : PooledStream(length, new List(chunks)) + private sealed class ReadStream(long length, byte[][] chunks) : PooledStream(length, [.. chunks]) { } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/SignatureComparer.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/SignatureComparer.cs index 9de17cde3aad8..67c9b538c5f15 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/SignatureComparer.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/SignatureComparer.cs @@ -62,7 +62,7 @@ public bool HaveSameSignature(IPropertySymbol property1, IPropertySymbol propert this.ParameterEquivalenceComparer); } - private static bool BadPropertyAccessor(IMethodSymbol method1, IMethodSymbol method2) + public static bool BadPropertyAccessor(IMethodSymbol method1, IMethodSymbol method2) { return method1 != null && (method2 == null || method2.DeclaredAccessibility != Accessibility.Public); @@ -137,6 +137,21 @@ public bool HaveSameSignature( } public bool HaveSameSignatureAndConstraintsAndReturnTypeAndAccessors(ISymbol symbol1, ISymbol symbol2, bool caseSensitive) + { + // NOTE - we're deliberately using reference equality here for speed. + if (symbol1 == symbol2) + return true; + + if (!HaveSameSignatureAndConstraintsAndReturnType(symbol1, symbol2, caseSensitive)) + return false; + + if (symbol1 is IPropertySymbol property1 && symbol2 is IPropertySymbol property2) + return HaveSameAccessors(property1, property2); + + return true; + } + + public bool HaveSameSignatureAndConstraintsAndReturnType(ISymbol symbol1, ISymbol symbol2, bool caseSensitive) { // NOTE - we're deliberately using reference equality here for speed. if (symbol1 == symbol2) @@ -158,8 +173,7 @@ public bool HaveSameSignatureAndConstraintsAndReturnTypeAndAccessors(ISymbol sym return property1.ReturnsByRef == property2.ReturnsByRef && property1.ReturnsByRefReadonly == property2.ReturnsByRefReadonly && - this.SignatureTypeEquivalenceComparer.Equals(property1.Type, property2.Type) && - HaveSameAccessors(property1, property2); + this.SignatureTypeEquivalenceComparer.Equals(property1.Type, property2.Type); case SymbolKind.Event: var ev1 = (IEventSymbol)symbol1; var ev2 = (IEventSymbol)symbol2; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/TaskExtensions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/TaskExtensions.cs index 1d0e72637d447..4f6c229cbcd91 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/TaskExtensions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/TaskExtensions.cs @@ -10,7 +10,6 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.ErrorReporting; -using Microsoft.CodeAnalysis.Shared.TestHooks; namespace Roslyn.Utilities; @@ -59,270 +58,6 @@ public static T WaitAndGetResult_CanCallOnBackground(this Task task, Cance return task.Result; } - // NOTE(cyrusn): Once we switch over to .NET Framework 4.5 we can make our SafeContinueWith overloads - // simply call into task.ContinueWith(..., TaskContinuationOptions.LazyCancellation, ...) as - // that will have the semantics that we want. From the TPL guys: - // - // In this situation: -#if false - Task A = Task.Run(...); - Task B = A.ContinueWith(..., cancellationToken); - Task C = B.ContinueWith(...); -#endif - // If "cancellationToken" is signaled, B completes immediately (if it has not yet started). - // Which means that C can start before A completes, which would seem to violate the rules of - // the dependency chain. - // - // We've added TaskContinuationOptions.LazyCancellation option to signify "this continuation - // will not complete due to cancellation until its antecedent has completed". We considered - // simply changing the default underlying behavior, but rejected that idea because there was - // a good chance that existing users had already drawn a dependency on the current behavior. - - [SuppressMessage("Style", "VSTHRD200:Use \"Async\" suffix for async methods", Justification = "This is a Task wrapper, not an asynchronous method.")] - public static Task SafeContinueWith( - this Task task, - Action continuationAction, - CancellationToken cancellationToken, - TaskContinuationOptions continuationOptions, - TaskScheduler scheduler) - { - Contract.ThrowIfNull(continuationAction, nameof(continuationAction)); - - bool continuationFunction(Task antecedent) - { - continuationAction(antecedent); - return true; - } - - return task.SafeContinueWith(continuationFunction, cancellationToken, continuationOptions, scheduler); - } - - [SuppressMessage("Style", "VSTHRD200:Use \"Async\" suffix for async methods", Justification = "This is a Task wrapper, not an asynchronous method.")] - public static Task SafeContinueWith( - this Task task, - Func, TResult> continuationFunction, - CancellationToken cancellationToken, - TaskContinuationOptions continuationOptions, - TaskScheduler scheduler) - { - Contract.ThrowIfNull(continuationFunction, nameof(continuationFunction)); - - return task.SafeContinueWith( - (Task antecedent) => continuationFunction((Task)antecedent), cancellationToken, continuationOptions, scheduler); - } - - [SuppressMessage("Style", "VSTHRD200:Use \"Async\" suffix for async methods", Justification = "This is a Task wrapper, not an asynchronous method.")] - public static Task SafeContinueWith( - this Task task, - Action> continuationAction, - CancellationToken cancellationToken, - TaskContinuationOptions continuationOptions, - TaskScheduler scheduler) - { - Contract.ThrowIfNull(continuationAction, nameof(continuationAction)); - - return task.SafeContinueWith( - (Task antecedent) => continuationAction((Task)antecedent), cancellationToken, continuationOptions, scheduler); - } - - [SuppressMessage("Style", "VSTHRD200:Use \"Async\" suffix for async methods", Justification = "This is a Task wrapper, not an asynchronous method.")] - public static Task SafeContinueWith( - this Task task, - Func continuationFunction, - CancellationToken cancellationToken, - TaskContinuationOptions continuationOptions, - TaskScheduler scheduler) - { - // So here's the deal. Say you do the following: -#if false - // CancellationToken ct1 = ..., ct2 = ...; - - // Task A = Task.Factory.StartNew(..., ct1); - // Task B = A.ContinueWith(..., ct1); - // Task C = B.ContinueWith(..., ct2); -#endif - // If ct1 is cancelled then the following may occur: - // 1) Task A can still be running (as it hasn't responded to the cancellation request - // yet). - // 2) Task C can start running. How? Well if B hasn't started running, it may - // immediately transition to the 'Cancelled/Completed' state. Moving to that state will - // immediately trigger C to run. - // - // We do not want this, so we pass the LazyCancellation flag to the TPL which implements - // the behavior we want. - - Contract.ThrowIfNull(continuationFunction, nameof(continuationFunction)); - - static TResult outerFunction(Task t, object? state) - { - try - { - var continuationFunction = (Func)state!; - return continuationFunction(t); - } - catch (Exception e) when (FatalError.ReportAndPropagateUnlessCanceled(e)) - { - throw ExceptionUtilities.Unreachable(); - } - } - - // This is the only place in the code where we're allowed to call ContinueWith. - return task.ContinueWith(outerFunction, continuationFunction, cancellationToken, continuationOptions | TaskContinuationOptions.LazyCancellation, scheduler); - } - - [SuppressMessage("Style", "VSTHRD200:Use \"Async\" suffix for async methods", Justification = "This is a Task wrapper, not an asynchronous method.")] - public static Task SafeContinueWith( - this Task task, - Action continuationAction, - TaskScheduler scheduler) - { - return task.SafeContinueWith(continuationAction, CancellationToken.None, TaskContinuationOptions.None, scheduler); - } - - [SuppressMessage("Style", "VSTHRD200:Use \"Async\" suffix for async methods", Justification = "This is a Task wrapper, not an asynchronous method.")] - public static Task SafeContinueWith( - this Task task, - Action continuationAction, - CancellationToken cancellationToken, - TaskScheduler scheduler) - { - return task.SafeContinueWith(continuationAction, cancellationToken, TaskContinuationOptions.None, scheduler); - } - - public static Task SafeContinueWithFromAsync( - this Task task, - Func, Task> continuationFunction, - CancellationToken cancellationToken, - TaskContinuationOptions continuationOptions, - TaskScheduler scheduler) - { - Contract.ThrowIfNull(continuationFunction, nameof(continuationFunction)); - - return task.SafeContinueWithFromAsync( - (Task antecedent) => continuationFunction((Task)antecedent), cancellationToken, continuationOptions, scheduler); - } - - public static Task SafeContinueWithFromAsync( - this Task task, - Func> continuationFunction, - CancellationToken cancellationToken, - TaskContinuationOptions continuationOptions, - TaskScheduler scheduler) - { - // So here's the deal. Say you do the following: -#if false - // CancellationToken ct1 = ..., ct2 = ...; - - // Task A = Task.Factory.StartNew(..., ct1); - // Task B = A.ContinueWith(..., ct1); - // Task C = B.ContinueWith(..., ct2); -#endif - // If ct1 is cancelled then the following may occur: - // 1) Task A can still be running (as it hasn't responded to the cancellation request - // yet). - // 2) Task C can start running. How? Well if B hasn't started running, it may - // immediately transition to the 'Cancelled/Completed' state. Moving to that state will - // immediately trigger C to run. - // - // We do not want this, so we pass the LazyCancellation flag to the TPL which implements - // the behavior we want. - // This is the only place in the code where we're allowed to call ContinueWith. - var nextTask = task.ContinueWith(continuationFunction, cancellationToken, continuationOptions | TaskContinuationOptions.LazyCancellation, scheduler).Unwrap(); - - nextTask.ContinueWith(ReportNonFatalError, continuationFunction, - CancellationToken.None, - TaskContinuationOptions.OnlyOnFaulted | TaskContinuationOptions.ExecuteSynchronously, - TaskScheduler.Default); - - return nextTask; - } - - public static Task SafeContinueWithFromAsync( - this Task task, - Func continuationFunction, - CancellationToken cancellationToken, - TaskScheduler scheduler) - { - return task.SafeContinueWithFromAsync(continuationFunction, cancellationToken, TaskContinuationOptions.None, scheduler); - } - - public static Task SafeContinueWithFromAsync( - this Task task, - Func continuationFunction, - CancellationToken cancellationToken, - TaskContinuationOptions continuationOptions, - TaskScheduler scheduler) - { - // So here's the deal. Say you do the following: -#if false - // CancellationToken ct1 = ..., ct2 = ...; - - // Task A = Task.Factory.StartNew(..., ct1); - // Task B = A.ContinueWith(..., ct1); - // Task C = B.ContinueWith(..., ct2); -#endif - // If ct1 is cancelled then the following may occur: - // 1) Task A can still be running (as it hasn't responded to the cancellation request - // yet). - // 2) Task C can start running. How? Well if B hasn't started running, it may - // immediately transition to the 'Cancelled/Completed' state. Moving to that state will - // immediately trigger C to run. - // - // We do not want this, so we pass the LazyCancellation flag to the TPL which implements - // the behavior we want. - // This is the only place in the code where we're allowed to call ContinueWith. - var nextTask = task.ContinueWith(continuationFunction, cancellationToken, continuationOptions | TaskContinuationOptions.LazyCancellation, scheduler).Unwrap(); - ReportNonFatalError(nextTask, continuationFunction); - return nextTask; - } - - public static Task SafeContinueWithFromAsync( - this Task task, - Func, Task> continuationFunction, - CancellationToken cancellationToken, - TaskContinuationOptions continuationOptions, - TaskScheduler scheduler) - { - // So here's the deal. Say you do the following: -#if false - // CancellationToken ct1 = ..., ct2 = ...; - - // Task A = Task.Factory.StartNew(..., ct1); - // Task B = A.ContinueWith(..., ct1); - // Task C = B.ContinueWith(..., ct2); -#endif - // If ct1 is cancelled then the following may occur: - // 1) Task A can still be running (as it hasn't responded to the cancellation request - // yet). - // 2) Task C can start running. How? Well if B hasn't started running, it may - // immediately transition to the 'Cancelled/Completed' state. Moving to that state will - // immediately trigger C to run. - // - // We do not want this, so we pass the LazyCancellation flag to the TPL which implements - // the behavior we want. - // This is the only place in the code where we're allowed to call ContinueWith. - var nextTask = task.ContinueWith(continuationFunction, cancellationToken, continuationOptions | TaskContinuationOptions.LazyCancellation, scheduler).Unwrap(); - ReportNonFatalError(nextTask, continuationFunction); - return nextTask; - } - - public static Task ContinueWithAfterDelayFromAsync( - this Task task, - Func continuationFunction, - CancellationToken cancellationToken, - TimeSpan delay, - IExpeditableDelaySource delaySource, - TaskContinuationOptions taskContinuationOptions, - TaskScheduler scheduler) - { - Contract.ThrowIfNull(continuationFunction, nameof(continuationFunction)); - - return task.SafeContinueWith(t => - delaySource.Delay(delay, cancellationToken).SafeContinueWithFromAsync( - _ => continuationFunction(t), cancellationToken, TaskContinuationOptions.None, scheduler), - cancellationToken, taskContinuationOptions, scheduler).Unwrap(); - } - internal static void ReportNonFatalError(Task task, object? continuationFunction) { task.ContinueWith(ReportNonFatalErrorWorker, continuationFunction, diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/TaskFactoryExtensions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/TaskFactoryExtensions.cs deleted file mode 100644 index 42436478cb859..0000000000000 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/TaskFactoryExtensions.cs +++ /dev/null @@ -1,69 +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.CodeAnalysis; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.CodeAnalysis.ErrorReporting; - -namespace Roslyn.Utilities; - -// TODO: revisit https://github.com/dotnet/roslyn/issues/39222 - -[SuppressMessage("ApiDesign", "CA1068:CancellationToken parameters must come last", Justification = "Matching TPL Signatures")] -internal static partial class TaskFactoryExtensions -{ - [SuppressMessage("Style", "VSTHRD200:Use \"Async\" suffix for async methods", Justification = "This is a Task wrapper, not an asynchronous method.")] - public static Task SafeStartNew(this TaskFactory factory, Action action, CancellationToken cancellationToken, TaskScheduler scheduler) - { - void wrapped() - { - try - { - action(); - } - catch (Exception e) when (FatalError.ReportAndPropagateUnlessCanceled(e)) - { - throw ExceptionUtilities.Unreachable(); - } - } - - return factory.StartNew(wrapped, cancellationToken, TaskCreationOptions.None, scheduler); - } - - [SuppressMessage("Style", "VSTHRD200:Use \"Async\" suffix for async methods", Justification = "This is a Task wrapper, not an asynchronous method.")] - public static Task SafeStartNew(this TaskFactory factory, Func func, CancellationToken cancellationToken, TaskScheduler scheduler) - { - TResult wrapped() - { - try - { - return func(); - } - catch (Exception e) when (FatalError.ReportAndPropagateUnlessCanceled(e)) - { - throw ExceptionUtilities.Unreachable(); - } - } - - return factory.StartNew(wrapped, cancellationToken, TaskCreationOptions.None, scheduler); - } - - public static Task SafeStartNewFromAsync(this TaskFactory factory, Func actionAsync, CancellationToken cancellationToken, TaskScheduler scheduler) - { - // The one and only place we can call StartNew<>(). - var task = factory.StartNew(actionAsync, cancellationToken, TaskCreationOptions.None, scheduler).Unwrap(); - TaskExtensions.ReportNonFatalError(task, actionAsync); - return task; - } - - public static Task SafeStartNewFromAsync(this TaskFactory factory, Func> funcAsync, CancellationToken cancellationToken, TaskScheduler scheduler) - { - // The one and only place we can call StartNew<>(). - var task = factory.StartNew(funcAsync, cancellationToken, TaskCreationOptions.None, scheduler).Unwrap(); - TaskExtensions.ReportNonFatalError(task, funcAsync); - return task; - } -} diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/TopologicalSorter.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/TopologicalSorter.cs index b39eff256f8a9..fcc13458f68b0 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/TopologicalSorter.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/TopologicalSorter.cs @@ -56,7 +56,7 @@ private static Func> CreateCombinedItemsBefore(IEnumerable< var naturalItemsBefore = itemsBefore != null ? itemsBefore(item) : null; if (naturalItemsBefore != null) { - return naturalItemsBefore.ToList(); + return [.. naturalItemsBefore]; } else { diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/xlf/CompilerExtensionsResources.cs.xlf b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/xlf/CompilerExtensionsResources.cs.xlf index 237585e76b2b6..e0c34f269a931 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/xlf/CompilerExtensionsResources.cs.xlf +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/xlf/CompilerExtensionsResources.cs.xlf @@ -2,6 +2,16 @@ + + A language name cannot be specified for this option. + A language name cannot be specified for this option. + + + + A language name must be specified for this option. + A language name must be specified for this option. + + Absolute path expected. Očekávala se absolutní cesta. @@ -52,6 +62,11 @@ Předvolby polí + + Indentation and spacing + Indentation and spacing + + Instantiated part(s) threw exception(s) from IDisposable.Dispose(). Části v instancích vrátily výjimky z metody IDisposable.Dispose(). @@ -177,6 +192,11 @@ Statická metoda {locked: static}{locked: method} These are keywords (unless the order of words or capitalization should be handled differently) + + Stream must support read and seek operations. + Stream must support read and seek operations. + + Struct Struct @@ -232,6 +252,11 @@ Typy {locked:types} unless the capitalization should be handled differently + + Value too large to be represented as a 30 bit unsigned integer. + Value too large to be represented as a 30 bit unsigned integer. + + this. and Me. preferences Předvolby pro this. a Me. diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/xlf/CompilerExtensionsResources.de.xlf b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/xlf/CompilerExtensionsResources.de.xlf index 834aac1a19100..32c442eb17157 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/xlf/CompilerExtensionsResources.de.xlf +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/xlf/CompilerExtensionsResources.de.xlf @@ -2,6 +2,16 @@ + + A language name cannot be specified for this option. + A language name cannot be specified for this option. + + + + A language name must be specified for this option. + A language name must be specified for this option. + + Absolute path expected. Absoluter Pfad erwartet. @@ -52,6 +62,11 @@ Einstellungen für Felder + + Indentation and spacing + Indentation and spacing + + Instantiated part(s) threw exception(s) from IDisposable.Dispose(). Instanziierte Teile haben Ausnahmen aus IDisposable.Dispose() ausgelöst. @@ -177,6 +192,11 @@ Statische Methode {locked: static}{locked: method} These are keywords (unless the order of words or capitalization should be handled differently) + + Stream must support read and seek operations. + Stream must support read and seek operations. + + Struct Struct @@ -232,6 +252,11 @@ Typen {locked:types} unless the capitalization should be handled differently + + Value too large to be represented as a 30 bit unsigned integer. + Value too large to be represented as a 30 bit unsigned integer. + + this. and Me. preferences this.- und Me.-Einstellungen diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/xlf/CompilerExtensionsResources.es.xlf b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/xlf/CompilerExtensionsResources.es.xlf index 6b8aaca0e0cbe..6c59b85fa5a2f 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/xlf/CompilerExtensionsResources.es.xlf +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/xlf/CompilerExtensionsResources.es.xlf @@ -2,6 +2,16 @@ + + A language name cannot be specified for this option. + A language name cannot be specified for this option. + + + + A language name must be specified for this option. + A language name must be specified for this option. + + Absolute path expected. Ruta de acceso absoluta esperada. @@ -52,6 +62,11 @@ Preferencias de campo + + Indentation and spacing + Indentation and spacing + + Instantiated part(s) threw exception(s) from IDisposable.Dispose(). Los elementos con instancias produjeron excepciones desde IDisposable.Dispose(). @@ -177,6 +192,11 @@ Método estático {locked: static}{locked: method} These are keywords (unless the order of words or capitalization should be handled differently) + + Stream must support read and seek operations. + Stream must support read and seek operations. + + Struct Struct @@ -232,6 +252,11 @@ Tipos {locked:types} unless the capitalization should be handled differently + + Value too large to be represented as a 30 bit unsigned integer. + Value too large to be represented as a 30 bit unsigned integer. + + this. and Me. preferences Preferencias de this. y .me diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/xlf/CompilerExtensionsResources.fr.xlf b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/xlf/CompilerExtensionsResources.fr.xlf index 0ae3c56734669..b090ead34d63b 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/xlf/CompilerExtensionsResources.fr.xlf +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/xlf/CompilerExtensionsResources.fr.xlf @@ -2,6 +2,16 @@ + + A language name cannot be specified for this option. + A language name cannot be specified for this option. + + + + A language name must be specified for this option. + A language name must be specified for this option. + + Absolute path expected. Chemin d'accès absolu attendu. @@ -52,6 +62,11 @@ Préférences de champ + + Indentation and spacing + Indentation and spacing + + Instantiated part(s) threw exception(s) from IDisposable.Dispose(). La ou les parties instanciées ont levé une ou plusieurs exceptions à partir de IDisposable.Dispose(). @@ -177,6 +192,11 @@ Méthode statique {locked: static}{locked: method} These are keywords (unless the order of words or capitalization should be handled differently) + + Stream must support read and seek operations. + Stream must support read and seek operations. + + Struct Struct @@ -232,6 +252,11 @@ Types {locked:types} unless the capitalization should be handled differently + + Value too large to be represented as a 30 bit unsigned integer. + Value too large to be represented as a 30 bit unsigned integer. + + this. and Me. preferences Préférences de this. et Me. diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/xlf/CompilerExtensionsResources.it.xlf b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/xlf/CompilerExtensionsResources.it.xlf index 826fadff9c091..bc258c2dbdfbc 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/xlf/CompilerExtensionsResources.it.xlf +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/xlf/CompilerExtensionsResources.it.xlf @@ -2,6 +2,16 @@ + + A language name cannot be specified for this option. + A language name cannot be specified for this option. + + + + A language name must be specified for this option. + A language name must be specified for this option. + + Absolute path expected. È previsto il percorso assoluto. @@ -52,6 +62,11 @@ Preferenze per campi + + Indentation and spacing + Indentation and spacing + + Instantiated part(s) threw exception(s) from IDisposable.Dispose(). Le parti di cui è stata creata un'istanza hanno generato eccezioni da IDisposable.Dispose(). @@ -177,6 +192,11 @@ Metodo statico {locked: static}{locked: method} These are keywords (unless the order of words or capitalization should be handled differently) + + Stream must support read and seek operations. + Stream must support read and seek operations. + + Struct Struct @@ -232,6 +252,11 @@ Tipi {locked:types} unless the capitalization should be handled differently + + Value too large to be represented as a 30 bit unsigned integer. + Value too large to be represented as a 30 bit unsigned integer. + + this. and Me. preferences Preferenze per this. e Me. diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/xlf/CompilerExtensionsResources.ja.xlf b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/xlf/CompilerExtensionsResources.ja.xlf index 4b26c3ab7d2b3..88cced8049903 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/xlf/CompilerExtensionsResources.ja.xlf +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/xlf/CompilerExtensionsResources.ja.xlf @@ -2,6 +2,16 @@ + + A language name cannot be specified for this option. + A language name cannot be specified for this option. + + + + A language name must be specified for this option. + A language name must be specified for this option. + + Absolute path expected. 絶対パスが必要です。 @@ -52,6 +62,11 @@ フィールド設定 + + Indentation and spacing + Indentation and spacing + + Instantiated part(s) threw exception(s) from IDisposable.Dispose(). インスタンス化されたパーツが IDisposable.Dispose() から例外をスローしました。 @@ -177,6 +192,11 @@ 静的メソッド {locked: static}{locked: method} These are keywords (unless the order of words or capitalization should be handled differently) + + Stream must support read and seek operations. + Stream must support read and seek operations. + + Struct Struct @@ -232,6 +252,11 @@ {locked:types} unless the capitalization should be handled differently + + Value too large to be represented as a 30 bit unsigned integer. + Value too large to be represented as a 30 bit unsigned integer. + + this. and Me. preferences this. と Me. の設定 diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/xlf/CompilerExtensionsResources.ko.xlf b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/xlf/CompilerExtensionsResources.ko.xlf index ee02f41cd9d3b..09bad15ba92c2 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/xlf/CompilerExtensionsResources.ko.xlf +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/xlf/CompilerExtensionsResources.ko.xlf @@ -2,6 +2,16 @@ + + A language name cannot be specified for this option. + A language name cannot be specified for this option. + + + + A language name must be specified for this option. + A language name must be specified for this option. + + Absolute path expected. 절대 경로가 필요합니다. @@ -52,6 +62,11 @@ 필드 기본 설정 + + Indentation and spacing + Indentation and spacing + + Instantiated part(s) threw exception(s) from IDisposable.Dispose(). IDisposable.Dispose()의 인스턴스화된 파트에서 예외가 발생했습니다. @@ -177,6 +192,11 @@ 정적 메서드 {locked: static}{locked: method} These are keywords (unless the order of words or capitalization should be handled differently) + + Stream must support read and seek operations. + Stream must support read and seek operations. + + Struct Struct @@ -232,6 +252,11 @@ 형식 {locked:types} unless the capitalization should be handled differently + + Value too large to be represented as a 30 bit unsigned integer. + Value too large to be represented as a 30 bit unsigned integer. + + this. and Me. preferences this. 및 Me. 기본 설정 diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/xlf/CompilerExtensionsResources.pl.xlf b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/xlf/CompilerExtensionsResources.pl.xlf index ef85ef2b0ecb0..6fc6dd0fe8dc8 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/xlf/CompilerExtensionsResources.pl.xlf +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/xlf/CompilerExtensionsResources.pl.xlf @@ -2,6 +2,16 @@ + + A language name cannot be specified for this option. + A language name cannot be specified for this option. + + + + A language name must be specified for this option. + A language name must be specified for this option. + + Absolute path expected. Oczekiwano ścieżki bezwzględnej. @@ -52,6 +62,11 @@ Preferencje pól + + Indentation and spacing + Indentation and spacing + + Instantiated part(s) threw exception(s) from IDisposable.Dispose(). Części z utworzonymi wystąpieniami zgłosiły wyjątki z elementu IDisposable.Dispose(). @@ -177,6 +192,11 @@ Metoda statyczna {locked: static}{locked: method} These are keywords (unless the order of words or capitalization should be handled differently) + + Stream must support read and seek operations. + Stream must support read and seek operations. + + Struct Struct @@ -232,6 +252,11 @@ Typy {locked:types} unless the capitalization should be handled differently + + Value too large to be represented as a 30 bit unsigned integer. + Value too large to be represented as a 30 bit unsigned integer. + + this. and Me. preferences Preferencje dotyczące słów kluczowych this. i Me. diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/xlf/CompilerExtensionsResources.pt-BR.xlf b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/xlf/CompilerExtensionsResources.pt-BR.xlf index fd27315e14805..e6450f68881b0 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/xlf/CompilerExtensionsResources.pt-BR.xlf +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/xlf/CompilerExtensionsResources.pt-BR.xlf @@ -2,6 +2,16 @@ + + A language name cannot be specified for this option. + A language name cannot be specified for this option. + + + + A language name must be specified for this option. + A language name must be specified for this option. + + Absolute path expected. Caminho absoluto esperado. @@ -52,6 +62,11 @@ Preferências de campo + + Indentation and spacing + Indentation and spacing + + Instantiated part(s) threw exception(s) from IDisposable.Dispose(). As partes instanciadas geraram exceções por meio de IDisposable.Dispose(). @@ -177,6 +192,11 @@ Método Estático {locked: static}{locked: method} These are keywords (unless the order of words or capitalization should be handled differently) + + Stream must support read and seek operations. + Stream must support read and seek operations. + + Struct Struct @@ -232,6 +252,11 @@ Tipos {locked:types} unless the capitalization should be handled differently + + Value too large to be represented as a 30 bit unsigned integer. + Value too large to be represented as a 30 bit unsigned integer. + + this. and Me. preferences Preferências diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/xlf/CompilerExtensionsResources.ru.xlf b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/xlf/CompilerExtensionsResources.ru.xlf index 72f203b535b63..6bf75cf7423b5 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/xlf/CompilerExtensionsResources.ru.xlf +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/xlf/CompilerExtensionsResources.ru.xlf @@ -2,6 +2,16 @@ + + A language name cannot be specified for this option. + A language name cannot be specified for this option. + + + + A language name must be specified for this option. + A language name must be specified for this option. + + Absolute path expected. Ожидался абсолютный путь. @@ -52,6 +62,11 @@ Предпочтения для полей + + Indentation and spacing + Indentation and spacing + + Instantiated part(s) threw exception(s) from IDisposable.Dispose(). Возникли исключения в частях с созданными экземплярами из IDisposable.Dispose(). @@ -177,6 +192,11 @@ Статический метод {locked: static}{locked: method} These are keywords (unless the order of words or capitalization should be handled differently) + + Stream must support read and seek operations. + Stream must support read and seek operations. + + Struct Struct @@ -232,6 +252,11 @@ Типы {locked:types} unless the capitalization should be handled differently + + Value too large to be represented as a 30 bit unsigned integer. + Value too large to be represented as a 30 bit unsigned integer. + + this. and Me. preferences Предпочтения для this. и Me. diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/xlf/CompilerExtensionsResources.tr.xlf b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/xlf/CompilerExtensionsResources.tr.xlf index 7093ab6cb8ac2..2108bb3650547 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/xlf/CompilerExtensionsResources.tr.xlf +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/xlf/CompilerExtensionsResources.tr.xlf @@ -2,6 +2,16 @@ + + A language name cannot be specified for this option. + A language name cannot be specified for this option. + + + + A language name must be specified for this option. + A language name must be specified for this option. + + Absolute path expected. Mutlak yok bekleniyor. @@ -52,6 +62,11 @@ Alan tercihleri + + Indentation and spacing + Indentation and spacing + + Instantiated part(s) threw exception(s) from IDisposable.Dispose(). Örneği oluşturulan bölümler, IDisposable.Dispose() öğesinden özel durumlar oluşturdu. @@ -177,6 +192,11 @@ Statik Metot {locked: static}{locked: method} These are keywords (unless the order of words or capitalization should be handled differently) + + Stream must support read and seek operations. + Stream must support read and seek operations. + + Struct Struct @@ -232,6 +252,11 @@ Türler {locked:types} unless the capitalization should be handled differently + + Value too large to be represented as a 30 bit unsigned integer. + Value too large to be represented as a 30 bit unsigned integer. + + this. and Me. preferences Bu. ve bana tercihleri diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/xlf/CompilerExtensionsResources.zh-Hans.xlf b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/xlf/CompilerExtensionsResources.zh-Hans.xlf index b54d25a42c326..a6ff47683510f 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/xlf/CompilerExtensionsResources.zh-Hans.xlf +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/xlf/CompilerExtensionsResources.zh-Hans.xlf @@ -2,6 +2,16 @@ + + A language name cannot be specified for this option. + A language name cannot be specified for this option. + + + + A language name must be specified for this option. + A language name must be specified for this option. + + Absolute path expected. 预期的绝对路径。 @@ -52,6 +62,11 @@ 字段首选项 + + Indentation and spacing + Indentation and spacing + + Instantiated part(s) threw exception(s) from IDisposable.Dispose(). 实例化的部件从 IDisposable.Dispose() 中引发异常。 @@ -177,6 +192,11 @@ 静态方法 {locked: static}{locked: method} These are keywords (unless the order of words or capitalization should be handled differently) + + Stream must support read and seek operations. + Stream must support read and seek operations. + + Struct Struct @@ -232,6 +252,11 @@ 类型 {locked:types} unless the capitalization should be handled differently + + Value too large to be represented as a 30 bit unsigned integer. + Value too large to be represented as a 30 bit unsigned integer. + + this. and Me. preferences this. 和 Me. 首选项 diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/xlf/CompilerExtensionsResources.zh-Hant.xlf b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/xlf/CompilerExtensionsResources.zh-Hant.xlf index c3f574e61b0ad..ce23e63d317f9 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/xlf/CompilerExtensionsResources.zh-Hant.xlf +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/xlf/CompilerExtensionsResources.zh-Hant.xlf @@ -2,6 +2,16 @@ + + A language name cannot be specified for this option. + A language name cannot be specified for this option. + + + + A language name must be specified for this option. + A language name must be specified for this option. + + Absolute path expected. 必須是絕對路徑。 @@ -52,6 +62,11 @@ 欄位喜好設定 + + Indentation and spacing + Indentation and spacing + + Instantiated part(s) threw exception(s) from IDisposable.Dispose(). 從 IDisposable.Dispose() 執行個體化的部分擲回的例外狀況。 @@ -177,6 +192,11 @@ 靜態方法 {locked: static}{locked: method} These are keywords (unless the order of words or capitalization should be handled differently) + + Stream must support read and seek operations. + Stream must support read and seek operations. + + Struct Struct @@ -232,6 +252,11 @@ 型別 {locked:types} unless the capitalization should be handled differently + + Value too large to be represented as a 30 bit unsigned integer. + Value too large to be represented as a 30 bit unsigned integer. + + this. and Me. preferences this. 和 Me. 喜好設定 diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/VisualBasic/Extensions/ParenthesizedExpressionSyntaxExtensions.vb b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/VisualBasic/Extensions/ParenthesizedExpressionSyntaxExtensions.vb index 31e7232f7baf8..da471f2baced0 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/VisualBasic/Extensions/ParenthesizedExpressionSyntaxExtensions.vb +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/VisualBasic/Extensions/ParenthesizedExpressionSyntaxExtensions.vb @@ -508,13 +508,34 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Extensions nextToken.IsKindOrHasMatchingText(SyntaxKind.CloseBraceToken) OrElse node.CloseParenToken.IsLastTokenOfStatement() Then + Dim nextTokenTextKind = SyntaxFacts.GetContextualKeywordKind(nextToken.Text) + Select Case nextTokenTextKind + Case SyntaxKind.AscendingKeyword, + SyntaxKind.DescendingKeyword, + SyntaxKind.DistinctKeyword, + SyntaxKind.GroupKeyword, + SyntaxKind.IntoKeyword, + SyntaxKind.OrderKeyword, + SyntaxKind.SkipKeyword, + SyntaxKind.TakeKeyword, + SyntaxKind.WhereKeyword, + SyntaxKind.JoinKeyword, + SyntaxKind.InKeyword, + SyntaxKind.LetKeyword, + SyntaxKind.OnKeyword, + SyntaxKind.SelectKeyword, + SyntaxKind.AggregateKeyword, + SyntaxKind.FromKeyword + Return False + End Select + If Not (nextToken.IsKindOrHasMatchingText(SyntaxKind.DotToken) AndAlso nextToken.Parent.IsKind(SyntaxKind.SimpleMemberAccessExpression)) AndAlso Not (nextToken.IsKindOrHasMatchingText(SyntaxKind.SelectKeyword) AndAlso nextToken.Parent.IsKind(SyntaxKind.SelectStatement)) AndAlso - Not (nextToken.IsKindOrHasMatchingText(SyntaxKind.ExclamationToken) AndAlso - lastToken.IsKeyword AndAlso - nextToken.Parent.IsKind(SyntaxKind.DictionaryAccessExpression)) Then + Not (nextToken.IsKindOrHasMatchingText(SyntaxKind.ExclamationToken) AndAlso + lastToken.IsKeyword AndAlso + nextToken.Parent.IsKind(SyntaxKind.DictionaryAccessExpression)) Then Return True End If diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/VisualBasic/Extensions/SemanticModelExtensions.vb b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/VisualBasic/Extensions/SemanticModelExtensions.vb index 918017f2cbc08..72b3513d0a02c 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/VisualBasic/Extensions/SemanticModelExtensions.vb +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/VisualBasic/Extensions/SemanticModelExtensions.vb @@ -11,7 +11,7 @@ Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Namespace Microsoft.CodeAnalysis.VisualBasic.Extensions Partial Friend Module SemanticModelExtensions - + Public Function LookupTypeRegardlessOfArity(semanticModel As SemanticModel, name As SyntaxToken, cancellationToken As CancellationToken) As IList(Of ITypeSymbol) @@ -26,7 +26,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Extensions Return SpecializedCollections.EmptyList(Of ITypeSymbol)() End Function - + Public Function LookupName(semanticModel As SemanticModel, name As SyntaxToken, namespacesAndTypesOnly As Boolean, cancellationToken As CancellationToken) As IList(Of ISymbol) @@ -38,7 +38,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Extensions Return SpecializedCollections.EmptyList(Of ISymbol)() End Function - + Public Function LookupName(semanticModel As SemanticModel, expression As ExpressionSyntax, namespacesAndTypesOnly As Boolean, @@ -68,17 +68,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Extensions semanticModel.LookupSymbols(expr.SpanStart, container:=symbol, name:=name)) End Function - - Public Function GetSymbolInfo(semanticModel As SemanticModel, token As SyntaxToken) As SymbolInfo - Dim expression = TryCast(token.Parent, ExpressionSyntax) - If expression Is Nothing Then - Return Nothing - End If - - Return semanticModel.GetSymbolInfo(expression) - End Function - - + Public Function GetImportNamespacesInScope(semanticModel As SemanticModel, location As SyntaxNode) As ISet(Of INamespaceSymbol) Dim q = From u In location.GetAncestorOrThis(Of CompilationUnitSyntax).Imports @@ -92,7 +82,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Extensions Return q.ToSet() End Function - + Public Function GetAliasInfo(semanticModel As SemanticModel, expression As ExpressionSyntax, cancellationToken As CancellationToken) As IAliasSymbol Dim nameSyntax = TryCast(expression, IdentifierNameSyntax) If nameSyntax Is Nothing Then @@ -102,7 +92,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Extensions End If End Function - + Public Function DetermineAccessibilityConstraint(semanticModel As SemanticModel, type As TypeSyntax, cancellationToken As CancellationToken) As Accessibility diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/VisualBasic/Extensions/SyntaxNodeExtensions.vb b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/VisualBasic/Extensions/SyntaxNodeExtensions.vb index 3cb98c6dd2d6a..9871ba0073b32 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/VisualBasic/Extensions/SyntaxNodeExtensions.vb +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/VisualBasic/Extensions/SyntaxNodeExtensions.vb @@ -841,7 +841,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Extensions Dim topMostExpression = node _ .AncestorsAndSelf() _ - .TakeWhile(Function(n) Not TypeOf n Is StatementSyntax) _ + .TakeWhile(Function(n) TypeOf n IsNot StatementSyntax) _ .OfType(Of ExpressionSyntax) _ .LastOrDefault() diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/VisualBasic/Services/SemanticFacts/VisualBasicSemanticFacts.vb b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/VisualBasic/Services/SemanticFacts/VisualBasicSemanticFacts.vb index 4a4790a665427..540dba1f7d0b4 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/VisualBasic/Services/SemanticFacts/VisualBasicSemanticFacts.vb +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/VisualBasic/Services/SemanticFacts/VisualBasicSemanticFacts.vb @@ -65,10 +65,10 @@ Namespace Microsoft.CodeAnalysis.VisualBasic Dim location = token.GetLocation() For Each ancestor In token.GetAncestors(Of SyntaxNode)() - If Not TypeOf ancestor Is AggregationRangeVariableSyntax AndAlso - Not TypeOf ancestor Is CollectionRangeVariableSyntax AndAlso - Not TypeOf ancestor Is ExpressionRangeVariableSyntax AndAlso - Not TypeOf ancestor Is InferredFieldInitializerSyntax Then + If TypeOf ancestor IsNot AggregationRangeVariableSyntax AndAlso + TypeOf ancestor IsNot CollectionRangeVariableSyntax AndAlso + TypeOf ancestor IsNot ExpressionRangeVariableSyntax AndAlso + TypeOf ancestor IsNot InferredFieldInitializerSyntax Then Dim symbol = semanticModel.GetDeclaredSymbol(ancestor, cancellationToken) diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/VisualBasic/Services/SyntaxFacts/VisualBasicBlockFacts.vb b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/VisualBasic/Services/SyntaxFacts/VisualBasicBlockFacts.vb index 3435fc11564f7..3d07caae68aa8 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/VisualBasic/Services/SyntaxFacts/VisualBasicBlockFacts.vb +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/VisualBasic/Services/SyntaxFacts/VisualBasicBlockFacts.vb @@ -3,12 +3,13 @@ ' See the LICENSE file in the project root for more information. Imports Microsoft.CodeAnalysis.LanguageService +Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Namespace Microsoft.CodeAnalysis.VisualBasic.LanguageService Friend Class VisualBasicBlockFacts - Inherits AbstractBlockFacts + Inherits AbstractBlockFacts(Of StatementSyntax) - Public Shared ReadOnly Instance As IBlockFacts = New VisualBasicBlockFacts() + Public Shared ReadOnly Instance As New VisualBasicBlockFacts() Public Overrides Function IsScopeBlock(node As SyntaxNode) As Boolean ' VB has no equivalent of curly braces. @@ -19,7 +20,11 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.LanguageService Return node.IsExecutableBlock() End Function - Public Overrides Function GetExecutableBlockStatements(node As SyntaxNode) As IReadOnlyList(Of SyntaxNode) + Public Overrides Function GetImmediateParentExecutableBlockForStatement(statement As StatementSyntax) As SyntaxNode + Return If(IsExecutableBlock(statement.Parent), statement.Parent, Nothing) + End Function + + Public Overrides Function GetExecutableBlockStatements(node As SyntaxNode) As IReadOnlyList(Of StatementSyntax) Return node.GetExecutableBlockStatements() End Function @@ -31,7 +36,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.LanguageService Return IsExecutableBlock(node) End Function - Public Overrides Function GetStatementContainerStatements(node As SyntaxNode) As IReadOnlyList(Of SyntaxNode) + Public Overrides Function GetStatementContainerStatements(node As SyntaxNode) As IReadOnlyList(Of StatementSyntax) Return GetExecutableBlockStatements(node) End Function End Class diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/VisualBasic/Services/SyntaxFacts/VisualBasicFileBannerFacts.vb b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/VisualBasic/Services/SyntaxFacts/VisualBasicFileBannerFacts.vb index 3747015c69543..7957182876b5c 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/VisualBasic/Services/SyntaxFacts/VisualBasicFileBannerFacts.vb +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/VisualBasic/Services/SyntaxFacts/VisualBasicFileBannerFacts.vb @@ -24,5 +24,11 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.LanguageService Return VisualBasicDocumentationCommentService.Instance End Get End Property + + Public Overrides Function CreateTrivia(trivia As SyntaxTrivia, text As String) As SyntaxTrivia + Return If(trivia.Kind() = SyntaxKind.CommentTrivia OrElse trivia.Kind() = SyntaxKind.DocumentationCommentTrivia, + SyntaxFactory.CommentTrivia(text), + trivia) + End Function End Class End Namespace diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/VisualBasic/Services/SyntaxFacts/VisualBasicSyntaxFacts.vb b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/VisualBasic/Services/SyntaxFacts/VisualBasicSyntaxFacts.vb index f763bf800fc50..f5a6fee82047e 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/VisualBasic/Services/SyntaxFacts/VisualBasicSyntaxFacts.vb +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/VisualBasic/Services/SyntaxFacts/VisualBasicSyntaxFacts.vb @@ -33,29 +33,13 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.LanguageService Protected Sub New() End Sub - Public ReadOnly Property IsCaseSensitive As Boolean Implements ISyntaxFacts.IsCaseSensitive - Get - Return False - End Get - End Property - - Public ReadOnly Property StringComparer As StringComparer Implements ISyntaxFacts.StringComparer - Get - Return CaseInsensitiveComparison.Comparer - End Get - End Property - - Public ReadOnly Property ElasticMarker As SyntaxTrivia Implements ISyntaxFacts.ElasticMarker - Get - Return SyntaxFactory.ElasticMarker - End Get - End Property - - Public ReadOnly Property ElasticCarriageReturnLineFeed As SyntaxTrivia Implements ISyntaxFacts.ElasticCarriageReturnLineFeed - Get - Return SyntaxFactory.ElasticCarriageReturnLineFeed - End Get - End Property + Public ReadOnly Property IsCaseSensitive As Boolean = False Implements ISyntaxFacts.IsCaseSensitive + + Public ReadOnly Property StringComparer As StringComparer = CaseInsensitiveComparison.Comparer Implements ISyntaxFacts.StringComparer + + Public ReadOnly Property ElasticMarker As SyntaxTrivia = SyntaxFactory.ElasticMarker Implements ISyntaxFacts.ElasticMarker + + Public ReadOnly Property ElasticCarriageReturnLineFeed As SyntaxTrivia = SyntaxFactory.ElasticCarriageReturnLineFeed Implements ISyntaxFacts.ElasticCarriageReturnLineFeed Public ReadOnly Property SyntaxKinds As ISyntaxKinds = VisualBasicSyntaxKinds.Instance Implements ISyntaxFacts.SyntaxKinds @@ -88,6 +72,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.LanguageService End Function Public Function SupportsTupleDeconstruction(options As ParseOptions) As Boolean Implements ISyntaxFacts.SupportsTupleDeconstruction + ' While VB supports tuples, it does not support deconstruction. Return False End Function @@ -95,6 +80,10 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.LanguageService Return False End Function + Public Function SupportsImplicitImplementationOfNonPublicInterfaceMembers(options As ParseOptions) As Boolean Implements ISyntaxFacts.SupportsImplicitImplementationOfNonPublicInterfaceMembers + Return True + End Function + Public Function ParseToken(text As String) As SyntaxToken Implements ISyntaxFacts.ParseToken Return SyntaxFactory.ParseToken(text, startStatement:=True) End Function @@ -214,6 +203,10 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.LanguageService Return False End Function + Public Function IsUsingLocalDeclarationStatement(node As SyntaxNode) As Boolean Implements ISyntaxFacts.IsUsingLocalDeclarationStatement + Return False + End Function + Public Function IsStatement(node As SyntaxNode) As Boolean Implements ISyntaxFacts.IsStatement Return TypeOf node Is StatementSyntax End Function @@ -232,13 +225,6 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.LanguageService Throw New InvalidOperationException(DoesNotExistInVBErrorMessage) End Function - Public Function AreStatementsInSameContainer(firstStatement As SyntaxNode, secondStatement As SyntaxNode) As Boolean Implements ISyntaxFacts.AreStatementsInSameContainer - Debug.Assert(IsStatement(firstStatement)) - Debug.Assert(IsStatement(secondStatement)) - - Return firstStatement.Parent Is secondStatement.Parent - End Function - Public Function IsMethodBody(node As SyntaxNode) As Boolean Implements ISyntaxFacts.IsMethodBody Return TypeOf node Is MethodBlockBaseSyntax End Function @@ -513,7 +499,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.LanguageService Return token.IsKind(SyntaxKind.StringLiteralToken, SyntaxKind.InterpolatedStringTextToken) End Function - Public Function IsBindableToken(token As SyntaxToken) As Boolean Implements ISyntaxFacts.IsBindableToken + Public Function IsBindableToken(semanticModel As SemanticModel, token As SyntaxToken) As Boolean Implements ISyntaxFacts.IsBindableToken Return Me.IsWord(token) OrElse Me.IsLiteral(token) OrElse Me.IsOperator(token) @@ -706,19 +692,19 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.LanguageService Public Function GetContainingMemberDeclaration(root As SyntaxNode, position As Integer, Optional useFullSpan As Boolean = True) As SyntaxNode Implements ISyntaxFacts.GetContainingMemberDeclaration Dim isApplicableDeclaration = Function(node As SyntaxNode) - If TypeOf node Is MethodBlockBaseSyntax AndAlso Not TypeOf node.Parent Is PropertyBlockSyntax Then + If TypeOf node Is MethodBlockBaseSyntax AndAlso TypeOf node.Parent IsNot PropertyBlockSyntax Then Return True End If - If TypeOf node Is MethodBaseSyntax AndAlso Not TypeOf node.Parent Is MethodBlockBaseSyntax Then + If TypeOf node Is MethodBaseSyntax AndAlso TypeOf node.Parent IsNot MethodBlockBaseSyntax Then Return True End If - If TypeOf node Is PropertyStatementSyntax AndAlso Not TypeOf node.Parent Is PropertyBlockSyntax Then + If TypeOf node Is PropertyStatementSyntax AndAlso TypeOf node.Parent IsNot PropertyBlockSyntax Then Return True End If - If TypeOf node Is EventStatementSyntax AndAlso Not TypeOf node.Parent Is EventBlockSyntax Then + If TypeOf node Is EventStatementSyntax AndAlso TypeOf node.Parent IsNot EventBlockSyntax Then Return True End If @@ -739,11 +725,11 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.LanguageService Public Function GetContainingMethodDeclaration(root As SyntaxNode, position As Integer, Optional useFullSpan As Boolean = True) As SyntaxNode Implements ISyntaxFacts.GetContainingMethodDeclaration Dim isApplicableDeclaration = Function(node As SyntaxNode) - If TypeOf node Is MethodBlockBaseSyntax AndAlso Not TypeOf node.Parent Is PropertyBlockSyntax Then + If TypeOf node Is MethodBlockBaseSyntax AndAlso TypeOf node.Parent IsNot PropertyBlockSyntax Then Return True End If - If TypeOf node Is MethodBaseSyntax AndAlso Not TypeOf node.Parent Is MethodBlockBaseSyntax Then + If TypeOf node Is MethodBaseSyntax AndAlso TypeOf node.Parent IsNot MethodBlockBaseSyntax Then Return True End If @@ -784,23 +770,23 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.LanguageService ' like AccessorStatementSyntax and DelegateStatementSyntax that we never want to tread as method level ' members. - If TypeOf node Is MethodStatementSyntax AndAlso Not TypeOf node.Parent Is MethodBlockBaseSyntax Then + If TypeOf node Is MethodStatementSyntax AndAlso TypeOf node.Parent IsNot MethodBlockBaseSyntax Then Return True End If - If TypeOf node Is SubNewStatementSyntax AndAlso Not TypeOf node.Parent Is MethodBlockBaseSyntax Then + If TypeOf node Is SubNewStatementSyntax AndAlso TypeOf node.Parent IsNot MethodBlockBaseSyntax Then Return True End If - If TypeOf node Is OperatorStatementSyntax AndAlso Not TypeOf node.Parent Is MethodBlockBaseSyntax Then + If TypeOf node Is OperatorStatementSyntax AndAlso TypeOf node.Parent IsNot MethodBlockBaseSyntax Then Return True End If - If TypeOf node Is PropertyStatementSyntax AndAlso Not TypeOf node.Parent Is PropertyBlockSyntax Then + If TypeOf node Is PropertyStatementSyntax AndAlso TypeOf node.Parent IsNot PropertyBlockSyntax Then Return True End If - If TypeOf node Is EventStatementSyntax AndAlso Not TypeOf node.Parent Is EventBlockSyntax Then + If TypeOf node Is EventStatementSyntax AndAlso TypeOf node.Parent IsNot EventBlockSyntax Then Return True End If @@ -1476,6 +1462,14 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.LanguageService Return SyntaxFacts.IsPreprocessorDirective(trivia.Kind()) End Function + Public Function GetMatchingDirective(directive As SyntaxNode, cancellationToken As CancellationToken) As SyntaxNode Implements ISyntaxFacts.GetMatchingDirective + Return DirectCast(directive, DirectiveTriviaSyntax).GetMatchingStartOrEndDirective(cancellationToken) + End Function + + Public Function GetMatchingConditionalDirectives(directive As SyntaxNode, cancellationToken As CancellationToken) As ImmutableArray(Of SyntaxNode) Implements ISyntaxFacts.GetMatchingConditionalDirectives + Return DirectCast(directive, DirectiveTriviaSyntax).GetMatchingConditionalDirectives(cancellationToken).CastArray(Of SyntaxNode) + End Function + Public Function IsRegularComment(trivia As SyntaxTrivia) As Boolean Implements ISyntaxFacts.IsRegularComment Return trivia.Kind = SyntaxKind.CommentTrivia End Function @@ -1822,6 +1816,10 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.LanguageService #Region "GetPartsOfXXX members" + Public Sub GetPartsOfAliasQualifiedName(node As SyntaxNode, ByRef [alias] As SyntaxNode, ByRef colonColonToken As SyntaxToken, ByRef name As SyntaxNode) Implements ISyntaxFacts.GetPartsOfAliasQualifiedName + Throw New InvalidOperationException(DoesNotExistInVBErrorMessage) + End Sub + Public Sub GetPartsOfArgumentList(node As SyntaxNode, ByRef openParenToken As SyntaxToken, ByRef arguments As SeparatedSyntaxList(Of SyntaxNode), ByRef closeParenToken As SyntaxToken) Implements ISyntaxFacts.GetPartsOfArgumentList Dim argumentList = DirectCast(node, ArgumentListSyntax) openParenToken = argumentList.OpenParenToken diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/VisualBasic/Services/SyntaxFacts/VisualBasicSyntaxKinds.vb b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/VisualBasic/Services/SyntaxFacts/VisualBasicSyntaxKinds.vb index 0bb05a16e1f5b..6921dc24cad4d 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/VisualBasic/Services/SyntaxFacts/VisualBasicSyntaxKinds.vb +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/VisualBasic/Services/SyntaxFacts/VisualBasicSyntaxKinds.vb @@ -75,6 +75,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.LanguageService Public ReadOnly Property TrueKeyword As Integer = SyntaxKind.TrueKeyword Implements ISyntaxKinds.TrueKeyword Public ReadOnly Property UsingKeyword As Integer = SyntaxKind.UsingKeyword Implements ISyntaxKinds.UsingKeyword + Public ReadOnly Property AliasQualifiedName As Integer? Implements ISyntaxKinds.AliasQualifiedName Public ReadOnly Property GenericName As Integer = SyntaxKind.GenericName Implements ISyntaxKinds.GenericName Public ReadOnly Property IdentifierName As Integer = SyntaxKind.IdentifierName Implements ISyntaxKinds.IdentifierName Public ReadOnly Property QualifiedName As Integer = SyntaxKind.QualifiedName Implements ISyntaxKinds.QualifiedName @@ -98,6 +99,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.LanguageService Public ReadOnly Property CollectionInitializerExpression As Integer = SyntaxKind.CollectionInitializer Implements ISyntaxKinds.CollectionInitializerExpression Public ReadOnly Property ConditionalAccessExpression As Integer = SyntaxKind.ConditionalAccessExpression Implements ISyntaxKinds.ConditionalAccessExpression Public ReadOnly Property ConditionalExpression As Integer = SyntaxKind.TernaryConditionalExpression Implements ISyntaxKinds.ConditionalExpression + Public ReadOnly Property FieldExpression As Integer? Implements ISyntaxKinds.FieldExpression Public ReadOnly Property ImplicitArrayCreationExpression As Integer? Implements ISyntaxKinds.ImplicitArrayCreationExpression Public ReadOnly Property ImplicitObjectCreationExpression As Integer? Implements ISyntaxKinds.ImplicitObjectCreationExpression Public ReadOnly Property IndexExpression As Integer? Implements ISyntaxKinds.IndexExpression @@ -115,6 +117,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.LanguageService Public ReadOnly Property RefExpression As Integer? Implements ISyntaxKinds.RefExpression Public ReadOnly Property ReferenceEqualsExpression As Integer = SyntaxKind.IsExpression Implements ISyntaxKinds.ReferenceEqualsExpression Public ReadOnly Property ReferenceNotEqualsExpression As Integer = SyntaxKind.IsNotExpression Implements ISyntaxKinds.ReferenceNotEqualsExpression + Public ReadOnly Property SimpleAssignmentExpression As Integer = SyntaxKind.SimpleAssignmentStatement Implements ISyntaxKinds.SimpleAssignmentExpression Public ReadOnly Property SimpleMemberAccessExpression As Integer = SyntaxKind.SimpleMemberAccessExpression Implements ISyntaxKinds.SimpleMemberAccessExpression Public ReadOnly Property SuppressNullableWarningExpression As Integer? Implements ISyntaxKinds.SuppressNullableWarningExpression Public ReadOnly Property TernaryConditionalExpression As Integer = SyntaxKind.TernaryConditionalExpression Implements ISyntaxKinds.TernaryConditionalExpression @@ -179,5 +182,6 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.LanguageService Public ReadOnly Property InterpolatedStringExpression As Integer = SyntaxKind.InterpolatedStringExpression Implements ISyntaxKinds.InterpolatedStringExpression Public ReadOnly Property InterpolatedStringText As Integer = SyntaxKind.InterpolatedStringText Implements ISyntaxKinds.InterpolatedStringText Public ReadOnly Property IndexerMemberCref As Integer? Implements ISyntaxKinds.IndexerMemberCref + Public ReadOnly Property PrimaryConstructorBaseType As Integer? Implements ISyntaxKinds.PrimaryConstructorBaseType End Class End Namespace diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/CSharpWorkspaceExtensions.projitems b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/CSharpWorkspaceExtensions.projitems index 1ee3201aed7fb..2db3182cbc458 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/CSharpWorkspaceExtensions.projitems +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/CSharpWorkspaceExtensions.projitems @@ -69,6 +69,7 @@ + @@ -83,12 +84,12 @@ + - diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/CodeGeneration/AttributeGenerator.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/CodeGeneration/AttributeGenerator.cs index 24d4b62d7382f..5746ccb5dbe43 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/CodeGeneration/AttributeGenerator.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/CodeGeneration/AttributeGenerator.cs @@ -8,6 +8,7 @@ using Microsoft.CodeAnalysis.CSharp.Extensions; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Editing; +using Microsoft.CodeAnalysis.PooledObjects; using Roslyn.Utilities; using static Microsoft.CodeAnalysis.CodeGeneration.CodeGenerationHelpers; @@ -63,38 +64,60 @@ public static SyntaxList GenerateAttributeLists( if (IsCompilerInternalAttribute(attribute)) return null; - if (!info.Context.MergeAttributes) - { - var reusableSyntax = GetReuseableSyntaxNodeForAttribute(attribute, info); - if (reusableSyntax != null) - { - return reusableSyntax; - } - } + var reusableSyntax = GetReuseableSyntaxNodeForAttribute(attribute); + if (info.Context.ReuseSyntax && reusableSyntax != null) + return reusableSyntax; if (attribute.AttributeClass == null) return null; - var attributeArguments = GenerateAttributeArgumentList(info.Generator, attribute); + var attributeArguments = GenerateAttributeArgumentList( + attribute, reusableSyntax); return attribute.AttributeClass.GenerateTypeSyntax() is NameSyntax nameSyntax ? Attribute(nameSyntax, attributeArguments) : null; } - private static AttributeArgumentListSyntax? GenerateAttributeArgumentList(SyntaxGenerator generator, AttributeData attribute) + private static AttributeArgumentListSyntax? GenerateAttributeArgumentList( + AttributeData attribute, AttributeSyntax? existingSyntax) { if (attribute.ConstructorArguments.Length == 0 && attribute.NamedArguments.Length == 0) return null; - var arguments = new List(); - arguments.AddRange(attribute.ConstructorArguments.Select(c => - AttributeArgument(ExpressionGenerator.GenerateExpression(generator, c)))); + using var _ = ArrayBuilder.GetInstance(out var arguments); - arguments.AddRange(attribute.NamedArguments.Select(kvp => - AttributeArgument( - NameEquals(IdentifierName(kvp.Key)), null, - ExpressionGenerator.GenerateExpression(generator, kvp.Value)))); + foreach (var argument in attribute.ConstructorArguments) + arguments.Add(AttributeArgument(GenerateAttributeSyntax(argument))); + + foreach (var argument in attribute.NamedArguments) + { + arguments.Add(AttributeArgument( + NameEquals(IdentifierName(argument.Key)), + nameColon: null, + GenerateAttributeSyntax(argument.Value))); + } - return AttributeArgumentList([.. arguments]); + return AttributeArgumentList(SeparatedList(arguments)); + + ExpressionSyntax GenerateAttributeSyntax(TypedConstant constant) + { + // In the case of a string constant with value "x", see if the originating syntax was a `nameof(x)` + // expression and attempt to preserve that. + if (existingSyntax?.ArgumentList != null && constant.Value is string stringValue) + { + foreach (var existingArgument in existingSyntax.ArgumentList.Arguments) + { + if (existingArgument.Expression is InvocationExpressionSyntax { ArgumentList.Arguments: [{ Expression: var nameofArgument }] } invocation && + invocation.IsNameOfInvocation()) + { + var inferredName = nameofArgument.TryGetInferredMemberName(); + if (inferredName == stringValue) + return existingArgument.Expression.WithoutTrivia(); + } + } + } + + return ExpressionGenerator.GenerateExpression(constant); + } } } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/CodeGeneration/CSharpCodeGenerationService.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/CodeGeneration/CSharpCodeGenerationService.cs index fcc39d5ffff17..2a2dace9c17a9 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/CodeGeneration/CSharpCodeGenerationService.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/CodeGeneration/CSharpCodeGenerationService.cs @@ -325,7 +325,7 @@ public override TDeclarationNode AddAttributes( throw new ArgumentException("target"); } - var attributeSyntaxList = AttributeGenerator.GenerateAttributeLists(attributes.ToImmutableArray(), info, target).ToArray(); + var attributeSyntaxList = AttributeGenerator.GenerateAttributeLists([.. attributes], info, target).ToArray(); return destination switch { @@ -344,20 +344,22 @@ protected override TDeclarationNode AddMembers(TDeclarationNod if (destination is EnumDeclarationSyntax enumDeclaration) { - return Cast(enumDeclaration.AddMembers(members.Cast().ToArray())); + enumDeclaration.EnsureOpenAndCloseBraceTokens(); + return Cast(enumDeclaration.AddMembers([.. members.Cast()])); } else if (destination is TypeDeclarationSyntax typeDeclaration) { - return Cast(typeDeclaration.AddMembers(members.Cast().ToArray())); + typeDeclaration = typeDeclaration.EnsureOpenAndCloseBraceTokens(); + return Cast(typeDeclaration.AddMembers([.. members.Cast()])); } else if (destination is BaseNamespaceDeclarationSyntax namespaceDeclaration) { - return Cast(namespaceDeclaration.AddMembers(members.Cast().ToArray())); + return Cast(namespaceDeclaration.AddMembers([.. members.Cast()])); } else { return Cast(Cast(destination) - .AddMembers(members.Cast().ToArray())); + .AddMembers([.. members.Cast()])); } } @@ -580,11 +582,33 @@ private static TDeclarationNode AddStatementsToBaseMethodDeclaration(finalMember); } + public static BlockSyntax AddStatementsToBlock(BlockSyntax block, IEnumerable statements) + { + var statementsArray = StatementGenerator.GenerateStatements(statements); + if (statementsArray.Count > 0) + { + var closeBraceTrivia = block.CloseBraceToken.LeadingTrivia; + var lastEndIf = closeBraceTrivia.LastOrDefault(t => t.GetStructure() is EndIfDirectiveTriviaSyntax); + if (lastEndIf != default) + { + var splitIndex = closeBraceTrivia.IndexOf(lastEndIf) + 1; + + statementsArray = statementsArray.Replace( + statementsArray[0], + statementsArray[0].WithPrependedLeadingTrivia(closeBraceTrivia.Take(splitIndex))); + block = block.WithCloseBraceToken( + block.CloseBraceToken.WithLeadingTrivia(closeBraceTrivia.Skip(splitIndex))); + } + } + + return block.WithStatements(block.Statements.AddRange(statementsArray)); + } + private static TDeclarationNode AddStatementsToLocalFunctionStatement( TDeclarationNode destinationMember, IEnumerable statements, LocalFunctionStatementSyntax localFunctionStatement) where TDeclarationNode : SyntaxNode { @@ -601,7 +625,7 @@ private static TDeclarationNode AddStatementsToLocalFunctionStatement(finalMember); } @@ -626,7 +650,7 @@ private static TDeclarationNode AddStatementsToAnonymousFunctions(finalMember); } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/CodeGeneration/CSharpFlagsEnumGenerator.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/CodeGeneration/CSharpFlagsEnumGenerator.cs index d6bf932c2a094..32b8c14c1e9ca 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/CodeGeneration/CSharpFlagsEnumGenerator.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/CodeGeneration/CSharpFlagsEnumGenerator.cs @@ -4,11 +4,10 @@ using Microsoft.CodeAnalysis.CodeGeneration; using Microsoft.CodeAnalysis.Editing; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CSharp.CodeGeneration; -internal class CSharpFlagsEnumGenerator : AbstractFlagsEnumGenerator +internal sealed class CSharpFlagsEnumGenerator : AbstractFlagsEnumGenerator { public static readonly CSharpFlagsEnumGenerator Instance = new(); @@ -16,14 +15,16 @@ private CSharpFlagsEnumGenerator() { } + protected override SyntaxGeneratorInternal SyntaxGenerator + => CSharpSyntaxGeneratorInternal.Instance; + protected override SyntaxNode CreateExplicitlyCastedLiteralValue( - SyntaxGenerator generator, INamedTypeSymbol enumType, SpecialType underlyingSpecialType, object constantValue) { var expression = ExpressionGenerator.GenerateNonEnumValueExpression( - generator, enumType.EnumUnderlyingType, constantValue, canUseFieldReference: true); + enumType.EnumUnderlyingType, constantValue, canUseFieldReference: true); var constantValueULong = underlyingSpecialType.ConvertUnderlyingValueToUInt64(constantValue); if (constantValueULong == 0) @@ -32,7 +33,7 @@ protected override SyntaxNode CreateExplicitlyCastedLiteralValue( return expression; } - return generator.CastExpression(enumType, expression); + return this.SyntaxGenerator.CastExpression(enumType, expression); } protected override bool IsValidName(INamedTypeSymbol enumType, string name) diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/CodeGeneration/ConversionGenerator.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/CodeGeneration/ConversionGenerator.cs index d8fa523840519..e40946c3756a7 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/CodeGeneration/ConversionGenerator.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/CodeGeneration/ConversionGenerator.cs @@ -3,12 +3,11 @@ // See the LICENSE file in the project root for more information. using System.Collections.Generic; -using System.Linq; using System.Threading; using Microsoft.CodeAnalysis.CodeGeneration; using Microsoft.CodeAnalysis.CSharp.Extensions; using Microsoft.CodeAnalysis.CSharp.Syntax; - +using Microsoft.CodeAnalysis.Shared.Collections; using static Microsoft.CodeAnalysis.CodeGeneration.CodeGenerationHelpers; using static Microsoft.CodeAnalysis.CSharp.CodeGeneration.CSharpCodeGenerationHelpers; @@ -61,16 +60,18 @@ private static ConversionOperatorDeclarationSyntax GenerateConversionDeclaration ? CheckedKeyword : default; + var isExplicit = method.ExplicitInterfaceImplementations.Length > 0; var hasNoBody = !info.Context.GenerateMethodBodies || method.IsExtern; + var declaration = ConversionOperatorDeclaration( attributeLists: AttributeGenerator.GenerateAttributeLists(method.GetAttributes(), info), - modifiers: GenerateModifiers(destination, method), + modifiers: GenerateModifiers(method, destination), implicitOrExplicitKeyword: keyword, explicitInterfaceSpecifier: GenerateExplicitInterfaceSpecifier(method.ExplicitInterfaceImplementations), operatorKeyword: OperatorKeyword, checkedKeyword: checkedKeyword, type: method.ReturnType.GenerateTypeSyntax(), - parameterList: ParameterGenerator.GenerateParameterList(method.Parameters, isExplicit: false, info: info), + parameterList: ParameterGenerator.GenerateParameterList(method.Parameters, isExplicit: isExplicit, info: info), body: hasNoBody ? null : StatementGenerator.GenerateBlock(method), expressionBody: null, semicolonToken: hasNoBody ? SemicolonToken : default); @@ -98,19 +99,22 @@ private static ConversionOperatorDeclarationSyntax UseExpressionBodyIfDesired( return declaration; } - private static SyntaxTokenList GenerateModifiers(CodeGenerationDestination destination, IMethodSymbol method) + private static SyntaxTokenList GenerateModifiers(IMethodSymbol method, CodeGenerationDestination destination) { - // Only "static" allowed if we're an explicit impl. - if (method.ExplicitInterfaceImplementations.Any()) - { - return method.IsStatic ? [StaticKeyword] : []; - } - else - { - // If these appear in interfaces they must be static abstract - return destination is CodeGenerationDestination.InterfaceType - ? ([StaticKeyword, AbstractKeyword]) - : ([PublicKeyword, StaticKeyword]); - } + // If these appear in interfaces they must be static abstract + if (destination is CodeGenerationDestination.InterfaceType) + return [StaticKeyword, AbstractKeyword]; + + using var tokens = TemporaryArray.Empty; + + if (method.ExplicitInterfaceImplementations.Length == 0) + tokens.Add(PublicKeyword); + + tokens.Add(StaticKeyword); + + if (method.IsAbstract) + tokens.Add(AbstractKeyword); + + return [.. tokens.ToImmutableAndClear()]; } } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/CodeGeneration/EnumMemberGenerator.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/CodeGeneration/EnumMemberGenerator.cs index 8e44b135cd38b..5abbf3f7fc960 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/CodeGeneration/EnumMemberGenerator.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/CodeGeneration/EnumMemberGenerator.cs @@ -62,7 +62,7 @@ public static EnumMemberDeclarationSyntax GenerateEnumMemberDeclaration( return reusableSyntax; } - var value = CreateEnumMemberValue(info.Generator, destination, enumMember); + var value = CreateEnumMemberValue(destination, enumMember); var member = EnumMemberDeclaration(enumMember.Name.ToIdentifierToken()) .WithEqualsValue(value == null ? null : EqualsValueClause(value: value)); @@ -71,7 +71,7 @@ public static EnumMemberDeclarationSyntax GenerateEnumMemberDeclaration( } private static ExpressionSyntax? CreateEnumMemberValue( - SyntaxGenerator generator, EnumDeclarationSyntax? destination, IFieldSymbol enumMember) + EnumDeclarationSyntax? destination, IFieldSymbol enumMember) { if (!enumMember.HasConstantValue) { @@ -161,7 +161,6 @@ not long and var underlyingType = namedType?.EnumUnderlyingType; return ExpressionGenerator.GenerateNonEnumValueExpression( - generator, underlyingType, enumMember.ConstantValue, canUseFieldReference: true); diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/CodeGeneration/EventGenerator.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/CodeGeneration/EventGenerator.cs index 6891dcb45c718..e8633f700d279 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/CodeGeneration/EventGenerator.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/CodeGeneration/EventGenerator.cs @@ -107,7 +107,8 @@ public static MemberDeclarationSyntax GenerateEventDeclaration( ? GenerateEventFieldDeclaration(@event, destination, info) : GenerateEventDeclarationWorker(@event, destination, info); - return ConditionallyAddDocumentationCommentTo(declaration, @event, info, cancellationToken); + return AddAnnotationsTo(@event, + ConditionallyAddDocumentationCommentTo(declaration, @event, info, cancellationToken)); } private static MemberDeclarationSyntax GenerateEventFieldDeclaration( @@ -128,8 +129,9 @@ private static MemberDeclarationSyntax GenerateEventDeclarationWorker( { var explicitInterfaceSpecifier = GenerateExplicitInterfaceSpecifier(@event.ExplicitInterfaceImplementations); + var isExplicit = explicitInterfaceSpecifier is not null; return AddFormatterAndCodeGeneratorAnnotationsTo(EventDeclaration( - attributeLists: AttributeGenerator.GenerateAttributeLists(@event.GetAttributes(), info), + attributeLists: GenerateAttributes(@event, isExplicit, info), modifiers: GenerateModifiers(@event, destination, info), type: @event.Type.GenerateTypeSyntax(), explicitInterfaceSpecifier: explicitInterfaceSpecifier, @@ -137,6 +139,23 @@ private static MemberDeclarationSyntax GenerateEventDeclarationWorker( accessorList: GenerateAccessorList(@event, destination, info))); } + private static SyntaxList GenerateAttributes( + IEventSymbol @event, bool isExplicit, CSharpCodeGenerationContextInfo info) + { + if (isExplicit) + { + return default; + } + + var attributes = @event.GetAttributes(); + if (attributes.Length == 0) + { + return default; + } + + return AttributeGenerator.GenerateAttributeLists(attributes, info); + } + private static AccessorListSyntax GenerateAccessorList( IEventSymbol @event, CodeGenerationDestination destination, CSharpCodeGenerationContextInfo info) { diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/CodeGeneration/ExpressionGenerator.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/CodeGeneration/ExpressionGenerator.cs index 1174ff620b305..fc72ce68b0246 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/CodeGeneration/ExpressionGenerator.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/CodeGeneration/ExpressionGenerator.cs @@ -9,7 +9,6 @@ using Microsoft.CodeAnalysis.CodeGeneration; using Microsoft.CodeAnalysis.CSharp.Extensions; using Microsoft.CodeAnalysis.CSharp.Syntax; -using Microsoft.CodeAnalysis.Editing; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Simplification; using Roslyn.Utilities; @@ -23,13 +22,13 @@ namespace Microsoft.CodeAnalysis.CSharp.CodeGeneration; internal static class ExpressionGenerator { public static ExpressionSyntax GenerateExpression( - SyntaxGenerator generator, TypedConstant typedConstant) + TypedConstant typedConstant) { switch (typedConstant.Kind) { case TypedConstantKind.Primitive: case TypedConstantKind.Enum: - return GenerateExpression(generator, typedConstant.Type, typedConstant.Value, canUseFieldReference: true); + return GenerateExpression(typedConstant.Type, typedConstant.Value, canUseFieldReference: true); case TypedConstantKind.Type: return typedConstant.Value is ITypeSymbol typeSymbol @@ -41,7 +40,7 @@ public static ExpressionSyntax GenerateExpression( ? GenerateNullLiteral() : ImplicitArrayCreationExpression( InitializerExpression(SyntaxKind.ArrayInitializerExpression, - [.. typedConstant.Values.Select(v => GenerateExpression(generator, v))])); + [.. typedConstant.Values.Select(v => GenerateExpression(v))])); default: return GenerateNullLiteral(); @@ -52,7 +51,6 @@ private static ExpressionSyntax GenerateNullLiteral() => LiteralExpression(SyntaxKind.NullLiteralExpression); internal static ExpressionSyntax GenerateExpression( - SyntaxGenerator generator, ITypeSymbol? type, object? value, bool canUseFieldReference) @@ -60,21 +58,21 @@ internal static ExpressionSyntax GenerateExpression( if (type != null && value != null) { if (type is INamedTypeSymbol { TypeKind: TypeKind.Enum } enumType) - return (ExpressionSyntax)CSharpFlagsEnumGenerator.Instance.CreateEnumConstantValue(generator, enumType, value); + return (ExpressionSyntax)CSharpFlagsEnumGenerator.Instance.CreateEnumConstantValue(enumType, value); if (type.IsNullable(out var underlyingType)) { // If the type of the argument is T?, then the type of the supplied default value can either be T // (e.g. int? x = 5) or it can be T? (e.g. SomeStruct? x = null). The below statement handles the case // where the type of the supplied default value is T. - return GenerateExpression(generator, underlyingType, value, canUseFieldReference); + return GenerateExpression(underlyingType, value, canUseFieldReference); } } - return GenerateNonEnumValueExpression(generator, type, value, canUseFieldReference); + return GenerateNonEnumValueExpression(type, value, canUseFieldReference); } - internal static ExpressionSyntax GenerateNonEnumValueExpression(SyntaxGenerator generator, ITypeSymbol? type, object? value, bool canUseFieldReference) + internal static ExpressionSyntax GenerateNonEnumValueExpression(ITypeSymbol? type, object? value, bool canUseFieldReference) => value switch { bool val => GenerateBooleanLiteralExpression(val), @@ -93,7 +91,7 @@ internal static ExpressionSyntax GenerateNonEnumValueExpression(SyntaxGenerator decimal val => GenerateLiteralExpression(type, val, LiteralSpecialValues.DecimalSpecialValues, formatString: null, canUseFieldReference, Literal, x => x < 0, x => -x, integerMinValueString: null), _ => type == null || type.IsReferenceType || type is IPointerTypeSymbol || type.IsNullable() ? GenerateNullLiteral() - : (ExpressionSyntax)generator.DefaultExpression(type), + : (ExpressionSyntax)CSharpSyntaxGeneratorInternal.Instance.DefaultExpression(type), }; private static ExpressionSyntax GenerateBooleanLiteralExpression(bool val) diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/CodeGeneration/FieldGenerator.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/CodeGeneration/FieldGenerator.cs index f6950b2e9d564..710d68afe5e25 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/CodeGeneration/FieldGenerator.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/CodeGeneration/FieldGenerator.cs @@ -95,7 +95,7 @@ public static FieldDeclarationSyntax GenerateFieldDeclaration( var initializer = CodeGenerationFieldInfo.GetInitializer(field) is ExpressionSyntax initializerNode ? EqualsValueClause(initializerNode) - : GenerateEqualsValue(info.Generator, field); + : GenerateEqualsValue(field); var fieldDeclaration = FieldDeclaration( AttributeGenerator.GenerateAttributeLists(field.GetAttributes(), info), @@ -108,12 +108,12 @@ public static FieldDeclarationSyntax GenerateFieldDeclaration( ConditionallyAddDocumentationCommentTo(fieldDeclaration, field, info, cancellationToken)); } - private static EqualsValueClauseSyntax? GenerateEqualsValue(SyntaxGenerator generator, IFieldSymbol field) + private static EqualsValueClauseSyntax? GenerateEqualsValue(IFieldSymbol field) { if (field.HasConstantValue) { var canUseFieldReference = field.Type != null && !field.Type.Equals(field.ContainingType); - return EqualsValueClause(ExpressionGenerator.GenerateExpression(generator, field.Type, field.ConstantValue, canUseFieldReference)); + return EqualsValueClause(ExpressionGenerator.GenerateExpression(field.Type, field.ConstantValue, canUseFieldReference)); } return null; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/CodeGeneration/MethodGenerator.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/CodeGeneration/MethodGenerator.cs index 96beaea6d97c0..a038c8dc0763b 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/CodeGeneration/MethodGenerator.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/CodeGeneration/MethodGenerator.cs @@ -6,6 +6,7 @@ using System.Collections.Immutable; using System.Diagnostics; using System.Linq; +using System.Runtime.CompilerServices; using System.Threading; using Microsoft.CodeAnalysis.CodeGeneration; using Microsoft.CodeAnalysis.CSharp.Extensions; @@ -119,14 +120,17 @@ private static MethodDeclarationSyntax GenerateMethodDeclarationWorker( var explicitInterfaceSpecifier = GenerateExplicitInterfaceSpecifier(method.ExplicitInterfaceImplementations); + var isExplicit = explicitInterfaceSpecifier != null; + var parameters = method.Parameters.SelectAsArray(static (p, destination) => FilterAttributes(p, destination), destination); + var methodDeclaration = MethodDeclaration( - attributeLists: GenerateAttributes(method, info, explicitInterfaceSpecifier != null), + attributeLists: GenerateAttributes(method, isExplicit, info), modifiers: GenerateModifiers(method, destination, info), returnType: method.GenerateReturnTypeSyntax(), explicitInterfaceSpecifier: explicitInterfaceSpecifier, identifier: method.Name.ToIdentifierToken(), typeParameterList: GenerateTypeParameterList(method, info), - parameterList: ParameterGenerator.GenerateParameterList(method.Parameters, explicitInterfaceSpecifier != null, info), + parameterList: ParameterGenerator.GenerateParameterList(parameters, isExplicit: isExplicit, info), constraintClauses: GenerateConstraintClauses(method), body: hasNoBody ? null : StatementGenerator.GenerateBlock(method), expressionBody: null, @@ -136,6 +140,27 @@ private static MethodDeclarationSyntax GenerateMethodDeclarationWorker( return AddFormatterAndCodeGeneratorAnnotationsTo(methodDeclaration); } + private static IParameterSymbol FilterAttributes(IParameterSymbol parameter, CodeGenerationDestination destination) + => parameter.WithAttributes(parameter.GetAttributes().WhereAsArray(static (a, destination) => FilterAttribute(a, destination), destination)); + + private static bool FilterAttribute(AttributeData attribute, CodeGenerationDestination destination) + { + if (destination is CodeGenerationDestination.InterfaceType) + { + // EnumeratorCancellation serves no purpose in an interface. Filter it out. + return attribute.AttributeClass is not + { + Name: nameof(EnumeratorCancellationAttribute), + ContainingNamespace.Name: nameof(System.Runtime.CompilerServices), + ContainingNamespace.ContainingNamespace.Name: nameof(System.Runtime), + ContainingNamespace.ContainingNamespace.ContainingNamespace.Name: nameof(System), + ContainingNamespace.ContainingNamespace.ContainingNamespace.ContainingNamespace.IsGlobalNamespace: true, + }; + } + + return true; + } + private static LocalFunctionStatementSyntax GenerateLocalFunctionDeclarationWorker( IMethodSymbol method, CodeGenerationDestination destination, CSharpCodeGenerationContextInfo info, CancellationToken cancellationToken) @@ -192,16 +217,18 @@ private static LocalFunctionStatementSyntax UseExpressionBodyIfDesired( } private static SyntaxList GenerateAttributes( - IMethodSymbol method, CSharpCodeGenerationContextInfo info, bool isExplicit) + IMethodSymbol method, bool isExplicit, CSharpCodeGenerationContextInfo info) { - var attributes = new List(); - - if (!isExplicit) + if (isExplicit) { - attributes.AddRange(AttributeGenerator.GenerateAttributeLists(method.GetAttributes(), info)); - attributes.AddRange(AttributeGenerator.GenerateAttributeLists(method.GetReturnTypeAttributes(), info, ReturnKeyword)); + return default; } + var attributes = new List(); + + attributes.AddRange(AttributeGenerator.GenerateAttributeLists(method.GetAttributes(), info)); + attributes.AddRange(AttributeGenerator.GenerateAttributeLists(method.GetReturnTypeAttributes(), info, ReturnKeyword)); + return [.. attributes]; } @@ -230,12 +257,7 @@ private static SyntaxList GenerateDefaultCo if (!referencedTypeParameters.Contains(typeParameter)) continue; - var constraint = typeParameter switch - { - { HasReferenceTypeConstraint: true } => s_classConstraint, - { HasValueTypeConstraint: true } => s_structConstraint, - _ => s_defaultConstraint - }; + var constraint = GetConstraint(typeParameter); listOfClauses.Add(TypeParameterConstraintClause( typeParameter.Name.ToIdentifierName(), @@ -245,6 +267,52 @@ private static SyntaxList GenerateDefaultCo return [.. listOfClauses]; } + private static TypeParameterConstraintSyntax GetConstraint(ITypeParameterSymbol typeParameter) + { + using var _ = PooledHashSet.GetInstance(out var visited); + var constraint = GetConstraintRecursive(typeParameter); + + return constraint ?? s_defaultConstraint; + + TypeParameterConstraintSyntax? GetConstraintRecursive(ITypeParameterSymbol typeParameter) + { + if (visited.Add(typeParameter)) + { + // If it is explicitly marked as `T : struct` or `T : class` then we want to have the same constraint on the override. + if (typeParameter.HasValueTypeConstraint) + return s_structConstraint; + + if (typeParameter.HasReferenceTypeConstraint) + return s_classConstraint; + + foreach (var constraintType in typeParameter.ConstraintTypes) + { + // If we ended up being constrained on a value type, then we have to have the `T : struct` + // constraint to align with that. + if (constraintType.IsValueType) + return s_structConstraint; + + // For all reference types *except* interfaces, we want the `T : class` constraint. An interface + // can be implemented by a value type or a referernce type, so it adds no information to the + // constraints. + if (constraintType.IsReferenceType && constraintType.TypeKind != TypeKind.Interface) + return s_classConstraint; + + // If we have `where T : U` then peek into the other contraint to see if it adds information. + if (constraintType is ITypeParameterSymbol constraintTypeParameter) + { + var constraint = GetConstraintRecursive(constraintTypeParameter); + if (constraint != null) + return constraint; + } + } + } + + // We learned nothing from this constraint. + return null; + } + } + private static TypeParameterListSyntax? GenerateTypeParameterList( IMethodSymbol method, CSharpCodeGenerationContextInfo info) { diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/CodeGeneration/OperatorGenerator.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/CodeGeneration/OperatorGenerator.cs index 1e0c1fd58a445..cc7576eadbb94 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/CodeGeneration/OperatorGenerator.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/CodeGeneration/OperatorGenerator.cs @@ -89,6 +89,7 @@ private static OperatorDeclarationSyntax GenerateOperatorDeclarationWorker( ? CheckedKeyword : default; + var isExplicit = method.ExplicitInterfaceImplementations.Length > 0; var operatorDecl = OperatorDeclaration( attributeLists: AttributeGenerator.GenerateAttributeLists(method.GetAttributes(), info), modifiers: GenerateModifiers(method, destination, hasNoBody), @@ -97,7 +98,7 @@ private static OperatorDeclarationSyntax GenerateOperatorDeclarationWorker( operatorKeyword: OperatorKeyword, checkedKeyword: checkedToken, operatorToken: operatorToken, - parameterList: ParameterGenerator.GenerateParameterList(method.Parameters, isExplicit: false, info: info), + parameterList: ParameterGenerator.GenerateParameterList(method.Parameters, isExplicit: isExplicit, info: info), body: hasNoBody ? null : StatementGenerator.GenerateBlock(method), expressionBody: null, semicolonToken: hasNoBody ? SemicolonToken : new SyntaxToken()); diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/CodeGeneration/ParameterGenerator.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/CodeGeneration/ParameterGenerator.cs index 4335961372e21..fde1d2f232ee3 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/CodeGeneration/ParameterGenerator.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/CodeGeneration/ParameterGenerator.cs @@ -68,8 +68,8 @@ internal static ParameterSyntax GetParameter(IParameterSymbol parameter, CSharpC return Parameter(parameter.Name.ToIdentifierToken()) .WithAttributeLists(GenerateAttributes(parameter, isExplicit, info)) .WithModifiers(GenerateModifiers(parameter, isFirstParam)) - .WithType(parameter.Type.GenerateTypeSyntax()) - .WithDefault(GenerateEqualsValueClause(info.Generator, parameter, isExplicit, seenOptional)); + .WithType(parameter.Type.GenerateTypeSyntax(allowVar: false)) + .WithDefault(GenerateEqualsValueClause(parameter, isExplicit, seenOptional)); } private static SyntaxTokenList GenerateModifiers( @@ -84,16 +84,10 @@ parameter.ContainingSymbol is IMethodSymbol methodSymbol && list = list.Add(ThisKeyword); } - if (parameter.IsParams) - { - list = list.Add(ParamsKeyword); - } - return list; } private static EqualsValueClauseSyntax? GenerateEqualsValueClause( - SyntaxGenerator generator, IParameterSymbol parameter, bool isExplicit, bool seenOptional) @@ -107,15 +101,15 @@ parameter.ContainingSymbol is IMethodSymbol methodSymbol && return null; return EqualsValueClause( - GenerateEqualsValueClauseWorker(generator, parameter, defaultValue)); + GenerateEqualsValueClauseWorker(parameter, defaultValue)); } } return null; } - private static ExpressionSyntax GenerateEqualsValueClauseWorker(SyntaxGenerator generator, IParameterSymbol parameter, object? value) - => ExpressionGenerator.GenerateExpression(generator, parameter.Type, value, canUseFieldReference: true); + private static ExpressionSyntax GenerateEqualsValueClauseWorker(IParameterSymbol parameter, object? value) + => ExpressionGenerator.GenerateExpression(parameter.Type, value, canUseFieldReference: true); private static SyntaxList GenerateAttributes( IParameterSymbol parameter, bool isExplicit, CSharpCodeGenerationContextInfo info) diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/CodeGeneration/PropertyGenerator.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/CodeGeneration/PropertyGenerator.cs index fb5130ab4ee32..8d968e130df2d 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/CodeGeneration/PropertyGenerator.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/CodeGeneration/PropertyGenerator.cs @@ -94,12 +94,13 @@ private static MemberDeclarationSyntax GenerateIndexerDeclaration( { var explicitInterfaceSpecifier = GenerateExplicitInterfaceSpecifier(property.ExplicitInterfaceImplementations); + var isExplicit = explicitInterfaceSpecifier is not null; var declaration = IndexerDeclaration( - attributeLists: AttributeGenerator.GenerateAttributeLists(property.GetAttributes(), info), + attributeLists: GenerateAttributes(property, isExplicit, info), modifiers: GenerateModifiers(property, destination, info), type: GenerateTypeSyntax(property), explicitInterfaceSpecifier: explicitInterfaceSpecifier, - parameterList: ParameterGenerator.GenerateBracketedParameterList(property.Parameters, explicitInterfaceSpecifier != null, info), + parameterList: ParameterGenerator.GenerateBracketedParameterList(property.Parameters, isExplicit: isExplicit, info), accessorList: GenerateAccessorList(property, destination, info, cancellationToken)); declaration = UseExpressionBodyIfDesired(info, declaration, cancellationToken); @@ -107,7 +108,7 @@ private static MemberDeclarationSyntax GenerateIndexerDeclaration( AddAnnotationsTo(property, declaration)); } - private static MemberDeclarationSyntax GeneratePropertyDeclaration( + private static PropertyDeclarationSyntax GeneratePropertyDeclaration( IPropertySymbol property, CodeGenerationDestination destination, CSharpCodeGenerationContextInfo info, CancellationToken cancellationToken) { @@ -117,10 +118,11 @@ private static MemberDeclarationSyntax GeneratePropertyDeclaration( var explicitInterfaceSpecifier = GenerateExplicitInterfaceSpecifier(property.ExplicitInterfaceImplementations); + var isExplicit = explicitInterfaceSpecifier is not null; var accessorList = GenerateAccessorList(property, destination, info, cancellationToken); var propertyDeclaration = PropertyDeclaration( - attributeLists: AttributeGenerator.GenerateAttributeLists(property.GetAttributes(), info), + attributeLists: GenerateAttributes(property, isExplicit, info), modifiers: GenerateModifiers(property, destination, info), type: GenerateTypeSyntax(property), explicitInterfaceSpecifier: explicitInterfaceSpecifier, @@ -136,6 +138,23 @@ private static MemberDeclarationSyntax GeneratePropertyDeclaration( AddAnnotationsTo(property, propertyDeclaration)); } + private static SyntaxList GenerateAttributes( + IPropertySymbol property, bool isExplicit, CSharpCodeGenerationContextInfo info) + { + if (isExplicit) + { + return default; + } + + var attributes = property.GetAttributes(); + if (attributes.Length == 0) + { + return default; + } + + return AttributeGenerator.GenerateAttributeLists(attributes, info); + } + private static TypeSyntax GenerateTypeSyntax(IPropertySymbol property) { var returnType = property.Type; @@ -179,19 +198,15 @@ private static bool TryGetExpressionBody( private static PropertyDeclarationSyntax UseExpressionBodyIfDesired( CSharpCodeGenerationContextInfo info, PropertyDeclarationSyntax declaration, CancellationToken cancellationToken) { - if (declaration.ExpressionBody == null) + if (declaration.ExpressionBody == null && + declaration.Initializer == null && + TryGetExpressionBody( + declaration, info.LanguageVersion, info.Options.PreferExpressionBodiedProperties.Value, cancellationToken, + out var expressionBody, out var semicolonToken)) { - if (declaration.Initializer == null) - { - if (TryGetExpressionBody( - declaration, info.LanguageVersion, info.Options.PreferExpressionBodiedProperties.Value, cancellationToken, - out var expressionBody, out var semicolonToken)) - { - declaration = declaration.WithAccessorList(null) - .WithExpressionBody(expressionBody) - .WithSemicolonToken(semicolonToken); - } - } + declaration = declaration.WithAccessorList(null) + .WithExpressionBody(expressionBody) + .WithSemicolonToken(semicolonToken); } return declaration; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Extensions/BaseNamespaceDeclarationSyntaxExtensions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Extensions/BaseNamespaceDeclarationSyntaxExtensions.cs index 4fb6271a73530..55168f9a48bdf 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Extensions/BaseNamespaceDeclarationSyntaxExtensions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Extensions/BaseNamespaceDeclarationSyntaxExtensions.cs @@ -24,7 +24,7 @@ public static TNamespaceDeclarationSyntax AddUsingDirectives u.WithAdditionalAnnotations(annotations)).ToList(); + newUsings = [.. newUsings.Select(u => u.WithAdditionalAnnotations(annotations))]; var newNamespace = namespaceDeclaration.WithUsings([.. newUsings]); return (TNamespaceDeclarationSyntax)newNamespace; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Extensions/CompilationUnitSyntaxExtensions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Extensions/CompilationUnitSyntaxExtensions.cs index a67af769897d3..19ef52954751c 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Extensions/CompilationUnitSyntaxExtensions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Extensions/CompilationUnitSyntaxExtensions.cs @@ -18,15 +18,9 @@ namespace Microsoft.CodeAnalysis.CSharp.Extensions; internal static partial class CompilationUnitSyntaxExtensions { - public static bool CanAddUsingDirectives(this SyntaxNode contextNode, bool allowInHiddenRegions, CancellationToken cancellationToken) + public static bool CanAddUsingDirectives( + this SyntaxNode contextNode, bool allowInHiddenRegions, CancellationToken cancellationToken) { - var usingDirectiveAncestor = contextNode.GetAncestor(); - if (usingDirectiveAncestor?.Parent is CompilationUnitSyntax) - { - // We are inside a top level using directive (i.e. one that's directly in the compilation unit). - return false; - } - if (!allowInHiddenRegions && contextNode.SyntaxTree.HasHiddenRegions()) { var namespaceDeclaration = contextNode.GetInnermostNamespaceDeclarationWithUsings(); @@ -34,14 +28,7 @@ public static bool CanAddUsingDirectives(this SyntaxNode contextNode, bool allow var span = GetUsingsSpan(root, namespaceDeclaration); if (contextNode.SyntaxTree.OverlapsHiddenPosition(span, cancellationToken)) - { return false; - } - } - - if (cancellationToken.IsCancellationRequested) - { - return false; } return true; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Extensions/ContextQuery/SyntaxTreeExtensions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Extensions/ContextQuery/SyntaxTreeExtensions.cs index e35591ee10129..4e95eb1a04151 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Extensions/ContextQuery/SyntaxTreeExtensions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Extensions/ContextQuery/SyntaxTreeExtensions.cs @@ -1868,7 +1868,7 @@ token.Parent is ArgumentSyntax argument && } // scoped v| - if (token.IsKind(SyntaxKind.ScopedKeyword) && token.Parent is IncompleteMemberSyntax) + if (token.IsKind(SyntaxKind.ScopedKeyword) && token.Parent is IncompleteMemberSyntax or ScopedTypeSyntax) { return true; } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Extensions/ITypeSymbolExtensions.TypeSyntaxGeneratorVisitor.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Extensions/ITypeSymbolExtensions.TypeSyntaxGeneratorVisitor.cs index 22b6c9ab6bdce..304acc3ec1182 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Extensions/ITypeSymbolExtensions.TypeSyntaxGeneratorVisitor.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Extensions/ITypeSymbolExtensions.TypeSyntaxGeneratorVisitor.cs @@ -164,7 +164,7 @@ static FunctionPointerUnmanagedCallingConventionSyntax GetConventionForString(st var parameters = symbol.Signature.Parameters.Select(p => (p.Type, RefKindModifiers: CSharpSyntaxGeneratorInternal.GetParameterModifiers(p))) .Concat([( Type: symbol.Signature.ReturnType, - RefKindModifiers: CSharpSyntaxGeneratorInternal.GetParameterModifiers(isScoped: false, symbol.Signature.RefKind, forFunctionPointerReturnParameter: true))]) + RefKindModifiers: CSharpSyntaxGeneratorInternal.GetParameterModifiers(isScoped: false, symbol.Signature.RefKind, isParams: false, forFunctionPointerReturnParameter: true))]) .SelectAsArray(t => FunctionPointerParameter(t.Type.GenerateTypeSyntax()).WithModifiers(t.RefKindModifiers)); return AddInformationTo( diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Extensions/ITypeSymbolExtensions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Extensions/ITypeSymbolExtensions.cs index 5ad944b1633c9..b9610a98721e0 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Extensions/ITypeSymbolExtensions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Extensions/ITypeSymbolExtensions.cs @@ -72,9 +72,9 @@ private static TypeSyntax GenerateTypeSyntax( } public static TypeSyntax GenerateRefTypeSyntax( - this INamespaceOrTypeSymbol symbol) + this INamespaceOrTypeSymbol symbol, bool allowVar = true) { - var underlyingType = GenerateTypeSyntax(symbol) + var underlyingType = GenerateTypeSyntax(symbol, allowVar) .WithPrependedLeadingTrivia(ElasticMarker) .WithAdditionalAnnotations(Simplifier.Annotation); var refKeyword = RefKeyword; @@ -82,9 +82,9 @@ public static TypeSyntax GenerateRefTypeSyntax( } public static TypeSyntax GenerateRefReadOnlyTypeSyntax( - this INamespaceOrTypeSymbol symbol) + this INamespaceOrTypeSymbol symbol, bool allowVar = true) { - var underlyingType = GenerateTypeSyntax(symbol) + var underlyingType = GenerateTypeSyntax(symbol, allowVar) .WithPrependedLeadingTrivia(ElasticMarker) .WithAdditionalAnnotations(Simplifier.Annotation); var refKeyword = RefKeyword; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Extensions/SemanticModelExtensions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Extensions/SemanticModelExtensions.cs index 3f5b32a9b2233..579d936c6e8c2 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Extensions/SemanticModelExtensions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Extensions/SemanticModelExtensions.cs @@ -9,9 +9,9 @@ using System.Linq; using System.Threading; using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CodeGeneration; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Shared.Utilities; -using Microsoft.CodeAnalysis.Utilities; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CSharp @@ -68,9 +68,9 @@ public static ImmutableArray GenerateParameterNames( } public static ImmutableArray GenerateNames(IList reservedNames, ImmutableArray isFixed, ImmutableArray parameterNames) - => NameGenerator.EnsureUniqueness(parameterNames, isFixed) + => [.. NameGenerator.EnsureUniqueness(parameterNames, isFixed) .Select((name, index) => new ParameterName(name, isFixed[index])) - .Skip(reservedNames.Count).ToImmutableArray(); + .Skip(reservedNames.Count)]; public static ImmutableArray GenerateParameterNames( this SemanticModel semanticModel, diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Extensions/TypeSyntaxExtensions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Extensions/TypeSyntaxExtensions.cs index 9de84333a9b8b..86742c57226e1 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Extensions/TypeSyntaxExtensions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Extensions/TypeSyntaxExtensions.cs @@ -58,15 +58,15 @@ public static TypeSyntax GenerateReturnTypeSyntax(this IMethodSymbol method) if (method.ReturnsByRef) { - return returnType.GenerateRefTypeSyntax(); + return returnType.GenerateRefTypeSyntax(allowVar: false); } else if (method.ReturnsByRefReadonly) { - return returnType.GenerateRefReadOnlyTypeSyntax(); + return returnType.GenerateRefReadOnlyTypeSyntax(allowVar: false); } else { - return returnType.GenerateTypeSyntax(); + return returnType.GenerateTypeSyntax(allowVar: false); } } } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/LanguageServices/CSharpAddImportsService.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/LanguageServices/CSharpAddImportsService.cs index e99db49e025e5..49f49d397cb4f 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/LanguageServices/CSharpAddImportsService.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/LanguageServices/CSharpAddImportsService.cs @@ -21,15 +21,11 @@ namespace Microsoft.CodeAnalysis.CSharp.AddImport; [ExportLanguageService(typeof(IAddImportsService), LanguageNames.CSharp), Shared] -internal sealed class CSharpAddImportsService : AbstractAddImportsService< +[method: ImportingConstructor] +[method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] +internal sealed class CSharpAddImportsService() : AbstractAddImportsService< CompilationUnitSyntax, BaseNamespaceDeclarationSyntax, UsingDirectiveSyntax, ExternAliasDirectiveSyntax> { - [ImportingConstructor] - [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - public CSharpAddImportsService() - { - } - protected override string Language => LanguageNames.CSharp; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/LanguageServices/CSharpFileBannerFactsService.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/LanguageServices/CSharpFileBannerFactsService.cs index d30e052df0122..0bc6fe96e1e43 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/LanguageServices/CSharpFileBannerFactsService.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/LanguageServices/CSharpFileBannerFactsService.cs @@ -11,11 +11,6 @@ namespace Microsoft.CodeAnalysis.CSharp; [ExportLanguageService(typeof(IFileBannerFactsService), LanguageNames.CSharp), Shared] -internal class CSharpFileBannerFactsService : CSharpFileBannerFacts, IFileBannerFactsService -{ - [ImportingConstructor] - [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - public CSharpFileBannerFactsService() - { - } -} +[method: ImportingConstructor] +[method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] +internal sealed class CSharpFileBannerFactsService() : CSharpFileBannerFacts, IFileBannerFactsService; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/LanguageServices/CSharpSyntaxGeneratorInternal.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/LanguageServices/CSharpSyntaxGeneratorInternal.cs index 993aaf2805553..1f253c148da03 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/LanguageServices/CSharpSyntaxGeneratorInternal.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/LanguageServices/CSharpSyntaxGeneratorInternal.cs @@ -14,6 +14,8 @@ using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Operations; using Microsoft.CodeAnalysis.PooledObjects; +using Microsoft.CodeAnalysis.Shared.Extensions; +using Microsoft.CodeAnalysis.Simplification; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CSharp.CodeGeneration; @@ -21,14 +23,10 @@ namespace Microsoft.CodeAnalysis.CSharp.CodeGeneration; using static CSharpSyntaxTokens; [ExportLanguageService(typeof(SyntaxGeneratorInternal), LanguageNames.CSharp), Shared] -internal sealed class CSharpSyntaxGeneratorInternal : SyntaxGeneratorInternal +[method: ImportingConstructor] +[method: SuppressMessage("RoslynDiagnosticsReliability", "RS0033:Importing constructor should be [Obsolete]", Justification = "Incorrectly used in production code: https://github.com/dotnet/roslyn/issues/42839")] +internal sealed class CSharpSyntaxGeneratorInternal() : SyntaxGeneratorInternal { - [ImportingConstructor] - [SuppressMessage("RoslynDiagnosticsReliability", "RS0033:Importing constructor should be [Obsolete]", Justification = "Incorrectly used in production code: https://github.com/dotnet/roslyn/issues/42839")] - public CSharpSyntaxGeneratorInternal() - { - } - public static readonly SyntaxGeneratorInternal Instance = new CSharpSyntaxGeneratorInternal(); public override ISyntaxFacts SyntaxFacts @@ -135,10 +133,10 @@ public override SyntaxNode TypeParameterList(IEnumerable typeParameterNa internal static SyntaxTokenList GetParameterModifiers( IParameterSymbol parameter, bool forFunctionPointerReturnParameter = false) - => GetParameterModifiers(ParameterIsScoped(parameter), parameter.RefKind, forFunctionPointerReturnParameter); + => GetParameterModifiers(ParameterIsScoped(parameter), parameter.RefKind, parameter.IsParams, forFunctionPointerReturnParameter); internal static SyntaxTokenList GetParameterModifiers( - bool isScoped, RefKind refKind, bool forFunctionPointerReturnParameter = false) + bool isScoped, RefKind refKind, bool isParams, bool forFunctionPointerReturnParameter = false) { using var _ = ArrayBuilder.GetInstance(out var result); @@ -173,6 +171,9 @@ internal static SyntaxTokenList GetParameterModifiers( break; } + if (isParams) + result.Add(ParamsKeyword); + return SyntaxFactory.TokenList(result); } @@ -240,4 +241,100 @@ public override SyntaxNode UnaryPattern(SyntaxToken operatorToken, SyntaxNode pa => SyntaxFactory.UnaryPattern(operatorToken, (PatternSyntax)Parenthesize(pattern)); #endregion + + public override SyntaxNode CastExpression(SyntaxNode type, SyntaxNode expression) + => SyntaxFactory.CastExpression((TypeSyntax)type, (ExpressionSyntax)Parenthesize(expression)).WithAdditionalAnnotations(Simplifier.Annotation); + + public override SyntaxNode DefaultExpression(SyntaxNode type) + => SyntaxFactory.DefaultExpression((TypeSyntax)type).WithAdditionalAnnotations(Simplifier.Annotation); + + public override SyntaxNode DefaultExpression(ITypeSymbol type) + { + // If it's just a reference type, then "null" is the default expression for it. Note: + // this counts for actual reference type, or a type parameter with a 'class' constraint. + // Also, if it's a nullable type, then we can use "null". + if (type.IsReferenceType || + type is IPointerTypeSymbol || + type.IsNullable()) + { + return SyntaxFactory.LiteralExpression(SyntaxKind.NullLiteralExpression); + } + + switch (type.SpecialType) + { + case SpecialType.System_Boolean: + return SyntaxFactory.LiteralExpression(SyntaxKind.FalseLiteralExpression); + case SpecialType.System_SByte: + case SpecialType.System_Byte: + case SpecialType.System_Int16: + case SpecialType.System_UInt16: + case SpecialType.System_Int32: + case SpecialType.System_UInt32: + case SpecialType.System_Int64: + case SpecialType.System_UInt64: + case SpecialType.System_Decimal: + case SpecialType.System_Single: + case SpecialType.System_Double: + return SyntaxFactory.LiteralExpression( + SyntaxKind.NumericLiteralExpression, SyntaxFactory.Literal("0", 0)); + } + + // Default to a "default()" expression. + return DefaultExpression(type.GenerateTypeSyntax()); + } + + public override SyntaxNode TypeExpression(ITypeSymbol typeSymbol, RefKind refKind) + { + var type = typeSymbol.GenerateTypeSyntax(); + return refKind switch + { + RefKind.Ref => SyntaxFactory.RefType(type), + RefKind.RefReadOnly => SyntaxFactory.RefType(RefKeyword, ReadOnlyKeyword, type), + _ => type, + }; + } + + public override SyntaxNode MemberAccessExpressionWorker(SyntaxNode? expression, SyntaxNode simpleName) + { + // can only be null in VB + Contract.ThrowIfNull(expression); + + return SyntaxFactory.MemberAccessExpression( + SyntaxKind.SimpleMemberAccessExpression, + ParenthesizeLeft((ExpressionSyntax)expression), + (SimpleNameSyntax)simpleName); + } + + /// + /// Parenthesize the left hand size of a member access, invocation or element access expression + /// + internal static ExpressionSyntax ParenthesizeLeft(ExpressionSyntax expression) + { + if (expression is TypeSyntax || + expression.Kind() + is SyntaxKind.ThisExpression + or SyntaxKind.BaseExpression + or SyntaxKind.ParenthesizedExpression + or SyntaxKind.SimpleMemberAccessExpression + or SyntaxKind.InvocationExpression + or SyntaxKind.ElementAccessExpression + or SyntaxKind.MemberBindingExpression) + { + return expression; + } + + return (ExpressionSyntax)Parenthesize(expression); + } + + public override SyntaxNode BitwiseOrExpression(SyntaxNode left, SyntaxNode right) + => CreateBinaryExpression(SyntaxKind.BitwiseOrExpression, left, right); + + public static SyntaxNode CreateBinaryExpression(SyntaxKind syntaxKind, SyntaxNode left, SyntaxNode right) + => SyntaxFactory.BinaryExpression(syntaxKind, (ExpressionSyntax)Parenthesize(left), (ExpressionSyntax)Parenthesize(right)); + + public override SyntaxNode IdentifierName(string identifier) + => identifier.ToIdentifierName(); + + public override SyntaxNode ConvertExpression(SyntaxNode type, SyntaxNode expression) + => SyntaxFactory.CastExpression((TypeSyntax)type, (ExpressionSyntax)Parenthesize(expression)).WithAdditionalAnnotations(Simplifier.Annotation); } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/LanguageServices/CSharpTypeInferenceService.TypeInferrer.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/LanguageServices/CSharpTypeInferenceService.TypeInferrer.cs index a44bd6b9e8deb..8b9aeb302b308 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/LanguageServices/CSharpTypeInferenceService.TypeInferrer.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/LanguageServices/CSharpTypeInferenceService.TypeInferrer.cs @@ -274,46 +274,50 @@ private IEnumerable InferTypeInArgument( return []; } - if (argument.Parent != null) + if (argument is { Parent.Parent: ConstructorInitializerSyntax initializer }) { - if (argument.Parent.Parent is ConstructorInitializerSyntax initializer) - { - var index = initializer.ArgumentList.Arguments.IndexOf(argument); - return InferTypeInConstructorInitializer(initializer, index, argument); - } + var index = initializer.ArgumentList.Arguments.IndexOf(argument); + return InferTypeInConstructorInitializer(initializer, index, argument); + } - if (argument.Parent?.Parent is InvocationExpressionSyntax invocation) - { - var index = invocation.ArgumentList.Arguments.IndexOf(argument); - return InferTypeInInvocationExpression(invocation, index, argument); - } + if (argument is { Parent.Parent: InvocationExpressionSyntax invocation }) + { + var index = invocation.ArgumentList.Arguments.IndexOf(argument); + return InferTypeInInvocationExpression(invocation, index, argument); + } - if (argument.Parent?.Parent is BaseObjectCreationExpressionSyntax creation) - { - // new Outer(Goo()); - // - // new Outer(a: Goo()); - // - // etc. - var index = creation.ArgumentList.Arguments.IndexOf(argument); - return InferTypeInObjectCreationExpression(creation, index, argument); - } + if (argument is { Parent.Parent: BaseObjectCreationExpressionSyntax creation }) + { + // new Outer(Goo()); + // + // new Outer(a: Goo()); + // + // etc. + var index = creation.ArgumentList.Arguments.IndexOf(argument); + return InferTypeInObjectCreationExpression(creation, index, argument); + } - if (argument.Parent?.Parent is ElementAccessExpressionSyntax elementAccess) - { - // Outer[Goo()]; - // - // Outer[a: Goo()]; - // - // etc. - var index = elementAccess.ArgumentList.Arguments.IndexOf(argument); - return InferTypeInElementAccessExpression(elementAccess, index, argument); - } + if (argument is { Parent.Parent: PrimaryConstructorBaseTypeSyntax primaryConstructorBaseType }) + { + // class C() : Base(Goo()); + var index = primaryConstructorBaseType.ArgumentList.Arguments.IndexOf(argument); + return InferTypeInPrimaryConstructorBaseType(primaryConstructorBaseType, index, argument); + } - if (argument?.Parent is TupleExpressionSyntax tupleExpression) - { - return InferTypeInTupleExpression(tupleExpression, argument); - } + if (argument is { Parent.Parent: ElementAccessExpressionSyntax elementAccess }) + { + // Outer[Goo()]; + // + // Outer[a: Goo()]; + // + // etc. + var index = elementAccess.ArgumentList.Arguments.IndexOf(argument); + return InferTypeInElementAccessExpression(elementAccess, index, argument); + } + + if (argument is { Parent: TupleExpressionSyntax tupleExpression }) + { + return InferTypeInTupleExpression(tupleExpression, argument); } if (argument.Parent.IsParentKind(SyntaxKind.ImplicitElementAccess) && @@ -449,6 +453,18 @@ private IEnumerable InferTypeInObjectCreationExpression(BaseO return InferTypeInArgument(index, constructors, argumentOpt, parentInvocationExpressionToTypeInfer: null); } + private IEnumerable InferTypeInPrimaryConstructorBaseType( + PrimaryConstructorBaseTypeSyntax primaryConstructorBaseType, int index, ArgumentSyntax argumentOpt = null) + { + var info = SemanticModel.GetTypeInfo(primaryConstructorBaseType.Type, CancellationToken); + + if (info.Type is not INamedTypeSymbol type) + return []; + + var constructors = type.InstanceConstructors.Where(m => m.Parameters.Length > index); + return InferTypeInArgument(index, constructors, argumentOpt, parentInvocationExpressionToTypeInfer: null); + } + private IEnumerable InferTypeInInvocationExpression( InvocationExpressionSyntax invocation, int index, ArgumentSyntax argumentOpt = null) { diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/LanguageServices/CSharpTypeInferenceService.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/LanguageServices/CSharpTypeInferenceService.cs index 9ce8de391a02c..7d7990d485e2d 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/LanguageServices/CSharpTypeInferenceService.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/LanguageServices/CSharpTypeInferenceService.cs @@ -14,16 +14,12 @@ namespace Microsoft.CodeAnalysis.CSharp; [ExportLanguageService(typeof(ITypeInferenceService), LanguageNames.CSharp), Shared] -internal partial class CSharpTypeInferenceService : AbstractTypeInferenceService +[method: ImportingConstructor] +[method: SuppressMessage("RoslynDiagnosticsReliability", "RS0033:Importing constructor should be [Obsolete]", Justification = "Incorrectly used in production code: https://github.com/dotnet/roslyn/issues/42839")] +internal sealed partial class CSharpTypeInferenceService() : AbstractTypeInferenceService { public static readonly CSharpTypeInferenceService Instance = new(); - [ImportingConstructor] - [SuppressMessage("RoslynDiagnosticsReliability", "RS0033:Importing constructor should be [Obsolete]", Justification = "Incorrectly used in production code: https://github.com/dotnet/roslyn/issues/42839")] - public CSharpTypeInferenceService() - { - } - protected override AbstractTypeInferrer CreateTypeInferrer(SemanticModel semanticModel, CancellationToken cancellationToken) => new TypeInferrer(semanticModel, cancellationToken); } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/LanguageServices/InitializeParameter/CSharpInitializeParameterService.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/LanguageServices/InitializeParameter/CSharpInitializeParameterService.cs new file mode 100644 index 0000000000000..6ecd7a2066f84 --- /dev/null +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/LanguageServices/InitializeParameter/CSharpInitializeParameterService.cs @@ -0,0 +1,111 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.Composition; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.Editing; +using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.CodeAnalysis.InitializeParameter; +using Microsoft.CodeAnalysis.Operations; + +namespace Microsoft.CodeAnalysis.CSharp.InitializeParameter; + +using static InitializeParameterHelpersCore; + +[ExportLanguageService(typeof(IInitializeParameterService), LanguageNames.CSharp), Shared] +[method: ImportingConstructor] +[method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] +internal sealed class CSharpInitializeParameterService() : AbstractInitializerParameterService +{ + protected override SyntaxNode? GetAccessorBody(IMethodSymbol accessor, CancellationToken cancellationToken) + => InitializeParameterHelpers.GetAccessorBody(accessor, cancellationToken); + + protected override bool IsFunctionDeclaration(SyntaxNode node) + => InitializeParameterHelpers.IsFunctionDeclaration(node); + + protected override SyntaxNode GetBody(SyntaxNode methodNode) + => InitializeParameterHelpers.GetBody(methodNode); + + protected override SyntaxNode? TryGetLastStatement(IBlockOperation? blockStatement) + => InitializeParameterHelpers.TryGetLastStatement(blockStatement); + + protected override void InsertStatement(SyntaxEditor editor, SyntaxNode functionDeclaration, bool returnsVoid, SyntaxNode? statementToAddAfter, StatementSyntax statement) + => InitializeParameterHelpers.InsertStatement(editor, functionDeclaration, returnsVoid, statementToAddAfter, statement); + + protected override bool TryUpdateTupleAssignment( + IBlockOperation? blockStatement, + IParameterSymbol parameter, + ISymbol fieldOrProperty, + SyntaxEditor editor) + { + if (blockStatement is null) + return false; + + foreach (var (tupleLeft, tupleRight) in TryGetAssignmentExpressions(blockStatement)) + { + if (tupleLeft.Syntax is TupleExpressionSyntax tupleLeftSyntax && + tupleRight.Syntax is TupleExpressionSyntax tupleRightSyntax) + { + var generator = editor.Generator; + foreach (var (sibling, before) in GetSiblingParameters(parameter)) + { + if (TryFindSiblingAssignment(tupleLeft, tupleRight, sibling, out var index)) + { + // If we found assignment to a parameter before us, then add after that. + var insertionPosition = before ? index + 1 : index; + + var left = (ArgumentSyntax)generator.Argument(generator.MemberAccessExpression(generator.ThisExpression(), generator.IdentifierName(fieldOrProperty.Name))); + var right = (ArgumentSyntax)generator.Argument(generator.IdentifierName(parameter.Name)); + + editor.ReplaceNode( + tupleLeftSyntax, + tupleLeftSyntax.WithArguments(tupleLeftSyntax.Arguments.Insert(insertionPosition, left))); + editor.ReplaceNode( + tupleRightSyntax, + tupleRightSyntax.WithArguments(tupleRightSyntax.Arguments.Insert(insertionPosition, right))); + + return true; + } + } + } + } + + return false; + } + + private static bool TryFindSiblingAssignment( + ITupleOperation tupleLeft, ITupleOperation tupleRight, IParameterSymbol sibling, out int index) + { + for (int i = 0, n = tupleLeft.Elements.Length; i < n; i++) + { + // rhs tuple has to directly reference the sibling parameter. lhs has to be a reference to a field/prop in this type. + + if (tupleRight.Elements[i] is IParameterReferenceOperation parameterReference && sibling.Equals(parameterReference.Parameter) && + IsFieldOrPropertyReference(tupleLeft.Elements[i], sibling.ContainingType, out _)) + { + index = i; + return true; + } + } + + index = -1; + return false; + } + + private static IEnumerable<(ITupleOperation targetTuple, ITupleOperation valueTuple)> TryGetAssignmentExpressions(IBlockOperation blockOperation) + { + foreach (var operation in blockOperation.Operations) + { + if (TryGetPartsOfTupleAssignmentOperation(operation, out var targetTuple, out var valueTuple)) + yield return (targetTuple, valueTuple); + } + } + + protected override Task TryAddAssignmentForPrimaryConstructorAsync(Document document, IParameterSymbol parameter, ISymbol fieldOrProperty, CancellationToken cancellationToken) + => InitializeParameterHelpers.AddAssignmentForPrimaryConstructorAsync(document, parameter, fieldOrProperty, cancellationToken); +} diff --git a/src/Features/CSharp/Portable/InitializeParameter/InitializeParameterHelpers.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/LanguageServices/InitializeParameter/InitializeParameterHelpers.cs similarity index 59% rename from src/Features/CSharp/Portable/InitializeParameter/InitializeParameterHelpers.cs rename to src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/LanguageServices/InitializeParameter/InitializeParameterHelpers.cs index eeaff6bfc8f3e..dbd5e6e5b6286 100644 --- a/src/Features/CSharp/Portable/InitializeParameter/InitializeParameterHelpers.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/LanguageServices/InitializeParameter/InitializeParameterHelpers.cs @@ -7,26 +7,132 @@ using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.CodeGeneration; using Microsoft.CodeAnalysis.CSharp.Extensions; using Microsoft.CodeAnalysis.CSharp.LanguageService; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Editing; +using Microsoft.CodeAnalysis.FindSymbols; using Microsoft.CodeAnalysis.Formatting; +using Microsoft.CodeAnalysis.InitializeParameter; using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Operations; -using Microsoft.CodeAnalysis.PooledObjects; +using Microsoft.CodeAnalysis.Shared.Extensions; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CSharp.InitializeParameter; using static CSharpSyntaxTokens; +using static SyntaxFactory; internal static class InitializeParameterHelpers { + public static Argument GetArgument(ArgumentSyntax argument) + => new(argument.GetRefKind(), argument.NameColon?.Name.Identifier.ValueText, argument.Expression); + + public static async Task AddAssignmentForPrimaryConstructorAsync( + Document document, + IParameterSymbol parameter, + ISymbol fieldOrProperty, + CancellationToken cancellationToken) + { + var project = document.Project; + var solution = project.Solution; + + var solutionEditor = new SolutionEditor(solution); + var initializer = EqualsValueClause(IdentifierName(parameter.Name.EscapeIdentifier())); + + // We're assigning the parameter to a field/prop. Convert all existing references to this primary constructor + // parameter (within this type) to refer to the field/prop now instead. + await UpdateParameterReferencesAsync( + solutionEditor, parameter, fieldOrProperty, cancellationToken).ConfigureAwait(false); + + // We're updating an exiting field/prop. + if (fieldOrProperty is IPropertySymbol property) + { + var compilation = await project.GetRequiredCompilationAsync(cancellationToken).ConfigureAwait(false); + var initializeParameterService = document.GetRequiredLanguageService(); + var isThrowNotImplementedProperty = initializeParameterService.IsThrowNotImplementedProperty( + compilation, property, cancellationToken); + + foreach (var syntaxRef in property.DeclaringSyntaxReferences) + { + if (syntaxRef.GetSyntax(cancellationToken) is PropertyDeclarationSyntax propertyDeclaration) + { + var editingDocument = solution.GetRequiredDocument(propertyDeclaration.SyntaxTree); + var editor = await solutionEditor.GetDocumentEditorAsync(editingDocument.Id, cancellationToken).ConfigureAwait(false); + + // If the user had a property that has 'throw NotImplementedException' in it, then remove those throws. + var newPropertyDeclaration = isThrowNotImplementedProperty ? RemoveThrowNotImplemented(propertyDeclaration) : propertyDeclaration; + editor.ReplaceNode( + propertyDeclaration, + newPropertyDeclaration.WithoutTrailingTrivia() + .WithSemicolonToken(SemicolonToken.WithTrailingTrivia(newPropertyDeclaration.GetTrailingTrivia())) + .WithInitializer(initializer)); + break; + } + } + } + else if (fieldOrProperty is IFieldSymbol field) + { + foreach (var syntaxRef in field.DeclaringSyntaxReferences) + { + if (syntaxRef.GetSyntax(cancellationToken) is VariableDeclaratorSyntax variableDeclarator) + { + var editingDocument = solution.GetRequiredDocument(variableDeclarator.SyntaxTree); + var editor = await solutionEditor.GetDocumentEditorAsync(editingDocument.Id, cancellationToken).ConfigureAwait(false); + editor.ReplaceNode( + variableDeclarator, + variableDeclarator.WithInitializer(initializer)); + break; + } + } + } + + return solutionEditor.GetChangedSolution(); + } + + public static async Task UpdateParameterReferencesAsync( + SolutionEditor solutionEditor, + IParameterSymbol parameter, + ISymbol fieldOrProperty, + CancellationToken cancellationToken) + { + var solution = solutionEditor.OriginalSolution; + var namedType = parameter.ContainingType; + var documents = namedType.DeclaringSyntaxReferences + .Select(r => solution.GetRequiredDocument(r.SyntaxTree)) + .ToImmutableHashSet(); + + var references = await SymbolFinder.FindReferencesAsync(parameter, solution, documents, cancellationToken).ConfigureAwait(false); + var groups = references.SelectMany(static r => r.Locations.Where(loc => !loc.IsImplicit)).GroupBy(static loc => loc.Document); + + foreach (var group in groups) + { + var editor = await solutionEditor.GetDocumentEditorAsync(group.Key.Id, cancellationToken).ConfigureAwait(false); + + // We may hit a location multiple times due to how we do FAR for linked symbols, but each linked symbol is + // allowed to report the entire set of references it think it is compatible with. So ensure we're hitting + // each location only once. + foreach (var location in group.Distinct(LinkedFileReferenceLocationEqualityComparer.Instance)) + { + var node = location.Location.FindNode(getInnermostNodeForTie: true, cancellationToken); + if (node is IdentifierNameSyntax { Parent: not NameColonSyntax } identifierName && + identifierName.Identifier.ValueText == parameter.Name) + { + // we may have things like `new MyType(x: ...)` we don't want to update `x` there to 'X' + // just because we're generating a new property 'X' for the parameter to be assigned to. + editor.ReplaceNode( + identifierName, + IdentifierName(fieldOrProperty.Name.EscapeIdentifier()).WithTriviaFrom(identifierName)); + } + } + } + } + public static bool IsFunctionDeclaration(SyntaxNode node) - => node is BaseMethodDeclarationSyntax - or LocalFunctionStatementSyntax - or AnonymousFunctionExpressionSyntax; + => node is BaseMethodDeclarationSyntax or LocalFunctionStatementSyntax or AnonymousFunctionExpressionSyntax; public static SyntaxNode GetBody(SyntaxNode functionDeclaration) => functionDeclaration switch @@ -194,34 +300,4 @@ private static AccessorDeclarationSyntax RemoveThrowNotImplemented(AccessorDecla return result.WithTrailingTrivia(accessorDeclaration.Body?.GetTrailingTrivia() ?? accessorDeclaration.SemicolonToken.TrailingTrivia); } - - public static bool IsThrowNotImplementedProperty(Compilation compilation, IPropertySymbol property, CancellationToken cancellationToken) - { - using var _ = ArrayBuilder.GetInstance(out var accessors); - - if (property.GetMethod != null) - accessors.AddIfNotNull(GetAccessorBody(property.GetMethod, cancellationToken)); - - if (property.SetMethod != null) - accessors.AddIfNotNull(GetAccessorBody(property.SetMethod, cancellationToken)); - - if (accessors.Count == 0) - return false; - - foreach (var group in accessors.GroupBy(node => node.SyntaxTree)) - { - var semanticModel = compilation.GetSemanticModel(group.Key); - foreach (var accessorBody in accessors) - { - var operation = semanticModel.GetOperation(accessorBody, cancellationToken); - if (operation is null) - return false; - - if (!operation.IsSingleThrowNotImplementedOperation()) - return false; - } - } - - return true; - } } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Utilities/NullableHelpers/NullableHelpers.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Utilities/NullableHelpers/NullableHelpers.cs deleted file mode 100644 index 7fe0dc6410a40..0000000000000 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Utilities/NullableHelpers/NullableHelpers.cs +++ /dev/null @@ -1,111 +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.Linq; -using System.Threading; -using Microsoft.CodeAnalysis.CSharp; -using Microsoft.CodeAnalysis.CSharp.Syntax; -using Microsoft.CodeAnalysis.Operations; -using Microsoft.CodeAnalysis.Shared.Extensions; - -namespace Microsoft.CodeAnalysis; - -internal static class NullableHelpers -{ - /// - /// Gets the declared symbol and root operation from the passed in declarationSyntax and calls - /// . Note - /// that this is bool and not bool? because we know that the symbol is at the very least declared, - /// so there's no need to return a null value. - /// - public static bool IsDeclaredSymbolAssignedPossiblyNullValue(SemanticModel semanticModel, SyntaxNode declarationSyntax, CancellationToken cancellationToken) - { - var declaredSymbol = semanticModel.GetRequiredDeclaredSymbol(declarationSyntax, cancellationToken); - var declaredOperation = semanticModel.GetRequiredOperation(declarationSyntax, cancellationToken); - - var rootOperation = declaredOperation; - - // Walk up the tree to find a root for the operation - // that contains the declaration - while (rootOperation is not IBlockOperation && - rootOperation.Parent is not null) - { - rootOperation = rootOperation.Parent; - } - - return IsSymbolAssignedPossiblyNullValue(semanticModel, rootOperation, declaredSymbol) == true; - } - - /// - /// Given an operation, goes through all decendent operations and returns true if the symbol passed in - /// is ever assigned a possibly null value as determined by nullable flow state. Returns - /// null if no references are found, letting the caller determine what to do with that information - /// - public static bool? IsSymbolAssignedPossiblyNullValue(SemanticModel semanticModel, IOperation operation, ISymbol symbol) - { - var references = operation.DescendantsAndSelf() - .Where(o => IsSymbolReferencedByOperation(o, symbol)); - - var hasReference = false; - - foreach (var reference in references) - { - hasReference = true; - - // foreach statements are handled special because the iterator is not assignable, so the elementtype - // annotation is accurate for determining if the loop declaration has a reference that allows the symbol - // to be null - if (reference is IForEachLoopOperation forEachLoop) - { - var foreachInfo = semanticModel.GetForEachStatementInfo((CommonForEachStatementSyntax)forEachLoop.Syntax); - - if (foreachInfo.ElementType is null) - { - continue; - } - - // Use NotAnnotated here to keep both Annotated and None (oblivious) treated the same, since - // this is directly looking at the annotation and not the flow state - if (foreachInfo.ElementType.NullableAnnotation != NullableAnnotation.NotAnnotated) - { - return true; - } - - continue; - } - - var syntax = reference is IVariableDeclaratorOperation variableDeclarator - ? variableDeclarator.GetVariableInitializer()!.Value.Syntax - : reference.Syntax; - - var typeInfo = semanticModel.GetTypeInfo(syntax); - - if (typeInfo.Nullability.FlowState == NullableFlowState.MaybeNull) - { - return true; - } - } - - return hasReference ? (bool?)false : null; - } - - /// - /// Determines if an operations references a specific symbol. Note that this will recurse in some - /// cases to work for operations like IAssignmentOperation, which logically references a symbol even if it - /// is the Target operation that actually does. - /// - private static bool IsSymbolReferencedByOperation(IOperation operation, ISymbol symbol) - => operation switch - { - ILocalReferenceOperation localReference => localReference.Local.Equals(symbol), - IParameterReferenceOperation parameterReference => parameterReference.Parameter.Equals(symbol), - IAssignmentOperation assignment => IsSymbolReferencedByOperation(assignment.Target, symbol), - ITupleOperation tupleOperation => tupleOperation.Elements.Any(static (element, symbol) => IsSymbolReferencedByOperation(element, symbol), symbol), - IForEachLoopOperation { LoopControlVariable: IVariableDeclaratorOperation variableDeclarator } => variableDeclarator.Symbol.Equals(symbol), - - // A variable initializer is required for this to be a meaningful operation for determining possible null assignment - IVariableDeclaratorOperation variableDeclarator => variableDeclarator.GetVariableInitializer() != null && variableDeclarator.Symbol.Equals(symbol), - _ => false - }; -} diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/AbstractFlagsEnumGenerator.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/AbstractFlagsEnumGenerator.cs index 8a7cf272e9a97..74dc1d229e1f3 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/AbstractFlagsEnumGenerator.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/AbstractFlagsEnumGenerator.cs @@ -12,22 +12,24 @@ namespace Microsoft.CodeAnalysis.CodeGeneration; internal abstract class AbstractFlagsEnumGenerator : IComparer<(IFieldSymbol field, ulong value)> { - protected abstract SyntaxNode CreateExplicitlyCastedLiteralValue(SyntaxGenerator generator, INamedTypeSymbol enumType, SpecialType underlyingSpecialType, object constantValue); + protected abstract SyntaxNode CreateExplicitlyCastedLiteralValue(INamedTypeSymbol enumType, SpecialType underlyingSpecialType, object constantValue); protected abstract bool IsValidName(INamedTypeSymbol enumType, string name); - public SyntaxNode CreateEnumConstantValue(SyntaxGenerator generator, INamedTypeSymbol enumType, object constantValue) + protected abstract SyntaxGeneratorInternal SyntaxGenerator { get; } + + public SyntaxNode CreateEnumConstantValue(INamedTypeSymbol enumType, object constantValue) { // Code copied from System.Enum. var isFlagsEnum = IsFlagsEnum(enumType); if (isFlagsEnum) { - return CreateFlagsEnumConstantValue(generator, enumType, constantValue); + return CreateFlagsEnumConstantValue(enumType, constantValue); } else { // Try to see if its one of the enum values. If so, add that. Otherwise, just add // the literal value of the enum. - return CreateNonFlagsEnumConstantValue(generator, enumType, constantValue); + return CreateNonFlagsEnumConstantValue(enumType, constantValue); } } @@ -60,18 +62,17 @@ private static bool IsFlagsEnum(INamedTypeSymbol typeSymbol) return false; } - private SyntaxNode CreateFlagsEnumConstantValue(SyntaxGenerator generator, INamedTypeSymbol enumType, object constantValue) + private SyntaxNode CreateFlagsEnumConstantValue(INamedTypeSymbol enumType, object constantValue) { // These values are sorted by value. Don't change this. var allFieldsAndValues = new List<(IFieldSymbol field, ulong value)>(); GetSortedEnumFieldsAndValues(enumType, allFieldsAndValues); var usedFieldsAndValues = new List<(IFieldSymbol field, ulong value)>(); - return CreateFlagsEnumConstantValue(generator, enumType, constantValue, allFieldsAndValues, usedFieldsAndValues); + return CreateFlagsEnumConstantValue(enumType, constantValue, allFieldsAndValues, usedFieldsAndValues); } private SyntaxNode CreateFlagsEnumConstantValue( - SyntaxGenerator generator, INamedTypeSymbol enumType, object constantValue, List<(IFieldSymbol field, ulong value)> allFieldsAndValues, @@ -107,14 +108,14 @@ private SyntaxNode CreateFlagsEnumConstantValue( for (var i = usedFieldsAndValues.Count - 1; i >= 0; i--) { var field = usedFieldsAndValues[i]; - var node = CreateMemberAccessExpression(generator, field.field, enumType, underlyingSpecialType); + var node = CreateMemberAccessExpression(field.field, enumType, underlyingSpecialType); if (finalNode == null) { finalNode = node; } else { - finalNode = generator.BitwiseOrExpression(finalNode, node); + finalNode = this.SyntaxGenerator.BitwiseOrExpression(finalNode, node); } } @@ -128,28 +129,28 @@ private SyntaxNode CreateFlagsEnumConstantValue( var zeroField = GetZeroField(allFieldsAndValues); if (constantValueULong == 0 && zeroField != null) { - return CreateMemberAccessExpression(generator, zeroField, enumType, underlyingSpecialType); + return CreateMemberAccessExpression(zeroField, enumType, underlyingSpecialType); } else { // Add anything else in as a literal value. - return CreateExplicitlyCastedLiteralValue(generator, enumType, underlyingSpecialType, constantValue); + return CreateExplicitlyCastedLiteralValue(enumType, underlyingSpecialType, constantValue); } } private SyntaxNode CreateMemberAccessExpression( - SyntaxGenerator generator, IFieldSymbol field, INamedTypeSymbol enumType, SpecialType underlyingSpecialType) + IFieldSymbol field, INamedTypeSymbol enumType, SpecialType underlyingSpecialType) { if (IsValidName(enumType, field.Name)) { - return generator.MemberAccessExpression( - generator.TypeExpression(enumType), - generator.IdentifierName(field.Name)); + return this.SyntaxGenerator.MemberAccessExpression( + this.SyntaxGenerator.TypeExpression(enumType), + this.SyntaxGenerator.IdentifierName(field.Name)); } else { Contract.ThrowIfNull(field.ConstantValue); - return CreateExplicitlyCastedLiteralValue(generator, enumType, underlyingSpecialType, field.ConstantValue); + return CreateExplicitlyCastedLiteralValue(enumType, underlyingSpecialType, field.ConstantValue); } } @@ -185,7 +186,7 @@ private void GetSortedEnumFieldsAndValues( allFieldsAndValues.Sort(this); } - private SyntaxNode CreateNonFlagsEnumConstantValue(SyntaxGenerator generator, INamedTypeSymbol enumType, object constantValue) + private SyntaxNode CreateNonFlagsEnumConstantValue(INamedTypeSymbol enumType, object constantValue) { Contract.ThrowIfNull(enumType.EnumUnderlyingType); var underlyingSpecialType = enumType.EnumUnderlyingType.SpecialType; @@ -198,14 +199,12 @@ private SyntaxNode CreateNonFlagsEnumConstantValue(SyntaxGenerator generator, IN { var fieldValue = underlyingSpecialType.ConvertUnderlyingValueToUInt64(field.ConstantValue); if (constantValueULong == fieldValue) - { - return CreateMemberAccessExpression(generator, field, enumType, underlyingSpecialType); - } + return CreateMemberAccessExpression(field, enumType, underlyingSpecialType); } } // Otherwise, just add the enum as a literal. - return CreateExplicitlyCastedLiteralValue(generator, enumType, underlyingSpecialType, constantValue); + return CreateExplicitlyCastedLiteralValue(enumType, underlyingSpecialType, constantValue); } int IComparer<(IFieldSymbol field, ulong value)>.Compare((IFieldSymbol field, ulong value) x, (IFieldSymbol field, ulong value) y) diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/CodeGenerationHelpers.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/CodeGenerationHelpers.cs index 8d272db6b1b46..476a0c1001178 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/CodeGenerationHelpers.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/CodeGenerationHelpers.cs @@ -175,12 +175,12 @@ public static T RemoveLeadingDirectiveTrivia(T node) where T : SyntaxNode return node.WithLeadingTrivia(leadingTrivia); } - public static T? GetReuseableSyntaxNodeForAttribute(AttributeData attribute, CodeGenerationContextInfo info) + public static T? GetReuseableSyntaxNodeForAttribute(AttributeData attribute) where T : SyntaxNode { Contract.ThrowIfNull(attribute); - return info.Context.ReuseSyntax && attribute.ApplicationSyntaxReference != null + return attribute.ApplicationSyntaxReference != null ? attribute.ApplicationSyntaxReference.GetSyntax() as T : null; } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/CodeGenerationSymbolFactory.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/CodeGenerationSymbolFactory.cs index c0e38b5abedbb..b318dd2bf523f 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/CodeGenerationSymbolFactory.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/CodeGenerationSymbolFactory.cs @@ -83,7 +83,7 @@ public static IPropertySymbol CreatePropertySymbol( ImmutableArray attributes, Accessibility accessibility, DeclarationModifiers modifiers, ITypeSymbol type, RefKind refKind, ImmutableArray explicitInterfaceImplementations, string name, ImmutableArray parameters, IMethodSymbol? getMethod, IMethodSymbol? setMethod, - bool isIndexer = false) + bool isIndexer = false, SyntaxNode? initializer = null) { return CreatePropertySymbol( containingType: null, @@ -97,7 +97,8 @@ public static IPropertySymbol CreatePropertySymbol( parameters: parameters, getMethod: getMethod, setMethod: setMethod, - isIndexer: isIndexer); + isIndexer: isIndexer, + initializer: initializer); } /// @@ -286,7 +287,7 @@ public static IParameterSymbol CreateParameterSymbol( /// /// Creates a parameter symbol that can be used to describe a parameter declaration. /// - internal static IParameterSymbol CreateParameterSymbol( + public static IParameterSymbol CreateParameterSymbol( IParameterSymbol parameter, ImmutableArray? attributes = null, RefKind? refKind = null, @@ -453,7 +454,7 @@ public static INamedTypeSymbol CreateNamedTypeSymbol( containingAssembly, null, attributes, accessibility, modifiers, isRecord, typeKind, name, typeParameters, baseType, interfaces, specialType, nullableAnnotation, members.WhereAsArray(m => m is not INamedTypeSymbol), - members.OfType().Select(n => n.ToCodeGenerationSymbol()).ToImmutableArray(), + [.. members.OfType().Select(n => n.ToCodeGenerationSymbol())], enumUnderlyingType: null); } @@ -551,7 +552,8 @@ internal static IPropertySymbol CreatePropertySymbol( string? name = null, bool? isIndexer = null, IMethodSymbol? getMethod = null, - IMethodSymbol? setMethod = null) + IMethodSymbol? setMethod = null, + SyntaxNode? initializer = null) { return CreatePropertySymbol( attributes, @@ -564,7 +566,8 @@ internal static IPropertySymbol CreatePropertySymbol( parameters ?? property.Parameters, getMethod, setMethod, - isIndexer ?? property.IsIndexer); + isIndexer ?? property.IsIndexer, + initializer: initializer); } internal static IEventSymbol CreateEventSymbol( diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/Symbols/CodeGenerationConstructedNamedTypeSymbol.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/Symbols/CodeGenerationConstructedNamedTypeSymbol.cs index 820b1072c34ce..da89c00faee5b 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/Symbols/CodeGenerationConstructedNamedTypeSymbol.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/Symbols/CodeGenerationConstructedNamedTypeSymbol.cs @@ -87,7 +87,7 @@ public override ImmutableArray Constructors public override ImmutableArray GetTypeMembers() { // TODO(cyrusn): construct these. - return ImmutableArray.CreateRange(_constructedFrom.TypeMembers.Cast()); + return [.. _constructedFrom.TypeMembers.Cast()]; } public override TypeKind TypeKind => _constructedFrom.TypeKind; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/Symbols/CodeGenerationConstructorSymbol.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/Symbols/CodeGenerationConstructorSymbol.cs index 5f81a1a3fdbf7..4ba1d6ad75bed 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/Symbols/CodeGenerationConstructorSymbol.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/Symbols/CodeGenerationConstructorSymbol.cs @@ -27,9 +27,9 @@ internal sealed class CodeGenerationConstructorSymbol( refKind: RefKind.None, explicitInterfaceImplementations: default, name: string.Empty, - typeParameters: ImmutableArray.Empty, + typeParameters: [], parameters: parameters, - returnTypeAttributes: ImmutableArray.Empty) + returnTypeAttributes: []) { public override MethodKind MethodKind => MethodKind.Constructor; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/Symbols/CodeGenerationConversionSymbol.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/Symbols/CodeGenerationConversionSymbol.cs index e904c5103815c..303ef6233fe75 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/Symbols/CodeGenerationConversionSymbol.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/Symbols/CodeGenerationConversionSymbol.cs @@ -33,8 +33,8 @@ internal sealed class CodeGenerationConversionSymbol( name: isImplicit ? WellKnownMemberNames.ImplicitConversionName : WellKnownMemberNames.ExplicitConversionName, - typeParameters: ImmutableArray.Empty, - parameters: ImmutableArray.Create(fromType), + typeParameters: [], + parameters: [fromType], returnTypeAttributes: toTypeAttributes, documentationCommentXml) { diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/Symbols/CodeGenerationDestructorSymbol.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/Symbols/CodeGenerationDestructorSymbol.cs index 419834acf4327..bff02db796c93 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/Symbols/CodeGenerationDestructorSymbol.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/Symbols/CodeGenerationDestructorSymbol.cs @@ -18,9 +18,9 @@ internal sealed class CodeGenerationDestructorSymbol( refKind: RefKind.None, explicitInterfaceImplementations: default, name: string.Empty, - typeParameters: ImmutableArray.Empty, - parameters: ImmutableArray.Empty, - returnTypeAttributes: ImmutableArray.Empty) + typeParameters: [], + parameters: [], + returnTypeAttributes: []) { public override MethodKind MethodKind => MethodKind.Destructor; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/Symbols/CodeGenerationNamedTypeSymbol.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/Symbols/CodeGenerationNamedTypeSymbol.cs index 3b16804a7844d..2b1c38add159a 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/Symbols/CodeGenerationNamedTypeSymbol.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/Symbols/CodeGenerationNamedTypeSymbol.cs @@ -145,7 +145,7 @@ public override ImmutableArray TypeParameters { get { - return ImmutableArray.CreateRange(_typeParameters); + return [.. _typeParameters]; } } @@ -155,23 +155,22 @@ public override ImmutableArray Interfaces { get { - return ImmutableArray.CreateRange(_interfaces); + return [.. _interfaces]; } } public override ImmutableArray GetMembers() - => ImmutableArray.CreateRange(_members.Concat(this.TypeMembers)); + => [.. _members.Concat(this.TypeMembers)]; public override ImmutableArray GetTypeMembers() - => ImmutableArray.CreateRange(this.TypeMembers.Cast()); + => [.. this.TypeMembers.Cast()]; public override ImmutableArray InstanceConstructors { get { // NOTE(cyrusn): remember to Construct the result if we implement this. - return ImmutableArray.CreateRange( - this.GetMembers().OfType().Where(m => m.MethodKind == MethodKind.Constructor && !m.IsStatic)); + return [.. this.GetMembers().OfType().Where(m => m.MethodKind == MethodKind.Constructor && !m.IsStatic)]; } } @@ -180,8 +179,7 @@ public override ImmutableArray StaticConstructors get { // NOTE(cyrusn): remember to Construct the result if we implement this. - return ImmutableArray.CreateRange( - this.GetMembers().OfType().Where(m => m.MethodKind == MethodKind.StaticConstructor && m.IsStatic)); + return [.. this.GetMembers().OfType().Where(m => m.MethodKind == MethodKind.StaticConstructor && m.IsStatic)]; } } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/Symbols/CodeGenerationOperatorSymbol.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/Symbols/CodeGenerationOperatorSymbol.cs index 6817aed1e15c7..0a7ac510f3da9 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/Symbols/CodeGenerationOperatorSymbol.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/Symbols/CodeGenerationOperatorSymbol.cs @@ -32,7 +32,7 @@ internal sealed class CodeGenerationOperatorSymbol( refKind: RefKind.None, explicitInterfaceImplementations: default, GetMetadataName(operatorKind), - typeParameters: ImmutableArray.Empty, + typeParameters: [], parameters, returnTypeAttributes, documentationCommentXml) diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Extensions/IMethodSymbolExtensions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Extensions/IMethodSymbolExtensions.cs index 4032634ac146a..6e27c285e13e3 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Extensions/IMethodSymbolExtensions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Extensions/IMethodSymbolExtensions.cs @@ -137,7 +137,7 @@ private static ImmutableArray RenameTypeParameters( newTypeParameter.ConstraintTypes = ImmutableArray.CreateRange(newTypeParameter.ConstraintTypes, t => t.SubstituteTypes(mapping, typeGenerator)); } - return newTypeParameters.Cast().ToImmutableArray(); + return [.. newTypeParameters.Cast()]; } public static IMethodSymbol RemoveInaccessibleAttributesAndAttributesOfTypes( diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Extensions/IParameterSymbolExtensions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Extensions/IParameterSymbolExtensions.cs index 0e1873f9f9fbb..53da2340c7cd0 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Extensions/IParameterSymbolExtensions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Extensions/IParameterSymbolExtensions.cs @@ -33,4 +33,19 @@ public static IParameterSymbol RenameParameter(this IParameterSymbol parameter, parameter.HasExplicitDefaultValue, parameter.HasExplicitDefaultValue ? parameter.ExplicitDefaultValue : null); } + + public static IParameterSymbol WithAttributes(this IParameterSymbol parameter, ImmutableArray attributes) + { + return parameter.GetAttributes() == attributes + ? parameter + : CodeGenerationSymbolFactory.CreateParameterSymbol( + attributes, + parameter.RefKind, + parameter.IsParams, + parameter.Type, + parameter.Name, + parameter.IsOptional, + parameter.HasExplicitDefaultValue, + parameter.HasExplicitDefaultValue ? parameter.ExplicitDefaultValue : null); + } } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Extensions/SyntaxGeneratorExtensions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Extensions/SyntaxGeneratorExtensions.cs index e1dd24c448120..98e638b4b02b6 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Extensions/SyntaxGeneratorExtensions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Extensions/SyntaxGeneratorExtensions.cs @@ -189,8 +189,12 @@ static SyntaxNode GenerateContainerName(SyntaxGenerator factory, ISymbol through } public static ImmutableArray GetGetAccessorStatements( - this SyntaxGenerator generator, Compilation compilation, - IPropertySymbol property, ISymbol? throughMember, bool preferAutoProperties) + this SyntaxGenerator generator, + Compilation compilation, + IPropertySymbol property, + IPropertySymbol? conflictingProperty, + ISymbol? throughMember, + bool preferAutoProperties) { if (throughMember != null) { @@ -209,12 +213,27 @@ public static ImmutableArray GetGetAccessorStatements( return [generator.ReturnStatement(expression)]; } - return preferAutoProperties ? default : generator.CreateThrowNotImplementedStatementBlock(compilation); + if (preferAutoProperties) + return default; + + // Forward from the explicit property we're creating to the existing property it conflicts with if possible. + if (conflictingProperty is { GetMethod: not null, Parameters.Length: 0 } && + property is { GetMethod: not null, Parameters.Length: 0 }) + { + if (compilation.ClassifyCommonConversion(conflictingProperty.Type, property.Type) is { Exists: true, IsImplicit: true }) + return [generator.ReturnStatement(generator.MemberAccessExpression(generator.ThisExpression(), property.Name))]; + } + + return generator.CreateThrowNotImplementedStatementBlock(compilation); } public static ImmutableArray GetSetAccessorStatements( - this SyntaxGenerator generator, Compilation compilation, - IPropertySymbol property, ISymbol? throughMember, bool preferAutoProperties) + this SyntaxGenerator generator, + Compilation compilation, + IPropertySymbol property, + IPropertySymbol? conflictingProperty, + ISymbol? throughMember, + bool preferAutoProperties) { if (throughMember != null) { @@ -235,9 +254,18 @@ public static ImmutableArray GetSetAccessorStatements( return [generator.ExpressionStatement(expression)]; } - return preferAutoProperties - ? default - : generator.CreateThrowNotImplementedStatementBlock(compilation); + if (preferAutoProperties) + return default; + + // Forward from the explicit property we're creating to the existing property it conflicts with if possible. + if (conflictingProperty is { SetMethod.Parameters.Length: 1 } && + property is { SetMethod.Parameters: [var parameter] }) + { + if (compilation.ClassifyCommonConversion(property.Type, conflictingProperty.Type) is { Exists: true, IsImplicit: true }) + return [generator.ExpressionStatement(generator.AssignmentStatement(generator.MemberAccessExpression(generator.ThisExpression(), property.Name), generator.IdentifierName(parameter.Name)))]; + } + + return generator.CreateThrowNotImplementedStatementBlock(compilation); } private static bool TryGetValue(IDictionary? dictionary, string key, [NotNullWhen(true)] out string? value) @@ -322,8 +350,8 @@ public static ImmutableArray CreateAssignmentStatements( bool addNullChecks, bool preferThrowExpression) { - var nullCheckStatements = ArrayBuilder.GetInstance(); - var assignStatements = ArrayBuilder.GetInstance(); + using var _1 = ArrayBuilder.GetInstance(out var nullCheckStatements); + using var _2 = ArrayBuilder.GetInstance(out var assignStatements); foreach (var parameter in parameters) { @@ -360,7 +388,7 @@ public static ImmutableArray CreateAssignmentStatements( } } - return nullCheckStatements.ToImmutableAndFree().Concat(assignStatements.ToImmutableAndFree()); + return [.. nullCheckStatements, .. assignStatements]; } public static void AddAssignmentStatements( diff --git a/src/Workspaces/Core/Portable/FindSymbols/LinkedFileReferenceLocationEqualityComparer.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/FindSymbols/LinkedFileReferenceLocationEqualityComparer.cs similarity index 100% rename from src/Workspaces/Core/Portable/FindSymbols/LinkedFileReferenceLocationEqualityComparer.cs rename to src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/FindSymbols/LinkedFileReferenceLocationEqualityComparer.cs diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/LanguageServices/AddImports/AbstractAddImportsService.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/LanguageServices/AddImports/AbstractAddImportsService.cs index 5c38e016c3970..655d0553ebb12 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/LanguageServices/AddImports/AbstractAddImportsService.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/LanguageServices/AddImports/AbstractAddImportsService.cs @@ -68,7 +68,7 @@ private static ImmutableArray GetAllContainers(SyntaxNode root, Synt contextLocation ??= root; var applicableContainer = GetFirstApplicableContainer(contextLocation); - return applicableContainer.GetAncestorsOrThis().ToImmutableArray(); + return [.. applicableContainer.GetAncestorsOrThis()]; } private bool HasExistingImport( diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/LanguageServices/InitializeParameter/AbstractInitializerParameterService.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/LanguageServices/InitializeParameter/AbstractInitializerParameterService.cs new file mode 100644 index 0000000000000..51e6ba441dc47 --- /dev/null +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/LanguageServices/InitializeParameter/AbstractInitializerParameterService.cs @@ -0,0 +1,222 @@ +// 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.Linq; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Editing; +using Microsoft.CodeAnalysis.LanguageService; +using Microsoft.CodeAnalysis.Operations; +using Microsoft.CodeAnalysis.PooledObjects; +using Microsoft.CodeAnalysis.Shared.Extensions; + +namespace Microsoft.CodeAnalysis.InitializeParameter; + +using static InitializeParameterHelpersCore; + +internal abstract class AbstractInitializerParameterService + : IInitializeParameterService + where TStatementSyntax : SyntaxNode +{ + protected abstract bool IsFunctionDeclaration(SyntaxNode node); + + protected abstract SyntaxNode? GetAccessorBody(IMethodSymbol accessor, CancellationToken cancellationToken); + + protected abstract SyntaxNode GetBody(SyntaxNode methodNode); + protected abstract SyntaxNode? TryGetLastStatement(IBlockOperation? blockStatement); + + protected abstract bool TryUpdateTupleAssignment(IBlockOperation? blockStatement, IParameterSymbol parameter, ISymbol fieldOrProperty, SyntaxEditor editor); + protected abstract Task TryAddAssignmentForPrimaryConstructorAsync( + Document document, IParameterSymbol parameter, ISymbol fieldOrProperty, CancellationToken cancellationToken); + + protected abstract void InsertStatement( + SyntaxEditor editor, SyntaxNode functionDeclaration, bool returnsVoid, SyntaxNode? statementToAddAfter, TStatementSyntax statement); + + public bool TryGetBlockForSingleParameterInitialization( + SyntaxNode functionDeclaration, + SemanticModel semanticModel, + ISyntaxFactsService syntaxFacts, + CancellationToken cancellationToken, + out IBlockOperation? blockStatement) + { + blockStatement = null; + + var functionBody = GetBody(functionDeclaration); + if (functionBody == null) + { + // We support initializing parameters, even when the containing member doesn't have a + // body. This is useful for when the user is typing a new constructor and hasn't written + // the body yet. + return true; + } + + // In order to get the block operation for the body of an anonymous function, we need to + // get it via `IAnonymousFunctionOperation.Body` instead of getting it directly from the body syntax. + + var operation = semanticModel.GetOperation( + syntaxFacts.IsAnonymousFunctionExpression(functionDeclaration) ? functionDeclaration : functionBody, + cancellationToken); + + if (operation == null) + return false; + + switch (operation.Kind) + { + case OperationKind.AnonymousFunction: + blockStatement = ((IAnonymousFunctionOperation)operation).Body; + break; + case OperationKind.Block: + blockStatement = (IBlockOperation)operation; + break; + default: + return false; + } + + return true; + } + + public void InsertStatement(SyntaxEditor editor, SyntaxNode functionDeclaration, bool returnsVoid, SyntaxNode? statementToAddAfter, SyntaxNode statement) + => InsertStatement(editor, functionDeclaration, returnsVoid, statementToAddAfter, (TStatementSyntax)statement); + + public async Task AddAssignmentAsync( + Document document, + IParameterSymbol parameter, + ISymbol fieldOrProperty, + CancellationToken cancellationToken) + { + if (parameter is { DeclaringSyntaxReferences: [var parameterReference] }) + { + var parameterDeclaration = parameterReference.GetSyntax(cancellationToken); + + var functionDeclaration = parameterDeclaration.FirstAncestorOrSelf(IsFunctionDeclaration); + if (functionDeclaration is not null) + { + // try to handle the case where the parameter is within something function-like (like a constructor) + + return await TryAddAssignmentForFunctionLikeDeclarationAsync( + document, parameter, fieldOrProperty, functionDeclaration, cancellationToken).ConfigureAwait(false); + } + else + { + // try to handle primary constructor case. + return await TryAddAssignmentForPrimaryConstructorAsync( + document, parameter, fieldOrProperty, cancellationToken).ConfigureAwait(false); + } + } + + return document.Project.Solution; + } + + private async Task TryAddAssignmentForFunctionLikeDeclarationAsync( + Document document, + IParameterSymbol parameter, + ISymbol fieldOrProperty, + SyntaxNode functionDeclaration, + CancellationToken cancellationToken) + { + var syntaxFacts = document.GetRequiredLanguageService(); + var semanticModel = await document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false); + + if (TryGetBlockForSingleParameterInitialization(functionDeclaration, semanticModel, syntaxFacts, cancellationToken, out var blockStatementOpt)) + { + var root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); + var editor = new SyntaxEditor(root, document.Project.Solution.Services); + AddAssignment(functionDeclaration, blockStatementOpt, parameter, fieldOrProperty, editor); + + var newDocument = document.WithSyntaxRoot(editor.GetChangedRoot()); + return newDocument.Project.Solution; + } + + return document.Project.Solution; + } + + private void AddAssignment( + SyntaxNode constructorDeclaration, + IBlockOperation? blockStatement, + IParameterSymbol parameter, + ISymbol fieldOrProperty, + SyntaxEditor editor) + { + // First see if the user has `(_x, y) = (x, y);` and attempt to update that. + if (TryUpdateTupleAssignment(blockStatement, parameter, fieldOrProperty, editor)) + return; + + var generator = editor.Generator; + + // Now that we've added any potential members, create an assignment between it + // and the parameter. + var initializationStatement = (TStatementSyntax)generator.ExpressionStatement( + generator.AssignmentStatement( + generator.MemberAccessExpression( + generator.ThisExpression(), + generator.IdentifierName(fieldOrProperty.Name)), + generator.IdentifierName(parameter.Name))); + + // Attempt to place the initialization in a good location in the constructor + // We'll want to keep initialization statements in the same order as we see + // parameters for the constructor. + var statementToAddAfter = TryGetStatementToAddInitializationAfter(parameter, blockStatement); + + InsertStatement(editor, constructorDeclaration, returnsVoid: true, statementToAddAfter, initializationStatement); + } + + private SyntaxNode? TryGetStatementToAddInitializationAfter( + IParameterSymbol parameter, IBlockOperation? blockStatement) + { + // look for an existing assignment for a parameter that comes before/after us. + // If we find one, we'll add ourselves before/after that parameter check. + foreach (var (sibling, before) in GetSiblingParameters(parameter)) + { + var statement = TryFindFieldOrPropertyAssignmentStatement(sibling, blockStatement); + if (statement != null) + { + if (before) + { + return statement.Syntax; + } + else + { + var statementIndex = blockStatement!.Operations.IndexOf(statement); + return statementIndex > 0 && blockStatement.Operations[statementIndex - 1] is { IsImplicit: false, Syntax: var priorSyntax } + ? priorSyntax + : null; + } + } + } + + // We couldn't find a reasonable location for the new initialization statement. + // Just place ourselves after the last statement in the constructor. + return TryGetLastStatement(blockStatement); + } + + public bool IsThrowNotImplementedProperty(Compilation compilation, IPropertySymbol property, CancellationToken cancellationToken) + { + using var _ = ArrayBuilder.GetInstance(out var accessors); + + if (property.GetMethod != null) + accessors.AddIfNotNull(GetAccessorBody(property.GetMethod, cancellationToken)); + + if (property.SetMethod != null) + accessors.AddIfNotNull(GetAccessorBody(property.SetMethod, cancellationToken)); + + if (accessors.Count == 0) + return false; + + foreach (var group in accessors.GroupBy(node => node.SyntaxTree)) + { + var semanticModel = compilation.GetSemanticModel(group.Key); + foreach (var accessorBody in accessors) + { + var operation = semanticModel.GetOperation(accessorBody, cancellationToken); + if (operation is null) + return false; + + if (!operation.IsSingleThrowNotImplementedOperation()) + return false; + } + } + + return true; + } +} diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/LanguageServices/InitializeParameter/IInitializeParameterService.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/LanguageServices/InitializeParameter/IInitializeParameterService.cs new file mode 100644 index 0000000000000..80c88c6bef232 --- /dev/null +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/LanguageServices/InitializeParameter/IInitializeParameterService.cs @@ -0,0 +1,30 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Editing; +using Microsoft.CodeAnalysis.Host; +using Microsoft.CodeAnalysis.LanguageService; +using Microsoft.CodeAnalysis.Operations; + +namespace Microsoft.CodeAnalysis.InitializeParameter; + +internal interface IInitializeParameterService : ILanguageService +{ + bool IsThrowNotImplementedProperty(Compilation compilation, IPropertySymbol property, CancellationToken cancellationToken); + + void InsertStatement( + SyntaxEditor editor, SyntaxNode functionDeclaration, bool returnsVoid, SyntaxNode? statementToAddAfter, SyntaxNode statement); + + Task AddAssignmentAsync( + Document document, IParameterSymbol parameter, ISymbol fieldOrProperty, CancellationToken cancellationToken); + + bool TryGetBlockForSingleParameterInitialization( + SyntaxNode functionDeclaration, + SemanticModel semanticModel, + ISyntaxFactsService syntaxFacts, + CancellationToken cancellationToken, + out IBlockOperation? blockStatement); +} diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/LanguageServices/InitializeParameter/InitializeParameterHelpersCore.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/LanguageServices/InitializeParameter/InitializeParameterHelpersCore.cs new file mode 100644 index 0000000000000..ad0c317f72421 --- /dev/null +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/LanguageServices/InitializeParameter/InitializeParameterHelpersCore.cs @@ -0,0 +1,182 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Immutable; +using System.Diagnostics.CodeAnalysis; +using Microsoft.CodeAnalysis.Diagnostics.Analyzers.NamingStyles; +using Microsoft.CodeAnalysis.Operations; +using Microsoft.CodeAnalysis.PooledObjects; +using Microsoft.CodeAnalysis.Shared.Utilities; + +namespace Microsoft.CodeAnalysis.InitializeParameter; + +internal static class InitializeParameterHelpersCore +{ + public static ImmutableArray<(IParameterSymbol parameter, bool before)> GetSiblingParameters(IParameterSymbol parameter) + { + using var _ = ArrayBuilder<(IParameterSymbol, bool before)>.GetInstance(out var siblings); + + if (parameter.ContainingSymbol is IMethodSymbol method) + { + var parameterIndex = method.Parameters.IndexOf(parameter); + + // look for an existing assignment for a parameter that comes before us. + // If we find one, we'll add ourselves after that parameter check. + for (var i = parameterIndex - 1; i >= 0; i--) + siblings.Add((method.Parameters[i], before: true)); + + // look for an existing check for a parameter that comes before us. + // If we find one, we'll add ourselves after that parameter check. + for (var i = parameterIndex + 1; i < method.Parameters.Length; i++) + siblings.Add((method.Parameters[i], before: false)); + } + + return siblings.ToImmutableAndClear(); + } + + public static bool IsParameterReference(IOperation? operation, IParameterSymbol parameter) + => operation.UnwrapImplicitConversion() is IParameterReferenceOperation parameterReference && + parameter.Equals(parameterReference.Parameter); + + public static bool IsParameterReferenceOrCoalesceOfParameterReference( + IOperation? value, IParameterSymbol parameter) + { + if (IsParameterReference(value, parameter)) + { + // We already have a member initialized with this parameter like: + // this.field = parameter + return true; + } + + if (value.UnwrapImplicitConversion() is ICoalesceOperation coalesceExpression && + IsParameterReference(coalesceExpression.Value, parameter)) + { + // We already have a member initialized with this parameter like: + // this.field = parameter ?? ... + return true; + } + + return false; + } + + public static string GenerateUniqueName(IParameterSymbol parameter, ImmutableArray parameterNameParts, NamingRule rule) + { + // Determine an appropriate name to call the new field. + var containingType = parameter.ContainingType; + var baseName = rule.NamingStyle.CreateName(parameterNameParts); + + // Ensure that the name is unique in the containing type so we + // don't stomp on an existing member. + var uniqueName = NameGenerator.GenerateUniqueName( + baseName, n => containingType.GetMembers(n).IsEmpty); + return uniqueName; + } + + public static IOperation? TryFindFieldOrPropertyAssignmentStatement(IParameterSymbol parameter, IBlockOperation? blockStatement) + => TryFindFieldOrPropertyAssignmentStatement(parameter, blockStatement, out _); + + private static IOperation? TryFindFieldOrPropertyAssignmentStatement( + IParameterSymbol parameter, IBlockOperation? blockStatement, out ISymbol? fieldOrProperty) + { + if (blockStatement != null) + { + var containingType = parameter.ContainingType; + foreach (var statement in blockStatement.Operations) + { + // look for something of the form: "this.s = s" or "this.s = s ?? ..." + if (IsFieldOrPropertyAssignment(statement, containingType, out var assignmentExpression, out fieldOrProperty) && + IsParameterReferenceOrCoalesceOfParameterReference(assignmentExpression, parameter)) + { + return statement; + } + + // look inside the form `(this.s, this.t) = (s, t)` + if (TryGetPartsOfTupleAssignmentOperation(statement, out var targetTuple, out var valueTuple)) + { + for (int i = 0, n = targetTuple.Elements.Length; i < n; i++) + { + var target = targetTuple.Elements[i]; + var value = valueTuple.Elements[i]; + + if (IsFieldOrPropertyReference(target, containingType, out fieldOrProperty) && + IsParameterReference(value, parameter)) + { + return statement; + } + } + } + } + } + + fieldOrProperty = null; + return null; + } + + public static bool TryGetPartsOfTupleAssignmentOperation( + IOperation operation, + [NotNullWhen(true)] out ITupleOperation? targetTuple, + [NotNullWhen(true)] out ITupleOperation? valueTuple) + { + if (operation is IExpressionStatementOperation + { + Operation: IDeconstructionAssignmentOperation + { + Target: ITupleOperation targetTupleTemp, + Value: IConversionOperation { Operand: ITupleOperation valueTupleTemp }, + } + } && + targetTupleTemp.Elements.Length == valueTupleTemp.Elements.Length) + { + targetTuple = targetTupleTemp; + valueTuple = valueTupleTemp; + return true; + } + + targetTuple = null; + valueTuple = null; + return false; + } + + private static bool IsParameterReferenceOrCoalesceOfParameterReference( + IAssignmentOperation assignmentExpression, IParameterSymbol parameter) + => IsParameterReferenceOrCoalesceOfParameterReference(assignmentExpression.Value, parameter); + + public static bool IsFieldOrPropertyReference( + IOperation? operation, INamedTypeSymbol containingType, + [NotNullWhen(true)] out ISymbol? fieldOrProperty) + { + if (operation is IMemberReferenceOperation memberReference && + memberReference.Member.ContainingType.Equals(containingType)) + { + if (memberReference.Member is IFieldSymbol or IPropertySymbol) + { + fieldOrProperty = memberReference.Member; + return true; + } + } + + fieldOrProperty = null; + return false; + } + + public static bool IsFieldOrPropertyAssignment(IOperation statement, INamedTypeSymbol containingType, [NotNullWhen(true)] out IAssignmentOperation? assignmentExpression) + => IsFieldOrPropertyAssignment(statement, containingType, out assignmentExpression, out _); + + public static bool IsFieldOrPropertyAssignment( + IOperation statement, INamedTypeSymbol containingType, + [NotNullWhen(true)] out IAssignmentOperation? assignmentExpression, + [NotNullWhen(true)] out ISymbol? fieldOrProperty) + { + if (statement is IExpressionStatementOperation expressionStatement && + expressionStatement.Operation is IAssignmentOperation assignment) + { + assignmentExpression = assignment; + return InitializeParameterHelpersCore.IsFieldOrPropertyReference(assignmentExpression.Target, containingType, out fieldOrProperty); + } + + fieldOrProperty = null; + assignmentExpression = null; + return false; + } +} diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/LanguageServices/MoveDeclarationNearReference/AbstractMoveDeclarationNearReferenceService.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/LanguageServices/MoveDeclarationNearReference/AbstractMoveDeclarationNearReferenceService.cs index 129959448690d..d742c69c03060 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/LanguageServices/MoveDeclarationNearReference/AbstractMoveDeclarationNearReferenceService.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/LanguageServices/MoveDeclarationNearReference/AbstractMoveDeclarationNearReferenceService.cs @@ -34,10 +34,13 @@ internal abstract partial class AbstractMoveDeclarationNearReferenceService< protected abstract SyntaxToken GetIdentifierOfVariableDeclarator(TVariableDeclaratorSyntax variableDeclarator); protected abstract Task TypesAreCompatibleAsync(Document document, ILocalSymbol localSymbol, TLocalDeclarationStatementSyntax declarationStatement, SyntaxNode right, CancellationToken cancellationToken); - public async Task CanMoveDeclarationNearReferenceAsync(Document document, SyntaxNode node, CancellationToken cancellationToken) + public async Task<(bool canMove, bool mayChangeSemantics)> CanMoveDeclarationNearReferenceAsync(Document document, SyntaxNode node, CancellationToken cancellationToken) { var state = await ComputeStateAsync(document, node, cancellationToken).ConfigureAwait(false); - return state != null; + if (state is null) + return default; + + return (canMove: true, CrossesMeaningfulBlock(state)); } private async Task ComputeStateAsync(Document document, SyntaxNode node, CancellationToken cancellationToken) @@ -75,9 +78,7 @@ public async Task MoveDeclarationNearReferenceAsync( { var state = await ComputeStateAsync(document, localDeclarationStatement, cancellationToken).ConfigureAwait(false); if (state == null) - { return document; - } var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); var editor = new SyntaxEditor(root, document.Project.Solution.Services); diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/LanguageServices/MoveDeclarationNearReference/IMoveDeclarationNearReferenceService.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/LanguageServices/MoveDeclarationNearReference/IMoveDeclarationNearReferenceService.cs index 168e41e4e92d3..c872efc5ce4ab 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/LanguageServices/MoveDeclarationNearReference/IMoveDeclarationNearReferenceService.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/LanguageServices/MoveDeclarationNearReference/IMoveDeclarationNearReferenceService.cs @@ -13,10 +13,10 @@ namespace Microsoft.CodeAnalysis.MoveDeclarationNearReference; internal interface IMoveDeclarationNearReferenceService : ILanguageService { /// - /// Returns true if is local declaration statement - /// that can be moved forward to be closer to its first reference. + /// Returns for canMove if is local + /// declaration statement that can be moved forward to be closer to its first reference. /// - Task CanMoveDeclarationNearReferenceAsync(Document document, SyntaxNode localDeclarationStatement, CancellationToken cancellationToken); + Task<(bool canMove, bool mayChangeSemantics)> CanMoveDeclarationNearReferenceAsync(Document document, SyntaxNode localDeclarationStatement, CancellationToken cancellationToken); /// /// Moves closer to its first reference. Only diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/LanguageServices/SyntaxGeneratorInternalExtensions/SyntaxGeneratorInternal.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/LanguageServices/SyntaxGeneratorInternalExtensions/SyntaxGeneratorInternal.cs index 5ab8c6e63bc72..271db0c4aaf77 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/LanguageServices/SyntaxGeneratorInternalExtensions/SyntaxGeneratorInternal.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/LanguageServices/SyntaxGeneratorInternalExtensions/SyntaxGeneratorInternal.cs @@ -2,10 +2,12 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System; using System.Collections.Generic; using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Operations; +using Microsoft.CodeAnalysis.Simplification; namespace Microsoft.CodeAnalysis.Editing; @@ -125,4 +127,32 @@ internal static bool ParameterIsScoped(IParameterSymbol symbol) public abstract SyntaxNode UnaryPattern(SyntaxToken operatorToken, SyntaxNode pattern); #endregion + + public abstract SyntaxNode DefaultExpression(ITypeSymbol type); + public abstract SyntaxNode DefaultExpression(SyntaxNode type); + + public abstract SyntaxNode CastExpression(SyntaxNode type, SyntaxNode expression); + + public SyntaxNode CastExpression(ITypeSymbol type, SyntaxNode expression) + => CastExpression(TypeExpression(type), expression); + + public SyntaxNode TypeExpression(ITypeSymbol typeSymbol) + => TypeExpression(typeSymbol, RefKind.None); + + public abstract SyntaxNode TypeExpression(ITypeSymbol typeSymbol, RefKind refKind); + + public abstract SyntaxNode BitwiseOrExpression(SyntaxNode left, SyntaxNode right); + + public SyntaxNode MemberAccessExpression(SyntaxNode? expression, SyntaxNode memberName) + { + return MemberAccessExpressionWorker(expression, memberName) + .WithAdditionalAnnotations(Simplifier.Annotation); + } + + public abstract SyntaxNode MemberAccessExpressionWorker(SyntaxNode? expression, SyntaxNode memberName); + public abstract SyntaxNode IdentifierName(string identifier); + + public abstract SyntaxNode ConvertExpression(SyntaxNode type, SyntaxNode expression); + public SyntaxNode ConvertExpression(ITypeSymbol type, SyntaxNode expression) + => ConvertExpression(TypeExpression(type), expression); } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/LanguageServices/TypeInferenceService/AbstractTypeInferenceService.AbstractTypeInferrer.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/LanguageServices/TypeInferenceService/AbstractTypeInferenceService.AbstractTypeInferrer.cs index ff11d0acf11fd..8880a61959ed0 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/LanguageServices/TypeInferenceService/AbstractTypeInferenceService.AbstractTypeInferrer.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/LanguageServices/TypeInferenceService/AbstractTypeInferenceService.AbstractTypeInferrer.cs @@ -75,9 +75,7 @@ protected IEnumerable GetTypes(SyntaxNode expression, bool ob private ImmutableArray Filter(IEnumerable types, bool filterUnusable = true) { - return types.Where(filterUnusable ? IsUsableTypeFunc : s_isNotNull) - .Distinct() - .ToImmutableArray(); + return [.. types.Where(filterUnusable ? IsUsableTypeFunc : s_isNotNull).Distinct()]; } protected IEnumerable CreateResult(SpecialType type, NullableAnnotation nullableAnnotation = NullableAnnotation.None) diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Simplification/AbstractSimplificationService.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Simplification/AbstractSimplificationService.cs index e054e086ca941..abc030986c383 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Simplification/AbstractSimplificationService.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Simplification/AbstractSimplificationService.cs @@ -22,7 +22,11 @@ namespace Microsoft.CodeAnalysis.Simplification; -internal abstract class AbstractSimplificationService : ISimplificationService +internal abstract class AbstractSimplificationService< + TCompilationUnitSyntax, + TExpressionSyntax, + TStatementSyntax, + TCrefSyntax>(ImmutableArray reducers) : ISimplificationService where TCompilationUnitSyntax : SyntaxNode where TExpressionSyntax : SyntaxNode where TStatementSyntax : SyntaxNode @@ -31,10 +35,7 @@ internal abstract class AbstractSimplificationService s_containsAnnotations = n => n.ContainsAnnotations; protected static readonly Func s_hasSimplifierAnnotation = n => n.HasAnnotation(Simplifier.Annotation); - private readonly ImmutableArray _reducers; - - protected AbstractSimplificationService(ImmutableArray reducers) - => _reducers = reducers; + private readonly ImmutableArray _reducers = reducers; protected abstract ImmutableArray GetNodesAndTokensToReduce(SyntaxNode root, Func isNodeOrTokenOutsideSimplifySpans); protected abstract SemanticModel GetSpeculativeSemanticModel(ref SyntaxNode nodeToSpeculate, SemanticModel originalSemanticModel, SyntaxNode originalNode); @@ -63,35 +64,22 @@ public async Task ReduceAsync( // we have no span if (!spanList.Any()) - { return document; - } var semanticModel = await document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false); - // Chaining of the Speculative SemanticModel (i.e. Generating a speculative SemanticModel from an existing Speculative SemanticModel) is not supported - // Hence make sure we always start working off of the actual SemanticModel instead of a speculative SemanticModel. + // Chaining of the Speculative SemanticModel (i.e. Generating a speculative SemanticModel from an existing + // Speculative SemanticModel) is not supported Hence make sure we always start working off of the actual + // SemanticModel instead of a speculative SemanticModel. Debug.Assert(!semanticModel.IsSpeculativeSemanticModel); - var root = await semanticModel.SyntaxTree.GetRootAsync(cancellationToken).ConfigureAwait(false); - -#if DEBUG - var originalDocHasErrors = await document.HasAnyErrorsAsync(cancellationToken).ConfigureAwait(false); -#endif - - var reduced = await this.ReduceCoreAsync(document, spanList, options, reducers, cancellationToken).ConfigureAwait(false); - - if (reduced != document) - { -#if DEBUG - if (!originalDocHasErrors) - { - await reduced.VerifyNoErrorsAsync("Error introduced by Simplification Service", cancellationToken).ConfigureAwait(false); - } -#endif - } + reducers = reducers.IsDefault ? _reducers : reducers; + // Take out any reducers that don't even apply with the current + // set of users options. i.e. no point running 'reduce to var' + // if the user doesn't have the 'var' preference set. + reducers = reducers.WhereAsArray(r => r.IsApplicable(options)); - return reduced; + return await this.ReduceCoreAsync(document, spanList, options, reducers, cancellationToken).ConfigureAwait(false); } } @@ -124,16 +112,6 @@ private async Task ReduceCoreAsync( if (nodesAndTokensToReduce.Any()) { - if (reducers.IsDefault) - { - reducers = _reducers; - } - - // Take out any reducers that don't even apply with the current - // set of users options. i.e. no point running 'reduce to var' - // if the user doesn't have the 'var' preference set. - reducers = reducers.WhereAsArray(r => r.IsApplicable(options)); - var reducedNodesMap = new ConcurrentDictionary(); var reducedTokensMap = new ConcurrentDictionary(); @@ -142,7 +120,7 @@ private async Task ReduceCoreAsync( // Note that this method doesn't update the original syntax tree. await this.ReduceAsync(document, root, nodesAndTokensToReduce, reducers, options, reducedNodesMap, reducedTokensMap, cancellationToken).ConfigureAwait(false); - if (reducedNodesMap.Any() || reducedTokensMap.Any()) + if (!reducedNodesMap.IsEmpty || !reducedTokensMap.IsEmpty) { // Update the syntax tree with reduced nodes/tokens. root = root.ReplaceSyntax( diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/SymbolFinder/SymbolFinderInternal.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/SymbolFinder/SymbolFinderInternal.cs new file mode 100644 index 0000000000000..d16e37c51fde3 --- /dev/null +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/SymbolFinder/SymbolFinderInternal.cs @@ -0,0 +1,94 @@ +// 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.Diagnostics.CodeAnalysis; +using System.Linq; +using System.Threading; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Shared.Extensions; +using Roslyn.Utilities; + +namespace Microsoft.CodeAnalysis.FindSymbols; + +internal static class SymbolFinderInternal +{ + /// + internal static ISymbol? FindSourceDefinition( + ISymbol? symbol, Solution solution, CancellationToken cancellationToken) + { + if (symbol != null) + { + symbol = symbol.GetOriginalUnreducedDefinition(); + switch (symbol.Kind) + { + case SymbolKind.Event: + case SymbolKind.Field: + case SymbolKind.Method: + case SymbolKind.Local: + case SymbolKind.NamedType: + case SymbolKind.Parameter: + case SymbolKind.Property: + case SymbolKind.TypeParameter: + case SymbolKind.Namespace: + return FindSourceDefinitionWorker(symbol, solution, cancellationToken); + } + } + + return null; + } + + private static ISymbol? FindSourceDefinitionWorker( + ISymbol symbol, + Solution solution, + CancellationToken cancellationToken) + { + // If it's already in source, then we might already be done + if (InSource(symbol)) + { + // If our symbol doesn't have a containing assembly, there's nothing better we can do to map this + // symbol somewhere else. The common case for this is a merged INamespaceSymbol that spans assemblies. + if (symbol.ContainingAssembly == null) + return symbol; + + // Just because it's a source symbol doesn't mean we have the final symbol we actually want. In retargeting cases, + // the retargeted symbol is from "source" but isn't equal to the actual source definition in the other project. Thus, + // we only want to return symbols from source here if it actually came from a project's compilation's assembly. If it isn't + // then we have a retargeting scenario and want to take our usual path below as if it was a metadata reference + foreach (var sourceProject in solution.Projects) + { + // If our symbol is actually a "regular" source symbol, then we know the compilation is holding the symbol alive + // and thus TryGetCompilation is sufficient. For another example of this pattern, see Solution.GetProject(IAssemblySymbol) + // which we happen to call below. + if (sourceProject.TryGetCompilation(out var compilation) && + symbol.ContainingAssembly.Equals(compilation.Assembly)) + { + return symbol; + } + } + } + else if (!symbol.Locations.Any(static loc => loc.IsInMetadata)) + { + // We have a symbol that's neither in source nor metadata + return null; + } + + var project = solution.GetProject(symbol.ContainingAssembly, cancellationToken); + + // Note: if the assembly came from a particular project, then we should be able to get the compilation without + // building it. That's because once we create the compilation, we'll hold onto it for the lifetime of the + // project, to avoid unnecessary recomputation. + if (project?.TryGetCompilation(out var projectCompilation) is true) + { + var symbolId = symbol.GetSymbolKey(cancellationToken); + var result = symbolId.Resolve(projectCompilation, ignoreAssemblyKey: true, cancellationToken: cancellationToken); + + return InSource(result.Symbol) ? result.Symbol : result.CandidateSymbols.FirstOrDefault(InSource); + } + + return null; + + static bool InSource([NotNullWhen(true)] ISymbol? symbol) + => symbol != null && symbol.Locations.Any(static loc => loc.IsInSource); + } +} diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Utilities/NullableHelpers.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Utilities/NullableHelpers.cs new file mode 100644 index 0000000000000..5a79af03350a3 --- /dev/null +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Utilities/NullableHelpers.cs @@ -0,0 +1,156 @@ +// 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.Linq; +using System.Threading; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.LanguageService; +using Microsoft.CodeAnalysis.Operations; +using Microsoft.CodeAnalysis.PooledObjects; +using Microsoft.CodeAnalysis.Shared.Extensions; +using Microsoft.CodeAnalysis.Text; + +namespace Microsoft.CodeAnalysis; + +internal static class NullableHelpers +{ + /// + /// Gets the declared symbol and root operation from the passed in declarationSyntax and calls . Note that this is bool and not bool? because we know that the symbol + /// is at the very least declared, so there's no need to return a null value. + /// + public static bool IsDeclaredSymbolAssignedPossiblyNullValue( + ISemanticFacts semanticFacts, + SemanticModel semanticModel, + SyntaxNode declarationSyntax, + CancellationToken cancellationToken) + { + var declaredSymbol = semanticModel.GetRequiredDeclaredSymbol(declarationSyntax, cancellationToken); + var declaredOperation = semanticModel.GetRequiredOperation(declarationSyntax, cancellationToken); + + var rootOperation = declaredOperation; + + // Walk up the tree to find a root for the operation + // that contains the declaration + while (rootOperation is not IBlockOperation && + rootOperation.Parent is not null) + { + rootOperation = rootOperation.Parent; + } + + return IsSymbolAssignedPossiblyNullValue( + semanticFacts, semanticModel, rootOperation, declaredSymbol, rootOperation.Syntax.Span, includeDeclaration: true, cancellationToken) == true; + } + + /// + /// Given an operation, goes through all descendent operations and returns true if the symbol passed in + /// is ever assigned a possibly null value as determined by nullable flow state. Returns + /// null if no references are found, letting the caller determine what to do with that information + /// + public static bool? IsSymbolAssignedPossiblyNullValue( + ISemanticFacts semanticFacts, + SemanticModel semanticModel, + IOperation rootOperation, + ISymbol symbol, + TextSpan span, + bool includeDeclaration, + CancellationToken cancellationToken) + { + var hasReference = false; + + using var _ = ArrayBuilder.GetInstance(out var stack); + stack.Push(rootOperation); + + while (stack.TryPop(out var operation)) + { + if (!span.IntersectsWith(operation.Syntax.Span)) + continue; + + if (span.Contains(operation.Syntax.Span) && + IsSymbolReferencedByOperation(operation)) + { + hasReference = true; + + if (operation is IAssignmentOperation assignmentOperation && + assignmentOperation.Syntax.RawKind == semanticFacts.SyntaxFacts.SyntaxKinds.SimpleAssignmentExpression) + { + // IsSymbolReferencedByOperation will ensure that the reference is the target of the assignment. + // + // Note: we care about the value after the assignment, so we have to check the RHS to see if maybe-null + // is flowing in. In other words `currentlyNotNull = maybeNUll;` will be maybe-null *after* the + // assignment. and should cause our caller to keep the type as nullable. + var typeInfo = semanticModel.GetTypeInfo(assignmentOperation.Value.Syntax, cancellationToken); + if (IsMaybeNull(typeInfo)) + return true; + + // We specifically are not recursing down the left side of this variable. If we have `x = not-null` + // then 'x' maybe-null in flowing in, but we care about what it is when flowing out, which the above + // check handled. + stack.Push(assignmentOperation.Value); + continue; + } + + // foreach statements are handled special because the iterator is not assignable, so the element type + // annotation is accurate for determining if the loop declaration has a reference that allows the symbol to + // be null + if (operation is IForEachLoopOperation forEachLoop) + { + var foreachInfo = semanticFacts.GetForEachSymbols(semanticModel, forEachLoop.Syntax); + + // Use NotAnnotated here to keep both Annotated and None (oblivious) treated the same, since + // this is directly looking at the annotation and not the flow state + if (foreachInfo.ElementType != null && foreachInfo.ElementType.NullableAnnotation != NullableAnnotation.NotAnnotated) + return true; + + // intentional fall through. + } + else if (operation is IVariableDeclaratorOperation variableDeclarator) + { + // IsSymbolReferencedByOperation ensures that GetVariableInitializer() returns a non-null value + var syntax = variableDeclarator.GetVariableInitializer()!.Value.Syntax; + var typeInfo = semanticModel.GetTypeInfo(syntax, cancellationToken); + if (IsMaybeNull(typeInfo)) + return true; + + // intentional fall through. + } + else + { + var typeInfo = semanticModel.GetTypeInfo(operation.Syntax, cancellationToken); + if (IsMaybeNull(typeInfo)) + return true; + + // intentional fall through. + } + } + + foreach (var childOperation in operation.ChildOperations.Reverse()) + stack.Push(childOperation); + } + + return hasReference ? false : null; + + static bool IsMaybeNull(TypeInfo typeInfo) + => typeInfo.Nullability.FlowState == NullableFlowState.MaybeNull; + + // + // Determines if an operations references a specific symbol. Note that this will recurse in some + // cases to work for operations like IAssignmentOperation, which logically references a symbol even if it + // is the Target operation that actually does. + // + bool IsSymbolReferencedByOperation(IOperation operation) + => operation switch + { + ILocalReferenceOperation localReference => localReference.Local.Equals(symbol), + IParameterReferenceOperation parameterReference => parameterReference.Parameter.Equals(symbol), + IAssignmentOperation assignment => IsSymbolReferencedByOperation(assignment.Target), + ITupleOperation tupleOperation => tupleOperation.Elements.Any(IsSymbolReferencedByOperation), + IForEachLoopOperation { LoopControlVariable: IVariableDeclaratorOperation variableDeclarator } => variableDeclarator.Symbol.Equals(symbol), + + // A variable initializer is required for this to be a meaningful operation for determining possible null assignment + IVariableDeclaratorOperation variableDeclarator when includeDeclaration => variableDeclarator.GetVariableInitializer() != null && variableDeclarator.Symbol.Equals(symbol), + _ => false + }; + } +} diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Utilities/SemanticDocument.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Utilities/SemanticDocument.cs index 34955fb3e05e9..6f57f0cf8e6c9 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Utilities/SemanticDocument.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Utilities/SemanticDocument.cs @@ -4,6 +4,7 @@ using System.Threading; using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; @@ -27,4 +28,7 @@ internal sealed class SemanticDocument(Document document, SourceText text, Synta var newDocument = this.Document.WithSyntaxRoot(root); return await CreateAsync(newDocument, cancellationToken).ConfigureAwait(false); } + + public TLanguageService GetRequiredLanguageService() where TLanguageService : class, ILanguageService + => this.Document.GetRequiredLanguageService(); } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Workspace/Mef/MefLanguageServices.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Workspace/Mef/MefLanguageServices.cs index 79cf67540bea4..3ed55fcf1f6ce 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Workspace/Mef/MefLanguageServices.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Workspace/Mef/MefLanguageServices.cs @@ -43,7 +43,7 @@ public MefLanguageServices( var factories = hostServices.GetExports() .Select(lz => (lazyService: new Lazy(() => lz.Value.CreateLanguageService(this), lz.Metadata), usesFactory: true)); - _services = services.Concat(factories).Where(lz => lz.lazyService.Metadata.Language == language).ToImmutableArray(); + _services = [.. services.Concat(factories).Where(lz => lz.lazyService.Metadata.Language == language)]; } public override HostWorkspaceServices WorkspaceServices => _workspaceServices; @@ -60,7 +60,7 @@ public override void Dispose() ImmutableArray disposableServices; lock (_gate) { - disposableServices = _ownedDisposableServices.ToImmutableArray(); + disposableServices = [.. _ownedDisposableServices]; _ownedDisposableServices.Clear(); } @@ -140,7 +140,7 @@ private bool TryGetService(Type serviceType, [NotNullWhen(true)] out Lazy> services) { public (string type, string layer)[] Metadata - => services.Select(s => (s.Metadata.ServiceType, s.Metadata.Layer)).ToArray(); + => [.. services.Select(s => (s.Metadata.ServiceType, s.Metadata.Layer))]; } } } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Workspace/Mef/MefWorkspaceServices.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Workspace/Mef/MefWorkspaceServices.cs index edb6c31002036..dd1225ec5575c 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Workspace/Mef/MefWorkspaceServices.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Workspace/Mef/MefWorkspaceServices.cs @@ -47,7 +47,7 @@ public MefWorkspaceServices(IMefHostExportProvider host, Workspace workspace) var factories = host.GetExports() .Select(lz => (new Lazy(() => lz.Value.CreateService(this), lz.Metadata), usesFactory: true)); - _services = services.Concat(factories).ToImmutableArray(); + _services = [.. services, .. factories]; } public override HostServices HostServices @@ -77,7 +77,7 @@ public override void Dispose() ImmutableArray disposableServices; lock (_gate) { - disposableServices = _ownedDisposableServices.ToImmutableArray(); + disposableServices = [.. _ownedDisposableServices]; _ownedDisposableServices.Clear(); } @@ -214,7 +214,7 @@ internal bool TryGetLanguageServices(string languageName, [NotNullWhen(true)] ou internal sealed class LazyServiceMetadataDebuggerProxy(ImmutableArray> services) { public (string type, string layer)[] Metadata - => services.Select(s => (s.Metadata.ServiceType, s.Metadata.Layer)).ToArray(); + => [.. services.Select(s => (s.Metadata.ServiceType, s.Metadata.Layer))]; } } } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/WorkspaceExtensions.projitems b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/WorkspaceExtensions.projitems index 32a4686da39e5..694d975b41450 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/WorkspaceExtensions.projitems +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/WorkspaceExtensions.projitems @@ -21,9 +21,13 @@ + + + + @@ -138,8 +142,10 @@ + + diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/VisualBasic/CodeGeneration/AttributeGenerator.vb b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/VisualBasic/CodeGeneration/AttributeGenerator.vb index 9aa1108d4d98f..159417c7c0c60 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/VisualBasic/CodeGeneration/AttributeGenerator.vb +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/VisualBasic/CodeGeneration/AttributeGenerator.vb @@ -28,14 +28,17 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeGeneration End Function Private Function GenerateAttribute(attribute As AttributeData, options As CodeGenerationContextInfo, target As SyntaxToken?) As AttributeSyntax - Dim reusableSyntax = GetReuseableSyntaxNodeForAttribute(Of AttributeSyntax)(attribute, options) + Dim reusableSyntax = If(options.Context.ReuseSyntax, + GetReuseableSyntaxNodeForAttribute(Of AttributeSyntax)(attribute), + Nothing) If reusableSyntax IsNot Nothing Then Return reusableSyntax End If - Return SyntaxFactory.Attribute(If(target.HasValue, SyntaxFactory.AttributeTarget(target.Value), Nothing), - attribute.AttributeClass.GenerateTypeSyntax(), - GenerateArgumentList(options.Generator, attribute)) + Return SyntaxFactory.Attribute( + If(target.HasValue, SyntaxFactory.AttributeTarget(target.Value), Nothing), + attribute.AttributeClass.GenerateTypeSyntax(), + GenerateArgumentList(options.Generator, attribute)) End Function Private Function GenerateArgumentList(generator As SyntaxGenerator, attribute As AttributeData) As ArgumentListSyntax diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/VisualBasic/CodeGeneration/ExpressionGenerator.vb b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/VisualBasic/CodeGeneration/ExpressionGenerator.vb index cf225e9b5861d..c350e520b28ac 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/VisualBasic/CodeGeneration/ExpressionGenerator.vb +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/VisualBasic/CodeGeneration/ExpressionGenerator.vb @@ -28,7 +28,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeGeneration SyntaxFactory.SeparatedList(typedConstant.Values.Select(Function(v) GenerateExpression(generator, v)))) End If Case TypedConstantKind.Type - If Not TypeOf typedConstant.Value Is ITypeSymbol Then + If TypeOf typedConstant.Value IsNot ITypeSymbol Then Return GenerateNothingLiteral() End If @@ -48,7 +48,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeGeneration Return GenerateExpression(generator, DirectCast(type, INamedTypeSymbol).TypeArguments(0), value, canUseFieldReference) ElseIf type?.TypeKind = TypeKind.Enum Then Return DirectCast(VisualBasicFlagsEnumGenerator.Instance.CreateEnumConstantValue( - generator, DirectCast(type, INamedTypeSymbol), value), ExpressionSyntax) + DirectCast(type, INamedTypeSymbol), value), ExpressionSyntax) End If End If diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/VisualBasic/CodeGeneration/NamespaceGenerator.vb b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/VisualBasic/CodeGeneration/NamespaceGenerator.vb index 8915c423b2d56..7dbb6d9ce1a28 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/VisualBasic/CodeGeneration/NamespaceGenerator.vb +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/VisualBasic/CodeGeneration/NamespaceGenerator.vb @@ -18,7 +18,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeGeneration availableIndices As IList(Of Boolean), cancellationToken As CancellationToken) As CompilationUnitSyntax Dim declaration = GenerateNamespaceDeclaration(service, [namespace], options, cancellationToken) - If Not TypeOf declaration Is NamespaceBlockSyntax Then + If TypeOf declaration IsNot NamespaceBlockSyntax Then Throw New ArgumentException(WorkspaceExtensionsResources.Namespace_can_not_be_added_in_this_destination) End If @@ -33,7 +33,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeGeneration availableIndices As IList(Of Boolean), cancellationToken As CancellationToken) As NamespaceBlockSyntax Dim declaration = GenerateNamespaceDeclaration(service, [namespace], options, cancellationToken) - If Not TypeOf declaration Is NamespaceBlockSyntax Then + If TypeOf declaration IsNot NamespaceBlockSyntax Then Throw New ArgumentException(WorkspaceExtensionsResources.Namespace_can_not_be_added_in_this_destination) End If diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/VisualBasic/CodeGeneration/VisualBasicFlagsEnumGenerator.vb b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/VisualBasic/CodeGeneration/VisualBasicFlagsEnumGenerator.vb index ebbe31d472e15..c66646e28a41c 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/VisualBasic/CodeGeneration/VisualBasicFlagsEnumGenerator.vb +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/VisualBasic/CodeGeneration/VisualBasicFlagsEnumGenerator.vb @@ -6,27 +6,32 @@ Imports Microsoft.CodeAnalysis.CodeGeneration Imports Microsoft.CodeAnalysis.Editing Namespace Microsoft.CodeAnalysis.VisualBasic.CodeGeneration - Friend Class VisualBasicFlagsEnumGenerator + Friend NotInheritable Class VisualBasicFlagsEnumGenerator Inherits AbstractFlagsEnumGenerator - Public Shared ReadOnly Instance As VisualBasicFlagsEnumGenerator = New VisualBasicFlagsEnumGenerator + Public Shared ReadOnly Instance As New VisualBasicFlagsEnumGenerator Private Sub New() End Sub + Protected Overrides ReadOnly Property SyntaxGenerator As SyntaxGeneratorInternal + Get + Return VisualBasicSyntaxGeneratorInternal.Instance + End Get + End Property + Protected Overrides Function CreateExplicitlyCastedLiteralValue( - generator As SyntaxGenerator, enumType As INamedTypeSymbol, underlyingSpecialType As SpecialType, constantValue As Object) As SyntaxNode - Dim expression = ExpressionGenerator.GenerateNonEnumValueExpression( + Dim expression = GenerateNonEnumValueExpression( enumType.EnumUnderlyingType, constantValue, canUseFieldReference:=True) Dim constantValueULong = underlyingSpecialType.ConvertUnderlyingValueToUInt64(constantValue) If constantValueULong = 0 Then Return expression End If - Return generator.ConvertExpression(enumType, expression) + Return Me.SyntaxGenerator.ConvertExpression(enumType, expression) End Function Protected Overrides Function IsValidName(enumType As INamedTypeSymbol, name As String) As Boolean diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/VisualBasic/Extensions/CompilationUnitSyntaxExtensions.vb b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/VisualBasic/Extensions/CompilationUnitSyntaxExtensions.vb index 89ad2b1f40df9..381d5bbced97b 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/VisualBasic/Extensions/CompilationUnitSyntaxExtensions.vb +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/VisualBasic/Extensions/CompilationUnitSyntaxExtensions.vb @@ -16,11 +16,10 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Extensions Friend Module CompilationUnitSyntaxExtensions - Public Function CanAddImportsStatements(contextNode As SyntaxNode, allowInHiddenRegions As Boolean, cancellationToken As CancellationToken) As Boolean - If contextNode.GetAncestor(Of ImportsStatementSyntax)() IsNot Nothing Then - Return False - End If - + Public Function CanAddImportsStatements( + contextNode As SyntaxNode, + allowInHiddenRegions As Boolean, + cancellationToken As CancellationToken) As Boolean If allowInHiddenRegions Then Return True End If diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/VisualBasic/Extensions/ObjectCreationExpressionExtensions.vb b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/VisualBasic/Extensions/ObjectCreationExpressionExtensions.vb index cfa61e90879bd..960352db235d5 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/VisualBasic/Extensions/ObjectCreationExpressionExtensions.vb +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/VisualBasic/Extensions/ObjectCreationExpressionExtensions.vb @@ -25,7 +25,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Extensions End If If nextToken.IsKindOrHasMatchingText(SyntaxKind.DotToken) Then - If Not TypeOf objectCreationExpression.Type Is PredefinedTypeSyntax Then + If TypeOf objectCreationExpression.Type IsNot PredefinedTypeSyntax Then Return False End If End If diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/VisualBasic/Extensions/SemanticModelExtensions.vb b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/VisualBasic/Extensions/SemanticModelExtensions.vb index 776ac42320244..6513086878e59 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/VisualBasic/Extensions/SemanticModelExtensions.vb +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/VisualBasic/Extensions/SemanticModelExtensions.vb @@ -6,10 +6,9 @@ Imports System.Collections.Immutable Imports System.Runtime.CompilerServices Imports System.Threading Imports Microsoft.CodeAnalysis +Imports Microsoft.CodeAnalysis.CodeGeneration Imports Microsoft.CodeAnalysis.Diagnostics.Analyzers.NamingStyles -Imports Microsoft.CodeAnalysis.Utilities Imports Microsoft.CodeAnalysis.VisualBasic.Syntax -Imports Microsoft.CodeAnalysis.VisualBasic.LanguageService Namespace Microsoft.CodeAnalysis.VisualBasic.Extensions Partial Friend Module SemanticModelExtensions diff --git a/src/Features/VisualBasic/Portable/InitializeParameter/InitializeParameterHelpers.vb b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/VisualBasic/LanguageServices/InitializeParameter/InitializeParameterHelpers.vb similarity index 88% rename from src/Features/VisualBasic/Portable/InitializeParameter/InitializeParameterHelpers.vb rename to src/Workspaces/SharedUtilitiesAndExtensions/Workspace/VisualBasic/LanguageServices/InitializeParameter/InitializeParameterHelpers.vb index 119e787ed401e..22d0b8b80d40c 100644 --- a/src/Features/VisualBasic/Portable/InitializeParameter/InitializeParameterHelpers.vb +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/VisualBasic/LanguageServices/InitializeParameter/InitializeParameterHelpers.vb @@ -3,6 +3,7 @@ ' See the LICENSE file in the project root for more information. Imports System.Collections.Immutable +Imports Microsoft.CodeAnalysis.CodeGeneration Imports Microsoft.CodeAnalysis.Editing Imports Microsoft.CodeAnalysis.Operations Imports Microsoft.CodeAnalysis.VisualBasic.Syntax @@ -57,5 +58,12 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.InitializeParameter editor.SetStatements(functionDeclaration, newStatements) End If End Sub + + Public Shared Function GetArgument(argument As ArgumentSyntax) As Argument(Of ExpressionSyntax) + Return New Argument(Of ExpressionSyntax)( + RefKind.None, + TryCast(argument, SimpleArgumentSyntax)?.NameColonEquals?.Name.Identifier.ValueText, + argument.GetArgumentExpression()) + End Function End Class End Namespace diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/VisualBasic/LanguageServices/InitializeParameter/VisualBasicInitializeParameterService.vb b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/VisualBasic/LanguageServices/InitializeParameter/VisualBasicInitializeParameterService.vb new file mode 100644 index 0000000000000..61424d25e5208 --- /dev/null +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/VisualBasic/LanguageServices/InitializeParameter/VisualBasicInitializeParameterService.vb @@ -0,0 +1,58 @@ +' Licensed to the .NET Foundation under one or more agreements. +' The .NET Foundation licenses this file to you under the MIT license. +' See the LICENSE file in the project root for more information. + +Imports System.Composition +Imports System.Threading +Imports Microsoft.CodeAnalysis.Editing +Imports Microsoft.CodeAnalysis.Host.Mef +Imports Microsoft.CodeAnalysis.InitializeParameter +Imports Microsoft.CodeAnalysis.Operations +Imports Microsoft.CodeAnalysis.VisualBasic.Syntax + +Namespace Microsoft.CodeAnalysis.VisualBasic.InitializeParameter + + Friend NotInheritable Class VisualBasicInitializeParameterService + Inherits AbstractInitializerParameterService(Of StatementSyntax) + + + + Public Sub New() + End Sub + + Protected Overrides Function GetAccessorBody(accessor As IMethodSymbol, cancellationToken As CancellationToken) As SyntaxNode + If accessor.DeclaringSyntaxReferences.Length = 0 Then + Return Nothing + End If + + Dim reference = accessor.DeclaringSyntaxReferences(0).GetSyntax(cancellationToken) + Return TryCast(TryCast(reference, AccessorStatementSyntax)?.Parent, AccessorBlockSyntax) + End Function + + Protected Overrides Function IsFunctionDeclaration(node As SyntaxNode) As Boolean + Return InitializeParameterHelpers.IsFunctionDeclaration(node) + End Function + + Protected Overrides Sub InsertStatement(editor As SyntaxEditor, functionDeclaration As SyntaxNode, returnsVoid As Boolean, statementToAddAfter As SyntaxNode, statement As StatementSyntax) + InitializeParameterHelpers.InsertStatement(editor, functionDeclaration, statementToAddAfter, statement) + End Sub + + Protected Overrides Function GetBody(methodNode As SyntaxNode) As SyntaxNode + Return InitializeParameterHelpers.GetBody(methodNode) + End Function + + Protected Overrides Function TryGetLastStatement(blockStatement As IBlockOperation) As SyntaxNode + Return InitializeParameterHelpers.TryGetLastStatement(blockStatement) + End Function + + Protected Overrides Function TryUpdateTupleAssignment(blockStatement As IBlockOperation, parameter As IParameterSymbol, fieldOrProperty As ISymbol, editor As SyntaxEditor) As Boolean + ' Not supported in VB + Return False + End Function + + Protected Overrides Function TryAddAssignmentForPrimaryConstructorAsync(document As Document, parameter As IParameterSymbol, fieldOrProperty As ISymbol, cancellationToken As CancellationToken) As Task(Of Solution) + ' Nothing to do in VB. + Return Task.FromResult(document.Project.Solution) + End Function + End Class +End Namespace diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/VisualBasic/LanguageServices/VisualBasicFileBannerFactsService.vb b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/VisualBasic/LanguageServices/VisualBasicFileBannerFactsService.vb index 0d4f75615a550..b8f83beec16b2 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/VisualBasic/LanguageServices/VisualBasicFileBannerFactsService.vb +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/VisualBasic/LanguageServices/VisualBasicFileBannerFactsService.vb @@ -8,7 +8,7 @@ Imports Microsoft.CodeAnalysis.LanguageService Namespace Microsoft.CodeAnalysis.VisualBasic.LanguageService - Friend Class VisualBasicFileBannerFactsService + Friend NotInheritable Class VisualBasicFileBannerFactsService Inherits VisualBasicFileBannerFacts Implements IFileBannerFactsService diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/VisualBasic/LanguageServices/VisualBasicSyntaxGeneratorInternal.vb b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/VisualBasic/LanguageServices/VisualBasicSyntaxGeneratorInternal.vb index c8d1a1c29926e..d67202e734f71 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/VisualBasic/LanguageServices/VisualBasicSyntaxGeneratorInternal.vb +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/VisualBasic/LanguageServices/VisualBasicSyntaxGeneratorInternal.vb @@ -9,6 +9,7 @@ Imports Microsoft.CodeAnalysis.Editing Imports Microsoft.CodeAnalysis.Host.Mef Imports Microsoft.CodeAnalysis.LanguageService Imports Microsoft.CodeAnalysis.Operations +Imports Microsoft.CodeAnalysis.Simplification Imports Microsoft.CodeAnalysis.VisualBasic.LanguageService Imports Microsoft.CodeAnalysis.VisualBasic.Syntax @@ -515,5 +516,55 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeGeneration End Function #End Region + + Public Overrides Function BitwiseOrExpression(left As SyntaxNode, right As SyntaxNode) As SyntaxNode + Return SyntaxFactory.OrExpression(Parenthesize(left), Parenthesize(right)) + End Function + + Public Overrides Function CastExpression(type As SyntaxNode, expression As SyntaxNode) As SyntaxNode + Return SyntaxFactory.DirectCastExpression(DirectCast(expression, ExpressionSyntax), DirectCast(type, TypeSyntax)).WithAdditionalAnnotations(Simplifier.Annotation) + End Function + + Public Overrides Function DefaultExpression(type As ITypeSymbol) As SyntaxNode + Return SyntaxFactory.NothingLiteralExpression(SyntaxFactory.Token(SyntaxKind.NothingKeyword)) + End Function + + Public Overrides Function DefaultExpression(type As SyntaxNode) As SyntaxNode + Return SyntaxFactory.NothingLiteralExpression(SyntaxFactory.Token(SyntaxKind.NothingKeyword)) + End Function + + Public Overrides Function IdentifierName(identifier As String) As SyntaxNode + Return identifier.ToIdentifierName() + End Function + + Public Overrides Function MemberAccessExpressionWorker(expression As SyntaxNode, simpleName As SyntaxNode) As SyntaxNode + Return SyntaxFactory.SimpleMemberAccessExpression( + If(expression IsNot Nothing, ParenthesizeLeft(expression), Nothing), + SyntaxFactory.Token(SyntaxKind.DotToken), + DirectCast(simpleName, SimpleNameSyntax)) + End Function + + ' parenthesize the left-side of a dot or target of an invocation if not unnecessary + Public Shared Function ParenthesizeLeft(expression As SyntaxNode) As ExpressionSyntax + Dim expressionSyntax = DirectCast(expression, ExpressionSyntax) + If TypeOf expressionSyntax Is TypeSyntax _ + OrElse expressionSyntax.IsMeMyBaseOrMyClass() _ + OrElse expressionSyntax.IsKind(SyntaxKind.ParenthesizedExpression) _ + OrElse expressionSyntax.IsKind(SyntaxKind.InvocationExpression) _ + OrElse expressionSyntax.IsKind(SyntaxKind.SimpleMemberAccessExpression) Then + Return expressionSyntax + Else + Return expressionSyntax.Parenthesize() + End If + End Function + + Public Overrides Function TypeExpression(typeSymbol As ITypeSymbol, refKind As RefKind) As SyntaxNode + ' VB doesn't support explicit ref-kinds for types. + Return typeSymbol.GenerateTypeSyntax() + End Function + + Public Overrides Function ConvertExpression(type As SyntaxNode, expression As SyntaxNode) As SyntaxNode + Return SyntaxFactory.CTypeExpression(DirectCast(expression, ExpressionSyntax), DirectCast(type, TypeSyntax)).WithAdditionalAnnotations(Simplifier.Annotation) + End Function End Class End Namespace diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/VisualBasic/LanguageServices/VisualBasicTypeInferenceService.TypeInferrer.vb b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/VisualBasic/LanguageServices/VisualBasicTypeInferenceService.TypeInferrer.vb index fc04b0fa103b9..ded2d6fb9db32 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/VisualBasic/LanguageServices/VisualBasicTypeInferenceService.TypeInferrer.vb +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/VisualBasic/LanguageServices/VisualBasicTypeInferenceService.TypeInferrer.vb @@ -10,9 +10,8 @@ Imports Microsoft.CodeAnalysis.VisualBasic.Symbols Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Namespace Microsoft.CodeAnalysis.VisualBasic - - Partial Friend Class VisualBasicTypeInferenceService - Private Class TypeInferrer + Partial Friend NotInheritable Class VisualBasicTypeInferenceService + Private NotInheritable Class TypeInferrer Inherits AbstractTypeInferrer Public Sub New(semanticModel As SemanticModel, cancellationToken As CancellationToken) @@ -26,7 +25,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic Protected Overrides Function GetTypes_DoNotCallDirectly(node As SyntaxNode, objectAsDefault As Boolean) As IEnumerable(Of TypeInferenceInfo) If node IsNot Nothing Then - Dim info = SemanticModel.GetTypeInfo(node) + Dim info = SemanticModel.GetTypeInfo(node, CancellationToken) If info.Type IsNot Nothing AndAlso info.Type.TypeKind <> TypeKind.Error Then Return CreateResult(info.Type) End If @@ -106,7 +105,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic Return SpecializedCollections.EmptyEnumerable(Of TypeInferenceInfo)() End If - Dim typeSymbol = SemanticModel.GetTypeInfo(expressionType).Type + Dim typeSymbol = SemanticModel.GetTypeInfo(expressionType, CancellationToken).Type If TypeOf typeSymbol IsNot INamedTypeSymbol Then Return SpecializedCollections.EmptyEnumerable(Of TypeInferenceInfo)() End If @@ -247,7 +246,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic Return SpecializedCollections.EmptyEnumerable(Of TypeInferenceInfo)() End If - Dim info = SemanticModel.GetSymbolInfo(invocation) + Dim info = SemanticModel.GetSymbolInfo(invocation, CancellationToken) ' Check all the methods that have at least enough arguments to support being ' called with argument at this position. Note: if they're calling an extension ' method then it will need one more argument in order for us to call it. @@ -277,7 +276,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic End If If targetExpression IsNot Nothing Then - Dim expressionType = SemanticModel.GetTypeInfo(targetExpression) + Dim expressionType = SemanticModel.GetTypeInfo(targetExpression, CancellationToken) If TypeOf expressionType.Type Is IArrayTypeSymbol Then Return CreateResult(Compilation.GetSpecialType(SpecialType.System_Int32)) End If @@ -290,7 +289,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic ' ' etc. Dim creation = TryCast(argumentList.Parent, ObjectCreationExpressionSyntax) - Dim info = SemanticModel.GetSymbolInfo(creation.Type) + Dim info = SemanticModel.GetSymbolInfo(creation.Type, CancellationToken) Dim namedType = TryCast(info.Symbol, INamedTypeSymbol) If namedType IsNot Nothing Then If namedType.TypeKind = TypeKind.Delegate Then @@ -331,7 +330,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic Return SpecializedCollections.EmptyEnumerable(Of TypeInferenceInfo)() End If - Dim info = SemanticModel.GetSymbolInfo(attribute) + Dim info = SemanticModel.GetSymbolInfo(attribute, CancellationToken) Dim symbols = info.GetBestOrAllSymbols() If symbols.Any() Then Dim methods = symbols.OfType(Of IMethodSymbol)() @@ -983,7 +982,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic If node.IsKind(SyntaxKind.IdentifierName) Then Dim identifier = DirectCast(node, IdentifierNameSyntax) If CaseInsensitiveComparison.Equals(parameterName, identifier.Identifier.ValueText) AndAlso - SemanticModel.GetSymbolInfo(identifier.Identifier).Symbol?.Kind = SymbolKind.Parameter Then + SemanticModel.GetSymbolInfo(identifier.Identifier, CancellationToken).Symbol?.Kind = SymbolKind.Parameter Then Return InferTypes(identifier).FirstOrDefault().InferredType End If Else @@ -1001,12 +1000,12 @@ Namespace Microsoft.CodeAnalysis.VisualBasic End Function Private Function InferTypeInNamedFieldInitializer(initializer As NamedFieldInitializerSyntax) As IEnumerable(Of TypeInferenceInfo) - Dim right = SemanticModel.GetTypeInfo(initializer.Name).Type + Dim right = SemanticModel.GetTypeInfo(initializer.Name, CancellationToken).Type If right IsNot Nothing AndAlso TypeOf right IsNot IErrorTypeSymbol Then Return CreateResult(right) End If - Return CreateResult(SemanticModel.GetTypeInfo(initializer.Expression).Type) + Return CreateResult(SemanticModel.GetTypeInfo(initializer.Expression, CancellationToken).Type) End Function Public Function InferTypeInCaseStatement(caseStatement As CaseStatementSyntax) As IEnumerable(Of TypeInferenceInfo) diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/VisualBasic/VisualBasicWorkspaceExtensions.projitems b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/VisualBasic/VisualBasicWorkspaceExtensions.projitems index d886374b01356..60d98682fafa9 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/VisualBasic/VisualBasicWorkspaceExtensions.projitems +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/VisualBasic/VisualBasicWorkspaceExtensions.projitems @@ -67,9 +67,11 @@ + + @@ -105,4 +107,7 @@ + + + \ No newline at end of file diff --git a/src/Workspaces/VisualBasic/Portable/Classification/SyntaxClassification/IdentifierNameSyntaxClassifier.vb b/src/Workspaces/VisualBasic/Portable/Classification/SyntaxClassification/IdentifierNameSyntaxClassifier.vb index 869de16deb2fe..a4f40b4977eb2 100644 --- a/src/Workspaces/VisualBasic/Portable/Classification/SyntaxClassification/IdentifierNameSyntaxClassifier.vb +++ b/src/Workspaces/VisualBasic/Portable/Classification/SyntaxClassification/IdentifierNameSyntaxClassifier.vb @@ -18,11 +18,17 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Classification.Classifiers Public Overrides ReadOnly Property SyntaxNodeTypes As ImmutableArray(Of Type) = ImmutableArray.Create(GetType(IdentifierNameSyntax)) - Public Overrides Sub AddClassifications(syntax As SyntaxNode, textSpan As TextSpan, semanticModel As SemanticModel, options As ClassificationOptions, result As SegmentedList(Of ClassifiedSpan), cancellationToken As CancellationToken) + Public Overrides Sub AddClassifications( + syntax As SyntaxNode, + textSpan As TextSpan, + semanticModel As SemanticModel, + options As ClassificationOptions, + result As SegmentedList(Of ClassifiedSpan), + cancellationToken As CancellationToken) Dim identifierName = DirectCast(syntax, IdentifierNameSyntax) Dim identifier = identifierName.Identifier If CaseInsensitiveComparison.Equals(identifier.ValueText, s_awaitText) Then - Dim symbolInfo = semanticModel.GetSymbolInfo(identifier) + Dim symbolInfo = semanticModel.GetSymbolInfo(identifier, cancellationToken) If symbolInfo.GetAnySymbol() Is Nothing Then result.Add(New ClassifiedSpan(ClassificationTypeNames.Keyword, identifier.Span)) Return diff --git a/src/Workspaces/VisualBasic/Portable/CodeCleanup/Providers/AddMissingTokensCodeCleanupProvider.vb b/src/Workspaces/VisualBasic/Portable/CodeCleanup/Providers/AddMissingTokensCodeCleanupProvider.vb index 5323ec7417111..f456bf60f08b5 100644 --- a/src/Workspaces/VisualBasic/Portable/CodeCleanup/Providers/AddMissingTokensCodeCleanupProvider.vb +++ b/src/Workspaces/VisualBasic/Portable/CodeCleanup/Providers/AddMissingTokensCodeCleanupProvider.vb @@ -141,9 +141,9 @@ Namespace Microsoft.CodeAnalysis.CodeCleanup.Providers Return newNode End If - If Not TypeOf node.Expression Is NameSyntax AndAlso - Not TypeOf node.Expression Is ParenthesizedExpressionSyntax AndAlso - Not TypeOf node.Expression Is MemberAccessExpressionSyntax Then + If TypeOf node.Expression IsNot NameSyntax AndAlso + TypeOf node.Expression IsNot ParenthesizedExpressionSyntax AndAlso + TypeOf node.Expression IsNot MemberAccessExpressionSyntax Then Return newNode End If diff --git a/src/Workspaces/VisualBasic/Portable/CodeGeneration/VisualBasicSyntaxGenerator.vb b/src/Workspaces/VisualBasic/Portable/CodeGeneration/VisualBasicSyntaxGenerator.vb index 0631af24ca037..a51af9b5cd3bf 100644 --- a/src/Workspaces/VisualBasic/Portable/CodeGeneration/VisualBasicSyntaxGenerator.vb +++ b/src/Workspaces/VisualBasic/Portable/CodeGeneration/VisualBasicSyntaxGenerator.vb @@ -132,18 +132,6 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeGeneration Return SyntaxFactory.AndExpression(Parenthesize(left), Parenthesize(right)) End Function - Public Overrides Function BitwiseOrExpression(left As SyntaxNode, right As SyntaxNode) As SyntaxNode - Return SyntaxFactory.OrExpression(Parenthesize(left), Parenthesize(right)) - End Function - - Public Overrides Function CastExpression(type As SyntaxNode, expression As SyntaxNode) As SyntaxNode - Return SyntaxFactory.DirectCastExpression(DirectCast(expression, ExpressionSyntax), DirectCast(type, TypeSyntax)).WithAdditionalAnnotations(Simplifier.Annotation) - End Function - - Public Overrides Function ConvertExpression(type As SyntaxNode, expression As SyntaxNode) As SyntaxNode - Return SyntaxFactory.CTypeExpression(DirectCast(expression, ExpressionSyntax), DirectCast(type, TypeSyntax)).WithAdditionalAnnotations(Simplifier.Annotation) - End Function - Public Overrides Function ConditionalExpression(condition As SyntaxNode, whenTrue As SyntaxNode, whenFalse As SyntaxNode) As SyntaxNode Return SyntaxFactory.TernaryConditionalExpression( DirectCast(condition, ExpressionSyntax), @@ -163,16 +151,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeGeneration Return SyntaxFactory.Literal(text, value) End Function - Public Overrides Function DefaultExpression(type As ITypeSymbol) As SyntaxNode - Return SyntaxFactory.NothingLiteralExpression(SyntaxFactory.Token(SyntaxKind.NothingKeyword)) - End Function - - Public Overrides Function DefaultExpression(type As SyntaxNode) As SyntaxNode - Return SyntaxFactory.NothingLiteralExpression(SyntaxFactory.Token(SyntaxKind.NothingKeyword)) - End Function - Public Overloads Overrides Function ElementAccessExpression(expression As SyntaxNode, arguments As IEnumerable(Of SyntaxNode)) As SyntaxNode - Return SyntaxFactory.InvocationExpression(ParenthesizeLeft(expression), CreateArgumentList(arguments)) + Return SyntaxFactory.InvocationExpression(VisualBasicSyntaxGeneratorInternal.ParenthesizeLeft(expression), CreateArgumentList(arguments)) End Function Public Overrides Function ExpressionStatement(expression As SyntaxNode) As SyntaxNode @@ -194,10 +174,6 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeGeneration SyntaxFactory.SeparatedList(typeArguments.Cast(Of TypeSyntax)()))).WithAdditionalAnnotations(Simplifier.Annotation) End Function - Public Overrides Function IdentifierName(identifier As String) As SyntaxNode - Return identifier.ToIdentifierName() - End Function - Public Overrides Function IfStatement(condition As SyntaxNode, trueStatements As IEnumerable(Of SyntaxNode), Optional falseStatements As IEnumerable(Of SyntaxNode) = Nothing) As SyntaxNode Dim ifStmt = SyntaxFactory.IfStatement(SyntaxFactory.Token(SyntaxKind.IfKeyword), @@ -250,7 +226,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeGeneration End Function Public Overloads Overrides Function InvocationExpression(expression As SyntaxNode, arguments As IEnumerable(Of SyntaxNode)) As SyntaxNode - Return SyntaxFactory.InvocationExpression(ParenthesizeLeft(expression), CreateArgumentList(arguments)) + Return SyntaxFactory.InvocationExpression(VisualBasicSyntaxGeneratorInternal.ParenthesizeLeft(expression), CreateArgumentList(arguments)) End Function Public Overrides Function IsTypeExpression(expression As SyntaxNode, type As SyntaxNode) As SyntaxNode @@ -273,13 +249,6 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeGeneration Return SyntaxFactory.OrElseExpression(Parenthesize(left), Parenthesize(right)) End Function - Friend Overrides Function MemberAccessExpressionWorker(expression As SyntaxNode, simpleName As SyntaxNode) As SyntaxNode - Return SyntaxFactory.SimpleMemberAccessExpression( - If(expression IsNot Nothing, ParenthesizeLeft(expression), Nothing), - SyntaxFactory.Token(SyntaxKind.DotToken), - DirectCast(simpleName, SimpleNameSyntax)) - End Function - Public Overrides Function ConditionalAccessExpression(expression As SyntaxNode, whenNotNull As SyntaxNode) As SyntaxNode Return SyntaxGeneratorInternal.ConditionalAccessExpression(expression, whenNotNull) End Function @@ -293,20 +262,6 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeGeneration SyntaxFactory.ArgumentList(CType(SyntaxFactory.SeparatedList(arguments), SeparatedSyntaxList(Of ArgumentSyntax)))) End Function - ' parenthesize the left-side of a dot or target of an invocation if not unnecessary - Private Shared Function ParenthesizeLeft(expression As SyntaxNode) As ExpressionSyntax - Dim expressionSyntax = DirectCast(expression, ExpressionSyntax) - If TypeOf expressionSyntax Is TypeSyntax _ - OrElse expressionSyntax.IsMeMyBaseOrMyClass() _ - OrElse expressionSyntax.IsKind(SyntaxKind.ParenthesizedExpression) _ - OrElse expressionSyntax.IsKind(SyntaxKind.InvocationExpression) _ - OrElse expressionSyntax.IsKind(SyntaxKind.SimpleMemberAccessExpression) Then - Return expressionSyntax - Else - Return expressionSyntax.Parenthesize() - End If - End Function - Public Overrides Function MultiplyExpression(left As SyntaxNode, right As SyntaxNode) As SyntaxNode Return SyntaxFactory.MultiplyExpression(Parenthesize(left), Parenthesize(right)) End Function @@ -383,11 +338,6 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeGeneration Return namespaceOrTypeSymbol.GenerateTypeSyntax() End Function - Private Protected Overrides Function TypeExpression(typeSymbol As ITypeSymbol, refKind As RefKind) As SyntaxNode - ' VB doesn't support explicit ref-kinds for types. - Return typeSymbol.GenerateTypeSyntax() - End Function - Public Overrides Function TypeExpression(specialType As SpecialType) As SyntaxNode Select Case specialType Case SpecialType.System_Boolean @@ -1446,7 +1396,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeGeneration End Function Private Shared Function AsNamespaceMembers(declarations As IEnumerable(Of SyntaxNode)) As SyntaxList(Of StatementSyntax) - Return If(declarations Is Nothing, Nothing, SyntaxFactory.List(declarations.OfType(Of StatementSyntax)().Where(Function(s) Not TypeOf s Is ImportsStatementSyntax))) + Return If(declarations Is Nothing, Nothing, SyntaxFactory.List(declarations.OfType(Of StatementSyntax)().Where(Function(s) TypeOf s IsNot ImportsStatementSyntax))) End Function Public Overrides Function NamespaceImportDeclaration(name As SyntaxNode) As SyntaxNode diff --git a/src/Workspaces/VisualBasic/Portable/Formatting/DefaultOperationProvider.vb b/src/Workspaces/VisualBasic/Portable/Formatting/DefaultOperationProvider.vb index 49c635c13a72f..2b9d4e515011e 100644 --- a/src/Workspaces/VisualBasic/Portable/Formatting/DefaultOperationProvider.vb +++ b/src/Workspaces/VisualBasic/Portable/Formatting/DefaultOperationProvider.vb @@ -183,7 +183,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Formatting If xmlDeclaration IsNot Nothing AndAlso xmlDeclaration.LessThanQuestionToken = currentToken AndAlso TypeOf xmlDeclaration.Parent Is XmlDocumentSyntax AndAlso - Not TypeOf xmlDeclaration.Parent.Parent Is XmlNodeSyntax Then + TypeOf xmlDeclaration.Parent.Parent IsNot XmlNodeSyntax Then Return True End If @@ -191,14 +191,14 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Formatting If startTag IsNot Nothing AndAlso startTag.LessThanToken = currentToken AndAlso TypeOf startTag.Parent Is XmlElementSyntax AndAlso - Not TypeOf startTag.Parent.Parent Is XmlNodeSyntax Then + TypeOf startTag.Parent.Parent IsNot XmlNodeSyntax Then Return True End If Dim emptyTag = TryCast(currentToken.Parent, XmlEmptyElementSyntax) If emptyTag IsNot Nothing AndAlso emptyTag.LessThanToken = currentToken AndAlso - Not TypeOf emptyTag.Parent Is XmlNodeSyntax Then + TypeOf emptyTag.Parent IsNot XmlNodeSyntax Then Return True End If diff --git a/src/Workspaces/VisualBasic/Portable/Formatting/Rules/ElasticTriviaFormattingRule.vb b/src/Workspaces/VisualBasic/Portable/Formatting/Rules/ElasticTriviaFormattingRule.vb index eac504169c6df..c7fcde489bde7 100644 --- a/src/Workspaces/VisualBasic/Portable/Formatting/Rules/ElasticTriviaFormattingRule.vb +++ b/src/Workspaces/VisualBasic/Portable/Formatting/Rules/ElasticTriviaFormattingRule.vb @@ -201,7 +201,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Formatting End If If AfterLastInheritsOrImplements(previousToken, currentToken) Then - If Not TypeOf currentToken.Parent Is EndBlockStatementSyntax Then + If TypeOf currentToken.Parent IsNot EndBlockStatementSyntax Then Return FormattingOperations.CreateAdjustNewLinesOperation(2, AdjustNewLinesOption.ForceLines) End If End If @@ -234,7 +234,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Formatting End If ' current one is not import statement - If Not TypeOf token.Parent Is NameSyntax Then + If TypeOf token.Parent IsNot NameSyntax Then Return False End If diff --git a/src/Workspaces/VisualBasic/Portable/Formatting/Rules/NodeBasedFormattingRule.vb b/src/Workspaces/VisualBasic/Portable/Formatting/Rules/NodeBasedFormattingRule.vb index b429560d3d29e..d20f7fea78a44 100644 --- a/src/Workspaces/VisualBasic/Portable/Formatting/Rules/NodeBasedFormattingRule.vb +++ b/src/Workspaces/VisualBasic/Portable/Formatting/Rules/NodeBasedFormattingRule.vb @@ -226,7 +226,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Formatting baseToken As SyntaxToken, startToken As SyntaxToken, endToken As SyntaxToken) - If Not TypeOf node.Parent Is XmlNodeSyntax Then + If TypeOf node.Parent IsNot XmlNodeSyntax Then SetAlignmentBlockOperation(operations, baseToken, startToken, endToken) End If @@ -241,12 +241,12 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Formatting alignmentEndToken As SyntaxToken, indentationStartToken As SyntaxToken, indentationEndToken As SyntaxToken) - If Not TypeOf xmlNode.Parent Is XmlNodeSyntax Then + If TypeOf xmlNode.Parent IsNot XmlNodeSyntax Then SetAlignmentBlockOperation(operations, baseToken, alignmentStartToken, alignmentEndToken) End If ' if parent is not xml node - If Not TypeOf xmlNode.Parent Is XmlNodeSyntax Then + If TypeOf xmlNode.Parent IsNot XmlNodeSyntax Then AddIndentBlockOperation(operations, baseToken, indentationStartToken, indentationEndToken) Return End If diff --git a/src/Workspaces/VisualBasic/Portable/LinkedFiles/BasicLinkedFileMergeConflictCommentAdditionService.vb b/src/Workspaces/VisualBasic/Portable/LinkedFiles/BasicLinkedFileMergeConflictCommentAdditionService.vb deleted file mode 100644 index dd5028bc16f55..0000000000000 --- a/src/Workspaces/VisualBasic/Portable/LinkedFiles/BasicLinkedFileMergeConflictCommentAdditionService.vb +++ /dev/null @@ -1,80 +0,0 @@ -' Licensed to the .NET Foundation under one or more agreements. -' The .NET Foundation licenses this file to you under the MIT license. -' See the LICENSE file in the project root for more information. - -Imports System.Composition -Imports System.Text -Imports System.Text.RegularExpressions -Imports Microsoft.CodeAnalysis.Host.Mef - -Namespace Microsoft.CodeAnalysis.VisualBasic - - Friend Class BasicLinkedFileMergeConflictCommentAdditionService - Inherits AbstractLinkedFileMergeConflictCommentAdditionService - - - - Public Sub New() - End Sub - - Friend Overrides Function GetConflictCommentText(header As String, beforeString As String, afterString As String) As String - If beforeString Is Nothing AndAlso afterString Is Nothing Then - Return Nothing - ElseIf beforeString Is Nothing Then - ' Added code - Return String.Format(" -' {0} -' {1} -{2} -", - header, - WorkspacesResources.Added_colon, - GetCommentedText(afterString)) - ElseIf afterString Is Nothing Then - ' Removed code - Return String.Format(" -' {0} -' {1} -{2} -", - header, - WorkspacesResources.Removed_colon, - GetCommentedText(beforeString)) - Else - Return String.Format(" -' {0} -' {1} -{2} -' {3} -{4} -", - header, - WorkspacesResources.Before_colon, - GetCommentedText(beforeString), - WorkspacesResources.After_colon, - GetCommentedText(afterString)) - - End If - End Function - - Private Shared Function GetCommentedText(text As String) As String - Dim lines = Regex.Split(text, "\r\n|\r|\n") - If Not lines.Any() Then - Return text - End If - - Dim newlines = Regex.Matches(text, "\r\n|\r|\n") - Debug.Assert(newlines.Count = lines.Length - 1) - - Dim builder = New StringBuilder() - - For i = 0 To lines.Length - 2 - builder.Append(String.Format("' {0}{1}", lines(i), newlines(i))) - Next - - builder.Append(String.Format("' {0}", lines.Last())) - - Return builder.ToString() - End Function - End Class -End Namespace diff --git a/src/Workspaces/VisualBasic/Portable/Recommendations/VisualBasicRecommendationServiceRunner.vb b/src/Workspaces/VisualBasic/Portable/Recommendations/VisualBasicRecommendationServiceRunner.vb index bcc0a31f389f2..842959d4c9c27 100644 --- a/src/Workspaces/VisualBasic/Portable/Recommendations/VisualBasicRecommendationServiceRunner.vb +++ b/src/Workspaces/VisualBasic/Portable/Recommendations/VisualBasicRecommendationServiceRunner.vb @@ -368,7 +368,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Recommendations Return associatedSymbol.Kind <> SymbolKind.Event AndAlso associatedSymbol.Kind <> SymbolKind.Property End If ElseIf s.Kind = SymbolKind.NamedType AndAlso s.IsImplicitlyDeclared Then - Return Not TypeOf DirectCast(s, INamedTypeSymbol).AssociatedSymbol Is IEventSymbol + Return TypeOf DirectCast(s, INamedTypeSymbol).AssociatedSymbol IsNot IEventSymbol End If Return True diff --git a/src/Workspaces/VisualBasic/Portable/Rename/LocalConflictVisitor.vb b/src/Workspaces/VisualBasic/Portable/Rename/LocalConflictVisitor.vb index d54f734454013..726d64620e9c4 100644 --- a/src/Workspaces/VisualBasic/Portable/Rename/LocalConflictVisitor.vb +++ b/src/Workspaces/VisualBasic/Portable/Rename/LocalConflictVisitor.vb @@ -11,12 +11,12 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Rename Inherits VisualBasicSyntaxVisitor Private ReadOnly _tracker As ConflictingIdentifierTracker - Private ReadOnly _newSolution As Solution + Private ReadOnly _semanticModel As SemanticModel Private ReadOnly _cancellationToken As CancellationToken - Public Sub New(tokenBeingRenamed As SyntaxToken, newSolution As Solution, cancellationToken As CancellationToken) + Public Sub New(tokenBeingRenamed As SyntaxToken, semanticModel As SemanticModel, cancellationToken As CancellationToken) _tracker = New ConflictingIdentifierTracker(tokenBeingRenamed, CaseInsensitiveComparison.Comparer) - _newSolution = newSolution + _semanticModel = semanticModel _cancellationToken = cancellationToken End Sub @@ -147,8 +147,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Rename ' it's only legal to have one name in the variable declarator for for and foreach loops. tokens.Add(DirectCast(controlVariable, VariableDeclaratorSyntax).Names.First().Identifier) Else - Dim semanticModel = _newSolution.GetDocument(controlVariable.SyntaxTree).GetSemanticModelAsync(_cancellationToken).WaitAndGetResult_CanCallOnBackground(_cancellationToken) - Dim symbol = semanticModel.GetSymbolInfo(controlVariable).Symbol + Dim symbol = _semanticModel.GetSymbolInfo(controlVariable, _cancellationToken).Symbol ' if it is a field we don't care If symbol IsNot Nothing AndAlso symbol.IsKind(SymbolKind.Local) Then @@ -189,11 +188,10 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Rename Public Overrides Sub VisitCatchBlock(node As CatchBlockSyntax) Dim tokens As New List(Of SyntaxToken) - Dim semanticModel = _newSolution.GetDocument(node.SyntaxTree).GetSemanticModelAsync(_cancellationToken).WaitAndGetResult_CanCallOnBackground(_cancellationToken) Dim identifierToken = node.CatchStatement.IdentifierName?.Identifier If identifierToken.HasValue Then - Dim symbol = semanticModel.GetSymbolInfo(identifierToken.Value).Symbol + Dim symbol = _semanticModel.GetSymbolInfo(identifierToken.Value, _cancellationToken).Symbol ' if it is a field we don't care If symbol IsNot Nothing AndAlso symbol.IsKind(SymbolKind.Local) Then diff --git a/src/Workspaces/VisualBasic/Portable/Rename/VisualBasicRenameRewriterLanguageService.vb b/src/Workspaces/VisualBasic/Portable/Rename/VisualBasicRenameRewriterLanguageService.vb index b263e810b1228..270760732b511 100644 --- a/src/Workspaces/VisualBasic/Portable/Rename/VisualBasicRenameRewriterLanguageService.vb +++ b/src/Workspaces/VisualBasic/Portable/Rename/VisualBasicRenameRewriterLanguageService.vb @@ -18,8 +18,7 @@ Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Imports Microsoft.CodeAnalysis.VisualBasic.Utilities Namespace Microsoft.CodeAnalysis.VisualBasic.Rename - - Friend Class VisualBasicRenameRewriterLanguageService + Friend NotInheritable Class VisualBasicRenameRewriterLanguageService Inherits AbstractRenameRewriterLanguageService Public Shared ReadOnly Instance As New VisualBasicRenameRewriterLanguageService() @@ -281,7 +280,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Rename Return newToken End Function - Private Async Function RenameAndAnnotateAsync(token As SyntaxToken, newToken As SyntaxToken, isRenameLocation As Boolean, isOldText As Boolean) As Task(Of SyntaxToken) + Private Function RenameAndAnnotate(token As SyntaxToken, newToken As SyntaxToken, isRenameLocation As Boolean, isOldText As Boolean) As SyntaxToken If newToken.IsKind(SyntaxKind.NewKeyword) Then ' The constructor definition cannot be renamed in Visual Basic Return newToken @@ -358,7 +357,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Rename End If Dim renameDeclarationLocations As RenameDeclarationLocationReference() = - Await ConflictResolver.CreateDeclarationLocationAnnotationsAsync(_solution, symbols, _cancellationToken).ConfigureAwait(False) + ConflictResolver.CreateDeclarationLocationAnnotations(_solution, symbols, _cancellationToken) Dim isNamespaceDeclarationReference = False If isRenameLocation AndAlso token.GetPreviousToken().Kind = SyntaxKind.NamespaceKeyword Then @@ -444,7 +443,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Rename IsPossibleNameConflict(_possibleNameConflicts, oldToken.ValueText) If tokenNeedsConflictCheck Then - newToken = RenameAndAnnotateAsync(oldToken, newToken, isRenameLocation, isOldText).WaitAndGetResult_CanCallOnBackground(_cancellationToken) + newToken = RenameAndAnnotate(oldToken, newToken, isRenameLocation, isOldText) If Not Me._isProcessingComplexifiedSpans Then _invocationExpressionsNeedingConflictChecks.AddRange(oldToken.GetAncestors(Of InvocationExpressionSyntax)()) @@ -487,8 +486,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Rename symbols = SpecializedCollections.SingletonEnumerable(symbolInfo.Symbol) End If - Dim renameDeclarationLocations As RenameDeclarationLocationReference() = - ConflictResolver.CreateDeclarationLocationAnnotationsAsync(_solution, symbols, _cancellationToken).WaitAndGetResult_CanCallOnBackground(_cancellationToken) + Dim renameDeclarationLocations = ConflictResolver.CreateDeclarationLocationAnnotations( + _solution, symbols, _cancellationToken) Dim renameAnnotation = New RenameActionAnnotation( identifierToken.Span, @@ -679,16 +678,15 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Rename Return False End Function - Public Overrides Function ComputeDeclarationConflictsAsync( - replacementText As String, - renamedSymbol As ISymbol, - renameSymbol As ISymbol, - referencedSymbols As IEnumerable(Of ISymbol), - baseSolution As Solution, - newSolution As Solution, - reverseMappedLocations As IDictionary(Of Location, Location), - cancellationToken As CancellationToken - ) As Task(Of ImmutableArray(Of Location)) + Public Overrides Async Function ComputeDeclarationConflictsAsync( + replacementText As String, + renamedSymbol As ISymbol, + renameSymbol As ISymbol, + referencedSymbols As IEnumerable(Of ISymbol), + baseSolution As Solution, + newSolution As Solution, + reverseMappedLocations As IDictionary(Of Location, Location), + cancellationToken As CancellationToken) As Task(Of ImmutableArray(Of Location)) Dim conflicts = ArrayBuilder(Of Location).GetInstance() @@ -700,14 +698,19 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Rename ' Find the method block or field declaration that we're in. Note the LastOrDefault ' so we find the uppermost one, since VariableDeclarators live in methods too. - Dim methodBase = token.Parent.AncestorsAndSelf.Where(Function(s) TypeOf s Is MethodBlockBaseSyntax OrElse TypeOf s Is VariableDeclaratorSyntax) _ - .LastOrDefault() - - Dim visitor As New LocalConflictVisitor(token, newSolution, cancellationToken) - visitor.Visit(methodBase) - - conflicts.AddRange(visitor.ConflictingTokens.Select(Function(t) t.GetLocation()) _ - .Select(Function(loc) reverseMappedLocations(loc))) + Dim methodBase = token.Parent. + AncestorsAndSelf(). + Where(Function(s) TypeOf s Is MethodBlockBaseSyntax OrElse TypeOf s Is VariableDeclaratorSyntax). + LastOrDefault() + + If methodBase IsNot Nothing Then + Dim semanticModel = Await newSolution. + GetRequiredDocument(methodBase.SyntaxTree). + GetSemanticModelAsync(cancellationToken).ConfigureAwait(False) + Dim visitor As New LocalConflictVisitor(token, semanticModel, cancellationToken) + visitor.Visit(methodBase) + conflicts.AddRange(visitor.ConflictingTokens.Select(Function(t) t.GetLocation()).Select(Function(loc) reverseMappedLocations(loc))) + End If ' If this is a parameter symbol for a partial method definition, be sure we visited ' the implementation part's body. @@ -719,11 +722,16 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Rename token = matchingParameterSymbol.Locations.Single().FindToken(cancellationToken) methodBase = token.GetAncestor(Of MethodBlockSyntax) - visitor = New LocalConflictVisitor(token, newSolution, cancellationToken) - visitor.Visit(methodBase) - conflicts.AddRange(visitor.ConflictingTokens.Select(Function(t) t.GetLocation()) _ - .Select(Function(loc) reverseMappedLocations(loc))) + If methodBase IsNot Nothing Then + Dim semanticModel = Await newSolution. + GetRequiredDocument(methodBase.SyntaxTree). + GetSemanticModelAsync(cancellationToken).ConfigureAwait(False) + Dim visitor = New LocalConflictVisitor(token, semanticModel, cancellationToken) + visitor.Visit(methodBase) + + conflicts.AddRange(visitor.ConflictingTokens.Select(Function(t) t.GetLocation()).Select(Function(loc) reverseMappedLocations(loc))) + End If End If End If @@ -792,7 +800,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Rename Next End If - Return Task.FromResult(conflicts.ToImmutableAndFree()) + Return conflicts.ToImmutableAndFree() End Function Public Overrides Async Function ComputeImplicitReferenceConflictsAsync( diff --git a/src/Workspaces/VisualBasic/Portable/Simplification/Reducers/VisualBasicCastReducer.vb b/src/Workspaces/VisualBasic/Portable/Simplification/Reducers/VisualBasicCastReducer.vb index a11ab9f3e84b1..6336cf3d77b43 100644 --- a/src/Workspaces/VisualBasic/Portable/Simplification/Reducers/VisualBasicCastReducer.vb +++ b/src/Workspaces/VisualBasic/Portable/Simplification/Reducers/VisualBasicCastReducer.vb @@ -3,7 +3,6 @@ ' See the LICENSE file in the project root for more information. Imports System.Threading -Imports Microsoft.CodeAnalysis.Options Imports Microsoft.CodeAnalysis.PooledObjects Imports Microsoft.CodeAnalysis.Simplification Imports Microsoft.CodeAnalysis.VisualBasic.Syntax diff --git a/src/Workspaces/VisualBasic/Portable/Simplification/Reducers/VisualBasicEscapingReducer.vb b/src/Workspaces/VisualBasic/Portable/Simplification/Reducers/VisualBasicEscapingReducer.vb index 9646191cfa63f..4ec5796c97fd7 100644 --- a/src/Workspaces/VisualBasic/Portable/Simplification/Reducers/VisualBasicEscapingReducer.vb +++ b/src/Workspaces/VisualBasic/Portable/Simplification/Reducers/VisualBasicEscapingReducer.vb @@ -50,7 +50,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Simplification ' Always escape keywords as identifier if they are not part of a qualified name or member access ' e.g. Class [Class] - If Not TypeOf (parent) Is ExpressionSyntax Then + If TypeOf (parent) IsNot ExpressionSyntax Then Return identifier Else ' always escape keywords on the left side of a dot diff --git a/src/Workspaces/VisualBasic/Portable/Simplification/Reducers/VisualBasicExtensionMethodReducer.vb b/src/Workspaces/VisualBasic/Portable/Simplification/Reducers/VisualBasicExtensionMethodReducer.vb index 8bd16d2d385b1..24ee11bf608f1 100644 --- a/src/Workspaces/VisualBasic/Portable/Simplification/Reducers/VisualBasicExtensionMethodReducer.vb +++ b/src/Workspaces/VisualBasic/Portable/Simplification/Reducers/VisualBasicExtensionMethodReducer.vb @@ -37,7 +37,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Simplification Dim memberAccess = DirectCast(invocationExpression.Expression, MemberAccessExpressionSyntax) Dim targetSymbol = semanticModel.GetSymbolInfo(memberAccess.Name, cancellationToken) - If (Not targetSymbol.Symbol Is Nothing) AndAlso targetSymbol.Symbol.Kind = SymbolKind.Method Then + If (targetSymbol.Symbol IsNot Nothing) AndAlso targetSymbol.Symbol.Kind = SymbolKind.Method Then Dim targetMethodSymbol = DirectCast(targetSymbol.Symbol, IMethodSymbol) If Not targetMethodSymbol.IsReducedExtension() Then Dim argumentList = invocationExpression.ArgumentList @@ -59,7 +59,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Simplification candidateRewrittenNode, SpeculativeBindingOption.BindAsExpression).Symbol - If Not oldSymbol Is Nothing And Not newSymbol Is Nothing Then + If oldSymbol IsNot Nothing And newSymbol IsNot Nothing Then If newSymbol.Kind = SymbolKind.Method And oldSymbol.Equals(DirectCast(newSymbol, IMethodSymbol).GetConstructedReducedFrom()) Then rewrittenNode = candidateRewrittenNode End If diff --git a/src/Workspaces/VisualBasic/Portable/Simplification/Reducers/VisualBasicVariableDeclaratorReducer.vb b/src/Workspaces/VisualBasic/Portable/Simplification/Reducers/VisualBasicVariableDeclaratorReducer.vb index 6e1271f8d602d..247431b559bac 100644 --- a/src/Workspaces/VisualBasic/Portable/Simplification/Reducers/VisualBasicVariableDeclaratorReducer.vb +++ b/src/Workspaces/VisualBasic/Portable/Simplification/Reducers/VisualBasicVariableDeclaratorReducer.vb @@ -146,7 +146,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Simplification Dim declaredSymbol = semanticModel.GetDeclaredSymbol(modifiedIdentifier) If declaredSymbol Is Nothing OrElse - (Not TypeOf declaredSymbol Is ILocalSymbol AndAlso Not TypeOf declaredSymbol Is IFieldSymbol) Then + (TypeOf declaredSymbol IsNot ILocalSymbol AndAlso TypeOf declaredSymbol IsNot IFieldSymbol) Then Return False End If diff --git a/src/Workspaces/VisualBasic/Portable/Simplification/Simplifiers/AbstractVisualBasicSimplifier.vb b/src/Workspaces/VisualBasic/Portable/Simplification/Simplifiers/AbstractVisualBasicSimplifier.vb index 07a47d4bfdef6..20748ca737186 100644 --- a/src/Workspaces/VisualBasic/Portable/Simplification/Simplifiers/AbstractVisualBasicSimplifier.vb +++ b/src/Workspaces/VisualBasic/Portable/Simplification/Simplifiers/AbstractVisualBasicSimplifier.vb @@ -85,7 +85,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Simplification.Simplifiers Dim aliasTypeInfo = semanticModel.GetSpeculativeAliasInfo(node.SpanStart, aliasIdentifier, SpeculativeBindingOption.BindAsTypeOrNamespace) - If Not aliasTypeInfo Is Nothing Then + If aliasTypeInfo IsNot Nothing Then aliasReplacement = aliasTypeInfo Return ValidateAliasForTarget(aliasReplacement, semanticModel, node, symbol) End If @@ -103,7 +103,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Simplification.Simplifiers Return False End If - If symbol Is Nothing OrElse Not TypeOf (symbol) Is INamespaceOrTypeSymbol Then + If symbol Is Nothing OrElse TypeOf (symbol) IsNot INamespaceOrTypeSymbol Then Return False End If @@ -113,7 +113,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Simplification.Simplifiers Dim qualifiedName = DirectCast(node, QualifiedNameSyntax) If Not qualifiedName.Right.HasAnnotation(Simplifier.SpecialTypeAnnotation) Then Dim type = semanticModel.GetTypeInfo(node).Type - If Not type Is Nothing Then + If type IsNot Nothing Then Dim keywordKind = GetPredefinedKeywordKind(type.SpecialType) If keywordKind <> SyntaxKind.None Then preferAliasToQualifiedName = False diff --git a/src/Workspaces/VisualBasic/Portable/Simplification/Simplifiers/ExpressionSimplifier.vb b/src/Workspaces/VisualBasic/Portable/Simplification/Simplifiers/ExpressionSimplifier.vb index a949101fa2470..5d59bc8eeecd9 100644 --- a/src/Workspaces/VisualBasic/Portable/Simplification/Simplifiers/ExpressionSimplifier.vb +++ b/src/Workspaces/VisualBasic/Portable/Simplification/Simplifiers/ExpressionSimplifier.vb @@ -198,7 +198,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Simplification.Simplifiers Dim qualifiedName = DirectCast(expression, QualifiedNameSyntax) Dim newLeft As ExpressionSyntax = Nothing If TrySimplifyMemberAccessOrQualifiedName(qualifiedName.Left, qualifiedName.Right, semanticModel, newLeft, issueSpan) Then - If Not TypeOf newLeft Is NameSyntax Then + If TypeOf newLeft IsNot NameSyntax Then Contract.Fail("QualifiedName Left = " + qualifiedName.Left.ToString() + " and QualifiedName Right = " + qualifiedName.Right.ToString() + " . Left is tried to be replaced with the PredefinedType " + replacementNode.ToString()) End If diff --git a/src/Workspaces/VisualBasic/Portable/Simplification/Simplifiers/NameSimplifier.vb b/src/Workspaces/VisualBasic/Portable/Simplification/Simplifiers/NameSimplifier.vb index 6220d00a10197..ff296801f59ae 100644 --- a/src/Workspaces/VisualBasic/Portable/Simplification/Simplifiers/NameSimplifier.vb +++ b/src/Workspaces/VisualBasic/Portable/Simplification/Simplifiers/NameSimplifier.vb @@ -51,7 +51,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Simplification.Simplifiers Return CanReplaceWithReducedName(name, replacementNode, semanticModel, cancellationToken) End If - If Not TypeOf symbol Is INamespaceOrTypeSymbol Then + If TypeOf symbol IsNot INamespaceOrTypeSymbol Then Return False End If Else @@ -313,7 +313,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Simplification.Simplifiers Private Shared Function IsNonNameSyntaxInImportsDirective(expression As ExpressionSyntax, simplifiedNode As ExpressionSyntax) As Boolean Return TypeOf expression.Parent Is ImportsClauseSyntax AndAlso - Not TypeOf simplifiedNode Is NameSyntax + TypeOf simplifiedNode IsNot NameSyntax End Function Private Shared Function IsNullableTypeSyntaxLeftOfDotInMemberAccess(expression As ExpressionSyntax, simplifiedNode As ExpressionSyntax) As Boolean diff --git a/src/Workspaces/VisualBasic/Portable/Simplification/VisualBasicSimplificationService.Expander.vb b/src/Workspaces/VisualBasic/Portable/Simplification/VisualBasicSimplificationService.Expander.vb index 017e41d1bebb2..ad535834eb03c 100644 --- a/src/Workspaces/VisualBasic/Portable/Simplification/VisualBasicSimplificationService.Expander.vb +++ b/src/Workspaces/VisualBasic/Portable/Simplification/VisualBasicSimplificationService.Expander.vb @@ -208,7 +208,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Simplification Dim memberAccess = DirectCast(node.Expression, MemberAccessExpressionSyntax) Dim targetSymbol = SimplificationHelpers.GetOriginalSymbolInfo(_semanticModel, memberAccess.Name) - If Not targetSymbol Is Nothing And targetSymbol.IsReducedExtension() AndAlso memberAccess.Expression IsNot Nothing Then + If targetSymbol IsNot Nothing And targetSymbol.IsReducedExtension() AndAlso memberAccess.Expression IsNot Nothing Then newInvocationExpression = RewriteExtensionMethodInvocation(node, newInvocationExpression, memberAccess.Expression, DirectCast(newInvocationExpression.Expression, MemberAccessExpressionSyntax).Expression, DirectCast(targetSymbol, IMethodSymbol)) End If End If @@ -235,7 +235,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Simplification Dim binding = _semanticModel.GetSpeculativeSymbolInfo(originalNode.SpanStart, expression, SpeculativeBindingOption.BindAsExpression) - If (Not binding.Symbol Is Nothing) Then + If (binding.Symbol IsNot Nothing) Then Return expression End If @@ -562,7 +562,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Simplification End If End If - Dim symbol = _semanticModel.GetSymbolInfo(originalSimpleName.Identifier).Symbol + Dim symbol = _semanticModel.GetSymbolInfo(originalSimpleName.Identifier, _cancellationToken).Symbol If symbol Is Nothing Then Return newNode End If @@ -613,7 +613,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Simplification ' do not complexify further for location where only simple names are allowed If (TypeOf (parent) Is FieldInitializerSyntax) OrElse - ((TypeOf (parent) Is DeclarationStatementSyntax) AndAlso Not TypeOf (parent) Is InheritsOrImplementsStatementSyntax) OrElse + ((TypeOf (parent) Is DeclarationStatementSyntax) AndAlso TypeOf (parent) IsNot InheritsOrImplementsStatementSyntax) OrElse (TypeOf (parent) Is MemberAccessExpressionSyntax AndAlso parent.Kind <> SyntaxKind.SimpleMemberAccessExpression) OrElse (parent.Kind = SyntaxKind.SimpleMemberAccessExpression AndAlso originalSimpleName.IsRightSideOfDot()) OrElse (parent.Kind = SyntaxKind.QualifiedName AndAlso originalSimpleName.IsRightSideOfQualifiedName()) Then